home *** CD-ROM | disk | FTP | other *** search
/ Programming a Multiplayer FPS in DirectX / Programming a Multiplayer FPS in DirectX (Companion CD).iso / DirectX / dxsdk_oct2004.exe / dxsdk.exe / Include / strsafe.h < prev    next >
Encoding:
C/C++ Source or Header  |  2004-04-01  |  216.0 KB  |  6,612 lines

  1. /******************************************************************
  2. *                                                                 *
  3. *  strsafe.h -- This module defines safer C library string        *
  4. *               routine replacements. These are meant to make C   *
  5. *               a bit more safe in reference to security and      *
  6. *               robustness                                        *
  7. *                                                                 *
  8. *  Copyright (c) Microsoft Corp.  All rights reserved.            *
  9. *                                                                 *
  10. ******************************************************************/
  11. #ifndef _STRSAFE_H_INCLUDED_
  12. #define _STRSAFE_H_INCLUDED_
  13. #pragma once
  14.  
  15. #include <stdio.h>      // for _vsnprintf, _vsnwprintf, getc, getwc
  16. #include <string.h>     // for memset
  17. #include <stdarg.h>     // for va_start, etc.
  18.  
  19.  
  20. #ifndef _SIZE_T_DEFINED
  21. #ifdef  _WIN64
  22. typedef unsigned __int64    size_t;
  23. #else
  24. typedef __w64 unsigned int  size_t;
  25. #endif  // !_WIN64
  26. #define _SIZE_T_DEFINED
  27. #endif  // !_SIZE_T_DEFINED
  28.  
  29. #if !defined(_WCHAR_T_DEFINED) && !defined(_NATIVE_WCHAR_T_DEFINED)
  30. typedef unsigned short wchar_t;
  31. #define _WCHAR_T_DEFINED
  32. #endif
  33.  
  34. #ifndef _HRESULT_DEFINED
  35. #define _HRESULT_DEFINED
  36. typedef long HRESULT;
  37. #endif // !_HRESULT_DEFINED
  38.  
  39. #ifndef SUCCEEDED
  40. #define SUCCEEDED(hr)  ((HRESULT)(hr) >= 0)
  41. #endif
  42.  
  43. #ifndef FAILED
  44. #define FAILED(hr)  ((HRESULT)(hr) < 0)
  45. #endif
  46.  
  47. #ifndef S_OK
  48. #define S_OK  ((HRESULT)0x00000000L)
  49. #endif
  50.  
  51. #ifdef __cplusplus
  52. #define _STRSAFE_EXTERN_C    extern "C"
  53. #else
  54. #define _STRSAFE_EXTERN_C    extern
  55. #endif
  56.  
  57. // If you do not want to use these functions inline (and instead want to link w/ strsafe.lib), then
  58. // #define STRSAFE_LIB before including this header file.
  59. #if defined(STRSAFE_LIB)
  60. #define STRSAFEAPI  _STRSAFE_EXTERN_C HRESULT __stdcall
  61. #pragma comment(lib, "strsafe.lib")
  62. #elif defined(STRSAFE_LIB_IMPL)
  63. #define STRSAFEAPI  _STRSAFE_EXTERN_C HRESULT __stdcall
  64. #else
  65. #define STRSAFEAPI  __inline HRESULT __stdcall
  66. #define STRSAFE_INLINE
  67. #endif
  68.  
  69. // Some functions always run inline because they use stdin and we want to avoid building multiple
  70. // versions of strsafe lib depending on if you use msvcrt, libcmt, etc.
  71. #define STRSAFE_INLINE_API  __inline HRESULT __stdcall
  72.  
  73. // The user can request no "Cb" or no "Cch" fuctions, but not both!
  74. #if defined(STRSAFE_NO_CB_FUNCTIONS) && defined(STRSAFE_NO_CCH_FUNCTIONS)
  75. #error cannot specify both STRSAFE_NO_CB_FUNCTIONS and STRSAFE_NO_CCH_FUNCTIONS !!
  76. #endif
  77.  
  78. // This should only be defined when we are building strsafe.lib
  79. #ifdef STRSAFE_LIB_IMPL
  80. #define STRSAFE_INLINE
  81. #endif
  82.  
  83.  
  84. // If both strsafe.h and ntstrsafe.h are included, only use definitions from one.
  85. #ifndef _NTSTRSAFE_H_INCLUDED_
  86.  
  87. #define STRSAFE_MAX_CCH  2147483647 // max # of characters we support (same as INT_MAX)
  88.  
  89. // Flags for controling the Ex functions
  90. //
  91. //      STRSAFE_FILL_BYTE(0xFF)     0x000000FF  // bottom byte specifies fill pattern
  92. #define STRSAFE_IGNORE_NULLS        0x00000100  // treat null as TEXT("") -- don't fault on NULL buffers
  93. #define STRSAFE_FILL_BEHIND_NULL    0x00000200  // fill in extra space behind the null terminator
  94. #define STRSAFE_FILL_ON_FAILURE     0x00000400  // on failure, overwrite pszDest with fill pattern and null terminate it
  95. #define STRSAFE_NULL_ON_FAILURE     0x00000800  // on failure, set *pszDest = TEXT('\0')
  96. #define STRSAFE_NO_TRUNCATION       0x00001000  // instead of returning a truncated result, copy/append nothing to pszDest and null terminate it
  97.  
  98. #define STRSAFE_VALID_FLAGS         (0x000000FF | STRSAFE_IGNORE_NULLS | STRSAFE_FILL_BEHIND_NULL | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION)
  99.  
  100. // helper macro to set the fill character and specify buffer filling
  101. #define STRSAFE_FILL_BYTE(x)        ((unsigned long)((x & 0x000000FF) | STRSAFE_FILL_BEHIND_NULL))
  102. #define STRSAFE_FAILURE_BYTE(x)     ((unsigned long)((x & 0x000000FF) | STRSAFE_FILL_ON_FAILURE))
  103.  
  104. #define STRSAFE_GET_FILL_PATTERN(dwFlags)  ((int)(dwFlags & 0x000000FF))
  105.  
  106. #endif // _NTSTRSAFE_H_INCLUDED_
  107.  
  108. // STRSAFE error return codes
  109. //
  110. #define STRSAFE_E_INSUFFICIENT_BUFFER       ((HRESULT)0x8007007AL)  // 0x7A = 122L = ERROR_INSUFFICIENT_BUFFER
  111. #define STRSAFE_E_INVALID_PARAMETER         ((HRESULT)0x80070057L)  // 0x57 =  87L = ERROR_INVALID_PARAMETER
  112. #define STRSAFE_E_END_OF_FILE               ((HRESULT)0x80070026L)  // 0x26 =  38L = ERROR_HANDLE_EOF
  113.  
  114. // prototypes for the worker functions
  115. #ifdef STRSAFE_INLINE
  116. STRSAFEAPI StringCopyWorkerA(char* pszDest, size_t cchDest, const char* pszSrc);
  117. STRSAFEAPI StringCopyWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc);
  118. STRSAFEAPI StringCopyExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  119. STRSAFEAPI StringCopyExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  120. STRSAFEAPI StringCopyNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc);
  121. STRSAFEAPI StringCopyNWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc);
  122. STRSAFEAPI StringCopyNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  123. STRSAFEAPI StringCopyNExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, size_t cchSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  124. STRSAFEAPI StringCatWorkerA(char* pszDest, size_t cchDest, const char* pszSrc);
  125. STRSAFEAPI StringCatWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc);
  126. STRSAFEAPI StringCatExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  127. STRSAFEAPI StringCatExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  128. STRSAFEAPI StringCatNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend);
  129. STRSAFEAPI StringCatNWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend);
  130. STRSAFEAPI StringCatNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  131. STRSAFEAPI StringCatNExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, size_t cchMaxAppend, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  132. STRSAFEAPI StringVPrintfWorkerA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList);
  133. STRSAFEAPI StringVPrintfWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, va_list argList);
  134. STRSAFEAPI StringVPrintfExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList);
  135. STRSAFEAPI StringVPrintfExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList);
  136. STRSAFEAPI StringLengthWorkerA(const char* psz, size_t cchMax, size_t* pcch);
  137. STRSAFEAPI StringLengthWorkerW(const wchar_t* psz, size_t cchMax, size_t* pcch);
  138. #endif  // STRSAFE_INLINE
  139.  
  140. #ifndef STRSAFE_LIB_IMPL
  141. // these functions are always inline
  142. STRSAFE_INLINE_API StringGetsExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  143. STRSAFE_INLINE_API StringGetsExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  144. #endif
  145.  
  146. #ifdef _NTSTRSAFE_H_INCLUDED_
  147. #pragma warning(push)
  148. #pragma warning(disable : 4995)
  149. #endif // _NTSTRSAFE_H_INCLUDED_
  150.  
  151.  
  152. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  153. /*++
  154.  
  155. STDAPI
  156. StringCchCopy(
  157.     OUT LPTSTR  pszDest,
  158.     IN  size_t  cchDest,
  159.     IN  LPCTSTR pszSrc
  160.     );
  161.  
  162. Routine Description:
  163.  
  164.     This routine is a safer version of the C built-in function 'strcpy'.
  165.     The size of the destination buffer (in characters) is a parameter and
  166.     this function will not write past the end of this buffer and it will
  167.     ALWAYS null terminate the destination buffer (unless it is zero length).
  168.  
  169.     This routine is not a replacement for strncpy.  That function will pad the
  170.     destination string with extra null termination characters if the count is
  171.     greater than the length of the source string, and it will fail to null
  172.     terminate the destination string if the source string length is greater
  173.     than or equal to the count. You can not blindly use this instead of strncpy:
  174.     it is common for code to use it to "patch" strings and you would introduce
  175.     errors if the code started null terminating in the middle of the string.
  176.  
  177.     This function returns a hresult, and not a pointer.  It returns
  178.     S_OK if the string was copied without truncation and null terminated,
  179.     otherwise it will return a failure code. In failure cases as much of
  180.     pszSrc will be copied to pszDest as possible, and pszDest will be null
  181.     terminated.
  182.  
  183. Arguments:
  184.  
  185.     pszDest        -   destination string
  186.  
  187.     cchDest        -   size of destination buffer in characters.
  188.                        length must be = (_tcslen(src) + 1) to hold all of the
  189.                        source including the null terminator
  190.  
  191.     pszSrc         -   source string which must be null terminated
  192.  
  193. Notes:
  194.     Behavior is undefined if source and destination strings overlap.
  195.  
  196.     pszDest and pszSrc should not be NULL. See StringCchCopyEx if you require
  197.     the handling of NULL values.
  198.  
  199. Return Value:
  200.  
  201.     S_OK           -   if there was source data and it was all copied and the
  202.                        resultant dest string was null terminated
  203.  
  204.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  205.                        error code for all hresult failure cases
  206.  
  207.       STRSAFE_E_INSUFFICIENT_BUFFER /
  208.       HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  209.                    -   this return value is an indication that the copy
  210.                        operation failed due to insufficient space. When this
  211.                        error occurs, the destination buffer is modified to
  212.                        contain a truncated version of the ideal result and is
  213.                        null terminated. This is useful for situations where
  214.                        truncation is ok
  215.  
  216.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  217.     return value of this function.
  218.  
  219. --*/
  220.  
  221. STRSAFEAPI StringCchCopyA(char* pszDest, size_t cchDest, const char* pszSrc);
  222. STRSAFEAPI StringCchCopyW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc);
  223. #ifdef UNICODE
  224. #define StringCchCopy  StringCchCopyW
  225. #else
  226. #define StringCchCopy  StringCchCopyA
  227. #endif // !UNICODE
  228.  
  229. #ifdef STRSAFE_INLINE
  230. STRSAFEAPI StringCchCopyA(char* pszDest, size_t cchDest, const char* pszSrc)
  231. {
  232.     HRESULT hr;
  233.  
  234.     if (cchDest > STRSAFE_MAX_CCH)
  235.     {
  236.         hr = STRSAFE_E_INVALID_PARAMETER;
  237.     }
  238.     else
  239.     {
  240.         hr = StringCopyWorkerA(pszDest, cchDest, pszSrc);
  241.     }
  242.  
  243.     return hr;
  244. }
  245.  
  246. STRSAFEAPI StringCchCopyW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc)
  247. {
  248.     HRESULT hr;
  249.  
  250.     if (cchDest > STRSAFE_MAX_CCH)
  251.     {
  252.         hr = STRSAFE_E_INVALID_PARAMETER;
  253.     }
  254.     else
  255.     {
  256.         hr = StringCopyWorkerW(pszDest, cchDest, pszSrc);
  257.     }
  258.  
  259.     return hr;
  260. }
  261. #endif  // STRSAFE_INLINE
  262. #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  263.  
  264.  
  265. #ifndef STRSAFE_NO_CB_FUNCTIONS
  266. /*++
  267.  
  268. STDAPI
  269. StringCbCopy(
  270.     OUT LPTSTR pszDest,
  271.     IN  size_t cbDest,
  272.     IN  LPCTSTR pszSrc
  273.     );
  274.  
  275. Routine Description:
  276.  
  277.     This routine is a safer version of the C built-in function 'strcpy'.
  278.     The size of the destination buffer (in bytes) is a parameter and this
  279.     function will not write past the end of this buffer and it will ALWAYS
  280.     null terminate the destination buffer (unless it is zero length).
  281.  
  282.     This routine is not a replacement for strncpy.  That function will pad the
  283.     destination string with extra null termination characters if the count is
  284.     greater than the length of the source string, and it will fail to null
  285.     terminate the destination string if the source string length is greater
  286.     than or equal to the count. You can not blindly use this instead of strncpy:
  287.     it is common for code to use it to "patch" strings and you would introduce
  288.     errors if the code started null terminating in the middle of the string.
  289.  
  290.     This function returns a hresult, and not a pointer.  It returns
  291.     S_OK if the string was copied without truncation and null terminated,
  292.     otherwise it will return a failure code. In failure cases as much of pszSrc
  293.     will be copied to pszDest as possible, and pszDest will be null terminated.
  294.  
  295. Arguments:
  296.  
  297.     pszDest        -   destination string
  298.  
  299.     cbDest         -   size of destination buffer in bytes.
  300.                        length must be = ((_tcslen(src) + 1) * sizeof(TCHAR)) to
  301.                        hold all of the source including the null terminator
  302.  
  303.     pszSrc         -   source string which must be null terminated
  304.  
  305. Notes:
  306.     Behavior is undefined if source and destination strings overlap.
  307.  
  308.     pszDest and pszSrc should not be NULL.  See StringCbCopyEx if you require
  309.     the handling of NULL values.
  310.  
  311. Return Value:
  312.  
  313.     S_OK           -   if there was source data and it was all copied and the
  314.                        resultant dest string was null terminated
  315.  
  316.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  317.                        error code for all hresult failure cases
  318.  
  319.       STRSAFE_E_INSUFFICIENT_BUFFER /
  320.       HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  321.                    -   this return value is an indication that the copy
  322.                        operation failed due to insufficient space. When this
  323.                        error occurs, the destination buffer is modified to
  324.                        contain a truncated version of the ideal result and is
  325.                        null terminated. This is useful for situations where
  326.                        truncation is ok
  327.  
  328.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  329.     return value of this function.
  330.  
  331. --*/
  332.  
  333. STRSAFEAPI StringCbCopyA(char* pszDest, size_t cbDest, const char* pszSrc);
  334. STRSAFEAPI StringCbCopyW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc);
  335. #ifdef UNICODE
  336. #define StringCbCopy  StringCbCopyW
  337. #else
  338. #define StringCbCopy  StringCbCopyA
  339. #endif // !UNICODE
  340.  
  341. #ifdef STRSAFE_INLINE
  342. STRSAFEAPI StringCbCopyA(char* pszDest, size_t cbDest, const char* pszSrc)
  343. {
  344.     HRESULT hr;
  345.     size_t cchDest;
  346.  
  347.     // convert to count of characters
  348.     cchDest = cbDest / sizeof(char);
  349.  
  350.     if (cchDest > STRSAFE_MAX_CCH)
  351.     {
  352.         hr = STRSAFE_E_INVALID_PARAMETER;
  353.     }
  354.     else
  355.     {
  356.         hr = StringCopyWorkerA(pszDest, cchDest, pszSrc);
  357.     }
  358.  
  359.     return hr;
  360. }
  361.  
  362. STRSAFEAPI StringCbCopyW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc)
  363. {
  364.     HRESULT hr;
  365.     size_t cchDest;
  366.  
  367.     // convert to count of characters
  368.     cchDest = cbDest / sizeof(wchar_t);
  369.  
  370.     if (cchDest > STRSAFE_MAX_CCH)
  371.     {
  372.         hr = STRSAFE_E_INVALID_PARAMETER;
  373.     }
  374.     else
  375.     {
  376.         hr = StringCopyWorkerW(pszDest, cchDest, pszSrc);
  377.     }
  378.  
  379.     return hr;
  380. }
  381. #endif  // STRSAFE_INLINE
  382. #endif  // !STRSAFE_NO_CB_FUNCTIONS
  383.  
  384.  
  385. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  386. /*++
  387.  
  388. STDAPI
  389. StringCchCopyEx(
  390.     OUT LPTSTR  pszDest         OPTIONAL,
  391.     IN  size_t  cchDest,
  392.     IN  LPCTSTR pszSrc          OPTIONAL,
  393.     OUT LPTSTR* ppszDestEnd     OPTIONAL,
  394.     OUT size_t* pcchRemaining   OPTIONAL,
  395.     IN  DWORD   dwFlags
  396.     );
  397.  
  398. Routine Description:
  399.  
  400.     This routine is a safer version of the C built-in function 'strcpy' with
  401.     some additional parameters.  In addition to functionality provided by
  402.     StringCchCopy, this routine also returns a pointer to the end of the
  403.     destination string and the number of characters left in the destination string
  404.     including the null terminator. The flags parameter allows additional controls.
  405.  
  406. Arguments:
  407.  
  408.     pszDest         -   destination string
  409.  
  410.     cchDest         -   size of destination buffer in characters.
  411.                         length must be = (_tcslen(pszSrc) + 1) to hold all of
  412.                         the source including the null terminator
  413.  
  414.     pszSrc          -   source string which must be null terminated
  415.  
  416.     ppszDestEnd     -   if ppszDestEnd is non-null, the function will return a
  417.                         pointer to the end of the destination string.  If the
  418.                         function copied any data, the result will point to the
  419.                         null termination character
  420.  
  421.     pcchRemaining   -   if pcchRemaining is non-null, the function will return the
  422.                         number of characters left in the destination string,
  423.                         including the null terminator
  424.  
  425.     dwFlags         -   controls some details of the string copy:
  426.  
  427.         STRSAFE_FILL_BEHIND_NULL
  428.                     if the function succeeds, the low byte of dwFlags will be
  429.                     used to fill the uninitialize part of destination buffer
  430.                     behind the null terminator
  431.  
  432.         STRSAFE_IGNORE_NULLS
  433.                     treat NULL string pointers like empty strings (TEXT("")).
  434.                     this flag is useful for emulating functions like lstrcpy
  435.  
  436.         STRSAFE_FILL_ON_FAILURE
  437.                     if the function fails, the low byte of dwFlags will be
  438.                     used to fill all of the destination buffer, and it will
  439.                     be null terminated. This will overwrite any truncated
  440.                     string returned when the failure is
  441.                     STRSAFE_E_INSUFFICIENT_BUFFER
  442.  
  443.         STRSAFE_NO_TRUNCATION /
  444.         STRSAFE_NULL_ON_FAILURE
  445.                     if the function fails, the destination buffer will be set
  446.                     to the empty string. This will overwrite any truncated string
  447.                     returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
  448.  
  449. Notes:
  450.     Behavior is undefined if source and destination strings overlap.
  451.  
  452.     pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  453.     is specified.  If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  454.     may be NULL.  An error may still be returned even though NULLS are ignored
  455.     due to insufficient space.
  456.  
  457. Return Value:
  458.  
  459.     S_OK           -   if there was source data and it was all copied and the
  460.                        resultant dest string was null terminated
  461.  
  462.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  463.                        error code for all hresult failure cases
  464.  
  465.       STRSAFE_E_INSUFFICIENT_BUFFER /
  466.       HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  467.                    -   this return value is an indication that the copy
  468.                        operation failed due to insufficient space. When this
  469.                        error occurs, the destination buffer is modified to
  470.                        contain a truncated version of the ideal result and is
  471.                        null terminated. This is useful for situations where
  472.                        truncation is ok.
  473.  
  474.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  475.     return value of this function
  476.  
  477. --*/
  478.  
  479. STRSAFEAPI StringCchCopyExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  480. STRSAFEAPI StringCchCopyExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  481. #ifdef UNICODE
  482. #define StringCchCopyEx  StringCchCopyExW
  483. #else
  484. #define StringCchCopyEx  StringCchCopyExA
  485. #endif // !UNICODE
  486.  
  487. #ifdef STRSAFE_INLINE
  488. STRSAFEAPI StringCchCopyExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  489. {
  490.     HRESULT hr;
  491.  
  492.     if (cchDest > STRSAFE_MAX_CCH)
  493.     {
  494.         hr = STRSAFE_E_INVALID_PARAMETER;
  495.     }
  496.     else
  497.     {
  498.         size_t cbDest;
  499.  
  500.         // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
  501.         cbDest = cchDest * sizeof(char);
  502.  
  503.         hr = StringCopyExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
  504.     }
  505.  
  506.     return hr;
  507. }
  508.  
  509. STRSAFEAPI StringCchCopyExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  510. {
  511.     HRESULT hr;
  512.  
  513.     if (cchDest > STRSAFE_MAX_CCH)
  514.     {
  515.         hr = STRSAFE_E_INVALID_PARAMETER;
  516.     }
  517.     else
  518.     {
  519.         size_t cbDest;
  520.  
  521.         // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  522.         cbDest = cchDest * sizeof(wchar_t);
  523.  
  524.         hr = StringCopyExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
  525.     }
  526.  
  527.     return hr;
  528. }
  529. #endif  // STRSAFE_INLINE
  530. #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  531.  
  532.  
  533. #ifndef STRSAFE_NO_CB_FUNCTIONS
  534. /*++
  535.  
  536. STDAPI
  537. StringCbCopyEx(
  538.     OUT LPTSTR  pszDest         OPTIONAL,
  539.     IN  size_t  cbDest,
  540.     IN  LPCTSTR pszSrc          OPTIONAL,
  541.     OUT LPTSTR* ppszDestEnd     OPTIONAL,
  542.     OUT size_t* pcbRemaining    OPTIONAL,
  543.     IN  DWORD   dwFlags
  544.     );
  545.  
  546. Routine Description:
  547.  
  548.     This routine is a safer version of the C built-in function 'strcpy' with
  549.     some additional parameters.  In addition to functionality provided by
  550.     StringCbCopy, this routine also returns a pointer to the end of the
  551.     destination string and the number of bytes left in the destination string
  552.     including the null terminator. The flags parameter allows additional controls.
  553.  
  554. Arguments:
  555.  
  556.     pszDest         -   destination string
  557.  
  558.     cbDest          -   size of destination buffer in bytes.
  559.                         length must be ((_tcslen(pszSrc) + 1) * sizeof(TCHAR)) to
  560.                         hold all of the source including the null terminator
  561.  
  562.     pszSrc          -   source string which must be null terminated
  563.  
  564.     ppszDestEnd     -   if ppszDestEnd is non-null, the function will return a
  565.                         pointer to the end of the destination string.  If the
  566.                         function copied any data, the result will point to the
  567.                         null termination character
  568.  
  569.     pcbRemaining    -   pcbRemaining is non-null,the function will return the
  570.                         number of bytes left in the destination string,
  571.                         including the null terminator
  572.  
  573.     dwFlags         -   controls some details of the string copy:
  574.  
  575.         STRSAFE_FILL_BEHIND_NULL
  576.                     if the function succeeds, the low byte of dwFlags will be
  577.                     used to fill the uninitialize part of destination buffer
  578.                     behind the null terminator
  579.  
  580.         STRSAFE_IGNORE_NULLS
  581.                     treat NULL string pointers like empty strings (TEXT("")).
  582.                     this flag is useful for emulating functions like lstrcpy
  583.  
  584.         STRSAFE_FILL_ON_FAILURE
  585.                     if the function fails, the low byte of dwFlags will be
  586.                     used to fill all of the destination buffer, and it will
  587.                     be null terminated. This will overwrite any truncated
  588.                     string returned when the failure is
  589.                     STRSAFE_E_INSUFFICIENT_BUFFER
  590.  
  591.         STRSAFE_NO_TRUNCATION /
  592.         STRSAFE_NULL_ON_FAILURE
  593.                     if the function fails, the destination buffer will be set
  594.                     to the empty string. This will overwrite any truncated string
  595.                     returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
  596.  
  597. Notes:
  598.     Behavior is undefined if source and destination strings overlap.
  599.  
  600.     pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  601.     is specified.  If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  602.     may be NULL.  An error may still be returned even though NULLS are ignored
  603.     due to insufficient space.
  604.  
  605. Return Value:
  606.  
  607.     S_OK           -   if there was source data and it was all copied and the
  608.                        resultant dest string was null terminated
  609.  
  610.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  611.                        error code for all hresult failure cases
  612.  
  613.       STRSAFE_E_INSUFFICIENT_BUFFER /
  614.       HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  615.                    -   this return value is an indication that the copy
  616.                        operation failed due to insufficient space. When this
  617.                        error occurs, the destination buffer is modified to
  618.                        contain a truncated version of the ideal result and is
  619.                        null terminated. This is useful for situations where
  620.                        truncation is ok.
  621.  
  622.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  623.     return value of this function
  624.  
  625. --*/
  626.  
  627. STRSAFEAPI StringCbCopyExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
  628. STRSAFEAPI StringCbCopyExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
  629. #ifdef UNICODE
  630. #define StringCbCopyEx  StringCbCopyExW
  631. #else
  632. #define StringCbCopyEx  StringCbCopyExA
  633. #endif // !UNICODE
  634.  
  635. #ifdef STRSAFE_INLINE
  636. STRSAFEAPI StringCbCopyExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
  637. {
  638.     HRESULT hr;
  639.     size_t cchDest;
  640.     size_t cchRemaining = 0;
  641.  
  642.     cchDest = cbDest / sizeof(char);
  643.  
  644.     if (cchDest > STRSAFE_MAX_CCH)
  645.     {
  646.         hr = STRSAFE_E_INVALID_PARAMETER;
  647.     }
  648.     else
  649.     {
  650.         hr = StringCopyExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags);
  651.     }
  652.  
  653.     if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  654.     {
  655.         if (pcbRemaining)
  656.         {
  657.             // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
  658.             *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
  659.         }
  660.     }
  661.  
  662.     return hr;
  663. }
  664.  
  665. STRSAFEAPI StringCbCopyExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
  666. {
  667.     HRESULT hr;
  668.     size_t cchDest;
  669.     size_t cchRemaining = 0;
  670.  
  671.     cchDest = cbDest / sizeof(wchar_t);
  672.  
  673.     if (cchDest > STRSAFE_MAX_CCH)
  674.     {
  675.         hr = STRSAFE_E_INVALID_PARAMETER;
  676.     }
  677.     else
  678.     {
  679.         hr = StringCopyExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags);
  680.     }
  681.  
  682.     if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  683.     {
  684.         if (pcbRemaining)
  685.         {
  686.             // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  687.             *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
  688.         }
  689.     }
  690.  
  691.     return hr;
  692. }
  693. #endif  // STRSAFE_INLINE
  694. #endif  // !STRSAFE_NO_CB_FUNCTIONS
  695.  
  696.  
  697. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  698. /*++
  699.  
  700. STDAPI
  701. StringCchCopyN(
  702.     OUT LPTSTR  pszDest,
  703.     IN  size_t  cchDest,
  704.     IN  LPCTSTR pszSrc,
  705.     IN  size_t  cchSrc
  706.     );
  707.  
  708. Routine Description:
  709.  
  710.     This routine is a safer version of the C built-in function 'strncpy'.
  711.     The size of the destination buffer (in characters) is a parameter and
  712.     this function will not write past the end of this buffer and it will
  713.     ALWAYS null terminate the destination buffer (unless it is zero length).
  714.  
  715.     This routine is meant as a replacement for strncpy, but it does behave
  716.     differently. This function will not pad the destination buffer with extra
  717.     null termination characters if cchSrc is greater than the length of pszSrc.
  718.  
  719.     This function returns a hresult, and not a pointer.  It returns
  720.     S_OK if the entire string or the first cchSrc characters were copied
  721.     without truncation and the resultant destination string was null terminated,
  722.     otherwise it will return a failure code. In failure cases as much of pszSrc
  723.     will be copied to pszDest as possible, and pszDest will be null terminated.
  724.  
  725. Arguments:
  726.  
  727.     pszDest        -   destination string
  728.  
  729.     cchDest        -   size of destination buffer in characters.
  730.                        length must be = (_tcslen(src) + 1) to hold all of the
  731.                        source including the null terminator
  732.  
  733.     pszSrc         -   source string
  734.  
  735.     cchSrc         -   maximum number of characters to copy from source string,
  736.                        not including the null terminator.
  737.  
  738. Notes:
  739.     Behavior is undefined if source and destination strings overlap.
  740.  
  741.     pszDest and pszSrc should not be NULL. See StringCchCopyNEx if you require
  742.     the handling of NULL values.
  743.  
  744. Return Value:
  745.  
  746.     S_OK           -   if there was source data and it was all copied and the
  747.                        resultant dest string was null terminated
  748.  
  749.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  750.                        error code for all hresult failure cases
  751.  
  752.       STRSAFE_E_INSUFFICIENT_BUFFER /
  753.       HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  754.                    -   this return value is an indication that the copy
  755.                        operation failed due to insufficient space. When this
  756.                        error occurs, the destination buffer is modified to
  757.                        contain a truncated version of the ideal result and is
  758.                        null terminated. This is useful for situations where
  759.                        truncation is ok
  760.  
  761.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  762.     return value of this function.
  763.  
  764. --*/
  765.  
  766. STRSAFEAPI StringCchCopyNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc);
  767. STRSAFEAPI StringCchCopyNW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc);
  768. #ifdef UNICODE
  769. #define StringCchCopyN  StringCchCopyNW
  770. #else
  771. #define StringCchCopyN  StringCchCopyNA
  772. #endif // !UNICODE
  773.  
  774. #ifdef STRSAFE_INLINE
  775. STRSAFEAPI StringCchCopyNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc)
  776. {
  777.     HRESULT hr;
  778.  
  779.     if ((cchDest > STRSAFE_MAX_CCH) ||
  780.         (cchSrc > STRSAFE_MAX_CCH))
  781.     {
  782.         hr = STRSAFE_E_INVALID_PARAMETER;
  783.     }
  784.     else
  785.     {
  786.         hr = StringCopyNWorkerA(pszDest, cchDest, pszSrc, cchSrc);
  787.     }
  788.  
  789.     return hr;
  790. }
  791.  
  792. STRSAFEAPI StringCchCopyNW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc)
  793. {
  794.     HRESULT hr;
  795.  
  796.     if ((cchDest > STRSAFE_MAX_CCH) ||
  797.         (cchSrc > STRSAFE_MAX_CCH))
  798.     {
  799.         hr = STRSAFE_E_INVALID_PARAMETER;
  800.     }
  801.     else
  802.     {
  803.         hr = StringCopyNWorkerW(pszDest, cchDest, pszSrc, cchSrc);
  804.     }
  805.  
  806.     return hr;
  807. }
  808. #endif  // STRSAFE_INLINE
  809. #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  810.  
  811.  
  812. #ifndef STRSAFE_NO_CB_FUNCTIONS
  813. /*++
  814.  
  815. STDAPI
  816. StringCbCopyN(
  817.     OUT LPTSTR  pszDest,
  818.     IN  size_t  cbDest,
  819.     IN  LPCTSTR pszSrc,
  820.     IN  size_t  cbSrc
  821.     );
  822.  
  823. Routine Description:
  824.  
  825.     This routine is a safer version of the C built-in function 'strncpy'.
  826.     The size of the destination buffer (in bytes) is a parameter and this
  827.     function will not write past the end of this buffer and it will ALWAYS
  828.     null terminate the destination buffer (unless it is zero length).
  829.  
  830.     This routine is meant as a replacement for strncpy, but it does behave
  831.     differently. This function will not pad the destination buffer with extra
  832.     null termination characters if cbSrc is greater than the size of pszSrc.
  833.  
  834.     This function returns a hresult, and not a pointer.  It returns
  835.     S_OK if the entire string or the first cbSrc characters were
  836.     copied without truncation and the resultant destination string was null
  837.     terminated, otherwise it will return a failure code. In failure cases as
  838.     much of pszSrc will be copied to pszDest as possible, and pszDest will be
  839.     null terminated.
  840.  
  841. Arguments:
  842.  
  843.     pszDest        -   destination string
  844.  
  845.     cbDest         -   size of destination buffer in bytes.
  846.                        length must be = ((_tcslen(src) + 1) * sizeof(TCHAR)) to
  847.                        hold all of the source including the null terminator
  848.  
  849.     pszSrc         -   source string
  850.  
  851.     cbSrc          -   maximum number of bytes to copy from source string,
  852.                        not including the null terminator.
  853.  
  854. Notes:
  855.     Behavior is undefined if source and destination strings overlap.
  856.  
  857.     pszDest and pszSrc should not be NULL.  See StringCbCopyEx if you require
  858.     the handling of NULL values.
  859.  
  860. Return Value:
  861.  
  862.     S_OK           -   if there was source data and it was all copied and the
  863.                        resultant dest string was null terminated
  864.  
  865.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  866.                        error code for all hresult failure cases
  867.  
  868.       STRSAFE_E_INSUFFICIENT_BUFFER /
  869.       HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  870.                    -   this return value is an indication that the copy
  871.                        operation failed due to insufficient space. When this
  872.                        error occurs, the destination buffer is modified to
  873.                        contain a truncated version of the ideal result and is
  874.                        null terminated. This is useful for situations where
  875.                        truncation is ok
  876.  
  877.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  878.     return value of this function.
  879.  
  880. --*/
  881.  
  882. STRSAFEAPI StringCbCopyNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc);
  883. STRSAFEAPI StringCbCopyNW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbSrc);
  884. #ifdef UNICODE
  885. #define StringCbCopyN  StringCbCopyNW
  886. #else
  887. #define StringCbCopyN  StringCbCopyNA
  888. #endif // !UNICODE
  889.  
  890. #ifdef STRSAFE_INLINE
  891. STRSAFEAPI StringCbCopyNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc)
  892. {
  893.     HRESULT hr;
  894.     size_t cchDest;
  895.     size_t cchSrc;
  896.  
  897.     // convert to count of characters
  898.     cchDest = cbDest / sizeof(char);
  899.     cchSrc = cbSrc / sizeof(char);
  900.  
  901.     if ((cchDest > STRSAFE_MAX_CCH) ||
  902.         (cchSrc > STRSAFE_MAX_CCH))
  903.     {
  904.         hr = STRSAFE_E_INVALID_PARAMETER;
  905.     }
  906.     else
  907.     {
  908.         hr = StringCopyNWorkerA(pszDest, cchDest, pszSrc, cchSrc);
  909.     }
  910.  
  911.     return hr;
  912. }
  913.  
  914. STRSAFEAPI StringCbCopyNW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbSrc)
  915. {
  916.     HRESULT hr;
  917.     size_t cchDest;
  918.     size_t cchSrc;
  919.  
  920.     // convert to count of characters
  921.     cchDest = cbDest / sizeof(wchar_t);
  922.     cchSrc = cbSrc / sizeof(wchar_t);
  923.  
  924.     if ((cchDest > STRSAFE_MAX_CCH) ||
  925.         (cchSrc > STRSAFE_MAX_CCH))
  926.     {
  927.         hr = STRSAFE_E_INVALID_PARAMETER;
  928.     }
  929.     else
  930.     {
  931.         hr = StringCopyNWorkerW(pszDest, cchDest, pszSrc, cchSrc);
  932.     }
  933.  
  934.     return hr;
  935. }
  936. #endif  // STRSAFE_INLINE
  937. #endif  // !STRSAFE_NO_CB_FUNCTIONS
  938.  
  939.  
  940. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  941. /*++
  942.  
  943. STDAPI
  944. StringCchCopyNEx(
  945.     OUT LPTSTR  pszDest         OPTIONAL,
  946.     IN  size_t  cchDest,
  947.     IN  LPCTSTR pszSrc          OPTIONAL,
  948.     IN  size_t  cchSrc,
  949.     OUT LPTSTR* ppszDestEnd     OPTIONAL,
  950.     OUT size_t* pcchRemaining   OPTIONAL,
  951.     IN  DWORD   dwFlags
  952.     );
  953.  
  954. Routine Description:
  955.  
  956.     This routine is a safer version of the C built-in function 'strncpy' with
  957.     some additional parameters.  In addition to functionality provided by
  958.     StringCchCopyN, this routine also returns a pointer to the end of the
  959.     destination string and the number of characters left in the destination
  960.     string including the null terminator. The flags parameter allows
  961.     additional controls.
  962.  
  963.     This routine is meant as a replacement for strncpy, but it does behave
  964.     differently. This function will not pad the destination buffer with extra
  965.     null termination characters if cchSrc is greater than the length of pszSrc.
  966.  
  967. Arguments:
  968.  
  969.     pszDest         -   destination string
  970.  
  971.     cchDest         -   size of destination buffer in characters.
  972.                         length must be = (_tcslen(pszSrc) + 1) to hold all of
  973.                         the source including the null terminator
  974.  
  975.     pszSrc          -   source string
  976.  
  977.     cchSrc          -   maximum number of characters to copy from the source
  978.                         string
  979.  
  980.     ppszDestEnd     -   if ppszDestEnd is non-null, the function will return a
  981.                         pointer to the end of the destination string.  If the
  982.                         function copied any data, the result will point to the
  983.                         null termination character
  984.  
  985.     pcchRemaining   -   if pcchRemaining is non-null, the function will return the
  986.                         number of characters left in the destination string,
  987.                         including the null terminator
  988.  
  989.     dwFlags         -   controls some details of the string copy:
  990.  
  991.         STRSAFE_FILL_BEHIND_NULL
  992.                     if the function succeeds, the low byte of dwFlags will be
  993.                     used to fill the uninitialize part of destination buffer
  994.                     behind the null terminator
  995.  
  996.         STRSAFE_IGNORE_NULLS
  997.                     treat NULL string pointers like empty strings (TEXT("")).
  998.                     this flag is useful for emulating functions like lstrcpy
  999.  
  1000.         STRSAFE_FILL_ON_FAILURE
  1001.                     if the function fails, the low byte of dwFlags will be
  1002.                     used to fill all of the destination buffer, and it will
  1003.                     be null terminated. This will overwrite any truncated
  1004.                     string returned when the failure is
  1005.                     STRSAFE_E_INSUFFICIENT_BUFFER
  1006.  
  1007.         STRSAFE_NO_TRUNCATION /
  1008.         STRSAFE_NULL_ON_FAILURE
  1009.                     if the function fails, the destination buffer will be set
  1010.                     to the empty string. This will overwrite any truncated string
  1011.                     returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
  1012.  
  1013. Notes:
  1014.     Behavior is undefined if source and destination strings overlap.
  1015.  
  1016.     pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  1017.     is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  1018.     may be NULL. An error may still be returned even though NULLS are ignored
  1019.     due to insufficient space.
  1020.  
  1021. Return Value:
  1022.  
  1023.     S_OK           -   if there was source data and it was all copied and the
  1024.                        resultant dest string was null terminated
  1025.  
  1026.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  1027.                        error code for all hresult failure cases
  1028.  
  1029.       STRSAFE_E_INSUFFICIENT_BUFFER /
  1030.       HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  1031.                    -   this return value is an indication that the copy
  1032.                        operation failed due to insufficient space. When this
  1033.                        error occurs, the destination buffer is modified to
  1034.                        contain a truncated version of the ideal result and is
  1035.                        null terminated. This is useful for situations where
  1036.                        truncation is ok.
  1037.  
  1038.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  1039.     return value of this function
  1040.  
  1041. --*/
  1042.  
  1043. STRSAFEAPI StringCchCopyNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  1044. STRSAFEAPI StringCchCopyNExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  1045. #ifdef UNICODE
  1046. #define StringCchCopyNEx  StringCchCopyNExW
  1047. #else
  1048. #define StringCchCopyNEx  StringCchCopyNExA
  1049. #endif // !UNICODE
  1050.  
  1051. #ifdef STRSAFE_INLINE
  1052. STRSAFEAPI StringCchCopyNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  1053. {
  1054.     HRESULT hr;
  1055.  
  1056.     if ((cchDest > STRSAFE_MAX_CCH) ||
  1057.         (cchSrc > STRSAFE_MAX_CCH))
  1058.     {
  1059.         hr = STRSAFE_E_INVALID_PARAMETER;
  1060.     }
  1061.     else
  1062.     {
  1063.         size_t cbDest;
  1064.  
  1065.         // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
  1066.         cbDest = cchDest * sizeof(char);
  1067.  
  1068.         hr = StringCopyNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, pcchRemaining, dwFlags);
  1069.     }
  1070.  
  1071.     return hr;
  1072. }
  1073.  
  1074. STRSAFEAPI StringCchCopyNExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  1075. {
  1076.     HRESULT hr;
  1077.  
  1078.     if ((cchDest > STRSAFE_MAX_CCH) ||
  1079.         (cchSrc > STRSAFE_MAX_CCH))
  1080.     {
  1081.         hr = STRSAFE_E_INVALID_PARAMETER;
  1082.     }
  1083.     else
  1084.     {
  1085.         size_t cbDest;
  1086.  
  1087.         // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  1088.         cbDest = cchDest * sizeof(wchar_t);
  1089.  
  1090.         hr = StringCopyNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, pcchRemaining, dwFlags);
  1091.     }
  1092.  
  1093.     return hr;
  1094. }
  1095. #endif  // STRSAFE_INLINE
  1096. #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  1097.  
  1098.  
  1099. #ifndef STRSAFE_NO_CB_FUNCTIONS
  1100. /*++
  1101.  
  1102. STDAPI
  1103. StringCbCopyNEx(
  1104.     OUT LPTSTR  pszDest         OPTIONAL,
  1105.     IN  size_t  cbDest,
  1106.     IN  LPCTSTR pszSrc          OPTIONAL,
  1107.     IN  size_t  cbSrc,
  1108.     OUT LPTSTR* ppszDestEnd     OPTIONAL,
  1109.     OUT size_t* pcbRemaining    OPTIONAL,
  1110.     IN  DWORD   dwFlags
  1111.     );
  1112.  
  1113. Routine Description:
  1114.  
  1115.     This routine is a safer version of the C built-in function 'strncpy' with
  1116.     some additional parameters.  In addition to functionality provided by
  1117.     StringCbCopyN, this routine also returns a pointer to the end of the
  1118.     destination string and the number of bytes left in the destination string
  1119.     including the null terminator. The flags parameter allows additional controls.
  1120.  
  1121.     This routine is meant as a replacement for strncpy, but it does behave
  1122.     differently. This function will not pad the destination buffer with extra
  1123.     null termination characters if cbSrc is greater than the size of pszSrc.
  1124.  
  1125. Arguments:
  1126.  
  1127.     pszDest         -   destination string
  1128.  
  1129.     cbDest          -   size of destination buffer in bytes.
  1130.                         length must be ((_tcslen(pszSrc) + 1) * sizeof(TCHAR)) to
  1131.                         hold all of the source including the null terminator
  1132.  
  1133.     pszSrc          -   source string
  1134.  
  1135.     cbSrc           -   maximum number of bytes to copy from source string
  1136.  
  1137.     ppszDestEnd     -   if ppszDestEnd is non-null, the function will return a
  1138.                         pointer to the end of the destination string.  If the
  1139.                         function copied any data, the result will point to the
  1140.                         null termination character
  1141.  
  1142.     pcbRemaining    -   pcbRemaining is non-null,the function will return the
  1143.                         number of bytes left in the destination string,
  1144.                         including the null terminator
  1145.  
  1146.     dwFlags         -   controls some details of the string copy:
  1147.  
  1148.         STRSAFE_FILL_BEHIND_NULL
  1149.                     if the function succeeds, the low byte of dwFlags will be
  1150.                     used to fill the uninitialize part of destination buffer
  1151.                     behind the null terminator
  1152.  
  1153.         STRSAFE_IGNORE_NULLS
  1154.                     treat NULL string pointers like empty strings (TEXT("")).
  1155.                     this flag is useful for emulating functions like lstrcpy
  1156.  
  1157.         STRSAFE_FILL_ON_FAILURE
  1158.                     if the function fails, the low byte of dwFlags will be
  1159.                     used to fill all of the destination buffer, and it will
  1160.                     be null terminated. This will overwrite any truncated
  1161.                     string returned when the failure is
  1162.                     STRSAFE_E_INSUFFICIENT_BUFFER
  1163.  
  1164.         STRSAFE_NO_TRUNCATION /
  1165.         STRSAFE_NULL_ON_FAILURE
  1166.                     if the function fails, the destination buffer will be set
  1167.                     to the empty string. This will overwrite any truncated string
  1168.                     returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
  1169.  
  1170. Notes:
  1171.     Behavior is undefined if source and destination strings overlap.
  1172.  
  1173.     pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  1174.     is specified.  If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  1175.     may be NULL.  An error may still be returned even though NULLS are ignored
  1176.     due to insufficient space.
  1177.  
  1178. Return Value:
  1179.  
  1180.     S_OK           -   if there was source data and it was all copied and the
  1181.                        resultant dest string was null terminated
  1182.  
  1183.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  1184.                        error code for all hresult failure cases
  1185.  
  1186.       STRSAFE_E_INSUFFICIENT_BUFFER /
  1187.       HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  1188.                    -   this return value is an indication that the copy
  1189.                        operation failed due to insufficient space. When this
  1190.                        error occurs, the destination buffer is modified to
  1191.                        contain a truncated version of the ideal result and is
  1192.                        null terminated. This is useful for situations where
  1193.                        truncation is ok.
  1194.  
  1195.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  1196.     return value of this function
  1197.  
  1198. --*/
  1199.  
  1200. STRSAFEAPI StringCbCopyNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
  1201. STRSAFEAPI StringCbCopyNExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
  1202. #ifdef UNICODE
  1203. #define StringCbCopyNEx  StringCbCopyNExW
  1204. #else
  1205. #define StringCbCopyNEx  StringCbCopyNExA
  1206. #endif // !UNICODE
  1207.  
  1208. #ifdef STRSAFE_INLINE
  1209. STRSAFEAPI StringCbCopyNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
  1210. {
  1211.     HRESULT hr;
  1212.     size_t cchDest;
  1213.     size_t cchSrc;
  1214.     size_t cchRemaining = 0;
  1215.  
  1216.     cchDest = cbDest / sizeof(char);
  1217.     cchSrc = cbSrc / sizeof(char);
  1218.  
  1219.     if ((cchDest > STRSAFE_MAX_CCH) ||
  1220.         (cchSrc > STRSAFE_MAX_CCH))
  1221.     {
  1222.         hr = STRSAFE_E_INVALID_PARAMETER;
  1223.     }
  1224.     else
  1225.     {
  1226.         hr = StringCopyNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, &cchRemaining, dwFlags);
  1227.     }
  1228.  
  1229.     if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  1230.     {
  1231.         if (pcbRemaining)
  1232.         {
  1233.             // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
  1234.             *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
  1235.         }
  1236.     }
  1237.  
  1238.     return hr;
  1239. }
  1240.  
  1241. STRSAFEAPI StringCbCopyNExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
  1242. {
  1243.     HRESULT hr;
  1244.     size_t cchDest;
  1245.     size_t cchSrc;
  1246.     size_t cchRemaining = 0;
  1247.  
  1248.     cchDest = cbDest / sizeof(wchar_t);
  1249.     cchSrc = cbSrc / sizeof(wchar_t);
  1250.  
  1251.     if ((cchDest > STRSAFE_MAX_CCH) ||
  1252.         (cchSrc > STRSAFE_MAX_CCH))
  1253.     {
  1254.         hr = STRSAFE_E_INVALID_PARAMETER;
  1255.     }
  1256.     else
  1257.     {
  1258.         hr = StringCopyNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchSrc, ppszDestEnd, &cchRemaining, dwFlags);
  1259.     }
  1260.  
  1261.     if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  1262.     {
  1263.         if (pcbRemaining)
  1264.         {
  1265.             // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  1266.             *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
  1267.         }
  1268.     }
  1269.  
  1270.     return hr;
  1271. }
  1272. #endif  // STRSAFE_INLINE
  1273. #endif  // !STRSAFE_NO_CB_FUNCTIONS
  1274.  
  1275.  
  1276. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  1277. /*++
  1278.  
  1279. STDAPI
  1280. StringCchCat(
  1281.     IN OUT LPTSTR  pszDest,
  1282.     IN     size_t  cchDest,
  1283.     IN     LPCTSTR pszSrc
  1284.     );
  1285.  
  1286. Routine Description:
  1287.  
  1288.     This routine is a safer version of the C built-in function 'strcat'.
  1289.     The size of the destination buffer (in characters) is a parameter and this
  1290.     function will not write past the end of this buffer and it will ALWAYS
  1291.     null terminate the destination buffer (unless it is zero length).
  1292.  
  1293.     This function returns a hresult, and not a pointer.  It returns
  1294.     S_OK if the string was concatenated without truncation and null terminated,
  1295.     otherwise it will return a failure code. In failure cases as much of pszSrc
  1296.     will be appended to pszDest as possible, and pszDest will be null
  1297.     terminated.
  1298.  
  1299. Arguments:
  1300.  
  1301.     pszDest     -  destination string which must be null terminated
  1302.  
  1303.     cchDest     -  size of destination buffer in characters.
  1304.                    length must be = (_tcslen(pszDest) + _tcslen(pszSrc) + 1)
  1305.                    to hold all of the combine string plus the null
  1306.                    terminator
  1307.  
  1308.     pszSrc      -  source string which must be null terminated
  1309.  
  1310. Notes:
  1311.     Behavior is undefined if source and destination strings overlap.
  1312.  
  1313.     pszDest and pszSrc should not be NULL.  See StringCchCatEx if you require
  1314.     the handling of NULL values.
  1315.  
  1316. Return Value:
  1317.  
  1318.     S_OK           -   if there was source data and it was all concatenated and
  1319.                        the resultant dest string was null terminated
  1320.  
  1321.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  1322.                        error code for all hresult failure cases
  1323.  
  1324.       STRSAFE_E_INSUFFICIENT_BUFFER /
  1325.       HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  1326.                    -   this return value is an indication that the operation
  1327.                        failed due to insufficient space. When this error occurs,
  1328.                        the destination buffer is modified to contain a truncated
  1329.                        version of the ideal result and is null terminated. This
  1330.                        is useful for situations where truncation is ok.
  1331.  
  1332.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  1333.     return value of this function
  1334.  
  1335. --*/
  1336.  
  1337. STRSAFEAPI StringCchCatA(char* pszDest, size_t cchDest, const char* pszSrc);
  1338. STRSAFEAPI StringCchCatW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc);
  1339. #ifdef UNICODE
  1340. #define StringCchCat  StringCchCatW
  1341. #else
  1342. #define StringCchCat  StringCchCatA
  1343. #endif // !UNICODE
  1344.  
  1345. #ifdef STRSAFE_INLINE
  1346. STRSAFEAPI StringCchCatA(char* pszDest, size_t cchDest, const char* pszSrc)
  1347. {
  1348.     HRESULT hr;
  1349.  
  1350.     if (cchDest > STRSAFE_MAX_CCH)
  1351.     {
  1352.         hr = STRSAFE_E_INVALID_PARAMETER;
  1353.     }
  1354.     else
  1355.     {
  1356.         hr = StringCatWorkerA(pszDest, cchDest, pszSrc);
  1357.     }
  1358.  
  1359.     return hr;
  1360. }
  1361.  
  1362. STRSAFEAPI StringCchCatW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc)
  1363. {
  1364.     HRESULT hr;
  1365.  
  1366.     if (cchDest > STRSAFE_MAX_CCH)
  1367.     {
  1368.         hr = STRSAFE_E_INVALID_PARAMETER;
  1369.     }
  1370.     else
  1371.     {
  1372.         hr = StringCatWorkerW(pszDest, cchDest, pszSrc);
  1373.     }
  1374.  
  1375.     return hr;
  1376. }
  1377. #endif  // STRSAFE_INLINE
  1378. #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  1379.  
  1380.  
  1381. #ifndef STRSAFE_NO_CB_FUNCTIONS
  1382. /*++
  1383.  
  1384. STDAPI
  1385. StringCbCat(
  1386.     IN OUT LPTSTR  pszDest,
  1387.     IN     size_t  cbDest,
  1388.     IN     LPCTSTR pszSrc
  1389.     );
  1390.  
  1391. Routine Description:
  1392.  
  1393.     This routine is a safer version of the C built-in function 'strcat'.
  1394.     The size of the destination buffer (in bytes) is a parameter and this
  1395.     function will not write past the end of this buffer and it will ALWAYS
  1396.     null terminate the destination buffer (unless it is zero length).
  1397.  
  1398.     This function returns a hresult, and not a pointer.  It returns
  1399.     S_OK if the string was concatenated without truncation and null terminated,
  1400.     otherwise it will return a failure code. In failure cases as much of pszSrc
  1401.     will be appended to pszDest as possible, and pszDest will be null
  1402.     terminated.
  1403.  
  1404. Arguments:
  1405.  
  1406.     pszDest     -  destination string which must be null terminated
  1407.  
  1408.     cbDest      -  size of destination buffer in bytes.
  1409.                    length must be = ((_tcslen(pszDest) + _tcslen(pszSrc) + 1) * sizeof(TCHAR)
  1410.                    to hold all of the combine string plus the null
  1411.                    terminator
  1412.  
  1413.     pszSrc      -  source string which must be null terminated
  1414.  
  1415. Notes:
  1416.     Behavior is undefined if source and destination strings overlap.
  1417.  
  1418.     pszDest and pszSrc should not be NULL.  See StringCbCatEx if you require
  1419.     the handling of NULL values.
  1420.  
  1421. Return Value:
  1422.  
  1423.     S_OK           -   if there was source data and it was all concatenated and
  1424.                        the resultant dest string was null terminated
  1425.  
  1426.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  1427.                        error code for all hresult failure cases
  1428.  
  1429.       STRSAFE_E_INSUFFICIENT_BUFFER /
  1430.       HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  1431.                    -   this return value is an indication that the operation
  1432.                        failed due to insufficient space. When this error occurs,
  1433.                        the destination buffer is modified to contain a truncated
  1434.                        version of the ideal result and is null terminated. This
  1435.                        is useful for situations where truncation is ok.
  1436.  
  1437.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  1438.     return value of this function
  1439.  
  1440. --*/
  1441.  
  1442. STRSAFEAPI StringCbCatA(char* pszDest, size_t cbDest, const char* pszSrc);
  1443. STRSAFEAPI StringCbCatW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc);
  1444. #ifdef UNICODE
  1445. #define StringCbCat  StringCbCatW
  1446. #else
  1447. #define StringCbCat  StringCbCatA
  1448. #endif // !UNICODE
  1449.  
  1450. #ifdef STRSAFE_INLINE
  1451. STRSAFEAPI StringCbCatA(char* pszDest, size_t cbDest, const char* pszSrc)
  1452. {
  1453.     HRESULT hr;
  1454.     size_t cchDest;
  1455.  
  1456.     cchDest = cbDest / sizeof(char);
  1457.  
  1458.     if (cchDest > STRSAFE_MAX_CCH)
  1459.     {
  1460.         hr = STRSAFE_E_INVALID_PARAMETER;
  1461.     }
  1462.     else
  1463.     {
  1464.         hr = StringCatWorkerA(pszDest, cchDest, pszSrc);
  1465.     }
  1466.  
  1467.     return hr;
  1468. }
  1469.  
  1470. STRSAFEAPI StringCbCatW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc)
  1471. {
  1472.     HRESULT hr;
  1473.     size_t cchDest;
  1474.  
  1475.     cchDest = cbDest / sizeof(wchar_t);
  1476.  
  1477.     if (cchDest > STRSAFE_MAX_CCH)
  1478.     {
  1479.         hr = STRSAFE_E_INVALID_PARAMETER;
  1480.     }
  1481.     else
  1482.     {
  1483.         hr = StringCatWorkerW(pszDest, cchDest, pszSrc);
  1484.     }
  1485.  
  1486.     return hr;
  1487. }
  1488. #endif  // STRSAFE_INLINE
  1489. #endif  // !STRSAFE_NO_CB_FUNCTIONS
  1490.  
  1491.  
  1492. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  1493. /*++
  1494.  
  1495. STDAPI
  1496. StringCchCatEx(
  1497.     IN OUT LPTSTR  pszDest         OPTIONAL,
  1498.     IN     size_t  cchDest,
  1499.     IN     LPCTSTR pszSrc          OPTIONAL,
  1500.     OUT    LPTSTR* ppszDestEnd     OPTIONAL,
  1501.     OUT    size_t* pcchRemaining   OPTIONAL,
  1502.     IN     DWORD   dwFlags
  1503.     );
  1504.  
  1505. Routine Description:
  1506.  
  1507.     This routine is a safer version of the C built-in function 'strcat' with
  1508.     some additional parameters.  In addition to functionality provided by
  1509.     StringCchCat, this routine also returns a pointer to the end of the
  1510.     destination string and the number of characters left in the destination string
  1511.     including the null terminator. The flags parameter allows additional controls.
  1512.  
  1513. Arguments:
  1514.  
  1515.     pszDest         -   destination string which must be null terminated
  1516.  
  1517.     cchDest         -   size of destination buffer in characters
  1518.                         length must be (_tcslen(pszDest) + _tcslen(pszSrc) + 1)
  1519.                         to hold all of the combine string plus the null
  1520.                         terminator.
  1521.  
  1522.     pszSrc          -   source string which must be null terminated
  1523.  
  1524.     ppszDestEnd     -   if ppszDestEnd is non-null, the function will return a
  1525.                         pointer to the end of the destination string.  If the
  1526.                         function appended any data, the result will point to the
  1527.                         null termination character
  1528.  
  1529.     pcchRemaining   -   if pcchRemaining is non-null, the function will return the
  1530.                         number of characters left in the destination string,
  1531.                         including the null terminator
  1532.  
  1533.     dwFlags         -   controls some details of the string copy:
  1534.  
  1535.         STRSAFE_FILL_BEHIND_NULL
  1536.                     if the function succeeds, the low byte of dwFlags will be
  1537.                     used to fill the uninitialize part of destination buffer
  1538.                     behind the null terminator
  1539.  
  1540.         STRSAFE_IGNORE_NULLS
  1541.                     treat NULL string pointers like empty strings (TEXT("")).
  1542.                     this flag is useful for emulating functions like lstrcat
  1543.  
  1544.         STRSAFE_FILL_ON_FAILURE
  1545.                     if the function fails, the low byte of dwFlags will be
  1546.                     used to fill all of the destination buffer, and it will
  1547.                     be null terminated. This will overwrite any pre-existing
  1548.                     or truncated string
  1549.  
  1550.         STRSAFE_NULL_ON_FAILURE
  1551.                     if the function fails, the destination buffer will be set
  1552.                     to the empty string. This will overwrite any pre-existing or
  1553.                     truncated string
  1554.  
  1555.         STRSAFE_NO_TRUNCATION
  1556.                     if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest
  1557.                     will not contain a truncated string, it will remain unchanged.
  1558.  
  1559. Notes:
  1560.     Behavior is undefined if source and destination strings overlap.
  1561.  
  1562.     pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  1563.     is specified.  If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  1564.     may be NULL.  An error may still be returned even though NULLS are ignored
  1565.     due to insufficient space.
  1566.  
  1567. Return Value:
  1568.  
  1569.     S_OK           -   if there was source data and it was all concatenated and
  1570.                        the resultant dest string was null terminated
  1571.  
  1572.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  1573.                        error code for all hresult failure cases
  1574.  
  1575.       STRSAFE_E_INSUFFICIENT_BUFFER /
  1576.       HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  1577.                    -   this return value is an indication that the operation
  1578.                        failed due to insufficient space. When this error
  1579.                        occurs, the destination buffer is modified to contain
  1580.                        a truncated version of the ideal result and is null
  1581.                        terminated. This is useful for situations where
  1582.                        truncation is ok.
  1583.  
  1584.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  1585.     return value of this function
  1586.  
  1587. --*/
  1588.  
  1589. STRSAFEAPI StringCchCatExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  1590. STRSAFEAPI StringCchCatExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  1591. #ifdef UNICODE
  1592. #define StringCchCatEx  StringCchCatExW
  1593. #else
  1594. #define StringCchCatEx  StringCchCatExA
  1595. #endif // !UNICODE
  1596.  
  1597. #ifdef STRSAFE_INLINE
  1598. STRSAFEAPI StringCchCatExA(char* pszDest, size_t cchDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  1599. {
  1600.     HRESULT hr;
  1601.  
  1602.     if (cchDest > STRSAFE_MAX_CCH)
  1603.     {
  1604.         hr = STRSAFE_E_INVALID_PARAMETER;
  1605.     }
  1606.     else
  1607.     {
  1608.         size_t cbDest;
  1609.  
  1610.         // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
  1611.         cbDest = cchDest * sizeof(char);
  1612.  
  1613.         hr = StringCatExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
  1614.     }
  1615.  
  1616.     return hr;
  1617. }
  1618.  
  1619. STRSAFEAPI StringCchCatExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  1620. {
  1621.     HRESULT hr;
  1622.  
  1623.     if (cchDest > STRSAFE_MAX_CCH)
  1624.     {
  1625.         hr = STRSAFE_E_INVALID_PARAMETER;
  1626.     }
  1627.     else
  1628.     {
  1629.         size_t cbDest;
  1630.  
  1631.         // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  1632.         cbDest = cchDest * sizeof(wchar_t);
  1633.  
  1634.         hr = StringCatExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, pcchRemaining, dwFlags);
  1635.     }
  1636.  
  1637.     return hr;
  1638. }
  1639. #endif  // STRSAFE_INLINE
  1640. #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  1641.  
  1642.  
  1643. #ifndef STRSAFE_NO_CB_FUNCTIONS
  1644. /*++
  1645.  
  1646. STDAPI
  1647. StringCbCatEx(
  1648.     IN OUT LPTSTR  pszDest         OPTIONAL,
  1649.     IN     size_t  cbDest,
  1650.     IN     LPCTSTR pszSrc          OPTIONAL,
  1651.     OUT    LPTSTR* ppszDestEnd     OPTIONAL,
  1652.     OUT    size_t* pcbRemaining    OPTIONAL,
  1653.     IN     DWORD   dwFlags
  1654.     );
  1655.  
  1656. Routine Description:
  1657.  
  1658.     This routine is a safer version of the C built-in function 'strcat' with
  1659.     some additional parameters.  In addition to functionality provided by
  1660.     StringCbCat, this routine also returns a pointer to the end of the
  1661.     destination string and the number of bytes left in the destination string
  1662.     including the null terminator. The flags parameter allows additional controls.
  1663.  
  1664. Arguments:
  1665.  
  1666.     pszDest         -   destination string which must be null terminated
  1667.  
  1668.     cbDest          -   size of destination buffer in bytes.
  1669.                         length must be ((_tcslen(pszDest) + _tcslen(pszSrc) + 1) * sizeof(TCHAR)
  1670.                         to hold all of the combine string plus the null
  1671.                         terminator.
  1672.  
  1673.     pszSrc          -   source string which must be null terminated
  1674.  
  1675.     ppszDestEnd     -   if ppszDestEnd is non-null, the function will return a
  1676.                         pointer to the end of the destination string.  If the
  1677.                         function appended any data, the result will point to the
  1678.                         null termination character
  1679.  
  1680.     pcbRemaining    -   if pcbRemaining is non-null, the function will return
  1681.                         the number of bytes left in the destination string,
  1682.                         including the null terminator
  1683.  
  1684.     dwFlags         -   controls some details of the string copy:
  1685.  
  1686.         STRSAFE_FILL_BEHIND_NULL
  1687.                     if the function succeeds, the low byte of dwFlags will be
  1688.                     used to fill the uninitialize part of destination buffer
  1689.                     behind the null terminator
  1690.  
  1691.         STRSAFE_IGNORE_NULLS
  1692.                     treat NULL string pointers like empty strings (TEXT("")).
  1693.                     this flag is useful for emulating functions like lstrcat
  1694.  
  1695.         STRSAFE_FILL_ON_FAILURE
  1696.                     if the function fails, the low byte of dwFlags will be
  1697.                     used to fill all of the destination buffer, and it will
  1698.                     be null terminated. This will overwrite any pre-existing
  1699.                     or truncated string
  1700.  
  1701.         STRSAFE_NULL_ON_FAILURE
  1702.                     if the function fails, the destination buffer will be set
  1703.                     to the empty string. This will overwrite any pre-existing or
  1704.                     truncated string
  1705.  
  1706.         STRSAFE_NO_TRUNCATION
  1707.                     if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest
  1708.                     will not contain a truncated string, it will remain unchanged.
  1709.  
  1710. Notes:
  1711.     Behavior is undefined if source and destination strings overlap.
  1712.  
  1713.     pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  1714.     is specified.  If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  1715.     may be NULL.  An error may still be returned even though NULLS are ignored
  1716.     due to insufficient space.
  1717.  
  1718. Return Value:
  1719.  
  1720.     S_OK           -   if there was source data and it was all concatenated
  1721.                        and the resultant dest string was null terminated
  1722.  
  1723.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  1724.                        error code for all hresult failure cases
  1725.  
  1726.       STRSAFE_E_INSUFFICIENT_BUFFER /
  1727.       HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  1728.                    -   this return value is an indication that the operation
  1729.                        failed due to insufficient space. When this error
  1730.                        occurs, the destination buffer is modified to contain
  1731.                        a truncated version of the ideal result and is null
  1732.                        terminated. This is useful for situations where
  1733.                        truncation is ok.
  1734.  
  1735.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  1736.     return value of this function
  1737.  
  1738. --*/
  1739.  
  1740. STRSAFEAPI StringCbCatExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
  1741. STRSAFEAPI StringCbCatExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
  1742. #ifdef UNICODE
  1743. #define StringCbCatEx  StringCbCatExW
  1744. #else
  1745. #define StringCbCatEx  StringCbCatExA
  1746. #endif // !UNICODE
  1747.  
  1748. #ifdef STRSAFE_INLINE
  1749. STRSAFEAPI StringCbCatExA(char* pszDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
  1750. {
  1751.     HRESULT hr;
  1752.     size_t cchDest;
  1753.     size_t cchRemaining = 0;
  1754.  
  1755.     cchDest = cbDest / sizeof(char);
  1756.  
  1757.     if (cchDest > STRSAFE_MAX_CCH)
  1758.     {
  1759.         hr = STRSAFE_E_INVALID_PARAMETER;
  1760.     }
  1761.     else
  1762.     {
  1763.         hr = StringCatExWorkerA(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags);
  1764.     }
  1765.  
  1766.     if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  1767.     {
  1768.         if (pcbRemaining)
  1769.         {
  1770.             // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
  1771.             *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
  1772.         }
  1773.     }
  1774.  
  1775.     return hr;
  1776. }
  1777.  
  1778. STRSAFEAPI StringCbCatExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
  1779. {
  1780.     HRESULT hr;
  1781.     size_t cchDest;
  1782.     size_t cchRemaining = 0;
  1783.  
  1784.     cchDest = cbDest / sizeof(wchar_t);
  1785.  
  1786.     if (cchDest > STRSAFE_MAX_CCH)
  1787.     {
  1788.         hr = STRSAFE_E_INVALID_PARAMETER;
  1789.     }
  1790.     else
  1791.     {
  1792.         hr = StringCatExWorkerW(pszDest, cchDest, cbDest, pszSrc, ppszDestEnd, &cchRemaining, dwFlags);
  1793.     }
  1794.  
  1795.     if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  1796.     {
  1797.         if (pcbRemaining)
  1798.         {
  1799.             // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  1800.             *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
  1801.         }
  1802.     }
  1803.  
  1804.     return hr;
  1805. }
  1806. #endif  // STRSAFE_INLINE
  1807. #endif  // !STRSAFE_NO_CB_FUNCTIONS
  1808.  
  1809.  
  1810. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  1811. /*++
  1812.  
  1813. STDAPI
  1814. StringCchCatN(
  1815.     IN OUT LPTSTR  pszDest,
  1816.     IN     size_t  cchDest,
  1817.     IN     LPCTSTR pszSrc,
  1818.     IN     size_t  cchMaxAppend
  1819.     );
  1820.  
  1821. Routine Description:
  1822.  
  1823.     This routine is a safer version of the C built-in function 'strncat'.
  1824.     The size of the destination buffer (in characters) is a parameter as well as
  1825.     the maximum number of characters to append, excluding the null terminator.
  1826.     This function will not write past the end of the destination buffer and it will
  1827.     ALWAYS null terminate pszDest (unless it is zero length).
  1828.  
  1829.     This function returns a hresult, and not a pointer.  It returns
  1830.     S_OK if all of pszSrc or the first cchMaxAppend characters were appended
  1831.     to the destination string and it was null terminated, otherwise it will
  1832.     return a failure code. In failure cases as much of pszSrc will be appended
  1833.     to pszDest as possible, and pszDest will be null terminated.
  1834.  
  1835. Arguments:
  1836.  
  1837.     pszDest         -   destination string which must be null terminated
  1838.  
  1839.     cchDest         -   size of destination buffer in characters.
  1840.                         length must be (_tcslen(pszDest) + min(cchMaxAppend, _tcslen(pszSrc)) + 1)
  1841.                         to hold all of the combine string plus the null
  1842.                         terminator.
  1843.  
  1844.     pszSrc          -   source string
  1845.  
  1846.     cchMaxAppend    -   maximum number of characters to append
  1847.  
  1848. Notes:
  1849.     Behavior is undefined if source and destination strings overlap.
  1850.  
  1851.     pszDest and pszSrc should not be NULL. See StringCchCatNEx if you require
  1852.     the handling of NULL values.
  1853.  
  1854. Return Value:
  1855.  
  1856.     S_OK           -   if all of pszSrc or the first cchMaxAppend characters
  1857.                        were concatenated to pszDest and the resultant dest
  1858.                        string was null terminated
  1859.  
  1860.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  1861.                        error code for all hresult failure cases
  1862.  
  1863.       STRSAFE_E_INSUFFICIENT_BUFFER /
  1864.       HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  1865.                    -   this return value is an indication that the operation
  1866.                        failed due to insufficient space. When this error
  1867.                        occurs, the destination buffer is modified to contain
  1868.                        a truncated version of the ideal result and is null
  1869.                        terminated. This is useful for situations where
  1870.                        truncation is ok.
  1871.  
  1872.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  1873.     return value of this function
  1874.  
  1875. --*/
  1876.  
  1877. STRSAFEAPI StringCchCatNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend);
  1878. STRSAFEAPI StringCchCatNW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend);
  1879. #ifdef UNICODE
  1880. #define StringCchCatN  StringCchCatNW
  1881. #else
  1882. #define StringCchCatN  StringCchCatNA
  1883. #endif // !UNICODE
  1884.  
  1885. #ifdef STRSAFE_INLINE
  1886. STRSAFEAPI StringCchCatNA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend)
  1887. {
  1888.     HRESULT hr;
  1889.  
  1890.     if (cchDest > STRSAFE_MAX_CCH)
  1891.     {
  1892.         hr = STRSAFE_E_INVALID_PARAMETER;
  1893.     }
  1894.     else
  1895.     {
  1896.         hr = StringCatNWorkerA(pszDest, cchDest, pszSrc, cchMaxAppend);
  1897.     }
  1898.  
  1899.     return hr;
  1900. }
  1901.  
  1902. STRSAFEAPI StringCchCatNW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend)
  1903. {
  1904.     HRESULT hr;
  1905.  
  1906.     if (cchDest > STRSAFE_MAX_CCH)
  1907.     {
  1908.         hr = STRSAFE_E_INVALID_PARAMETER;
  1909.     }
  1910.     else
  1911.     {
  1912.         hr = StringCatNWorkerW(pszDest, cchDest, pszSrc, cchMaxAppend);
  1913.     }
  1914.  
  1915.     return hr;
  1916. }
  1917. #endif  // STRSAFE_INLINE
  1918. #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  1919.  
  1920.  
  1921. #ifndef STRSAFE_NO_CB_FUNCTIONS
  1922. /*++
  1923.  
  1924. STDAPI
  1925. StringCbCatN(
  1926.     IN OUT LPTSTR  pszDest,
  1927.     IN     size_t  cbDest,
  1928.     IN     LPCTSTR pszSrc,
  1929.     IN     size_t  cbMaxAppend
  1930.     );
  1931.  
  1932. Routine Description:
  1933.  
  1934.     This routine is a safer version of the C built-in function 'strncat'.
  1935.     The size of the destination buffer (in bytes) is a parameter as well as
  1936.     the maximum number of bytes to append, excluding the null terminator.
  1937.     This function will not write past the end of the destination buffer and it will
  1938.     ALWAYS null terminate pszDest (unless it is zero length).
  1939.  
  1940.     This function returns a hresult, and not a pointer.  It returns
  1941.     S_OK if all of pszSrc or the first cbMaxAppend bytes were appended
  1942.     to the destination string and it was null terminated, otherwise it will
  1943.     return a failure code. In failure cases as much of pszSrc will be appended
  1944.     to pszDest as possible, and pszDest will be null terminated.
  1945.  
  1946. Arguments:
  1947.  
  1948.     pszDest         -   destination string which must be null terminated
  1949.  
  1950.     cbDest          -   size of destination buffer in bytes.
  1951.                         length must be ((_tcslen(pszDest) + min(cbMaxAppend / sizeof(TCHAR), _tcslen(pszSrc)) + 1) * sizeof(TCHAR)
  1952.                         to hold all of the combine string plus the null
  1953.                         terminator.
  1954.  
  1955.     pszSrc          -   source string
  1956.  
  1957.     cbMaxAppend     -   maximum number of bytes to append
  1958.  
  1959. Notes:
  1960.     Behavior is undefined if source and destination strings overlap.
  1961.  
  1962.     pszDest and pszSrc should not be NULL. See StringCbCatNEx if you require
  1963.     the handling of NULL values.
  1964.  
  1965. Return Value:
  1966.  
  1967.     S_OK           -   if all of pszSrc or the first cbMaxAppend bytes were
  1968.                        concatenated to pszDest and the resultant dest string
  1969.                        was null terminated
  1970.  
  1971.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  1972.                        error code for all hresult failure cases
  1973.  
  1974.       STRSAFE_E_INSUFFICIENT_BUFFER /
  1975.       HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  1976.                    -   this return value is an indication that the operation
  1977.                        failed due to insufficient space. When this error
  1978.                        occurs, the destination buffer is modified to contain
  1979.                        a truncated version of the ideal result and is null
  1980.                        terminated. This is useful for situations where
  1981.                        truncation is ok.
  1982.  
  1983.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  1984.     return value of this function
  1985.  
  1986. --*/
  1987.  
  1988. STRSAFEAPI StringCbCatNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend);
  1989. STRSAFEAPI StringCbCatNW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbMaxAppend);
  1990. #ifdef UNICODE
  1991. #define StringCbCatN  StringCbCatNW
  1992. #else
  1993. #define StringCbCatN  StringCbCatNA
  1994. #endif // !UNICODE
  1995.  
  1996. #ifdef STRSAFE_INLINE
  1997. STRSAFEAPI StringCbCatNA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend)
  1998. {
  1999.     HRESULT hr;
  2000.     size_t cchDest;
  2001.  
  2002.     cchDest = cbDest / sizeof(char);
  2003.  
  2004.     if (cchDest > STRSAFE_MAX_CCH)
  2005.     {
  2006.         hr = STRSAFE_E_INVALID_PARAMETER;
  2007.     }
  2008.     else
  2009.     {
  2010.         size_t cchMaxAppend;
  2011.  
  2012.         cchMaxAppend = cbMaxAppend / sizeof(char);
  2013.  
  2014.         hr = StringCatNWorkerA(pszDest, cchDest, pszSrc, cchMaxAppend);
  2015.     }
  2016.  
  2017.     return hr;
  2018. }
  2019.  
  2020. STRSAFEAPI StringCbCatNW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbMaxAppend)
  2021. {
  2022.     HRESULT hr;
  2023.     size_t cchDest;
  2024.  
  2025.     cchDest = cbDest / sizeof(wchar_t);
  2026.  
  2027.     if (cchDest > STRSAFE_MAX_CCH)
  2028.     {
  2029.         hr = STRSAFE_E_INVALID_PARAMETER;
  2030.     }
  2031.     else
  2032.     {
  2033.         size_t cchMaxAppend;
  2034.  
  2035.         cchMaxAppend = cbMaxAppend / sizeof(wchar_t);
  2036.  
  2037.         hr = StringCatNWorkerW(pszDest, cchDest, pszSrc, cchMaxAppend);
  2038.     }
  2039.  
  2040.     return hr;
  2041. }
  2042. #endif  // STRSAFE_INLINE
  2043. #endif  // !STRSAFE_NO_CB_FUNCTIONS
  2044.  
  2045.  
  2046. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  2047. /*++
  2048.  
  2049. STDAPI
  2050. StringCchCatNEx(
  2051.     IN OUT LPTSTR  pszDest         OPTIONAL,
  2052.     IN     size_t  cchDest,
  2053.     IN     LPCTSTR pszSrc          OPTIONAL,
  2054.     IN     size_t  cchMaxAppend,
  2055.     OUT    LPTSTR* ppszDestEnd     OPTIONAL,
  2056.     OUT    size_t* pcchRemaining   OPTIONAL,
  2057.     IN     DWORD   dwFlags
  2058.     );
  2059.  
  2060. Routine Description:
  2061.  
  2062.     This routine is a safer version of the C built-in function 'strncat', with
  2063.     some additional parameters.  In addition to functionality provided by
  2064.     StringCchCatN, this routine also returns a pointer to the end of the
  2065.     destination string and the number of characters left in the destination string
  2066.     including the null terminator. The flags parameter allows additional controls.
  2067.  
  2068. Arguments:
  2069.  
  2070.     pszDest         -   destination string which must be null terminated
  2071.  
  2072.     cchDest         -   size of destination buffer in characters.
  2073.                         length must be (_tcslen(pszDest) + min(cchMaxAppend, _tcslen(pszSrc)) + 1)
  2074.                         to hold all of the combine string plus the null
  2075.                         terminator.
  2076.  
  2077.     pszSrc          -   source string
  2078.  
  2079.     cchMaxAppend    -   maximum number of characters to append
  2080.  
  2081.     ppszDestEnd     -   if ppszDestEnd is non-null, the function will return a
  2082.                         pointer to the end of the destination string.  If the
  2083.                         function appended any data, the result will point to the
  2084.                         null termination character
  2085.  
  2086.     pcchRemaining   -   if pcchRemaining is non-null, the function will return the
  2087.                         number of characters left in the destination string,
  2088.                         including the null terminator
  2089.  
  2090.     dwFlags         -   controls some details of the string copy:
  2091.  
  2092.         STRSAFE_FILL_BEHIND_NULL
  2093.                     if the function succeeds, the low byte of dwFlags will be
  2094.                     used to fill the uninitialize part of destination buffer
  2095.                     behind the null terminator
  2096.  
  2097.         STRSAFE_IGNORE_NULLS
  2098.                     treat NULL string pointers like empty strings (TEXT(""))
  2099.  
  2100.         STRSAFE_FILL_ON_FAILURE
  2101.                     if the function fails, the low byte of dwFlags will be
  2102.                     used to fill all of the destination buffer, and it will
  2103.                     be null terminated. This will overwrite any pre-existing
  2104.                     or truncated string
  2105.  
  2106.         STRSAFE_NULL_ON_FAILURE
  2107.                     if the function fails, the destination buffer will be set
  2108.                     to the empty string. This will overwrite any pre-existing or
  2109.                     truncated string
  2110.  
  2111.         STRSAFE_NO_TRUNCATION
  2112.                     if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest
  2113.                     will not contain a truncated string, it will remain unchanged.
  2114.  
  2115. Notes:
  2116.     Behavior is undefined if source and destination strings overlap.
  2117.  
  2118.     pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  2119.     is specified.  If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  2120.     may be NULL.  An error may still be returned even though NULLS are ignored
  2121.     due to insufficient space.
  2122.  
  2123. Return Value:
  2124.  
  2125.     S_OK           -   if all of pszSrc or the first cchMaxAppend characters
  2126.                        were concatenated to pszDest and the resultant dest
  2127.                        string was null terminated
  2128.  
  2129.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  2130.                        error code for all hresult failure cases
  2131.  
  2132.       STRSAFE_E_INSUFFICIENT_BUFFER /
  2133.       HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  2134.                    -   this return value is an indication that the operation
  2135.                        failed due to insufficient space. When this error
  2136.                        occurs, the destination buffer is modified to contain
  2137.                        a truncated version of the ideal result and is null
  2138.                        terminated. This is useful for situations where
  2139.                        truncation is ok.
  2140.  
  2141.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  2142.     return value of this function
  2143.  
  2144. --*/
  2145.  
  2146. STRSAFEAPI StringCchCatNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  2147. STRSAFEAPI StringCchCatNExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  2148. #ifdef UNICODE
  2149. #define StringCchCatNEx  StringCchCatNExW
  2150. #else
  2151. #define StringCchCatNEx  StringCchCatNExA
  2152. #endif // !UNICODE
  2153.  
  2154. #ifdef STRSAFE_INLINE
  2155. STRSAFEAPI StringCchCatNExA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  2156. {
  2157.     HRESULT hr;
  2158.  
  2159.     if (cchDest > STRSAFE_MAX_CCH)
  2160.     {
  2161.         hr = STRSAFE_E_INVALID_PARAMETER;
  2162.     }
  2163.     else
  2164.     {
  2165.         size_t cbDest;
  2166.  
  2167.         // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
  2168.         cbDest = cchDest * sizeof(char);
  2169.  
  2170.         hr = StringCatNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, pcchRemaining, dwFlags);
  2171.     }
  2172.  
  2173.     return hr;
  2174. }
  2175.  
  2176. STRSAFEAPI StringCchCatNExW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  2177. {
  2178.     HRESULT hr;
  2179.  
  2180.     if (cchDest > STRSAFE_MAX_CCH)
  2181.     {
  2182.         hr = STRSAFE_E_INVALID_PARAMETER;
  2183.     }
  2184.     else
  2185.     {
  2186.         size_t cbDest;
  2187.  
  2188.         // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  2189.         cbDest = cchDest * sizeof(wchar_t);
  2190.  
  2191.         hr = StringCatNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, pcchRemaining, dwFlags);
  2192.     }
  2193.  
  2194.     return hr;
  2195. }
  2196. #endif  // STRSAFE_INLINE
  2197. #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  2198.  
  2199.  
  2200. #ifndef STRSAFE_NO_CB_FUNCTIONS
  2201. /*++
  2202.  
  2203. STDAPI
  2204. StringCbCatNEx(
  2205.     IN OUT LPTSTR  pszDest         OPTIONAL,
  2206.     IN     size_t  cbDest,
  2207.     IN     LPCTSTR pszSrc          OPTIONAL,
  2208.     IN     size_t  cbMaxAppend,
  2209.     OUT    LPTSTR* ppszDestEnd     OPTIONAL,
  2210.     OUT    size_t* pcchRemaining   OPTIONAL,
  2211.     IN     DWORD   dwFlags
  2212.     );
  2213.  
  2214. Routine Description:
  2215.  
  2216.     This routine is a safer version of the C built-in function 'strncat', with
  2217.     some additional parameters.  In addition to functionality provided by
  2218.     StringCbCatN, this routine also returns a pointer to the end of the
  2219.     destination string and the number of bytes left in the destination string
  2220.     including the null terminator. The flags parameter allows additional controls.
  2221.  
  2222. Arguments:
  2223.  
  2224.     pszDest         -   destination string which must be null terminated
  2225.  
  2226.     cbDest          -   size of destination buffer in bytes.
  2227.                         length must be ((_tcslen(pszDest) + min(cbMaxAppend / sizeof(TCHAR), _tcslen(pszSrc)) + 1) * sizeof(TCHAR)
  2228.                         to hold all of the combine string plus the null
  2229.                         terminator.
  2230.  
  2231.     pszSrc          -   source string
  2232.  
  2233.     cbMaxAppend     -   maximum number of bytes to append
  2234.  
  2235.     ppszDestEnd     -   if ppszDestEnd is non-null, the function will return a
  2236.                         pointer to the end of the destination string.  If the
  2237.                         function appended any data, the result will point to the
  2238.                         null termination character
  2239.  
  2240.     pcbRemaining    -   if pcbRemaining is non-null, the function will return the
  2241.                         number of bytes left in the destination string,
  2242.                         including the null terminator
  2243.  
  2244.     dwFlags         -   controls some details of the string copy:
  2245.  
  2246.         STRSAFE_FILL_BEHIND_NULL
  2247.                     if the function succeeds, the low byte of dwFlags will be
  2248.                     used to fill the uninitialize part of destination buffer
  2249.                     behind the null terminator
  2250.  
  2251.         STRSAFE_IGNORE_NULLS
  2252.                     treat NULL string pointers like empty strings (TEXT(""))
  2253.  
  2254.         STRSAFE_FILL_ON_FAILURE
  2255.                     if the function fails, the low byte of dwFlags will be
  2256.                     used to fill all of the destination buffer, and it will
  2257.                     be null terminated. This will overwrite any pre-existing
  2258.                     or truncated string
  2259.  
  2260.         STRSAFE_NULL_ON_FAILURE
  2261.                     if the function fails, the destination buffer will be set
  2262.                     to the empty string. This will overwrite any pre-existing or
  2263.                     truncated string
  2264.  
  2265.         STRSAFE_NO_TRUNCATION
  2266.                     if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest
  2267.                     will not contain a truncated string, it will remain unchanged.
  2268.  
  2269. Notes:
  2270.     Behavior is undefined if source and destination strings overlap.
  2271.  
  2272.     pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  2273.     is specified.  If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  2274.     may be NULL.  An error may still be returned even though NULLS are ignored
  2275.     due to insufficient space.
  2276.  
  2277. Return Value:
  2278.  
  2279.     S_OK           -   if all of pszSrc or the first cbMaxAppend bytes were
  2280.                        concatenated to pszDest and the resultant dest string
  2281.                        was null terminated
  2282.  
  2283.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  2284.                        error code for all hresult failure cases
  2285.  
  2286.       STRSAFE_E_INSUFFICIENT_BUFFER /
  2287.       HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  2288.                    -   this return value is an indication that the operation
  2289.                        failed due to insufficient space. When this error
  2290.                        occurs, the destination buffer is modified to contain
  2291.                        a truncated version of the ideal result and is null
  2292.                        terminated. This is useful for situations where
  2293.                        truncation is ok.
  2294.  
  2295.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  2296.     return value of this function
  2297.  
  2298. --*/
  2299.  
  2300. STRSAFEAPI StringCbCatNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
  2301. STRSAFEAPI StringCbCatNExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbMaxAppend, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
  2302. #ifdef UNICODE
  2303. #define StringCbCatNEx  StringCbCatNExW
  2304. #else
  2305. #define StringCbCatNEx  StringCbCatNExA
  2306. #endif // !UNICODE
  2307.  
  2308. #ifdef STRSAFE_INLINE
  2309. STRSAFEAPI StringCbCatNExA(char* pszDest, size_t cbDest, const char* pszSrc, size_t cbMaxAppend, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
  2310. {
  2311.     HRESULT hr;
  2312.     size_t cchDest;
  2313.     size_t cchRemaining = 0;
  2314.  
  2315.     cchDest = cbDest / sizeof(char);
  2316.  
  2317.     if (cchDest > STRSAFE_MAX_CCH)
  2318.     {
  2319.         hr = STRSAFE_E_INVALID_PARAMETER;
  2320.     }
  2321.     else
  2322.     {
  2323.         size_t cchMaxAppend;
  2324.  
  2325.         cchMaxAppend = cbMaxAppend / sizeof(char);
  2326.  
  2327.         hr = StringCatNExWorkerA(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, &cchRemaining, dwFlags);
  2328.     }
  2329.  
  2330.     if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  2331.     {
  2332.         if (pcbRemaining)
  2333.         {
  2334.             // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
  2335.             *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
  2336.         }
  2337.     }
  2338.  
  2339.     return hr;
  2340. }
  2341.  
  2342. STRSAFEAPI StringCbCatNExW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszSrc, size_t cbMaxAppend, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
  2343. {
  2344.     HRESULT hr;
  2345.     size_t cchDest;
  2346.     size_t cchRemaining = 0;
  2347.  
  2348.     cchDest = cbDest / sizeof(wchar_t);
  2349.  
  2350.     if (cchDest > STRSAFE_MAX_CCH)
  2351.     {
  2352.         hr = STRSAFE_E_INVALID_PARAMETER;
  2353.     }
  2354.     else
  2355.     {
  2356.         size_t cchMaxAppend;
  2357.  
  2358.         cchMaxAppend = cbMaxAppend / sizeof(wchar_t);
  2359.  
  2360.         hr = StringCatNExWorkerW(pszDest, cchDest, cbDest, pszSrc, cchMaxAppend, ppszDestEnd, &cchRemaining, dwFlags);
  2361.     }
  2362.  
  2363.     if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  2364.     {
  2365.         if (pcbRemaining)
  2366.         {
  2367.             // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  2368.             *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
  2369.         }
  2370.     }
  2371.  
  2372.     return hr;
  2373. }
  2374. #endif  // STRSAFE_INLINE
  2375. #endif  // !STRSAFE_NO_CB_FUNCTIONS
  2376.  
  2377.  
  2378. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  2379. /*++
  2380.  
  2381. STDAPI
  2382. StringCchVPrintf(
  2383.     OUT LPTSTR  pszDest,
  2384.     IN  size_t  cchDest,
  2385.     IN  LPCTSTR pszFormat,
  2386.     IN  va_list argList
  2387.     );
  2388.  
  2389. Routine Description:
  2390.  
  2391.     This routine is a safer version of the C built-in function 'vsprintf'.
  2392.     The size of the destination buffer (in characters) is a parameter and
  2393.     this function will not write past the end of this buffer and it will
  2394.     ALWAYS null terminate the destination buffer (unless it is zero length).
  2395.  
  2396.     This function returns a hresult, and not a pointer.  It returns
  2397.     S_OK if the string was printed without truncation and null terminated,
  2398.     otherwise it will return a failure code. In failure cases it will return
  2399.     a truncated version of the ideal result.
  2400.  
  2401. Arguments:
  2402.  
  2403.     pszDest     -  destination string
  2404.  
  2405.     cchDest     -  size of destination buffer in characters
  2406.                    length must be sufficient to hold the resulting formatted
  2407.                    string, including the null terminator.
  2408.  
  2409.     pszFormat   -  format string which must be null terminated
  2410.  
  2411.     argList     -  va_list from the variable arguments according to the
  2412.                    stdarg.h convention
  2413.  
  2414. Notes:
  2415.     Behavior is undefined if destination, format strings or any arguments
  2416.     strings overlap.
  2417.  
  2418.     pszDest and pszFormat should not be NULL.  See StringCchVPrintfEx if you
  2419.     require the handling of NULL values.
  2420.  
  2421. Return Value:
  2422.  
  2423.     S_OK           -   if there was sufficient space in the dest buffer for
  2424.                        the resultant string and it was null terminated.
  2425.  
  2426.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  2427.                        error code for all hresult failure cases
  2428.  
  2429.       STRSAFE_E_INSUFFICIENT_BUFFER /
  2430.       HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  2431.                    -   this return value is an indication that the print
  2432.                        operation failed due to insufficient space. When this
  2433.                        error occurs, the destination buffer is modified to
  2434.                        contain a truncated version of the ideal result and is
  2435.                        null terminated. This is useful for situations where
  2436.                        truncation is ok.
  2437.  
  2438.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  2439.     return value of this function
  2440.  
  2441. --*/
  2442.  
  2443. STRSAFEAPI StringCchVPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList);
  2444. STRSAFEAPI StringCchVPrintfW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, va_list argList);
  2445. #ifdef UNICODE
  2446. #define StringCchVPrintf  StringCchVPrintfW
  2447. #else
  2448. #define StringCchVPrintf  StringCchVPrintfA
  2449. #endif // !UNICODE
  2450.  
  2451. #ifdef STRSAFE_INLINE
  2452. STRSAFEAPI StringCchVPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList)
  2453. {
  2454.     HRESULT hr;
  2455.  
  2456.     if (cchDest > STRSAFE_MAX_CCH)
  2457.     {
  2458.         hr = STRSAFE_E_INVALID_PARAMETER;
  2459.     }
  2460.     else
  2461.     {
  2462.         hr = StringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList);
  2463.     }
  2464.  
  2465.     return hr;
  2466. }
  2467.  
  2468. STRSAFEAPI StringCchVPrintfW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, va_list argList)
  2469. {
  2470.     HRESULT hr;
  2471.  
  2472.     if (cchDest > STRSAFE_MAX_CCH)
  2473.     {
  2474.         hr = STRSAFE_E_INVALID_PARAMETER;
  2475.     }
  2476.     else
  2477.     {
  2478.         hr = StringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList);
  2479.     }
  2480.  
  2481.     return hr;
  2482. }
  2483. #endif  // STRSAFE_INLINE
  2484. #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  2485.  
  2486.  
  2487. #ifndef STRSAFE_NO_CB_FUNCTIONS
  2488. /*++
  2489.  
  2490. STDAPI
  2491. StringCbVPrintf(
  2492.     OUT LPTSTR  pszDest,
  2493.     IN  size_t  cbDest,
  2494.     IN  LPCTSTR pszFormat,
  2495.     IN  va_list argList
  2496.     );
  2497.  
  2498. Routine Description:
  2499.  
  2500.     This routine is a safer version of the C built-in function 'vsprintf'.
  2501.     The size of the destination buffer (in bytes) is a parameter and
  2502.     this function will not write past the end of this buffer and it will
  2503.     ALWAYS null terminate the destination buffer (unless it is zero length).
  2504.  
  2505.     This function returns a hresult, and not a pointer.  It returns
  2506.     S_OK if the string was printed without truncation and null terminated,
  2507.     otherwise it will return a failure code. In failure cases it will return
  2508.     a truncated version of the ideal result.
  2509.  
  2510. Arguments:
  2511.  
  2512.     pszDest     -  destination string
  2513.  
  2514.     cbDest      -  size of destination buffer in bytes
  2515.                    length must be sufficient to hold the resulting formatted
  2516.                    string, including the null terminator.
  2517.  
  2518.     pszFormat   -  format string which must be null terminated
  2519.  
  2520.     argList     -  va_list from the variable arguments according to the
  2521.                    stdarg.h convention
  2522.  
  2523. Notes:
  2524.     Behavior is undefined if destination, format strings or any arguments
  2525.     strings overlap.
  2526.  
  2527.     pszDest and pszFormat should not be NULL.  See StringCbVPrintfEx if you
  2528.     require the handling of NULL values.
  2529.  
  2530.  
  2531. Return Value:
  2532.  
  2533.     S_OK           -   if there was sufficient space in the dest buffer for
  2534.                        the resultant string and it was null terminated.
  2535.  
  2536.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  2537.                        error code for all hresult failure cases
  2538.  
  2539.       STRSAFE_E_INSUFFICIENT_BUFFER /
  2540.       HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  2541.                    -   this return value is an indication that the print
  2542.                        operation failed due to insufficient space. When this
  2543.                        error occurs, the destination buffer is modified to
  2544.                        contain a truncated version of the ideal result and is
  2545.                        null terminated. This is useful for situations where
  2546.                        truncation is ok.
  2547.  
  2548.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  2549.     return value of this function
  2550.  
  2551. --*/
  2552.  
  2553. STRSAFEAPI StringCbVPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, va_list argList);
  2554. STRSAFEAPI StringCbVPrintfW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszFormat, va_list argList);
  2555. #ifdef UNICODE
  2556. #define StringCbVPrintf  StringCbVPrintfW
  2557. #else
  2558. #define StringCbVPrintf  StringCbVPrintfA
  2559. #endif // !UNICODE
  2560.  
  2561. #ifdef STRSAFE_INLINE
  2562. STRSAFEAPI StringCbVPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, va_list argList)
  2563. {
  2564.     HRESULT hr;
  2565.     size_t cchDest;
  2566.  
  2567.     cchDest = cbDest / sizeof(char);
  2568.  
  2569.     if (cchDest > STRSAFE_MAX_CCH)
  2570.     {
  2571.         hr = STRSAFE_E_INVALID_PARAMETER;
  2572.     }
  2573.     else
  2574.     {
  2575.         hr = StringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList);
  2576.     }
  2577.  
  2578.     return hr;
  2579. }
  2580.  
  2581. STRSAFEAPI StringCbVPrintfW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszFormat, va_list argList)
  2582. {
  2583.     HRESULT hr;
  2584.     size_t cchDest;
  2585.  
  2586.     cchDest = cbDest / sizeof(wchar_t);
  2587.  
  2588.     if (cchDest > STRSAFE_MAX_CCH)
  2589.     {
  2590.         hr = STRSAFE_E_INVALID_PARAMETER;
  2591.     }
  2592.     else
  2593.     {
  2594.         hr = StringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList);
  2595.     }
  2596.  
  2597.     return hr;
  2598. }
  2599. #endif  // STRSAFE_INLINE
  2600. #endif  // !STRSAFE_NO_CB_FUNCTIONS
  2601.  
  2602.  
  2603. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  2604. /*++
  2605.  
  2606. STDAPI
  2607. StringCchPrintf(
  2608.     OUT LPTSTR  pszDest,
  2609.     IN  size_t  cchDest,
  2610.     IN  LPCTSTR pszFormat,
  2611.     ...
  2612.     );
  2613.  
  2614. Routine Description:
  2615.  
  2616.     This routine is a safer version of the C built-in function 'sprintf'.
  2617.     The size of the destination buffer (in characters) is a parameter and
  2618.     this function will not write past the end of this buffer and it will
  2619.     ALWAYS null terminate the destination buffer (unless it is zero length).
  2620.  
  2621.     This function returns a hresult, and not a pointer.  It returns
  2622.     S_OK if the string was printed without truncation and null terminated,
  2623.     otherwise it will return a failure code. In failure cases it will return
  2624.     a truncated version of the ideal result.
  2625.  
  2626. Arguments:
  2627.  
  2628.     pszDest     -  destination string
  2629.  
  2630.     cchDest     -  size of destination buffer in characters
  2631.                    length must be sufficient to hold the resulting formatted
  2632.                    string, including the null terminator.
  2633.  
  2634.     pszFormat   -  format string which must be null terminated
  2635.  
  2636.     ...         -  additional parameters to be formatted according to
  2637.                    the format string
  2638.  
  2639. Notes:
  2640.     Behavior is undefined if destination, format strings or any arguments
  2641.     strings overlap.
  2642.  
  2643.     pszDest and pszFormat should not be NULL.  See StringCchPrintfEx if you
  2644.     require the handling of NULL values.
  2645.  
  2646. Return Value:
  2647.  
  2648.     S_OK           -   if there was sufficient space in the dest buffer for
  2649.                        the resultant string and it was null terminated.
  2650.  
  2651.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  2652.                        error code for all hresult failure cases
  2653.  
  2654.       STRSAFE_E_INSUFFICIENT_BUFFER /
  2655.       HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  2656.                    -   this return value is an indication that the print
  2657.                        operation failed due to insufficient space. When this
  2658.                        error occurs, the destination buffer is modified to
  2659.                        contain a truncated version of the ideal result and is
  2660.                        null terminated. This is useful for situations where
  2661.                        truncation is ok.
  2662.  
  2663.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  2664.     return value of this function
  2665.  
  2666. --*/
  2667.  
  2668. STRSAFEAPI StringCchPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, ...);
  2669. STRSAFEAPI StringCchPrintfW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, ...);
  2670. #ifdef UNICODE
  2671. #define StringCchPrintf  StringCchPrintfW
  2672. #else
  2673. #define StringCchPrintf  StringCchPrintfA
  2674. #endif // !UNICODE
  2675.  
  2676. #ifdef STRSAFE_INLINE
  2677. STRSAFEAPI StringCchPrintfA(char* pszDest, size_t cchDest, const char* pszFormat, ...)
  2678. {
  2679.     HRESULT hr;
  2680.  
  2681.     if (cchDest > STRSAFE_MAX_CCH)
  2682.     {
  2683.         hr = STRSAFE_E_INVALID_PARAMETER;
  2684.     }
  2685.     else
  2686.     {
  2687.         va_list argList;
  2688.  
  2689.         va_start(argList, pszFormat);
  2690.  
  2691.         hr = StringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList);
  2692.  
  2693.         va_end(argList);
  2694.     }
  2695.  
  2696.     return hr;
  2697. }
  2698.  
  2699. STRSAFEAPI StringCchPrintfW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, ...)
  2700. {
  2701.     HRESULT hr;
  2702.  
  2703.     if (cchDest > STRSAFE_MAX_CCH)
  2704.     {
  2705.         hr = STRSAFE_E_INVALID_PARAMETER;
  2706.     }
  2707.     else
  2708.     {
  2709.         va_list argList;
  2710.  
  2711.         va_start(argList, pszFormat);
  2712.  
  2713.         hr = StringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList);
  2714.  
  2715.         va_end(argList);
  2716.     }
  2717.  
  2718.     return hr;
  2719. }
  2720. #endif  // STRSAFE_INLINE
  2721. #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  2722.  
  2723.  
  2724. #ifndef STRSAFE_NO_CB_FUNCTIONS
  2725. /*++
  2726.  
  2727. STDAPI
  2728. StringCbPrintf(
  2729.     OUT LPTSTR  pszDest,
  2730.     IN  size_t  cbDest,
  2731.     IN  LPCTSTR pszFormat,
  2732.     ...
  2733.     );
  2734.  
  2735. Routine Description:
  2736.  
  2737.     This routine is a safer version of the C built-in function 'sprintf'.
  2738.     The size of the destination buffer (in bytes) is a parameter and
  2739.     this function will not write past the end of this buffer and it will
  2740.     ALWAYS null terminate the destination buffer (unless it is zero length).
  2741.  
  2742.     This function returns a hresult, and not a pointer.  It returns
  2743.     S_OK if the string was printed without truncation and null terminated,
  2744.     otherwise it will return a failure code. In failure cases it will return
  2745.     a truncated version of the ideal result.
  2746.  
  2747. Arguments:
  2748.  
  2749.     pszDest     -  destination string
  2750.  
  2751.     cbDest      -  size of destination buffer in bytes
  2752.                    length must be sufficient to hold the resulting formatted
  2753.                    string, including the null terminator.
  2754.  
  2755.     pszFormat   -  format string which must be null terminated
  2756.  
  2757.     ...         -  additional parameters to be formatted according to
  2758.                    the format string
  2759.  
  2760. Notes:
  2761.     Behavior is undefined if destination, format strings or any arguments
  2762.     strings overlap.
  2763.  
  2764.     pszDest and pszFormat should not be NULL.  See StringCbPrintfEx if you
  2765.     require the handling of NULL values.
  2766.  
  2767.  
  2768. Return Value:
  2769.  
  2770.     S_OK           -   if there was sufficient space in the dest buffer for
  2771.                        the resultant string and it was null terminated.
  2772.  
  2773.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  2774.                        error code for all hresult failure cases
  2775.  
  2776.       STRSAFE_E_INSUFFICIENT_BUFFER /
  2777.       HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  2778.                    -   this return value is an indication that the print
  2779.                        operation failed due to insufficient space. When this
  2780.                        error occurs, the destination buffer is modified to
  2781.                        contain a truncated version of the ideal result and is
  2782.                        null terminated. This is useful for situations where
  2783.                        truncation is ok.
  2784.  
  2785.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  2786.     return value of this function
  2787.  
  2788. --*/
  2789.  
  2790. STRSAFEAPI StringCbPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, ...);
  2791. STRSAFEAPI StringCbPrintfW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszFormat, ...);
  2792. #ifdef UNICODE
  2793. #define StringCbPrintf  StringCbPrintfW
  2794. #else
  2795. #define StringCbPrintf  StringCbPrintfA
  2796. #endif // !UNICODE
  2797.  
  2798. #ifdef STRSAFE_INLINE
  2799. STRSAFEAPI StringCbPrintfA(char* pszDest, size_t cbDest, const char* pszFormat, ...)
  2800. {
  2801.     HRESULT hr;
  2802.     size_t cchDest;
  2803.  
  2804.     cchDest = cbDest / sizeof(char);
  2805.  
  2806.     if (cchDest > STRSAFE_MAX_CCH)
  2807.     {
  2808.         hr = STRSAFE_E_INVALID_PARAMETER;
  2809.     }
  2810.     else
  2811.     {
  2812.         va_list argList;
  2813.  
  2814.         va_start(argList, pszFormat);
  2815.  
  2816.         hr = StringVPrintfWorkerA(pszDest, cchDest, pszFormat, argList);
  2817.  
  2818.         va_end(argList);
  2819.     }
  2820.  
  2821.     return hr;
  2822. }
  2823.  
  2824. STRSAFEAPI StringCbPrintfW(wchar_t* pszDest, size_t cbDest, const wchar_t* pszFormat, ...)
  2825. {
  2826.     HRESULT hr;
  2827.     size_t cchDest;
  2828.  
  2829.     cchDest = cbDest / sizeof(wchar_t);
  2830.  
  2831.     if (cchDest > STRSAFE_MAX_CCH)
  2832.     {
  2833.         hr = STRSAFE_E_INVALID_PARAMETER;
  2834.     }
  2835.     else
  2836.     {
  2837.         va_list argList;
  2838.  
  2839.         va_start(argList, pszFormat);
  2840.  
  2841.         hr = StringVPrintfWorkerW(pszDest, cchDest, pszFormat, argList);
  2842.  
  2843.         va_end(argList);
  2844.     }
  2845.  
  2846.     return hr;
  2847. }
  2848. #endif  // STRSAFE_INLINE
  2849. #endif  // !STRSAFE_NO_CB_FUNCTIONS
  2850.  
  2851.  
  2852. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  2853. /*++
  2854.  
  2855. STDAPI
  2856. StringCchPrintfEx(
  2857.     OUT LPTSTR  pszDest         OPTIONAL,
  2858.     IN  size_t  cchDest,
  2859.     OUT LPTSTR* ppszDestEnd     OPTIONAL,
  2860.     OUT size_t* pcchRemaining   OPTIONAL,
  2861.     IN  DWORD   dwFlags,
  2862.     IN  LPCTSTR pszFormat       OPTIONAL,
  2863.     ...
  2864.     );
  2865.  
  2866. Routine Description:
  2867.  
  2868.     This routine is a safer version of the C built-in function 'sprintf' with
  2869.     some additional parameters.  In addition to functionality provided by
  2870.     StringCchPrintf, this routine also returns a pointer to the end of the
  2871.     destination string and the number of characters left in the destination string
  2872.     including the null terminator. The flags parameter allows additional controls.
  2873.  
  2874. Arguments:
  2875.  
  2876.     pszDest         -   destination string
  2877.  
  2878.     cchDest         -   size of destination buffer in characters.
  2879.                         length must be sufficient to contain the resulting
  2880.                         formatted string plus the null terminator.
  2881.  
  2882.     ppszDestEnd     -   if ppszDestEnd is non-null, the function will return a
  2883.                         pointer to the end of the destination string.  If the
  2884.                         function printed any data, the result will point to the
  2885.                         null termination character
  2886.  
  2887.     pcchRemaining   -   if pcchRemaining is non-null, the function will return
  2888.                         the number of characters left in the destination string,
  2889.                         including the null terminator
  2890.  
  2891.     dwFlags         -   controls some details of the string copy:
  2892.  
  2893.         STRSAFE_FILL_BEHIND_NULL
  2894.                     if the function succeeds, the low byte of dwFlags will be
  2895.                     used to fill the uninitialize part of destination buffer
  2896.                     behind the null terminator
  2897.  
  2898.         STRSAFE_IGNORE_NULLS
  2899.                     treat NULL string pointers like empty strings (TEXT(""))
  2900.  
  2901.         STRSAFE_FILL_ON_FAILURE
  2902.                     if the function fails, the low byte of dwFlags will be
  2903.                     used to fill all of the destination buffer, and it will
  2904.                     be null terminated. This will overwrite any truncated
  2905.                     string returned when the failure is
  2906.                     STRSAFE_E_INSUFFICIENT_BUFFER
  2907.  
  2908.         STRSAFE_NO_TRUNCATION /
  2909.         STRSAFE_NULL_ON_FAILURE
  2910.                     if the function fails, the destination buffer will be set
  2911.                     to the empty string. This will overwrite any truncated string
  2912.                     returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
  2913.  
  2914.     pszFormat       -   format string which must be null terminated
  2915.  
  2916.     ...             -   additional parameters to be formatted according to
  2917.                         the format string
  2918.  
  2919. Notes:
  2920.     Behavior is undefined if destination, format strings or any arguments
  2921.     strings overlap.
  2922.  
  2923.     pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS
  2924.     flag is specified.  If STRSAFE_IGNORE_NULLS is passed, both pszDest and
  2925.     pszFormat may be NULL.  An error may still be returned even though NULLS
  2926.     are ignored due to insufficient space.
  2927.  
  2928. Return Value:
  2929.  
  2930.     S_OK           -   if there was source data and it was all concatenated and
  2931.                        the resultant dest string was null terminated
  2932.  
  2933.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  2934.                        error code for all hresult failure cases
  2935.  
  2936.       STRSAFE_E_INSUFFICIENT_BUFFER /
  2937.       HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  2938.                    -   this return value is an indication that the print
  2939.                        operation failed due to insufficient space. When this
  2940.                        error occurs, the destination buffer is modified to
  2941.                        contain a truncated version of the ideal result and is
  2942.                        null terminated. This is useful for situations where
  2943.                        truncation is ok.
  2944.  
  2945.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  2946.     return value of this function
  2947.  
  2948. --*/
  2949.  
  2950. STRSAFEAPI StringCchPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, ...);
  2951. STRSAFEAPI StringCchPrintfExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, ...);
  2952. #ifdef UNICODE
  2953. #define StringCchPrintfEx  StringCchPrintfExW
  2954. #else
  2955. #define StringCchPrintfEx  StringCchPrintfExA
  2956. #endif // !UNICODE
  2957.  
  2958. #ifdef STRSAFE_INLINE
  2959. STRSAFEAPI StringCchPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, ...)
  2960. {
  2961.     HRESULT hr;
  2962.  
  2963.     if (cchDest > STRSAFE_MAX_CCH)
  2964.     {
  2965.         hr = STRSAFE_E_INVALID_PARAMETER;
  2966.     }
  2967.     else
  2968.     {
  2969.         size_t cbDest;
  2970.         va_list argList;
  2971.  
  2972.         // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
  2973.         cbDest = cchDest * sizeof(char);
  2974.         va_start(argList, pszFormat);
  2975.  
  2976.         hr = StringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList);
  2977.  
  2978.         va_end(argList);
  2979.     }
  2980.  
  2981.     return hr;
  2982. }
  2983.  
  2984. STRSAFEAPI StringCchPrintfExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, ...)
  2985. {
  2986.     HRESULT hr;
  2987.  
  2988.     if (cchDest > STRSAFE_MAX_CCH)
  2989.     {
  2990.         hr = STRSAFE_E_INVALID_PARAMETER;
  2991.     }
  2992.     else
  2993.     {
  2994.         size_t cbDest;
  2995.         va_list argList;
  2996.  
  2997.         // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  2998.         cbDest = cchDest * sizeof(wchar_t);
  2999.         va_start(argList, pszFormat);
  3000.  
  3001.         hr = StringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList);
  3002.  
  3003.         va_end(argList);
  3004.     }
  3005.  
  3006.     return hr;
  3007. }
  3008. #endif  // STRSAFE_INLINE
  3009. #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  3010.  
  3011.  
  3012. #ifndef STRSAFE_NO_CB_FUNCTIONS
  3013. /*++
  3014.  
  3015. STDAPI
  3016. StringCbPrintfEx(
  3017.     OUT LPTSTR  pszDest         OPTIONAL,
  3018.     IN  size_t  cbDest,
  3019.     OUT LPTSTR* ppszDestEnd     OPTIONAL,
  3020.     OUT size_t* pcbRemaining    OPTIONAL,
  3021.     IN  DWORD   dwFlags,
  3022.     IN  LPCTSTR pszFormat       OPTIONAL,
  3023.     ...
  3024.     );
  3025.  
  3026. Routine Description:
  3027.  
  3028.     This routine is a safer version of the C built-in function 'sprintf' with
  3029.     some additional parameters.  In addition to functionality provided by
  3030.     StringCbPrintf, this routine also returns a pointer to the end of the
  3031.     destination string and the number of bytes left in the destination string
  3032.     including the null terminator. The flags parameter allows additional controls.
  3033.  
  3034. Arguments:
  3035.  
  3036.     pszDest         -   destination string
  3037.  
  3038.     cbDest          -   size of destination buffer in bytes.
  3039.                         length must be sufficient to contain the resulting
  3040.                         formatted string plus the null terminator.
  3041.  
  3042.     ppszDestEnd     -   if ppszDestEnd is non-null, the function will return a
  3043.                         pointer to the end of the destination string.  If the
  3044.                         function printed any data, the result will point to the
  3045.                         null termination character
  3046.  
  3047.     pcbRemaining    -   if pcbRemaining is non-null, the function will return
  3048.                         the number of bytes left in the destination string,
  3049.                         including the null terminator
  3050.  
  3051.     dwFlags         -   controls some details of the string copy:
  3052.  
  3053.         STRSAFE_FILL_BEHIND_NULL
  3054.                     if the function succeeds, the low byte of dwFlags will be
  3055.                     used to fill the uninitialize part of destination buffer
  3056.                     behind the null terminator
  3057.  
  3058.         STRSAFE_IGNORE_NULLS
  3059.                     treat NULL string pointers like empty strings (TEXT(""))
  3060.  
  3061.         STRSAFE_FILL_ON_FAILURE
  3062.                     if the function fails, the low byte of dwFlags will be
  3063.                     used to fill all of the destination buffer, and it will
  3064.                     be null terminated. This will overwrite any truncated
  3065.                     string returned when the failure is
  3066.                     STRSAFE_E_INSUFFICIENT_BUFFER
  3067.  
  3068.         STRSAFE_NO_TRUNCATION /
  3069.         STRSAFE_NULL_ON_FAILURE
  3070.                     if the function fails, the destination buffer will be set
  3071.                     to the empty string. This will overwrite any truncated string
  3072.                     returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
  3073.  
  3074.     pszFormat       -   format string which must be null terminated
  3075.  
  3076.     ...             -   additional parameters to be formatted according to
  3077.                         the format string
  3078.  
  3079. Notes:
  3080.     Behavior is undefined if destination, format strings or any arguments
  3081.     strings overlap.
  3082.  
  3083.     pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS
  3084.     flag is specified.  If STRSAFE_IGNORE_NULLS is passed, both pszDest and
  3085.     pszFormat may be NULL.  An error may still be returned even though NULLS
  3086.     are ignored due to insufficient space.
  3087.  
  3088. Return Value:
  3089.  
  3090.     S_OK           -   if there was source data and it was all concatenated and
  3091.                        the resultant dest string was null terminated
  3092.  
  3093.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  3094.                        error code for all hresult failure cases
  3095.  
  3096.       STRSAFE_E_INSUFFICIENT_BUFFER /
  3097.       HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  3098.                    -   this return value is an indication that the print
  3099.                        operation failed due to insufficient space. When this
  3100.                        error occurs, the destination buffer is modified to
  3101.                        contain a truncated version of the ideal result and is
  3102.                        null terminated. This is useful for situations where
  3103.                        truncation is ok.
  3104.  
  3105.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  3106.     return value of this function
  3107.  
  3108. --*/
  3109.  
  3110. STRSAFEAPI StringCbPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, ...);
  3111. STRSAFEAPI StringCbPrintfExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const wchar_t* pszFormat, ...);
  3112. #ifdef UNICODE
  3113. #define StringCbPrintfEx  StringCbPrintfExW
  3114. #else
  3115. #define StringCbPrintfEx  StringCbPrintfExA
  3116. #endif // !UNICODE
  3117.  
  3118. #ifdef STRSAFE_INLINE
  3119. STRSAFEAPI StringCbPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, ...)
  3120. {
  3121.     HRESULT hr;
  3122.     size_t cchDest;
  3123.     size_t cchRemaining = 0;
  3124.  
  3125.     cchDest = cbDest / sizeof(char);
  3126.  
  3127.     if (cchDest > STRSAFE_MAX_CCH)
  3128.     {
  3129.         hr = STRSAFE_E_INVALID_PARAMETER;
  3130.     }
  3131.     else
  3132.     {
  3133.         va_list argList;
  3134.  
  3135.         va_start(argList, pszFormat);
  3136.  
  3137.         hr = StringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList);
  3138.  
  3139.         va_end(argList);
  3140.     }
  3141.  
  3142.     if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  3143.     {
  3144.         if (pcbRemaining)
  3145.         {
  3146.             // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
  3147.             *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
  3148.         }
  3149.     }
  3150.  
  3151.     return hr;
  3152. }
  3153.  
  3154. STRSAFEAPI StringCbPrintfExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const wchar_t* pszFormat, ...)
  3155. {
  3156.     HRESULT hr;
  3157.     size_t cchDest;
  3158.     size_t cchRemaining = 0;
  3159.  
  3160.     cchDest = cbDest / sizeof(wchar_t);
  3161.  
  3162.     if (cchDest > STRSAFE_MAX_CCH)
  3163.     {
  3164.         hr = STRSAFE_E_INVALID_PARAMETER;
  3165.     }
  3166.     else
  3167.     {
  3168.         va_list argList;
  3169.  
  3170.         va_start(argList, pszFormat);
  3171.  
  3172.         hr = StringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList);
  3173.  
  3174.         va_end(argList);
  3175.     }
  3176.  
  3177.     if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  3178.     {
  3179.         if (pcbRemaining)
  3180.         {
  3181.             // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  3182.             *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
  3183.         }
  3184.     }
  3185.  
  3186.     return hr;
  3187. }
  3188. #endif  // STRSAFE_INLINE
  3189. #endif  // !STRSAFE_NO_CB_FUNCTIONS
  3190.  
  3191.  
  3192. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  3193. /*++
  3194.  
  3195. STDAPI
  3196. StringCchVPrintfEx(
  3197.     OUT LPTSTR  pszDest         OPTIONAL,
  3198.     IN  size_t  cchDest,
  3199.     OUT LPTSTR* ppszDestEnd     OPTIONAL,
  3200.     OUT size_t* pcchRemaining   OPTIONAL,
  3201.     IN  DWORD   dwFlags,
  3202.     IN  LPCTSTR pszFormat       OPTIONAL,
  3203.     IN  va_list argList
  3204.     );
  3205.  
  3206. Routine Description:
  3207.  
  3208.     This routine is a safer version of the C built-in function 'vsprintf' with
  3209.     some additional parameters.  In addition to functionality provided by
  3210.     StringCchVPrintf, this routine also returns a pointer to the end of the
  3211.     destination string and the number of characters left in the destination string
  3212.     including the null terminator. The flags parameter allows additional controls.
  3213.  
  3214. Arguments:
  3215.  
  3216.     pszDest         -   destination string
  3217.  
  3218.     cchDest         -   size of destination buffer in characters.
  3219.                         length must be sufficient to contain the resulting
  3220.                         formatted string plus the null terminator.
  3221.  
  3222.     ppszDestEnd     -   if ppszDestEnd is non-null, the function will return a
  3223.                         pointer to the end of the destination string.  If the
  3224.                         function printed any data, the result will point to the
  3225.                         null termination character
  3226.  
  3227.     pcchRemaining   -   if pcchRemaining is non-null, the function will return
  3228.                         the number of characters left in the destination string,
  3229.                         including the null terminator
  3230.  
  3231.     dwFlags         -   controls some details of the string copy:
  3232.  
  3233.         STRSAFE_FILL_BEHIND_NULL
  3234.                     if the function succeeds, the low byte of dwFlags will be
  3235.                     used to fill the uninitialize part of destination buffer
  3236.                     behind the null terminator
  3237.  
  3238.         STRSAFE_IGNORE_NULLS
  3239.                     treat NULL string pointers like empty strings (TEXT(""))
  3240.  
  3241.         STRSAFE_FILL_ON_FAILURE
  3242.                     if the function fails, the low byte of dwFlags will be
  3243.                     used to fill all of the destination buffer, and it will
  3244.                     be null terminated. This will overwrite any truncated
  3245.                     string returned when the failure is
  3246.                     STRSAFE_E_INSUFFICIENT_BUFFER
  3247.  
  3248.         STRSAFE_NO_TRUNCATION /
  3249.         STRSAFE_NULL_ON_FAILURE
  3250.                     if the function fails, the destination buffer will be set
  3251.                     to the empty string. This will overwrite any truncated string
  3252.                     returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
  3253.  
  3254.     pszFormat       -   format string which must be null terminated
  3255.  
  3256.     argList         -   va_list from the variable arguments according to the
  3257.                         stdarg.h convention
  3258.  
  3259. Notes:
  3260.     Behavior is undefined if destination, format strings or any arguments
  3261.     strings overlap.
  3262.  
  3263.     pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS
  3264.     flag is specified.  If STRSAFE_IGNORE_NULLS is passed, both pszDest and
  3265.     pszFormat may be NULL.  An error may still be returned even though NULLS
  3266.     are ignored due to insufficient space.
  3267.  
  3268. Return Value:
  3269.  
  3270.     S_OK           -   if there was source data and it was all concatenated and
  3271.                        the resultant dest string was null terminated
  3272.  
  3273.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  3274.                        error code for all hresult failure cases
  3275.  
  3276.       STRSAFE_E_INSUFFICIENT_BUFFER /
  3277.       HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  3278.                    -   this return value is an indication that the print
  3279.                        operation failed due to insufficient space. When this
  3280.                        error occurs, the destination buffer is modified to
  3281.                        contain a truncated version of the ideal result and is
  3282.                        null terminated. This is useful for situations where
  3283.                        truncation is ok.
  3284.  
  3285.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  3286.     return value of this function
  3287.  
  3288. --*/
  3289.  
  3290. STRSAFEAPI StringCchVPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList);
  3291. STRSAFEAPI StringCchVPrintfExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList);
  3292. #ifdef UNICODE
  3293. #define StringCchVPrintfEx  StringCchVPrintfExW
  3294. #else
  3295. #define StringCchVPrintfEx  StringCchVPrintfExA
  3296. #endif // !UNICODE
  3297.  
  3298. #ifdef STRSAFE_INLINE
  3299. STRSAFEAPI StringCchVPrintfExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList)
  3300. {
  3301.     HRESULT hr;
  3302.  
  3303.     if (cchDest > STRSAFE_MAX_CCH)
  3304.     {
  3305.         hr = STRSAFE_E_INVALID_PARAMETER;
  3306.     }
  3307.     else
  3308.     {
  3309.         size_t cbDest;
  3310.  
  3311.         // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
  3312.         cbDest = cchDest * sizeof(char);
  3313.  
  3314.         hr = StringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList);
  3315.     }
  3316.  
  3317.     return hr;
  3318. }
  3319.  
  3320. STRSAFEAPI StringCchVPrintfExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList)
  3321. {
  3322.     HRESULT hr;
  3323.  
  3324.     if (cchDest > STRSAFE_MAX_CCH)
  3325.     {
  3326.         hr = STRSAFE_E_INVALID_PARAMETER;
  3327.     }
  3328.     else
  3329.     {
  3330.         size_t cbDest;
  3331.  
  3332.         // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  3333.         cbDest = cchDest * sizeof(wchar_t);
  3334.  
  3335.         hr = StringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags, pszFormat, argList);
  3336.     }
  3337.  
  3338.     return hr;
  3339. }
  3340. #endif  // STRSAFE_INLINE
  3341. #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  3342.  
  3343.  
  3344. #ifndef STRSAFE_NO_CB_FUNCTIONS
  3345. /*++
  3346.  
  3347. STDAPI
  3348. StringCbVPrintfEx(
  3349.     OUT LPTSTR  pszDest         OPTIONAL,
  3350.     IN  size_t  cbDest,
  3351.     OUT LPTSTR* ppszDestEnd     OPTIONAL,
  3352.     OUT size_t* pcbRemaining    OPTIONAL,
  3353.     IN  DWORD   dwFlags,
  3354.     IN  LPCTSTR pszFormat       OPTIONAL,
  3355.     IN  va_list argList
  3356.     );
  3357.  
  3358. Routine Description:
  3359.  
  3360.     This routine is a safer version of the C built-in function 'vsprintf' with
  3361.     some additional parameters.  In addition to functionality provided by
  3362.     StringCbVPrintf, this routine also returns a pointer to the end of the
  3363.     destination string and the number of characters left in the destination string
  3364.     including the null terminator. The flags parameter allows additional controls.
  3365.  
  3366. Arguments:
  3367.  
  3368.     pszDest         -   destination string
  3369.  
  3370.     cbDest          -   size of destination buffer in bytes.
  3371.                         length must be sufficient to contain the resulting
  3372.                         formatted string plus the null terminator.
  3373.  
  3374.     ppszDestEnd     -   if ppszDestEnd is non-null, the function will return
  3375.                         a pointer to the end of the destination string.  If the
  3376.                         function printed any data, the result will point to the
  3377.                         null termination character
  3378.  
  3379.     pcbRemaining    -   if pcbRemaining is non-null, the function will return
  3380.                         the number of bytes left in the destination string,
  3381.                         including the null terminator
  3382.  
  3383.     dwFlags         -   controls some details of the string copy:
  3384.  
  3385.         STRSAFE_FILL_BEHIND_NULL
  3386.                     if the function succeeds, the low byte of dwFlags will be
  3387.                     used to fill the uninitialize part of destination buffer
  3388.                     behind the null terminator
  3389.  
  3390.         STRSAFE_IGNORE_NULLS
  3391.                     treat NULL string pointers like empty strings (TEXT(""))
  3392.  
  3393.         STRSAFE_FILL_ON_FAILURE
  3394.                     if the function fails, the low byte of dwFlags will be
  3395.                     used to fill all of the destination buffer, and it will
  3396.                     be null terminated. This will overwrite any truncated
  3397.                     string returned when the failure is
  3398.                     STRSAFE_E_INSUFFICIENT_BUFFER
  3399.  
  3400.         STRSAFE_NO_TRUNCATION /
  3401.         STRSAFE_NULL_ON_FAILURE
  3402.                     if the function fails, the destination buffer will be set
  3403.                     to the empty string. This will overwrite any truncated string
  3404.                     returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
  3405.  
  3406.     pszFormat       -   format string which must be null terminated
  3407.  
  3408.     argList         -   va_list from the variable arguments according to the
  3409.                         stdarg.h convention
  3410.  
  3411. Notes:
  3412.     Behavior is undefined if destination, format strings or any arguments
  3413.     strings overlap.
  3414.  
  3415.     pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS
  3416.     flag is specified.  If STRSAFE_IGNORE_NULLS is passed, both pszDest and
  3417.     pszFormat may be NULL.  An error may still be returned even though NULLS
  3418.     are ignored due to insufficient space.
  3419.  
  3420. Return Value:
  3421.  
  3422.     S_OK           -   if there was source data and it was all concatenated and
  3423.                        the resultant dest string was null terminated
  3424.  
  3425.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  3426.                        error code for all hresult failure cases
  3427.  
  3428.       STRSAFE_E_INSUFFICIENT_BUFFER /
  3429.       HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  3430.                    -   this return value is an indication that the print
  3431.                        operation failed due to insufficient space. When this
  3432.                        error occurs, the destination buffer is modified to
  3433.                        contain a truncated version of the ideal result and is
  3434.                        null terminated. This is useful for situations where
  3435.                        truncation is ok.
  3436.  
  3437.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  3438.     return value of this function
  3439.  
  3440. --*/
  3441.  
  3442. STRSAFEAPI StringCbVPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList);
  3443. STRSAFEAPI StringCbVPrintfExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList);
  3444. #ifdef UNICODE
  3445. #define StringCbVPrintfEx  StringCbVPrintfExW
  3446. #else
  3447. #define StringCbVPrintfEx  StringCbVPrintfExA
  3448. #endif // !UNICODE
  3449.  
  3450. #ifdef STRSAFE_INLINE
  3451. STRSAFEAPI StringCbVPrintfExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList)
  3452. {
  3453.     HRESULT hr;
  3454.     size_t cchDest;
  3455.     size_t cchRemaining = 0;
  3456.  
  3457.     cchDest = cbDest / sizeof(char);
  3458.  
  3459.     if (cchDest > STRSAFE_MAX_CCH)
  3460.     {
  3461.         hr = STRSAFE_E_INVALID_PARAMETER;
  3462.     }
  3463.     else
  3464.     {
  3465.         hr = StringVPrintfExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList);
  3466.     }
  3467.  
  3468.     if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  3469.     {
  3470.         if (pcbRemaining)
  3471.         {
  3472.             // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
  3473.             *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
  3474.         }
  3475.     }
  3476.  
  3477.     return hr;
  3478. }
  3479.  
  3480. STRSAFEAPI StringCbVPrintfExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList)
  3481. {
  3482.     HRESULT hr;
  3483.     size_t cchDest;
  3484.     size_t cchRemaining = 0;
  3485.  
  3486.     cchDest = cbDest / sizeof(wchar_t);
  3487.  
  3488.     if (cchDest > STRSAFE_MAX_CCH)
  3489.     {
  3490.         hr = STRSAFE_E_INVALID_PARAMETER;
  3491.     }
  3492.     else
  3493.     {
  3494.         hr = StringVPrintfExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags, pszFormat, argList);
  3495.     }
  3496.  
  3497.     if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  3498.     {
  3499.         if (pcbRemaining)
  3500.         {
  3501.             // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  3502.             *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
  3503.         }
  3504.     }
  3505.  
  3506.     return hr;
  3507. }
  3508. #endif  // STRSAFE_INLINE
  3509. #endif  // !STRSAFE_NO_CB_FUNCTIONS
  3510.  
  3511.  
  3512. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  3513. /*++
  3514.  
  3515. STDAPI
  3516. StringCchGets(
  3517.     OUT LPTSTR  pszDest,
  3518.     IN  size_t  cchDest
  3519.     );
  3520.  
  3521. Routine Description:
  3522.  
  3523.     This routine is a safer version of the C built-in function 'gets'.
  3524.     The size of the destination buffer (in characters) is a parameter and
  3525.     this function will not write past the end of this buffer and it will
  3526.     ALWAYS null terminate the destination buffer (unless it is zero length).
  3527.  
  3528.     This routine is not a replacement for fgets.  That function does not replace
  3529.     newline characters with a null terminator.
  3530.  
  3531.     This function returns a hresult, and not a pointer.  It returns
  3532.     S_OK if any characters were read from stdin and copied to pszDest and
  3533.     pszDest was null terminated, otherwise it will return a failure code.
  3534.  
  3535. Arguments:
  3536.  
  3537.     pszDest     -   destination string
  3538.  
  3539.     cchDest     -   size of destination buffer in characters.
  3540.  
  3541. Notes:
  3542.     pszDest should not be NULL. See StringCchGetsEx if you require the handling
  3543.     of NULL values.
  3544.  
  3545.     cchDest must be > 1 for this function to succeed.
  3546.  
  3547. Return Value:
  3548.  
  3549.     S_OK           -   data was read from stdin and copied, and the resultant
  3550.                        dest string was null terminated
  3551.  
  3552.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  3553.                        error code for all hresult failure cases
  3554.  
  3555.       STRSAFE_E_END_OF_FILE /
  3556.       HRESULT_CODE(hr) == ERROR_HANDLE_EOF
  3557.                    -   this return value indicates an error or end-of-file
  3558.                        condition, use feof or ferror to determine which one has
  3559.                        occured.
  3560.  
  3561.       STRSAFE_E_INSUFFICIENT_BUFFER /
  3562.       HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  3563.                    -   this return value is an indication that there was
  3564.                        insufficient space in the destination buffer to copy any
  3565.                        data
  3566.  
  3567.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  3568.     return value of this function.
  3569.  
  3570. --*/
  3571.  
  3572. #ifndef STRSAFE_LIB_IMPL
  3573. STRSAFE_INLINE_API StringCchGetsA(char* pszDest, size_t cchDest);
  3574. STRSAFE_INLINE_API StringCchGetsW(wchar_t* pszDest, size_t cchDest);
  3575. #ifdef UNICODE
  3576. #define StringCchGets  StringCchGetsW
  3577. #else
  3578. #define StringCchGets  StringCchGetsA
  3579. #endif // !UNICODE
  3580.  
  3581. STRSAFE_INLINE_API StringCchGetsA(char* pszDest, size_t cchDest)
  3582. {
  3583.     HRESULT hr;
  3584.  
  3585.     if (cchDest > STRSAFE_MAX_CCH)
  3586.     {
  3587.         hr = STRSAFE_E_INVALID_PARAMETER;
  3588.     }
  3589.     else
  3590.     {
  3591.         size_t cbDest;
  3592.  
  3593.         // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
  3594.         cbDest = cchDest * sizeof(char);
  3595.  
  3596.         hr = StringGetsExWorkerA(pszDest, cchDest, cbDest, NULL, NULL, 0);
  3597.     }
  3598.  
  3599.     return hr;
  3600. }
  3601.  
  3602. STRSAFE_INLINE_API StringCchGetsW(wchar_t* pszDest, size_t cchDest)
  3603. {
  3604.     HRESULT hr;
  3605.  
  3606.     if (cchDest > STRSAFE_MAX_CCH)
  3607.     {
  3608.         hr = STRSAFE_E_INVALID_PARAMETER;
  3609.     }
  3610.     else
  3611.     {
  3612.         size_t cbDest;
  3613.  
  3614.         // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  3615.         cbDest = cchDest * sizeof(wchar_t);
  3616.  
  3617.         hr = StringGetsExWorkerW(pszDest, cchDest, cbDest, NULL, NULL, 0);
  3618.     }
  3619.  
  3620.     return hr;
  3621. }
  3622. #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  3623. #endif  // !STRSAFE_LIB_IMPL
  3624.  
  3625. #ifndef STRSAFE_NO_CB_FUNCTIONS
  3626. /*++
  3627.  
  3628. STDAPI
  3629. StringCbGets(
  3630.     OUT LPTSTR  pszDest,
  3631.     IN  size_t  cbDest
  3632.     );
  3633.  
  3634. Routine Description:
  3635.  
  3636.     This routine is a safer version of the C built-in function 'gets'.
  3637.     The size of the destination buffer (in bytes) is a parameter and
  3638.     this function will not write past the end of this buffer and it will
  3639.     ALWAYS null terminate the destination buffer (unless it is zero length).
  3640.  
  3641.     This routine is not a replacement for fgets.  That function does not replace
  3642.     newline characters with a null terminator.
  3643.  
  3644.     This function returns a hresult, and not a pointer.  It returns
  3645.     S_OK if any characters were read from stdin and copied to pszDest
  3646.     and pszDest was null terminated, otherwise it will return a failure code.
  3647.  
  3648. Arguments:
  3649.  
  3650.     pszDest     -   destination string
  3651.  
  3652.     cbDest      -   size of destination buffer in bytes.
  3653.  
  3654. Notes:
  3655.     pszDest should not be NULL. See StringCbGetsEx if you require the handling
  3656.     of NULL values.
  3657.  
  3658.     cbDest must be > sizeof(TCHAR) for this function to succeed.
  3659.  
  3660. Return Value:
  3661.  
  3662.     S_OK           -   data was read from stdin and copied, and the resultant
  3663.                        dest string was null terminated
  3664.  
  3665.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  3666.                        error code for all hresult failure cases
  3667.  
  3668.       STRSAFE_E_END_OF_FILE /
  3669.       HRESULT_CODE(hr) == ERROR_HANDLE_EOF
  3670.                    -   this return value indicates an error or end-of-file
  3671.                        condition, use feof or ferror to determine which one has
  3672.                        occured.
  3673.  
  3674.       STRSAFE_E_INSUFFICIENT_BUFFER /
  3675.       HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  3676.                    -   this return value is an indication that there was
  3677.                        insufficient space in the destination buffer to copy any
  3678.                        data
  3679.  
  3680.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  3681.     return value of this function.
  3682.  
  3683. --*/
  3684.  
  3685. #ifndef STRSAFE_LIB_IMPL
  3686. STRSAFE_INLINE_API StringCbGetsA(char* pszDest, size_t cbDest);
  3687. STRSAFE_INLINE_API StringCbGetsW(wchar_t* pszDest, size_t cbDest);
  3688. #ifdef UNICODE
  3689. #define StringCbGets  StringCbGetsW
  3690. #else
  3691. #define StringCbGets  StringCbGetsA
  3692. #endif // !UNICODE
  3693.  
  3694. STRSAFE_INLINE_API StringCbGetsA(char* pszDest, size_t cbDest)
  3695. {
  3696.     HRESULT hr;
  3697.     size_t cchDest;
  3698.  
  3699.     // convert to count of characters
  3700.     cchDest = cbDest / sizeof(char);
  3701.  
  3702.     if (cchDest > STRSAFE_MAX_CCH)
  3703.     {
  3704.         hr = STRSAFE_E_INVALID_PARAMETER;
  3705.     }
  3706.     else
  3707.     {
  3708.         hr = StringGetsExWorkerA(pszDest, cchDest, cbDest, NULL, NULL, 0);
  3709.     }
  3710.  
  3711.     return hr;
  3712. }
  3713.  
  3714. STRSAFE_INLINE_API StringCbGetsW(wchar_t* pszDest, size_t cbDest)
  3715. {
  3716.     HRESULT hr;
  3717.     size_t cchDest;
  3718.  
  3719.     // convert to count of characters
  3720.     cchDest = cbDest / sizeof(wchar_t);
  3721.  
  3722.     if (cchDest > STRSAFE_MAX_CCH)
  3723.     {
  3724.         hr = STRSAFE_E_INVALID_PARAMETER;
  3725.     }
  3726.     else
  3727.     {
  3728.         hr = StringGetsExWorkerW(pszDest, cchDest, cbDest, NULL, NULL, 0);
  3729.     }
  3730.  
  3731.     return hr;
  3732. }
  3733. #endif  // !STRSAFE_NO_CB_FUNCTIONS
  3734. #endif  // !STRSAFE_LIB_IMPL
  3735.  
  3736. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  3737. /*++
  3738.  
  3739. STDAPI
  3740. StringCchGetsEx(
  3741.     OUT LPTSTR  pszDest         OPTIONAL,
  3742.     IN  size_t  cchDest,
  3743.     OUT LPTSTR* ppszDestEnd     OPTIONAL,
  3744.     OUT size_t* pcchRemaining   OPTIONAL,
  3745.     IN  DWORD   dwFlags
  3746.     );
  3747.  
  3748. Routine Description:
  3749.  
  3750.     This routine is a safer version of the C built-in function 'gets' with
  3751.     some additional parameters. In addition to functionality provided by
  3752.     StringCchGets, this routine also returns a pointer to the end of the
  3753.     destination string and the number of characters left in the destination string
  3754.     including the null terminator. The flags parameter allows additional controls.
  3755.  
  3756. Arguments:
  3757.  
  3758.     pszDest         -   destination string
  3759.  
  3760.     cchDest         -   size of destination buffer in characters.
  3761.  
  3762.     ppszDestEnd     -   if ppszDestEnd is non-null, the function will return a
  3763.                         pointer to the end of the destination string.  If the
  3764.                         function copied any data, the result will point to the
  3765.                         null termination character
  3766.  
  3767.     pcchRemaining   -   if pcchRemaining is non-null, the function will return the
  3768.                         number of characters left in the destination string,
  3769.                         including the null terminator
  3770.  
  3771.     dwFlags         -   controls some details of the string copy:
  3772.  
  3773.         STRSAFE_FILL_BEHIND_NULL
  3774.                     if the function succeeds, the low byte of dwFlags will be
  3775.                     used to fill the uninitialize part of destination buffer
  3776.                     behind the null terminator
  3777.  
  3778.         STRSAFE_IGNORE_NULLS
  3779.                     treat NULL string pointers like empty strings (TEXT("")).
  3780.  
  3781.         STRSAFE_FILL_ON_FAILURE
  3782.                     if the function fails, the low byte of dwFlags will be
  3783.                     used to fill all of the destination buffer, and it will
  3784.                     be null terminated.
  3785.  
  3786.         STRSAFE_NO_TRUNCATION /
  3787.         STRSAFE_NULL_ON_FAILURE
  3788.                     if the function fails, the destination buffer will be set
  3789.                     to the empty string.
  3790.  
  3791. Notes:
  3792.     pszDest should not be NULL unless the STRSAFE_IGNORE_NULLS flag is specified.
  3793.     If STRSAFE_IGNORE_NULLS is passed and pszDest is NULL, an error may still be
  3794.     returned even though NULLS are ignored
  3795.  
  3796.     cchDest must be > 1 for this function to succeed.
  3797.  
  3798. Return Value:
  3799.  
  3800.     S_OK           -   data was read from stdin and copied, and the resultant
  3801.                        dest string was null terminated
  3802.  
  3803.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  3804.                        error code for all hresult failure cases
  3805.  
  3806.       STRSAFE_E_END_OF_FILE /
  3807.       HRESULT_CODE(hr) == ERROR_HANDLE_EOF
  3808.                    -   this return value indicates an error or end-of-file
  3809.                        condition, use feof or ferror to determine which one has
  3810.                        occured.
  3811.  
  3812.       STRSAFE_E_INSUFFICIENT_BUFFER /
  3813.       HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  3814.                    -   this return value is an indication that there was
  3815.                        insufficient space in the destination buffer to copy any
  3816.                        data
  3817.  
  3818.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  3819.     return value of this function.
  3820.  
  3821. --*/
  3822.  
  3823. #ifndef STRSAFE_LIB_IMPL
  3824. STRSAFE_INLINE_API StringCchGetsExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  3825. STRSAFE_INLINE_API StringCchGetsExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags);
  3826. #ifdef UNICODE
  3827. #define StringCchGetsEx  StringCchGetsExW
  3828. #else
  3829. #define StringCchGetsEx  StringCchGetsExA
  3830. #endif // !UNICODE
  3831.  
  3832. STRSAFE_INLINE_API StringCchGetsExA(char* pszDest, size_t cchDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  3833. {
  3834.     HRESULT hr;
  3835.  
  3836.     if (cchDest > STRSAFE_MAX_CCH)
  3837.     {
  3838.         hr = STRSAFE_E_INVALID_PARAMETER;
  3839.     }
  3840.     else
  3841.     {
  3842.         size_t cbDest;
  3843.  
  3844.         // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
  3845.         cbDest = cchDest * sizeof(char);
  3846.  
  3847.         hr = StringGetsExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags);
  3848.     }
  3849.  
  3850.     return hr;
  3851. }
  3852.  
  3853. STRSAFE_INLINE_API StringCchGetsExW(wchar_t* pszDest, size_t cchDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  3854. {
  3855.     HRESULT hr;
  3856.  
  3857.     if (cchDest > STRSAFE_MAX_CCH)
  3858.     {
  3859.         hr = STRSAFE_E_INVALID_PARAMETER;
  3860.     }
  3861.     else
  3862.     {
  3863.         size_t cbDest;
  3864.  
  3865.         // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  3866.         cbDest = cchDest * sizeof(wchar_t);
  3867.  
  3868.         hr = StringGetsExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, pcchRemaining, dwFlags);
  3869.     }
  3870.  
  3871.     return hr;
  3872. }
  3873. #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  3874. #endif  // !STRSAFE_LIB_IMPL
  3875.  
  3876. #ifndef STRSAFE_NO_CB_FUNCTIONS
  3877. /*++
  3878.  
  3879. STDAPI
  3880. StringCbGetsEx(
  3881.     OUT LPTSTR  pszDest         OPTIONAL,
  3882.     IN  size_t  cbDest,
  3883.     OUT LPTSTR* ppszDestEnd     OPTIONAL,
  3884.     OUT size_t* pcbRemaining    OPTIONAL,
  3885.     IN  DWORD   dwFlags
  3886.     );
  3887.  
  3888. Routine Description:
  3889.  
  3890.     This routine is a safer version of the C built-in function 'gets' with
  3891.     some additional parameters. In addition to functionality provided by
  3892.     StringCbGets, this routine also returns a pointer to the end of the
  3893.     destination string and the number of characters left in the destination string
  3894.     including the null terminator. The flags parameter allows additional controls.
  3895.  
  3896. Arguments:
  3897.  
  3898.     pszDest         -   destination string
  3899.  
  3900.     cbDest          -   size of destination buffer in bytes.
  3901.  
  3902.     ppszDestEnd     -   if ppszDestEnd is non-null, the function will return a
  3903.                         pointer to the end of the destination string.  If the
  3904.                         function copied any data, the result will point to the
  3905.                         null termination character
  3906.  
  3907.     pcbRemaining    -   if pbRemaining is non-null, the function will return the
  3908.                         number of bytes left in the destination string,
  3909.                         including the null terminator
  3910.  
  3911.     dwFlags         -   controls some details of the string copy:
  3912.  
  3913.         STRSAFE_FILL_BEHIND_NULL
  3914.                     if the function succeeds, the low byte of dwFlags will be
  3915.                     used to fill the uninitialize part of destination buffer
  3916.                     behind the null terminator
  3917.  
  3918.         STRSAFE_IGNORE_NULLS
  3919.                     treat NULL string pointers like empty strings (TEXT("")).
  3920.  
  3921.         STRSAFE_FILL_ON_FAILURE
  3922.                     if the function fails, the low byte of dwFlags will be
  3923.                     used to fill all of the destination buffer, and it will
  3924.                     be null terminated.
  3925.  
  3926.         STRSAFE_NO_TRUNCATION /
  3927.         STRSAFE_NULL_ON_FAILURE
  3928.                     if the function fails, the destination buffer will be set
  3929.                     to the empty string.
  3930.  
  3931. Notes:
  3932.     pszDest should not be NULL unless the STRSAFE_IGNORE_NULLS flag is specified.
  3933.     If STRSAFE_IGNORE_NULLS is passed and pszDest is NULL, an error may still be
  3934.     returned even though NULLS are ignored
  3935.  
  3936.     cbDest must be > sizeof(TCHAR) for this function to succeed
  3937.  
  3938. Return Value:
  3939.  
  3940.     S_OK           -   data was read from stdin and copied, and the resultant
  3941.                        dest string was null terminated
  3942.  
  3943.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  3944.                        error code for all hresult failure cases
  3945.  
  3946.       STRSAFE_E_END_OF_FILE /
  3947.       HRESULT_CODE(hr) == ERROR_HANDLE_EOF
  3948.                    -   this return value indicates an error or end-of-file
  3949.                        condition, use feof or ferror to determine which one has
  3950.                        occured.
  3951.  
  3952.       STRSAFE_E_INSUFFICIENT_BUFFER /
  3953.       HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  3954.                    -   this return value is an indication that there was
  3955.                        insufficient space in the destination buffer to copy any
  3956.                        data
  3957.  
  3958.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  3959.     return value of this function.
  3960.  
  3961. --*/
  3962.  
  3963. #ifndef STRSAFE_LIB_IMPL
  3964. STRSAFE_INLINE_API StringCbGetsExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pbRemaining, unsigned long dwFlags);
  3965. STRSAFE_INLINE_API StringCbGetsExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags);
  3966. #ifdef UNICODE
  3967. #define StringCbGetsEx  StringCbGetsExW
  3968. #else
  3969. #define StringCbGetsEx  StringCbGetsExA
  3970. #endif // !UNICODE
  3971.  
  3972. STRSAFE_INLINE_API StringCbGetsExA(char* pszDest, size_t cbDest, char** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
  3973. {
  3974.     HRESULT hr;
  3975.     size_t cchDest;
  3976.     size_t cchRemaining = 0;
  3977.  
  3978.     cchDest = cbDest / sizeof(char);
  3979.  
  3980.     if (cchDest > STRSAFE_MAX_CCH)
  3981.     {
  3982.         hr = STRSAFE_E_INVALID_PARAMETER;
  3983.     }
  3984.     else
  3985.     {
  3986.         hr = StringGetsExWorkerA(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags);
  3987.     }
  3988.  
  3989.     if (SUCCEEDED(hr) ||
  3990.         (hr == STRSAFE_E_INSUFFICIENT_BUFFER) ||
  3991.         (hr == STRSAFE_E_END_OF_FILE))
  3992.     {
  3993.         if (pcbRemaining)
  3994.         {
  3995.             // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
  3996.             *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
  3997.         }
  3998.     }
  3999.  
  4000.     return hr;
  4001. }
  4002.  
  4003. STRSAFE_INLINE_API StringCbGetsExW(wchar_t* pszDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcbRemaining, unsigned long dwFlags)
  4004. {
  4005.     HRESULT hr;
  4006.     size_t cchDest;
  4007.     size_t cchRemaining = 0;
  4008.  
  4009.     cchDest = cbDest / sizeof(wchar_t);
  4010.  
  4011.     if (cchDest > STRSAFE_MAX_CCH)
  4012.     {
  4013.         hr = STRSAFE_E_INVALID_PARAMETER;
  4014.     }
  4015.     else
  4016.     {
  4017.         hr = StringGetsExWorkerW(pszDest, cchDest, cbDest, ppszDestEnd, &cchRemaining, dwFlags);
  4018.     }
  4019.  
  4020.     if (SUCCEEDED(hr) ||
  4021.         (hr == STRSAFE_E_INSUFFICIENT_BUFFER) ||
  4022.         (hr == STRSAFE_E_END_OF_FILE))
  4023.     {
  4024.         if (pcbRemaining)
  4025.         {
  4026.             // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  4027.             *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
  4028.         }
  4029.     }
  4030.  
  4031.     return hr;
  4032. }
  4033. #endif  // !STRSAFE_NO_CB_FUNCTIONS
  4034. #endif  // !STRSAFE_LIB_IMPL
  4035.  
  4036. #ifndef STRSAFE_NO_CCH_FUNCTIONS
  4037. /*++
  4038.  
  4039. STDAPI
  4040. StringCchLength(
  4041.     IN  LPCTSTR psz,
  4042.     IN  size_t  cchMax,
  4043.     OUT size_t* pcch    OPTIONAL
  4044.     );
  4045.  
  4046. Routine Description:
  4047.  
  4048.     This routine is a safer version of the C built-in function 'strlen'.
  4049.     It is used to make sure a string is not larger than a given length, and
  4050.     it optionally returns the current length in characters not including
  4051.     the null terminator.
  4052.  
  4053.     This function returns a hresult, and not a pointer.  It returns
  4054.     S_OK if the string is non-null and the length including the null
  4055.     terminator is less than or equal to cchMax characters.
  4056.  
  4057. Arguments:
  4058.  
  4059.     psz         -   string to check the length of
  4060.  
  4061.     cchMax      -   maximum number of characters including the null terminator
  4062.                     that psz is allowed to contain
  4063.  
  4064.     pcch        -   if the function succeeds and pcch is non-null, the current length
  4065.                     in characters of psz excluding the null terminator will be returned.
  4066.                     This out parameter is equivalent to the return value of strlen(psz)
  4067.  
  4068. Notes:
  4069.     psz can be null but the function will fail
  4070.  
  4071.     cchMax should be greater than zero or the function will fail
  4072.  
  4073. Return Value:
  4074.  
  4075.     S_OK           -   psz is non-null and the length including the null
  4076.                        terminator is less than or equal to cchMax characters
  4077.  
  4078.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  4079.                        error code for all hresult failure cases
  4080.  
  4081.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  4082.     return value of this function.
  4083.  
  4084. --*/
  4085.  
  4086. STRSAFEAPI StringCchLengthA(const char* psz, size_t cchMax, size_t* pcch);
  4087. STRSAFEAPI StringCchLengthW(const wchar_t* psz, size_t cchMax, size_t* pcch);
  4088. #ifdef UNICODE
  4089. #define StringCchLength  StringCchLengthW
  4090. #else
  4091. #define StringCchLength  StringCchLengthA
  4092. #endif // !UNICODE
  4093.  
  4094. #ifdef STRSAFE_INLINE
  4095. STRSAFEAPI StringCchLengthA(const char* psz, size_t cchMax, size_t* pcch)
  4096. {
  4097.     HRESULT hr;
  4098.  
  4099.     if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
  4100.     {
  4101.         hr = STRSAFE_E_INVALID_PARAMETER;
  4102.     }
  4103.     else
  4104.     {
  4105.         hr = StringLengthWorkerA(psz, cchMax, pcch);
  4106.     }
  4107.  
  4108.     return hr;
  4109. }
  4110.  
  4111. STRSAFEAPI StringCchLengthW(const wchar_t* psz, size_t cchMax, size_t* pcch)
  4112. {
  4113.     HRESULT hr;
  4114.  
  4115.     if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
  4116.     {
  4117.         hr = STRSAFE_E_INVALID_PARAMETER;
  4118.     }
  4119.     else
  4120.     {
  4121.         hr = StringLengthWorkerW(psz, cchMax, pcch);
  4122.     }
  4123.  
  4124.     return hr;
  4125. }
  4126. #endif  // STRSAFE_INLINE
  4127. #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  4128.  
  4129.  
  4130. #ifndef STRSAFE_NO_CB_FUNCTIONS
  4131. /*++
  4132.  
  4133. STDAPI
  4134. StringCbLength(
  4135.     IN  LPCTSTR psz,
  4136.     IN  size_t  cbMax,
  4137.     OUT size_t* pcb     OPTIONAL
  4138.     );
  4139.  
  4140. Routine Description:
  4141.  
  4142.     This routine is a safer version of the C built-in function 'strlen'.
  4143.     It is used to make sure a string is not larger than a given length, and
  4144.     it optionally returns the current length in bytes not including
  4145.     the null terminator.
  4146.  
  4147.     This function returns a hresult, and not a pointer.  It returns
  4148.     S_OK if the string is non-null and the length including the null
  4149.     terminator is less than or equal to cbMax bytes.
  4150.  
  4151. Arguments:
  4152.  
  4153.     psz         -   string to check the length of
  4154.  
  4155.     cbMax       -   maximum number of bytes including the null terminator
  4156.                     that psz is allowed to contain
  4157.  
  4158.     pcb         -   if the function succeeds and pcb is non-null, the current length
  4159.                     in bytes of psz excluding the null terminator will be returned.
  4160.                     This out parameter is equivalent to the return value of strlen(psz) * sizeof(TCHAR)
  4161.  
  4162. Notes:
  4163.     psz can be null but the function will fail
  4164.  
  4165.     cbMax should be greater than or equal to sizeof(TCHAR) or the function will fail
  4166.  
  4167. Return Value:
  4168.  
  4169.     S_OK           -   psz is non-null and the length including the null
  4170.                        terminator is less than or equal to cbMax bytes
  4171.  
  4172.     failure        -   you can use the macro HRESULT_CODE() to get a win32
  4173.                        error code for all hresult failure cases
  4174.  
  4175.     It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  4176.     return value of this function.
  4177.  
  4178. --*/
  4179.  
  4180. STRSAFEAPI StringCbLengthA(const char* psz, size_t cchMax, size_t* pcch);
  4181. STRSAFEAPI StringCbLengthW(const wchar_t* psz, size_t cchMax, size_t* pcch);
  4182. #ifdef UNICODE
  4183. #define StringCbLength  StringCbLengthW
  4184. #else
  4185. #define StringCbLength  StringCbLengthA
  4186. #endif // !UNICODE
  4187.  
  4188. #ifdef STRSAFE_INLINE
  4189. STRSAFEAPI StringCbLengthA(const char* psz, size_t cbMax, size_t* pcb)
  4190. {
  4191.     HRESULT hr;
  4192.     size_t cchMax;
  4193.     size_t cch = 0;
  4194.  
  4195.     cchMax = cbMax / sizeof(char);
  4196.  
  4197.     if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
  4198.     {
  4199.         hr = STRSAFE_E_INVALID_PARAMETER;
  4200.     }
  4201.     else
  4202.     {
  4203.         hr = StringLengthWorkerA(psz, cchMax, &cch);
  4204.     }
  4205.  
  4206.     if (SUCCEEDED(hr) && pcb)
  4207.     {
  4208.         // safe to multiply cch * sizeof(char) since cch < STRSAFE_MAX_CCH and sizeof(char) is 1
  4209.         *pcb = cch * sizeof(char);
  4210.     }
  4211.  
  4212.     return hr;
  4213. }
  4214.  
  4215. STRSAFEAPI StringCbLengthW(const wchar_t* psz, size_t cbMax, size_t* pcb)
  4216. {
  4217.     HRESULT hr;
  4218.     size_t cchMax;
  4219.     size_t cch = 0;
  4220.  
  4221.     cchMax = cbMax / sizeof(wchar_t);
  4222.  
  4223.     if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
  4224.     {
  4225.         hr = STRSAFE_E_INVALID_PARAMETER;
  4226.     }
  4227.     else
  4228.     {
  4229.         hr = StringLengthWorkerW(psz, cchMax, &cch);
  4230.     }
  4231.  
  4232.     if (SUCCEEDED(hr) && pcb)
  4233.     {
  4234.         // safe to multiply cch * sizeof(wchar_t) since cch < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
  4235.         *pcb = cch * sizeof(wchar_t);
  4236.     }
  4237.  
  4238.     return hr;
  4239. }
  4240. #endif  // STRSAFE_INLINE
  4241. #endif  // !STRSAFE_NO_CB_FUNCTIONS
  4242.  
  4243.  
  4244. // these are the worker functions that actually do the work
  4245. #ifdef STRSAFE_INLINE
  4246. STRSAFEAPI StringCopyWorkerA(char* pszDest, size_t cchDest, const char* pszSrc)
  4247. {
  4248.     HRESULT hr = S_OK;
  4249.  
  4250.     if (cchDest == 0)
  4251.     {
  4252.         // can not null terminate a zero-byte dest buffer
  4253.         hr = STRSAFE_E_INVALID_PARAMETER;
  4254.     }
  4255.     else
  4256.     {
  4257.         while (cchDest && (*pszSrc != '\0'))
  4258.         {
  4259.             *pszDest++ = *pszSrc++;
  4260.             cchDest--;
  4261.         }
  4262.  
  4263.         if (cchDest == 0)
  4264.         {
  4265.             // we are going to truncate pszDest
  4266.             pszDest--;
  4267.             hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  4268.         }
  4269.  
  4270.         *pszDest= '\0';
  4271.     }
  4272.  
  4273.     return hr;
  4274. }
  4275.  
  4276. STRSAFEAPI StringCopyWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc)
  4277. {
  4278.     HRESULT hr = S_OK;
  4279.  
  4280.     if (cchDest == 0)
  4281.     {
  4282.         // can not null terminate a zero-byte dest buffer
  4283.         hr = STRSAFE_E_INVALID_PARAMETER;
  4284.     }
  4285.     else
  4286.     {
  4287.         while (cchDest && (*pszSrc != L'\0'))
  4288.         {
  4289.             *pszDest++ = *pszSrc++;
  4290.             cchDest--;
  4291.         }
  4292.  
  4293.         if (cchDest == 0)
  4294.         {
  4295.             // we are going to truncate pszDest
  4296.             pszDest--;
  4297.             hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  4298.         }
  4299.  
  4300.         *pszDest= L'\0';
  4301.     }
  4302.  
  4303.     return hr;
  4304. }
  4305.  
  4306. STRSAFEAPI StringCopyExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  4307. {
  4308.     HRESULT hr = S_OK;
  4309.     char* pszDestEnd = pszDest;
  4310.     size_t cchRemaining = 0;
  4311.  
  4312.     // ASSERT(cbDest == (cchDest * sizeof(char))    ||
  4313.     //        cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
  4314.  
  4315.     // only accept valid flags
  4316.     if (dwFlags & (~STRSAFE_VALID_FLAGS))
  4317.     {
  4318.         hr = STRSAFE_E_INVALID_PARAMETER;
  4319.     }
  4320.     else
  4321.     {
  4322.         if (dwFlags & STRSAFE_IGNORE_NULLS)
  4323.         {
  4324.             if (pszDest == NULL)
  4325.             {
  4326.                 if ((cchDest != 0) || (cbDest != 0))
  4327.                 {
  4328.                     // NULL pszDest and non-zero cchDest/cbDest is invalid
  4329.                     hr = STRSAFE_E_INVALID_PARAMETER;
  4330.                 }
  4331.             }
  4332.  
  4333.             if (pszSrc == NULL)
  4334.             {
  4335.                 pszSrc = "";
  4336.             }
  4337.         }
  4338.  
  4339.         if (SUCCEEDED(hr))
  4340.         {
  4341.             if (cchDest == 0)
  4342.             {
  4343.                 pszDestEnd = pszDest;
  4344.                 cchRemaining = 0;
  4345.  
  4346.                 // only fail if there was actually src data to copy
  4347.                 if (*pszSrc != '\0')
  4348.                 {
  4349.                     if (pszDest == NULL)
  4350.                     {
  4351.                         hr = STRSAFE_E_INVALID_PARAMETER;
  4352.                     }
  4353.                     else
  4354.                     {
  4355.                         hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  4356.                     }
  4357.                 }
  4358.             }
  4359.             else
  4360.             {
  4361.                 pszDestEnd = pszDest;
  4362.                 cchRemaining = cchDest;
  4363.  
  4364.                 while (cchRemaining && (*pszSrc != '\0'))
  4365.                 {
  4366.                     *pszDestEnd++= *pszSrc++;
  4367.                     cchRemaining--;
  4368.                 }
  4369.  
  4370.                 if (cchRemaining > 0)
  4371.                 {
  4372.                     if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
  4373.                     {
  4374.                         memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char)));
  4375.                     }
  4376.                 }
  4377.                 else
  4378.                 {
  4379.                     // we are going to truncate pszDest
  4380.                     pszDestEnd--;
  4381.                     cchRemaining++;
  4382.  
  4383.                     hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  4384.                 }
  4385.  
  4386.                 *pszDestEnd = '\0';
  4387.             }
  4388.         }
  4389.     }
  4390.  
  4391.     if (FAILED(hr))
  4392.     {
  4393.         if (pszDest)
  4394.         {
  4395.             if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  4396.             {
  4397.                 memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  4398.  
  4399.                 if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  4400.                 {
  4401.                     pszDestEnd = pszDest;
  4402.                     cchRemaining = cchDest;
  4403.                 }
  4404.                 else if (cchDest > 0)
  4405.                 {
  4406.                     pszDestEnd = pszDest + cchDest - 1;
  4407.                     cchRemaining = 1;
  4408.  
  4409.                     // null terminate the end of the string
  4410.                     *pszDestEnd = '\0';
  4411.                 }
  4412.             }
  4413.  
  4414.             if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
  4415.             {
  4416.                 if (cchDest > 0)
  4417.                 {
  4418.                     pszDestEnd = pszDest;
  4419.                     cchRemaining = cchDest;
  4420.  
  4421.                     // null terminate the beginning of the string
  4422.                     *pszDestEnd = '\0';
  4423.                 }
  4424.             }
  4425.         }
  4426.     }
  4427.  
  4428.     if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  4429.     {
  4430.         if (ppszDestEnd)
  4431.         {
  4432.             *ppszDestEnd = pszDestEnd;
  4433.         }
  4434.  
  4435.         if (pcchRemaining)
  4436.         {
  4437.             *pcchRemaining = cchRemaining;
  4438.         }
  4439.     }
  4440.  
  4441.     return hr;
  4442. }
  4443.  
  4444. STRSAFEAPI StringCopyExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  4445. {
  4446.     HRESULT hr = S_OK;
  4447.     wchar_t* pszDestEnd = pszDest;
  4448.     size_t cchRemaining = 0;
  4449.  
  4450.     // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) ||
  4451.     //        cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
  4452.  
  4453.     // only accept valid flags
  4454.     if (dwFlags & (~STRSAFE_VALID_FLAGS))
  4455.     {
  4456.         hr = STRSAFE_E_INVALID_PARAMETER;
  4457.     }
  4458.     else
  4459.     {
  4460.         if (dwFlags & STRSAFE_IGNORE_NULLS)
  4461.         {
  4462.             if (pszDest == NULL)
  4463.             {
  4464.                 if ((cchDest != 0) || (cbDest != 0))
  4465.                 {
  4466.                     // NULL pszDest and non-zero cchDest/cbDest is invalid
  4467.                     hr = STRSAFE_E_INVALID_PARAMETER;
  4468.                 }
  4469.             }
  4470.  
  4471.             if (pszSrc == NULL)
  4472.             {
  4473.                 pszSrc = L"";
  4474.             }
  4475.         }
  4476.  
  4477.         if (SUCCEEDED(hr))
  4478.         {
  4479.             if (cchDest == 0)
  4480.             {
  4481.                 pszDestEnd = pszDest;
  4482.                 cchRemaining = 0;
  4483.  
  4484.                 // only fail if there was actually src data to copy
  4485.                 if (*pszSrc != L'\0')
  4486.                 {
  4487.                     if (pszDest == NULL)
  4488.                     {
  4489.                         hr = STRSAFE_E_INVALID_PARAMETER;
  4490.                     }
  4491.                     else
  4492.                     {
  4493.                         hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  4494.                     }
  4495.                 }
  4496.             }
  4497.             else
  4498.             {
  4499.                 pszDestEnd = pszDest;
  4500.                 cchRemaining = cchDest;
  4501.  
  4502.                 while (cchRemaining && (*pszSrc != L'\0'))
  4503.                 {
  4504.                     *pszDestEnd++= *pszSrc++;
  4505.                     cchRemaining--;
  4506.                 }
  4507.  
  4508.                 if (cchRemaining > 0)
  4509.                 {
  4510.                     if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
  4511.                     {
  4512.                         memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
  4513.                     }
  4514.                 }
  4515.                 else
  4516.                 {
  4517.                     // we are going to truncate pszDest
  4518.                     pszDestEnd--;
  4519.                     cchRemaining++;
  4520.  
  4521.                     hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  4522.                 }
  4523.  
  4524.                 *pszDestEnd = L'\0';
  4525.             }
  4526.         }
  4527.     }
  4528.  
  4529.     if (FAILED(hr))
  4530.     {
  4531.         if (pszDest)
  4532.         {
  4533.             if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  4534.             {
  4535.                 memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  4536.  
  4537.                 if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  4538.                 {
  4539.                     pszDestEnd = pszDest;
  4540.                     cchRemaining = cchDest;
  4541.                 }
  4542.                 else if (cchDest > 0)
  4543.                 {
  4544.                     pszDestEnd = pszDest + cchDest - 1;
  4545.                     cchRemaining = 1;
  4546.  
  4547.                     // null terminate the end of the string
  4548.                     *pszDestEnd = L'\0';
  4549.                 }
  4550.             }
  4551.  
  4552.             if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
  4553.             {
  4554.                 if (cchDest > 0)
  4555.                 {
  4556.                     pszDestEnd = pszDest;
  4557.                     cchRemaining = cchDest;
  4558.  
  4559.                     // null terminate the beginning of the string
  4560.                     *pszDestEnd = L'\0';
  4561.                 }
  4562.             }
  4563.         }
  4564.     }
  4565.  
  4566.     if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  4567.     {
  4568.         if (ppszDestEnd)
  4569.         {
  4570.             *ppszDestEnd = pszDestEnd;
  4571.         }
  4572.  
  4573.         if (pcchRemaining)
  4574.         {
  4575.             *pcchRemaining = cchRemaining;
  4576.         }
  4577.     }
  4578.  
  4579.     return hr;
  4580. }
  4581.  
  4582. STRSAFEAPI StringCopyNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchSrc)
  4583. {
  4584.     HRESULT hr = S_OK;
  4585.  
  4586.     if (cchDest == 0)
  4587.     {
  4588.         // can not null terminate a zero-byte dest buffer
  4589.         hr = STRSAFE_E_INVALID_PARAMETER;
  4590.     }
  4591.     else
  4592.     {
  4593.         while (cchDest && cchSrc && (*pszSrc != '\0'))
  4594.         {
  4595.             *pszDest++= *pszSrc++;
  4596.             cchDest--;
  4597.             cchSrc--;
  4598.         }
  4599.  
  4600.         if (cchDest == 0)
  4601.         {
  4602.             // we are going to truncate pszDest
  4603.             pszDest--;
  4604.             hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  4605.         }
  4606.  
  4607.         *pszDest= '\0';
  4608.     }
  4609.  
  4610.     return hr;
  4611. }
  4612.  
  4613. STRSAFEAPI StringCopyNWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchSrc)
  4614. {
  4615.     HRESULT hr = S_OK;
  4616.  
  4617.     if (cchDest == 0)
  4618.     {
  4619.         // can not null terminate a zero-byte dest buffer
  4620.         hr = STRSAFE_E_INVALID_PARAMETER;
  4621.     }
  4622.     else
  4623.     {
  4624.         while (cchDest && cchSrc && (*pszSrc != L'\0'))
  4625.         {
  4626.             *pszDest++= *pszSrc++;
  4627.             cchDest--;
  4628.             cchSrc--;
  4629.         }
  4630.  
  4631.         if (cchDest == 0)
  4632.         {
  4633.             // we are going to truncate pszDest
  4634.             pszDest--;
  4635.             hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  4636.         }
  4637.  
  4638.         *pszDest= L'\0';
  4639.     }
  4640.  
  4641.     return hr;
  4642. }
  4643.  
  4644. STRSAFEAPI StringCopyNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  4645. {
  4646.     HRESULT hr = S_OK;
  4647.     char* pszDestEnd = pszDest;
  4648.     size_t cchRemaining = 0;
  4649.  
  4650.     // ASSERT(cbDest == (cchDest * sizeof(char))    ||
  4651.     //        cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
  4652.  
  4653.     // only accept valid flags
  4654.     if (dwFlags & (~STRSAFE_VALID_FLAGS))
  4655.     {
  4656.         hr = STRSAFE_E_INVALID_PARAMETER;
  4657.     }
  4658.     else
  4659.     {
  4660.         if (dwFlags & STRSAFE_IGNORE_NULLS)
  4661.         {
  4662.             if (pszDest == NULL)
  4663.             {
  4664.                 if ((cchDest != 0) || (cbDest != 0))
  4665.                 {
  4666.                     // NULL pszDest and non-zero cchDest/cbDest is invalid
  4667.                     hr = STRSAFE_E_INVALID_PARAMETER;
  4668.                 }
  4669.             }
  4670.  
  4671.             if (pszSrc == NULL)
  4672.             {
  4673.                 pszSrc = "";
  4674.             }
  4675.         }
  4676.  
  4677.         if (SUCCEEDED(hr))
  4678.         {
  4679.             if (cchDest == 0)
  4680.             {
  4681.                 pszDestEnd = pszDest;
  4682.                 cchRemaining = 0;
  4683.  
  4684.                 // only fail if there was actually src data to copy
  4685.                 if (*pszSrc != '\0')
  4686.                 {
  4687.                     if (pszDest == NULL)
  4688.                     {
  4689.                         hr = STRSAFE_E_INVALID_PARAMETER;
  4690.                     }
  4691.                     else
  4692.                     {
  4693.                         hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  4694.                     }
  4695.                 }
  4696.             }
  4697.             else
  4698.             {
  4699.                 pszDestEnd = pszDest;
  4700.                 cchRemaining = cchDest;
  4701.  
  4702.                 while (cchRemaining && cchSrc && (*pszSrc != '\0'))
  4703.                 {
  4704.                     *pszDestEnd++= *pszSrc++;
  4705.                     cchRemaining--;
  4706.                     cchSrc--;
  4707.                 }
  4708.  
  4709.                 if (cchRemaining > 0)
  4710.                 {
  4711.                     if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
  4712.                     {
  4713.                         memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char)));
  4714.                     }
  4715.                 }
  4716.                 else
  4717.                 {
  4718.                     // we are going to truncate pszDest
  4719.                     pszDestEnd--;
  4720.                     cchRemaining++;
  4721.  
  4722.                     hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  4723.                 }
  4724.  
  4725.                 *pszDestEnd = '\0';
  4726.             }
  4727.         }
  4728.     }
  4729.  
  4730.     if (FAILED(hr))
  4731.     {
  4732.         if (pszDest)
  4733.         {
  4734.             if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  4735.             {
  4736.                 memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  4737.  
  4738.                 if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  4739.                 {
  4740.                     pszDestEnd = pszDest;
  4741.                     cchRemaining = cchDest;
  4742.                 }
  4743.                 else if (cchDest > 0)
  4744.                 {
  4745.                     pszDestEnd = pszDest + cchDest - 1;
  4746.                     cchRemaining = 1;
  4747.  
  4748.                     // null terminate the end of the string
  4749.                     *pszDestEnd = '\0';
  4750.                 }
  4751.             }
  4752.  
  4753.             if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
  4754.             {
  4755.                 if (cchDest > 0)
  4756.                 {
  4757.                     pszDestEnd = pszDest;
  4758.                     cchRemaining = cchDest;
  4759.  
  4760.                     // null terminate the beginning of the string
  4761.                     *pszDestEnd = '\0';
  4762.                 }
  4763.             }
  4764.         }
  4765.     }
  4766.  
  4767.     if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  4768.     {
  4769.         if (ppszDestEnd)
  4770.         {
  4771.             *ppszDestEnd = pszDestEnd;
  4772.         }
  4773.  
  4774.         if (pcchRemaining)
  4775.         {
  4776.             *pcchRemaining = cchRemaining;
  4777.         }
  4778.     }
  4779.  
  4780.     return hr;
  4781. }
  4782.  
  4783. STRSAFEAPI StringCopyNExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, size_t cchSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  4784. {
  4785.     HRESULT hr = S_OK;
  4786.     wchar_t* pszDestEnd = pszDest;
  4787.     size_t cchRemaining = 0;
  4788.  
  4789.     // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) ||
  4790.     //        cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
  4791.  
  4792.     // only accept valid flags
  4793.     if (dwFlags & (~STRSAFE_VALID_FLAGS))
  4794.     {
  4795.         hr = STRSAFE_E_INVALID_PARAMETER;
  4796.     }
  4797.     else
  4798.     {
  4799.         if (dwFlags & STRSAFE_IGNORE_NULLS)
  4800.         {
  4801.             if (pszDest == NULL)
  4802.             {
  4803.                 if ((cchDest != 0) || (cbDest != 0))
  4804.                 {
  4805.                     // NULL pszDest and non-zero cchDest/cbDest is invalid
  4806.                     hr = STRSAFE_E_INVALID_PARAMETER;
  4807.                 }
  4808.             }
  4809.  
  4810.             if (pszSrc == NULL)
  4811.             {
  4812.                 pszSrc = L"";
  4813.             }
  4814.         }
  4815.  
  4816.         if (SUCCEEDED(hr))
  4817.         {
  4818.             if (cchDest == 0)
  4819.             {
  4820.                 pszDestEnd = pszDest;
  4821.                 cchRemaining = 0;
  4822.  
  4823.                 // only fail if there was actually src data to copy
  4824.                 if (*pszSrc != L'\0')
  4825.                 {
  4826.                     if (pszDest == NULL)
  4827.                     {
  4828.                         hr = STRSAFE_E_INVALID_PARAMETER;
  4829.                     }
  4830.                     else
  4831.                     {
  4832.                         hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  4833.                     }
  4834.                 }
  4835.             }
  4836.             else
  4837.             {
  4838.                 pszDestEnd = pszDest;
  4839.                 cchRemaining = cchDest;
  4840.  
  4841.                 while (cchRemaining && cchSrc && (*pszSrc != L'\0'))
  4842.                 {
  4843.                     *pszDestEnd++= *pszSrc++;
  4844.                     cchRemaining--;
  4845.                     cchSrc--;
  4846.                 }
  4847.  
  4848.                 if (cchRemaining > 0)
  4849.                 {
  4850.                     if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
  4851.                     {
  4852.                         memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
  4853.                     }
  4854.                 }
  4855.                 else
  4856.                 {
  4857.                     // we are going to truncate pszDest
  4858.                     pszDestEnd--;
  4859.                     cchRemaining++;
  4860.  
  4861.                     hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  4862.                 }
  4863.  
  4864.                 *pszDestEnd = L'\0';
  4865.             }
  4866.         }
  4867.     }
  4868.  
  4869.     if (FAILED(hr))
  4870.     {
  4871.         if (pszDest)
  4872.         {
  4873.             if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  4874.             {
  4875.                 memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  4876.  
  4877.                 if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  4878.                 {
  4879.                     pszDestEnd = pszDest;
  4880.                     cchRemaining = cchDest;
  4881.                 }
  4882.                 else if (cchDest > 0)
  4883.                 {
  4884.                     pszDestEnd = pszDest + cchDest - 1;
  4885.                     cchRemaining = 1;
  4886.  
  4887.                     // null terminate the end of the string
  4888.                     *pszDestEnd = L'\0';
  4889.                 }
  4890.             }
  4891.  
  4892.             if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
  4893.             {
  4894.                 if (cchDest > 0)
  4895.                 {
  4896.                     pszDestEnd = pszDest;
  4897.                     cchRemaining = cchDest;
  4898.  
  4899.                     // null terminate the beginning of the string
  4900.                     *pszDestEnd = L'\0';
  4901.                 }
  4902.             }
  4903.         }
  4904.     }
  4905.  
  4906.     if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  4907.     {
  4908.         if (ppszDestEnd)
  4909.         {
  4910.             *ppszDestEnd = pszDestEnd;
  4911.         }
  4912.  
  4913.         if (pcchRemaining)
  4914.         {
  4915.             *pcchRemaining = cchRemaining;
  4916.         }
  4917.     }
  4918.  
  4919.     return hr;
  4920. }
  4921.  
  4922. STRSAFEAPI StringCatWorkerA(char* pszDest, size_t cchDest, const char* pszSrc)
  4923. {
  4924.    HRESULT hr;
  4925.    size_t cchDestCurrent;
  4926.  
  4927.    hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
  4928.  
  4929.    if (SUCCEEDED(hr))
  4930.    {
  4931.        hr = StringCopyWorkerA(pszDest + cchDestCurrent,
  4932.                               cchDest - cchDestCurrent,
  4933.                               pszSrc);
  4934.    }
  4935.  
  4936.    return hr;
  4937. }
  4938.  
  4939. STRSAFEAPI StringCatWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc)
  4940. {
  4941.    HRESULT hr;
  4942.    size_t cchDestCurrent;
  4943.  
  4944.    hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
  4945.  
  4946.    if (SUCCEEDED(hr))
  4947.    {
  4948.        hr = StringCopyWorkerW(pszDest + cchDestCurrent,
  4949.                               cchDest - cchDestCurrent,
  4950.                               pszSrc);
  4951.    }
  4952.  
  4953.    return hr;
  4954. }
  4955.  
  4956. STRSAFEAPI StringCatExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  4957. {
  4958.     HRESULT hr = S_OK;
  4959.     char* pszDestEnd = pszDest;
  4960.     size_t cchRemaining = 0;
  4961.  
  4962.     // ASSERT(cbDest == (cchDest * sizeof(char))    ||
  4963.     //        cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
  4964.  
  4965.     // only accept valid flags
  4966.     if (dwFlags & (~STRSAFE_VALID_FLAGS))
  4967.     {
  4968.         hr = STRSAFE_E_INVALID_PARAMETER;
  4969.     }
  4970.     else
  4971.     {
  4972.         size_t cchDestCurrent;
  4973.  
  4974.         if (dwFlags & STRSAFE_IGNORE_NULLS)
  4975.         {
  4976.             if (pszDest == NULL)
  4977.             {
  4978.                 if ((cchDest == 0) && (cbDest == 0))
  4979.                 {
  4980.                     cchDestCurrent = 0;
  4981.                 }
  4982.                 else
  4983.                 {
  4984.                     // NULL pszDest and non-zero cchDest/cbDest is invalid
  4985.                     hr = STRSAFE_E_INVALID_PARAMETER;
  4986.                 }
  4987.             }
  4988.             else
  4989.             {
  4990.                 hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
  4991.  
  4992.                 if (SUCCEEDED(hr))
  4993.                 {
  4994.                     pszDestEnd = pszDest + cchDestCurrent;
  4995.                     cchRemaining = cchDest - cchDestCurrent;
  4996.                 }
  4997.             }
  4998.  
  4999.             if (pszSrc == NULL)
  5000.             {
  5001.                 pszSrc = "";
  5002.             }
  5003.         }
  5004.         else
  5005.         {
  5006.             hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
  5007.  
  5008.             if (SUCCEEDED(hr))
  5009.             {
  5010.                 pszDestEnd = pszDest + cchDestCurrent;
  5011.                 cchRemaining = cchDest - cchDestCurrent;
  5012.             }
  5013.         }
  5014.  
  5015.         if (SUCCEEDED(hr))
  5016.         {
  5017.             if (cchDest == 0)
  5018.             {
  5019.                 // only fail if there was actually src data to append
  5020.                 if (*pszSrc != '\0')
  5021.                 {
  5022.                     if (pszDest == NULL)
  5023.                     {
  5024.                         hr = STRSAFE_E_INVALID_PARAMETER;
  5025.                     }
  5026.                     else
  5027.                     {
  5028.                         hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  5029.                     }
  5030.                 }
  5031.             }
  5032.             else
  5033.             {
  5034.                 // we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass
  5035.                 // those flags through
  5036.                 hr = StringCopyExWorkerA(pszDestEnd,
  5037.                                          cchRemaining,
  5038.                                          (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)),
  5039.                                          pszSrc,
  5040.                                          &pszDestEnd,
  5041.                                          &cchRemaining,
  5042.                                          dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)));
  5043.             }
  5044.         }
  5045.     }
  5046.  
  5047.     if (FAILED(hr))
  5048.     {
  5049.         if (pszDest)
  5050.         {
  5051.             // STRSAFE_NO_TRUNCATION is taken care of by StringCopyExWorkerA()
  5052.  
  5053.             if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  5054.             {
  5055.                 memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  5056.  
  5057.                 if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  5058.                 {
  5059.                     pszDestEnd = pszDest;
  5060.                     cchRemaining = cchDest;
  5061.                 }
  5062.                 else
  5063.                 if (cchDest > 0)
  5064.                 {
  5065.                     pszDestEnd = pszDest + cchDest - 1;
  5066.                     cchRemaining = 1;
  5067.  
  5068.                     // null terminate the end of the string
  5069.                     *pszDestEnd = '\0';
  5070.                 }
  5071.             }
  5072.  
  5073.             if (dwFlags & STRSAFE_NULL_ON_FAILURE)
  5074.             {
  5075.                 if (cchDest > 0)
  5076.                 {
  5077.                     pszDestEnd = pszDest;
  5078.                     cchRemaining = cchDest;
  5079.  
  5080.                     // null terminate the beginning of the string
  5081.                     *pszDestEnd = '\0';
  5082.                 }
  5083.             }
  5084.         }
  5085.     }
  5086.  
  5087.     if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  5088.     {
  5089.         if (ppszDestEnd)
  5090.         {
  5091.             *ppszDestEnd = pszDestEnd;
  5092.         }
  5093.  
  5094.         if (pcchRemaining)
  5095.         {
  5096.             *pcchRemaining = cchRemaining;
  5097.         }
  5098.     }
  5099.  
  5100.     return hr;
  5101. }
  5102.  
  5103. STRSAFEAPI StringCatExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  5104. {
  5105.     HRESULT hr = S_OK;
  5106.     wchar_t* pszDestEnd = pszDest;
  5107.     size_t cchRemaining = 0;
  5108.  
  5109.     // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) ||
  5110.     //        cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
  5111.  
  5112.     // only accept valid flags
  5113.     if (dwFlags & (~STRSAFE_VALID_FLAGS))
  5114.     {
  5115.         hr = STRSAFE_E_INVALID_PARAMETER;
  5116.     }
  5117.     else
  5118.     {
  5119.         size_t cchDestCurrent;
  5120.  
  5121.         if (dwFlags & STRSAFE_IGNORE_NULLS)
  5122.         {
  5123.             if (pszDest == NULL)
  5124.             {
  5125.                 if ((cchDest == 0) && (cbDest == 0))
  5126.                 {
  5127.                     cchDestCurrent = 0;
  5128.                 }
  5129.                 else
  5130.                 {
  5131.                     // NULL pszDest and non-zero cchDest/cbDest is invalid
  5132.                     hr = STRSAFE_E_INVALID_PARAMETER;
  5133.                 }
  5134.             }
  5135.             else
  5136.             {
  5137.                 hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
  5138.  
  5139.                 if (SUCCEEDED(hr))
  5140.                 {
  5141.                     pszDestEnd = pszDest + cchDestCurrent;
  5142.                     cchRemaining = cchDest - cchDestCurrent;
  5143.                 }
  5144.             }
  5145.  
  5146.             if (pszSrc == NULL)
  5147.             {
  5148.                 pszSrc = L"";
  5149.             }
  5150.         }
  5151.         else
  5152.         {
  5153.             hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
  5154.  
  5155.             if (SUCCEEDED(hr))
  5156.             {
  5157.                 pszDestEnd = pszDest + cchDestCurrent;
  5158.                 cchRemaining = cchDest - cchDestCurrent;
  5159.             }
  5160.         }
  5161.  
  5162.         if (SUCCEEDED(hr))
  5163.         {
  5164.             if (cchDest == 0)
  5165.             {
  5166.                 // only fail if there was actually src data to append
  5167.                 if (*pszSrc != L'\0')
  5168.                 {
  5169.                     if (pszDest == NULL)
  5170.                     {
  5171.                         hr = STRSAFE_E_INVALID_PARAMETER;
  5172.                     }
  5173.                     else
  5174.                     {
  5175.                         hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  5176.                     }
  5177.                 }
  5178.             }
  5179.             else
  5180.             {
  5181.                 // we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass
  5182.                 // those flags through
  5183.                 hr = StringCopyExWorkerW(pszDestEnd,
  5184.                                          cchRemaining,
  5185.                                          (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)),
  5186.                                          pszSrc,
  5187.                                          &pszDestEnd,
  5188.                                          &cchRemaining,
  5189.                                          dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)));
  5190.             }
  5191.         }
  5192.     }
  5193.  
  5194.     if (FAILED(hr))
  5195.     {
  5196.         if (pszDest)
  5197.         {
  5198.             // STRSAFE_NO_TRUNCATION is taken care of by StringCopyExWorkerW()
  5199.  
  5200.             if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  5201.             {
  5202.                 memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  5203.  
  5204.                 if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  5205.                 {
  5206.                     pszDestEnd = pszDest;
  5207.                     cchRemaining = cchDest;
  5208.                 }
  5209.                 else if (cchDest > 0)
  5210.                 {
  5211.                     pszDestEnd = pszDest + cchDest - 1;
  5212.                     cchRemaining = 1;
  5213.  
  5214.                     // null terminate the end of the string
  5215.                     *pszDestEnd = L'\0';
  5216.                 }
  5217.             }
  5218.  
  5219.             if (dwFlags & STRSAFE_NULL_ON_FAILURE)
  5220.             {
  5221.                 if (cchDest > 0)
  5222.                 {
  5223.                     pszDestEnd = pszDest;
  5224.                     cchRemaining = cchDest;
  5225.  
  5226.                     // null terminate the beginning of the string
  5227.                     *pszDestEnd = L'\0';
  5228.                 }
  5229.             }
  5230.         }
  5231.     }
  5232.  
  5233.     if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  5234.     {
  5235.         if (ppszDestEnd)
  5236.         {
  5237.             *ppszDestEnd = pszDestEnd;
  5238.         }
  5239.  
  5240.         if (pcchRemaining)
  5241.         {
  5242.             *pcchRemaining = cchRemaining;
  5243.         }
  5244.     }
  5245.  
  5246.     return hr;
  5247. }
  5248.  
  5249. STRSAFEAPI StringCatNWorkerA(char* pszDest, size_t cchDest, const char* pszSrc, size_t cchMaxAppend)
  5250. {
  5251.     HRESULT hr;
  5252.     size_t cchDestCurrent;
  5253.  
  5254.     hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
  5255.  
  5256.     if (SUCCEEDED(hr))
  5257.     {
  5258.         hr = StringCopyNWorkerA(pszDest + cchDestCurrent,
  5259.                                 cchDest - cchDestCurrent,
  5260.                                 pszSrc,
  5261.                                 cchMaxAppend);
  5262.     }
  5263.  
  5264.     return hr;
  5265. }
  5266.  
  5267. STRSAFEAPI StringCatNWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszSrc, size_t cchMaxAppend)
  5268. {
  5269.     HRESULT hr;
  5270.     size_t cchDestCurrent;
  5271.  
  5272.     hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
  5273.  
  5274.     if (SUCCEEDED(hr))
  5275.     {
  5276.         hr = StringCopyNWorkerW(pszDest + cchDestCurrent,
  5277.                                 cchDest - cchDestCurrent,
  5278.                                 pszSrc,
  5279.                                 cchMaxAppend);
  5280.     }
  5281.  
  5282.     return hr;
  5283. }
  5284.  
  5285. STRSAFEAPI StringCatNExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, const char* pszSrc, size_t cchMaxAppend, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  5286. {
  5287.     HRESULT hr = S_OK;
  5288.     char* pszDestEnd = pszDest;
  5289.     size_t cchRemaining = 0;
  5290.     size_t cchDestCurrent = 0;
  5291.  
  5292.     // ASSERT(cbDest == (cchDest * sizeof(char))    ||
  5293.     //        cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
  5294.  
  5295.     // only accept valid flags
  5296.     if (dwFlags & (~STRSAFE_VALID_FLAGS))
  5297.     {
  5298.         hr = STRSAFE_E_INVALID_PARAMETER;
  5299.     }
  5300.     else
  5301.     {
  5302.         if (dwFlags & STRSAFE_IGNORE_NULLS)
  5303.         {
  5304.             if (pszDest == NULL)
  5305.             {
  5306.                 if ((cchDest == 0) && (cbDest == 0))
  5307.                 {
  5308.                     cchDestCurrent = 0;
  5309.                 }
  5310.                 else
  5311.                 {
  5312.                     // NULL pszDest and non-zero cchDest/cbDest is invalid
  5313.                     hr = STRSAFE_E_INVALID_PARAMETER;
  5314.                 }
  5315.             }
  5316.             else
  5317.             {
  5318.                 hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
  5319.  
  5320.                 if (SUCCEEDED(hr))
  5321.                 {
  5322.                     pszDestEnd = pszDest + cchDestCurrent;
  5323.                     cchRemaining = cchDest - cchDestCurrent;
  5324.                 }
  5325.             }
  5326.  
  5327.             if (pszSrc == NULL)
  5328.             {
  5329.                 pszSrc = "";
  5330.             }
  5331.         }
  5332.         else
  5333.         {
  5334.             hr = StringLengthWorkerA(pszDest, cchDest, &cchDestCurrent);
  5335.  
  5336.             if (SUCCEEDED(hr))
  5337.             {
  5338.                 pszDestEnd = pszDest + cchDestCurrent;
  5339.                 cchRemaining = cchDest - cchDestCurrent;
  5340.             }
  5341.         }
  5342.  
  5343.         if (SUCCEEDED(hr))
  5344.         {
  5345.             if (cchDest == 0)
  5346.             {
  5347.                 // only fail if there was actually src data to append
  5348.                 if (*pszSrc != '\0')
  5349.                 {
  5350.                     if (pszDest == NULL)
  5351.                     {
  5352.                         hr = STRSAFE_E_INVALID_PARAMETER;
  5353.                     }
  5354.                     else
  5355.                     {
  5356.                         hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  5357.                     }
  5358.                 }
  5359.             }
  5360.             else
  5361.             {
  5362.                 // we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass
  5363.                 // those flags through
  5364.                 hr = StringCopyNExWorkerA(pszDestEnd,
  5365.                                           cchRemaining,
  5366.                                           (cchRemaining * sizeof(char)) + (cbDest % sizeof(char)),
  5367.                                           pszSrc,
  5368.                                           cchMaxAppend,
  5369.                                           &pszDestEnd,
  5370.                                           &cchRemaining,
  5371.                                           dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)));
  5372.             }
  5373.         }
  5374.     }
  5375.  
  5376.     if (FAILED(hr))
  5377.     {
  5378.         if (pszDest)
  5379.         {
  5380.             // STRSAFE_NO_TRUNCATION is taken care of by StringCopyNExWorkerA()
  5381.  
  5382.             if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  5383.             {
  5384.                 memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  5385.  
  5386.                 if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  5387.                 {
  5388.                     pszDestEnd = pszDest;
  5389.                     cchRemaining = cchDest;
  5390.                 }
  5391.                 else if (cchDest > 0)
  5392.                 {
  5393.                     pszDestEnd = pszDest + cchDest - 1;
  5394.                     cchRemaining = 1;
  5395.  
  5396.                     // null terminate the end of the string
  5397.                     *pszDestEnd = '\0';
  5398.                 }
  5399.             }
  5400.  
  5401.             if (dwFlags & (STRSAFE_NULL_ON_FAILURE))
  5402.             {
  5403.                 if (cchDest > 0)
  5404.                 {
  5405.                     pszDestEnd = pszDest;
  5406.                     cchRemaining = cchDest;
  5407.  
  5408.                     // null terminate the beginning of the string
  5409.                     *pszDestEnd = '\0';
  5410.                 }
  5411.             }
  5412.         }
  5413.     }
  5414.  
  5415.     if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  5416.     {
  5417.         if (ppszDestEnd)
  5418.         {
  5419.             *ppszDestEnd = pszDestEnd;
  5420.         }
  5421.  
  5422.         if (pcchRemaining)
  5423.         {
  5424.             *pcchRemaining = cchRemaining;
  5425.         }
  5426.     }
  5427.  
  5428.     return hr;
  5429. }
  5430.  
  5431. STRSAFEAPI StringCatNExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, const wchar_t* pszSrc, size_t cchMaxAppend, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  5432. {
  5433.     HRESULT hr = S_OK;
  5434.     wchar_t* pszDestEnd = pszDest;
  5435.     size_t cchRemaining = 0;
  5436.     size_t cchDestCurrent = 0;
  5437.  
  5438.  
  5439.     // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) ||
  5440.     //        cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
  5441.  
  5442.     // only accept valid flags
  5443.     if (dwFlags & (~STRSAFE_VALID_FLAGS))
  5444.     {
  5445.         hr = STRSAFE_E_INVALID_PARAMETER;
  5446.     }
  5447.     else
  5448.     {
  5449.         if (dwFlags & STRSAFE_IGNORE_NULLS)
  5450.         {
  5451.             if (pszDest == NULL)
  5452.             {
  5453.                 if ((cchDest == 0) && (cbDest == 0))
  5454.                 {
  5455.                     cchDestCurrent = 0;
  5456.                 }
  5457.                 else
  5458.                 {
  5459.                     // NULL pszDest and non-zero cchDest/cbDest is invalid
  5460.                     hr = STRSAFE_E_INVALID_PARAMETER;
  5461.                 }
  5462.             }
  5463.             else
  5464.             {
  5465.                 hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
  5466.  
  5467.                 if (SUCCEEDED(hr))
  5468.                 {
  5469.                     pszDestEnd = pszDest + cchDestCurrent;
  5470.                     cchRemaining = cchDest - cchDestCurrent;
  5471.                 }
  5472.             }
  5473.  
  5474.             if (pszSrc == NULL)
  5475.             {
  5476.                 pszSrc = L"";
  5477.             }
  5478.         }
  5479.         else
  5480.         {
  5481.             hr = StringLengthWorkerW(pszDest, cchDest, &cchDestCurrent);
  5482.  
  5483.             if (SUCCEEDED(hr))
  5484.             {
  5485.                 pszDestEnd = pszDest + cchDestCurrent;
  5486.                 cchRemaining = cchDest - cchDestCurrent;
  5487.             }
  5488.         }
  5489.  
  5490.         if (SUCCEEDED(hr))
  5491.         {
  5492.             if (cchDest == 0)
  5493.             {
  5494.                 // only fail if there was actually src data to append
  5495.                 if (*pszSrc != L'\0')
  5496.                 {
  5497.                     if (pszDest == NULL)
  5498.                     {
  5499.                         hr = STRSAFE_E_INVALID_PARAMETER;
  5500.                     }
  5501.                     else
  5502.                     {
  5503.                         hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  5504.                     }
  5505.                 }
  5506.             }
  5507.             else
  5508.             {
  5509.                 // we handle the STRSAFE_FILL_ON_FAILURE and STRSAFE_NULL_ON_FAILURE cases below, so do not pass
  5510.                 // those flags through
  5511.                 hr = StringCopyNExWorkerW(pszDestEnd,
  5512.                                           cchRemaining,
  5513.                                           (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)),
  5514.                                           pszSrc,
  5515.                                           cchMaxAppend,
  5516.                                           &pszDestEnd,
  5517.                                           &cchRemaining,
  5518.                                           dwFlags & (~(STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)));
  5519.             }
  5520.         }
  5521.     }
  5522.  
  5523.     if (FAILED(hr))
  5524.     {
  5525.         if (pszDest)
  5526.         {
  5527.             // STRSAFE_NO_TRUNCATION is taken care of by StringCopyNExWorkerW()
  5528.  
  5529.             if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  5530.             {
  5531.                 memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  5532.  
  5533.                 if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  5534.                 {
  5535.                     pszDestEnd = pszDest;
  5536.                     cchRemaining = cchDest;
  5537.                 }
  5538.                 else if (cchDest > 0)
  5539.                 {
  5540.                     pszDestEnd = pszDest + cchDest - 1;
  5541.                     cchRemaining = 1;
  5542.  
  5543.                     // null terminate the end of the string
  5544.                     *pszDestEnd = L'\0';
  5545.                 }
  5546.             }
  5547.  
  5548.             if (dwFlags & (STRSAFE_NULL_ON_FAILURE))
  5549.             {
  5550.                 if (cchDest > 0)
  5551.                 {
  5552.                     pszDestEnd = pszDest;
  5553.                     cchRemaining = cchDest;
  5554.  
  5555.                     // null terminate the beginning of the string
  5556.                     *pszDestEnd = L'\0';
  5557.                 }
  5558.             }
  5559.         }
  5560.     }
  5561.  
  5562.     if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  5563.     {
  5564.         if (ppszDestEnd)
  5565.         {
  5566.             *ppszDestEnd = pszDestEnd;
  5567.         }
  5568.  
  5569.         if (pcchRemaining)
  5570.         {
  5571.             *pcchRemaining = cchRemaining;
  5572.         }
  5573.     }
  5574.  
  5575.     return hr;
  5576. }
  5577.  
  5578. STRSAFEAPI StringVPrintfWorkerA(char* pszDest, size_t cchDest, const char* pszFormat, va_list argList)
  5579. {
  5580.     HRESULT hr = S_OK;
  5581.  
  5582.     if (cchDest == 0)
  5583.     {
  5584.         // can not null terminate a zero-byte dest buffer
  5585.         hr = STRSAFE_E_INVALID_PARAMETER;
  5586.     }
  5587.     else
  5588.     {
  5589.         int iRet;
  5590.         size_t cchMax;
  5591.  
  5592.         // leave the last space for the null terminator
  5593.         cchMax = cchDest - 1;
  5594.  
  5595.         iRet = _vsnprintf(pszDest, cchMax, pszFormat, argList);
  5596.         // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
  5597.  
  5598.         if ((iRet < 0) || (((size_t)iRet) > cchMax))
  5599.         {
  5600.             // need to null terminate the string
  5601.             pszDest += cchMax;
  5602.             *pszDest = '\0';
  5603.  
  5604.             // we have truncated pszDest
  5605.             hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  5606.         }
  5607.         else if (((size_t)iRet) == cchMax)
  5608.         {
  5609.             // need to null terminate the string
  5610.             pszDest += cchMax;
  5611.             *pszDest = '\0';
  5612.         }
  5613.     }
  5614.  
  5615.     return hr;
  5616. }
  5617.  
  5618. STRSAFEAPI StringVPrintfWorkerW(wchar_t* pszDest, size_t cchDest, const wchar_t* pszFormat, va_list argList)
  5619. {
  5620.     HRESULT hr = S_OK;
  5621.  
  5622.     if (cchDest == 0)
  5623.     {
  5624.         // can not null terminate a zero-byte dest buffer
  5625.         hr = STRSAFE_E_INVALID_PARAMETER;
  5626.     }
  5627.     else
  5628.     {
  5629.         int iRet;
  5630.         size_t cchMax;
  5631.  
  5632.         // leave the last space for the null terminator
  5633.         cchMax = cchDest - 1;
  5634.  
  5635.         iRet = _vsnwprintf(pszDest, cchMax, pszFormat, argList);
  5636.         // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
  5637.  
  5638.         if ((iRet < 0) || (((size_t)iRet) > cchMax))
  5639.         {
  5640.             // need to null terminate the string
  5641.             pszDest += cchMax;
  5642.             *pszDest = L'\0';
  5643.  
  5644.             // we have truncated pszDest
  5645.             hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  5646.         }
  5647.         else if (((size_t)iRet) == cchMax)
  5648.         {
  5649.             // need to null terminate the string
  5650.             pszDest += cchMax;
  5651.             *pszDest = L'\0';
  5652.         }
  5653.     }
  5654.  
  5655.     return hr;
  5656. }
  5657.  
  5658. STRSAFEAPI StringVPrintfExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const char* pszFormat, va_list argList)
  5659. {
  5660.     HRESULT hr = S_OK;
  5661.     char* pszDestEnd = pszDest;
  5662.     size_t cchRemaining = 0;
  5663.  
  5664.     // ASSERT(cbDest == (cchDest * sizeof(char))    ||
  5665.     //        cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
  5666.  
  5667.     // only accept valid flags
  5668.     if (dwFlags & (~STRSAFE_VALID_FLAGS))
  5669.     {
  5670.         hr = STRSAFE_E_INVALID_PARAMETER;
  5671.     }
  5672.     else
  5673.     {
  5674.         if (dwFlags & STRSAFE_IGNORE_NULLS)
  5675.         {
  5676.             if (pszDest == NULL)
  5677.             {
  5678.                 if ((cchDest != 0) || (cbDest != 0))
  5679.                 {
  5680.                     // NULL pszDest and non-zero cchDest/cbDest is invalid
  5681.                     hr = STRSAFE_E_INVALID_PARAMETER;
  5682.                 }
  5683.             }
  5684.  
  5685.             if (pszFormat == NULL)
  5686.             {
  5687.                 pszFormat = "";
  5688.             }
  5689.         }
  5690.  
  5691.         if (SUCCEEDED(hr))
  5692.         {
  5693.             if (cchDest == 0)
  5694.             {
  5695.                 pszDestEnd = pszDest;
  5696.                 cchRemaining = 0;
  5697.  
  5698.                 // only fail if there was actually a non-empty format string
  5699.                 if (*pszFormat != '\0')
  5700.                 {
  5701.                     if (pszDest == NULL)
  5702.                     {
  5703.                         hr = STRSAFE_E_INVALID_PARAMETER;
  5704.                     }
  5705.                     else
  5706.                     {
  5707.                         hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  5708.                     }
  5709.                 }
  5710.             }
  5711.             else
  5712.             {
  5713.                 int iRet;
  5714.                 size_t cchMax;
  5715.  
  5716.                 // leave the last space for the null terminator
  5717.                 cchMax = cchDest - 1;
  5718.  
  5719.                 iRet = _vsnprintf(pszDest, cchMax, pszFormat, argList);
  5720.                 // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
  5721.  
  5722.                 if ((iRet < 0) || (((size_t)iRet) > cchMax))
  5723.                 {
  5724.                     // we have truncated pszDest
  5725.                     pszDestEnd = pszDest + cchMax;
  5726.                     cchRemaining = 1;
  5727.  
  5728.                     // need to null terminate the string
  5729.                     *pszDestEnd = '\0';
  5730.  
  5731.                     hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  5732.                 }
  5733.                 else if (((size_t)iRet) == cchMax)
  5734.                 {
  5735.                     // string fit perfectly
  5736.                     pszDestEnd = pszDest + cchMax;
  5737.                     cchRemaining = 1;
  5738.  
  5739.                     // need to null terminate the string
  5740.                     *pszDestEnd = '\0';
  5741.                 }
  5742.                 else if (((size_t)iRet) < cchMax)
  5743.                 {
  5744.                     // there is extra room
  5745.                     pszDestEnd = pszDest + iRet;
  5746.                     cchRemaining = cchDest - iRet;
  5747.  
  5748.                     if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
  5749.                     {
  5750.                         memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char)));
  5751.                     }
  5752.                 }
  5753.             }
  5754.         }
  5755.     }
  5756.  
  5757.     if (FAILED(hr))
  5758.     {
  5759.         if (pszDest)
  5760.         {
  5761.             if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  5762.             {
  5763.                 memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  5764.  
  5765.                 if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  5766.                 {
  5767.                     pszDestEnd = pszDest;
  5768.                     cchRemaining = cchDest;
  5769.                 }
  5770.                 else if (cchDest > 0)
  5771.                 {
  5772.                     pszDestEnd = pszDest + cchDest - 1;
  5773.                     cchRemaining = 1;
  5774.  
  5775.                     // null terminate the end of the string
  5776.                     *pszDestEnd = '\0';
  5777.                 }
  5778.             }
  5779.  
  5780.             if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
  5781.             {
  5782.                 if (cchDest > 0)
  5783.                 {
  5784.                     pszDestEnd = pszDest;
  5785.                     cchRemaining = cchDest;
  5786.  
  5787.                     // null terminate the beginning of the string
  5788.                     *pszDestEnd = '\0';
  5789.                 }
  5790.             }
  5791.         }
  5792.     }
  5793.  
  5794.     if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  5795.     {
  5796.         if (ppszDestEnd)
  5797.         {
  5798.             *ppszDestEnd = pszDestEnd;
  5799.         }
  5800.  
  5801.         if (pcchRemaining)
  5802.         {
  5803.             *pcchRemaining = cchRemaining;
  5804.         }
  5805.     }
  5806.  
  5807.     return hr;
  5808. }
  5809.  
  5810. STRSAFEAPI StringVPrintfExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags, const wchar_t* pszFormat, va_list argList)
  5811. {
  5812.     HRESULT hr = S_OK;
  5813.     wchar_t* pszDestEnd = pszDest;
  5814.     size_t cchRemaining = 0;
  5815.  
  5816.     // ASSERT(cbDest == (cchDest * sizeof(wchar_t)) ||
  5817.     //        cbDest == (cchDest * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
  5818.  
  5819.     // only accept valid flags
  5820.     if (dwFlags & (~STRSAFE_VALID_FLAGS))
  5821.     {
  5822.         hr = STRSAFE_E_INVALID_PARAMETER;
  5823.     }
  5824.     else
  5825.     {
  5826.         if (dwFlags & STRSAFE_IGNORE_NULLS)
  5827.         {
  5828.             if (pszDest == NULL)
  5829.             {
  5830.                 if ((cchDest != 0) || (cbDest != 0))
  5831.                 {
  5832.                     // NULL pszDest and non-zero cchDest/cbDest is invalid
  5833.                     hr = STRSAFE_E_INVALID_PARAMETER;
  5834.                 }
  5835.             }
  5836.  
  5837.             if (pszFormat == NULL)
  5838.             {
  5839.                 pszFormat = L"";
  5840.             }
  5841.         }
  5842.  
  5843.         if (SUCCEEDED(hr))
  5844.         {
  5845.             if (cchDest == 0)
  5846.             {
  5847.                 pszDestEnd = pszDest;
  5848.                 cchRemaining = 0;
  5849.  
  5850.                 // only fail if there was actually a non-empty format string
  5851.                 if (*pszFormat != L'\0')
  5852.                 {
  5853.                     if (pszDest == NULL)
  5854.                     {
  5855.                         hr = STRSAFE_E_INVALID_PARAMETER;
  5856.                     }
  5857.                     else
  5858.                     {
  5859.                         hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  5860.                     }
  5861.                 }
  5862.             }
  5863.             else
  5864.             {
  5865.                 int iRet;
  5866.                 size_t cchMax;
  5867.  
  5868.                 // leave the last space for the null terminator
  5869.                 cchMax = cchDest - 1;
  5870.  
  5871.                 iRet = _vsnwprintf(pszDest, cchMax, pszFormat, argList);
  5872.                 // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
  5873.  
  5874.                 if ((iRet < 0) || (((size_t)iRet) > cchMax))
  5875.                 {
  5876.                     // we have truncated pszDest
  5877.                     pszDestEnd = pszDest + cchMax;
  5878.                     cchRemaining = 1;
  5879.  
  5880.                     // need to null terminate the string
  5881.                     *pszDestEnd = L'\0';
  5882.  
  5883.                     hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  5884.                 }
  5885.                 else if (((size_t)iRet) == cchMax)
  5886.                 {
  5887.                     // string fit perfectly
  5888.                     pszDestEnd = pszDest + cchMax;
  5889.                     cchRemaining = 1;
  5890.  
  5891.                     // need to null terminate the string
  5892.                     *pszDestEnd = L'\0';
  5893.                 }
  5894.                 else if (((size_t)iRet) < cchMax)
  5895.                 {
  5896.                     // there is extra room
  5897.                     pszDestEnd = pszDest + iRet;
  5898.                     cchRemaining = cchDest - iRet;
  5899.  
  5900.                     if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
  5901.                     {
  5902.                         memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
  5903.                     }
  5904.                 }
  5905.             }
  5906.         }
  5907.     }
  5908.  
  5909.     if (FAILED(hr))
  5910.     {
  5911.         if (pszDest)
  5912.         {
  5913.             if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  5914.             {
  5915.                 memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  5916.  
  5917.                 if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  5918.                 {
  5919.                     pszDestEnd = pszDest;
  5920.                     cchRemaining = cchDest;
  5921.                 }
  5922.                 else if (cchDest > 0)
  5923.                 {
  5924.                     pszDestEnd = pszDest + cchDest - 1;
  5925.                     cchRemaining = 1;
  5926.  
  5927.                     // null terminate the end of the string
  5928.                     *pszDestEnd = L'\0';
  5929.                 }
  5930.             }
  5931.  
  5932.             if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
  5933.             {
  5934.                 if (cchDest > 0)
  5935.                 {
  5936.                     pszDestEnd = pszDest;
  5937.                     cchRemaining = cchDest;
  5938.  
  5939.                     // null terminate the beginning of the string
  5940.                     *pszDestEnd = L'\0';
  5941.                 }
  5942.             }
  5943.         }
  5944.     }
  5945.  
  5946.     if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
  5947.     {
  5948.         if (ppszDestEnd)
  5949.         {
  5950.             *ppszDestEnd = pszDestEnd;
  5951.         }
  5952.  
  5953.         if (pcchRemaining)
  5954.         {
  5955.             *pcchRemaining = cchRemaining;
  5956.         }
  5957.     }
  5958.  
  5959.     return hr;
  5960. }
  5961.  
  5962. STRSAFEAPI StringLengthWorkerA(const char* psz, size_t cchMax, size_t* pcch)
  5963. {
  5964.     HRESULT hr = S_OK;
  5965.     size_t cchMaxPrev = cchMax;
  5966.  
  5967.     while (cchMax && (*psz != '\0'))
  5968.     {
  5969.         psz++;
  5970.         cchMax--;
  5971.     }
  5972.  
  5973.     if (cchMax == 0)
  5974.     {
  5975.         // the string is longer than cchMax
  5976.         hr = STRSAFE_E_INVALID_PARAMETER;
  5977.     }
  5978.  
  5979.     if (SUCCEEDED(hr) && pcch)
  5980.     {
  5981.         *pcch = cchMaxPrev - cchMax;
  5982.     }
  5983.  
  5984.     return hr;
  5985. }
  5986.  
  5987. STRSAFEAPI StringLengthWorkerW(const wchar_t* psz, size_t cchMax, size_t* pcch)
  5988. {
  5989.     HRESULT hr = S_OK;
  5990.     size_t cchMaxPrev = cchMax;
  5991.  
  5992.     while (cchMax && (*psz != L'\0'))
  5993.     {
  5994.         psz++;
  5995.         cchMax--;
  5996.     }
  5997.  
  5998.     if (cchMax == 0)
  5999.     {
  6000.         // the string is longer than cchMax
  6001.         hr = STRSAFE_E_INVALID_PARAMETER;
  6002.     }
  6003.  
  6004.     if (SUCCEEDED(hr) && pcch)
  6005.     {
  6006.         *pcch = cchMaxPrev - cchMax;
  6007.     }
  6008.  
  6009.     return hr;
  6010. }
  6011. #endif  // STRSAFE_INLINE
  6012.  
  6013. #ifndef STRSAFE_LIB_IMPL
  6014. STRSAFE_INLINE_API StringGetsExWorkerA(char* pszDest, size_t cchDest, size_t cbDest, char** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  6015. {
  6016.     HRESULT hr = S_OK;
  6017.     char* pszDestEnd = pszDest;
  6018.     size_t cchRemaining = 0;
  6019.  
  6020.     // ASSERT(cbDest == (cchDest * sizeof(char))    ||
  6021.     //        cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
  6022.  
  6023.     // only accept valid flags
  6024.     if (dwFlags & (~STRSAFE_VALID_FLAGS))
  6025.     {
  6026.         hr = STRSAFE_E_INVALID_PARAMETER;
  6027.     }
  6028.     else
  6029.     {
  6030.         if (dwFlags & STRSAFE_IGNORE_NULLS)
  6031.         {
  6032.             if (pszDest == NULL)
  6033.             {
  6034.                 if ((cchDest != 0) || (cbDest != 0))
  6035.                 {
  6036.                     // NULL pszDest and non-zero cchDest/cbDest is invalid
  6037.                     hr = STRSAFE_E_INVALID_PARAMETER;
  6038.                 }
  6039.             }
  6040.         }
  6041.  
  6042.         if (SUCCEEDED(hr))
  6043.         {
  6044.             if (cchDest <= 1)
  6045.             {
  6046.                 pszDestEnd = pszDest;
  6047.                 cchRemaining = cchDest;
  6048.  
  6049.                 if (cchDest == 1)
  6050.                 {
  6051.                     *pszDestEnd = '\0';
  6052.                 }
  6053.  
  6054.                 hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  6055.             }
  6056.             else
  6057.             {
  6058.                 char ch;
  6059.  
  6060.                 pszDestEnd = pszDest;
  6061.                 cchRemaining = cchDest;
  6062.  
  6063.                 while ((cchRemaining > 1) && (ch = (char)getc(stdin)) != '\n')
  6064.                 {
  6065.                     if (ch == EOF)
  6066.                     {
  6067.                         if (pszDestEnd == pszDest)
  6068.                         {
  6069.                             // we failed to read anything from stdin
  6070.                             hr = STRSAFE_E_END_OF_FILE;
  6071.                         }
  6072.                         break;
  6073.                     }
  6074.  
  6075.                     *pszDestEnd = ch;
  6076.  
  6077.                     pszDestEnd++;
  6078.                     cchRemaining--;
  6079.                 }
  6080.  
  6081.                 if (cchRemaining > 0)
  6082.                 {
  6083.                     // there is extra room
  6084.                     if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
  6085.                     {
  6086.                         memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(char)) + (cbDest % sizeof(char)));
  6087.                     }
  6088.                 }
  6089.  
  6090.                 *pszDestEnd = '\0';
  6091.             }
  6092.         }
  6093.     }
  6094.  
  6095.     if (FAILED(hr))
  6096.     {
  6097.         if (pszDest)
  6098.         {
  6099.             if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  6100.             {
  6101.                 memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  6102.  
  6103.                 if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  6104.                 {
  6105.                     pszDestEnd = pszDest;
  6106.                     cchRemaining = cchDest;
  6107.                 }
  6108.                 else if (cchDest > 0)
  6109.                 {
  6110.                     pszDestEnd = pszDest + cchDest - 1;
  6111.                     cchRemaining = 1;
  6112.  
  6113.                     // null terminate the end of the string
  6114.                     *pszDestEnd = '\0';
  6115.                 }
  6116.             }
  6117.  
  6118.             if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
  6119.             {
  6120.                 if (cchDest > 0)
  6121.                 {
  6122.                     pszDestEnd = pszDest;
  6123.                     cchRemaining = cchDest;
  6124.  
  6125.                     // null terminate the beginning of the string
  6126.                     *pszDestEnd = '\0';
  6127.                 }
  6128.             }
  6129.         }
  6130.     }
  6131.  
  6132.     if (SUCCEEDED(hr) ||
  6133.         (hr == STRSAFE_E_INSUFFICIENT_BUFFER) ||
  6134.         (hr == STRSAFE_E_END_OF_FILE))
  6135.     {
  6136.         if (ppszDestEnd)
  6137.         {
  6138.             *ppszDestEnd = pszDestEnd;
  6139.         }
  6140.  
  6141.         if (pcchRemaining)
  6142.         {
  6143.             *pcchRemaining = cchRemaining;
  6144.         }
  6145.     }
  6146.  
  6147.     return hr;
  6148. }
  6149.  
  6150. STRSAFE_INLINE_API StringGetsExWorkerW(wchar_t* pszDest, size_t cchDest, size_t cbDest, wchar_t** ppszDestEnd, size_t* pcchRemaining, unsigned long dwFlags)
  6151. {
  6152.     HRESULT hr = S_OK;
  6153.     wchar_t* pszDestEnd = pszDest;
  6154.     size_t cchRemaining = 0;
  6155.  
  6156.     // ASSERT(cbDest == (cchDest * sizeof(char))    ||
  6157.     //        cbDest == (cchDest * sizeof(char)) + (cbDest % sizeof(char)));
  6158.  
  6159.     // only accept valid flags
  6160.     if (dwFlags & (~STRSAFE_VALID_FLAGS))
  6161.     {
  6162.         hr = STRSAFE_E_INVALID_PARAMETER;
  6163.     }
  6164.     else
  6165.     {
  6166.         if (dwFlags & STRSAFE_IGNORE_NULLS)
  6167.         {
  6168.             if (pszDest == NULL)
  6169.             {
  6170.                 if ((cchDest != 0) || (cbDest != 0))
  6171.                 {
  6172.                     // NULL pszDest and non-zero cchDest/cbDest is invalid
  6173.                     hr = STRSAFE_E_INVALID_PARAMETER;
  6174.                 }
  6175.             }
  6176.         }
  6177.  
  6178.         if (SUCCEEDED(hr))
  6179.         {
  6180.             if (cchDest <= 1)
  6181.             {
  6182.                 pszDestEnd = pszDest;
  6183.                 cchRemaining = cchDest;
  6184.  
  6185.                 if (cchDest == 1)
  6186.                 {
  6187.                     *pszDestEnd = L'\0';
  6188.                 }
  6189.  
  6190.                 hr = STRSAFE_E_INSUFFICIENT_BUFFER;
  6191.             }
  6192.             else
  6193.             {
  6194.                 wchar_t ch;
  6195.  
  6196.                 pszDestEnd = pszDest;
  6197.                 cchRemaining = cchDest;
  6198.  
  6199.                 while ((cchRemaining > 1) && (ch = (wchar_t)getwc(stdin)) != L'\n')
  6200.                 {
  6201.                     if (ch == EOF)
  6202.                     {
  6203.                         if (pszDestEnd == pszDest)
  6204.                         {
  6205.                             // we failed to read anything from stdin
  6206.                             hr = STRSAFE_E_END_OF_FILE;
  6207.                         }
  6208.                         break;
  6209.                     }
  6210.  
  6211.                     *pszDestEnd = ch;
  6212.  
  6213.                     pszDestEnd++;
  6214.                     cchRemaining--;
  6215.                 }
  6216.  
  6217.                 if (cchRemaining > 0)
  6218.                 {
  6219.                     // there is extra room
  6220.                     if (dwFlags & STRSAFE_FILL_BEHIND_NULL)
  6221.                     {
  6222.                         memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), ((cchRemaining - 1) * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t)));
  6223.                     }
  6224.                 }
  6225.  
  6226.                 *pszDestEnd = L'\0';
  6227.             }
  6228.         }
  6229.     }
  6230.  
  6231.     if (FAILED(hr))
  6232.     {
  6233.         if (pszDest)
  6234.         {
  6235.             if (dwFlags & STRSAFE_FILL_ON_FAILURE)
  6236.             {
  6237.                 memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  6238.  
  6239.                 if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
  6240.                 {
  6241.                     pszDestEnd = pszDest;
  6242.                     cchRemaining = cchDest;
  6243.                 }
  6244.                 else if (cchDest > 0)
  6245.                 {
  6246.                     pszDestEnd = pszDest + cchDest - 1;
  6247.                     cchRemaining = 1;
  6248.  
  6249.                     // null terminate the end of the string
  6250.                     *pszDestEnd = L'\0';
  6251.                 }
  6252.             }
  6253.  
  6254.             if (dwFlags & (STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION))
  6255.             {
  6256.                 if (cchDest > 0)
  6257.                 {
  6258.                     pszDestEnd = pszDest;
  6259.                     cchRemaining = cchDest;
  6260.  
  6261.                     // null terminate the beginning of the string
  6262.                     *pszDestEnd = L'\0';
  6263.                 }
  6264.             }
  6265.         }
  6266.     }
  6267.  
  6268.     if (SUCCEEDED(hr) ||
  6269.         (hr == STRSAFE_E_INSUFFICIENT_BUFFER) ||
  6270.         (hr == STRSAFE_E_END_OF_FILE))
  6271.     {
  6272.         if (ppszDestEnd)
  6273.         {
  6274.             *ppszDestEnd = pszDestEnd;
  6275.         }
  6276.  
  6277.         if (pcchRemaining)
  6278.         {
  6279.             *pcchRemaining = cchRemaining;
  6280.         }
  6281.     }
  6282.  
  6283.     return hr;
  6284. }
  6285. #endif  // !STRSAFE_LIB_IMPL
  6286.  
  6287.  
  6288. // Do not call these functions, they are worker functions for internal use within this file
  6289. #ifdef DEPRECATE_SUPPORTED
  6290. #pragma deprecated(StringCopyWorkerA)
  6291. #pragma deprecated(StringCopyWorkerW)
  6292. #pragma deprecated(StringCopyExWorkerA)
  6293. #pragma deprecated(StringCopyExWorkerW)
  6294. #pragma deprecated(StringCatWorkerA)
  6295. #pragma deprecated(StringCatWorkerW)
  6296. #pragma deprecated(StringCatExWorkerA)
  6297. #pragma deprecated(StringCatExWorkerW)
  6298. #pragma deprecated(StringCatNWorkerA)
  6299. #pragma deprecated(StringCatNWorkerW)
  6300. #pragma deprecated(StringCatNExWorkerA)
  6301. #pragma deprecated(StringCatNExWorkerW)
  6302. #pragma deprecated(StringVPrintfWorkerA)
  6303. #pragma deprecated(StringVPrintfWorkerW)
  6304. #pragma deprecated(StringVPrintfExWorkerA)
  6305. #pragma deprecated(StringVPrintfExWorkerW)
  6306. #pragma deprecated(StringLengthWorkerA)
  6307. #pragma deprecated(StringLengthWorkerW)
  6308. #else
  6309. #define StringCopyWorkerA        StringCopyWorkerA_instead_use_StringCchCopyA_or_StringCchCopyExA;
  6310. #define StringCopyWorkerW        StringCopyWorkerW_instead_use_StringCchCopyW_or_StringCchCopyExW;
  6311. #define StringCopyExWorkerA      StringCopyExWorkerA_instead_use_StringCchCopyA_or_StringCchCopyExA;
  6312. #define StringCopyExWorkerW      StringCopyExWorkerW_instead_use_StringCchCopyW_or_StringCchCopyExW;
  6313. #define StringCatWorkerA         StringCatWorkerA_instead_use_StringCchCatA_or_StringCchCatExA;
  6314. #define StringCatWorkerW         StringCatWorkerW_instead_use_StringCchCatW_or_StringCchCatExW;
  6315. #define StringCatExWorkerA       StringCatExWorkerA_instead_use_StringCchCatA_or_StringCchCatExA;
  6316. #define StringCatExWorkerW       StringCatExWorkerW_instead_use_StringCchCatW_or_StringCchCatExW;
  6317. #define StringCatNWorkerA        StringCatNWorkerA_instead_use_StringCchCatNA_or_StrincCbCatNA;
  6318. #define StringCatNWorkerW        StringCatNWorkerW_instead_use_StringCchCatNW_or_StringCbCatNW;
  6319. #define StringCatNExWorkerA      StringCatNExWorkerA_instead_use_StringCchCatNExA_or_StringCbCatNExA;
  6320. #define StringCatNExWorkerW      StringCatNExWorkerW_instead_use_StringCchCatNExW_or_StringCbCatNExW;
  6321. #define StringVPrintfWorkerA     StringVPrintfWorkerA_instead_use_StringCchVPrintfA_or_StringCchVPrintfExA;
  6322. #define StringVPrintfWorkerW     StringVPrintfWorkerW_instead_use_StringCchVPrintfW_or_StringCchVPrintfExW;
  6323. #define StringVPrintfExWorkerA   StringVPrintfExWorkerA_instead_use_StringCchVPrintfA_or_StringCchVPrintfExA;
  6324. #define StringVPrintfExWorkerW   StringVPrintfExWorkerW_instead_use_StringCchVPrintfW_or_StringCchVPrintfExW;
  6325. #define StringLengthWorkerA      StringLengthWorkerA_instead_use_StringCchLengthA_or_StringCbLengthA;
  6326. #define StringLengthWorkerW      StringLengthWorkerW_instead_use_StringCchLengthW_or_StringCbLengthW;
  6327. #endif // !DEPRECATE_SUPPORTED
  6328.  
  6329.  
  6330. #ifndef STRSAFE_NO_DEPRECATE
  6331. // Deprecate all of the unsafe functions to generate compiletime errors. If you do not want
  6332. // this then you can #define STRSAFE_NO_DEPRECATE before including this file.
  6333. #ifdef DEPRECATE_SUPPORTED
  6334.  
  6335. // First all the names that are a/w variants (or shouldn't be #defined by now anyway).
  6336. #pragma deprecated(lstrcpyA)
  6337. #pragma deprecated(lstrcpyW)
  6338. #pragma deprecated(lstrcatA)
  6339. #pragma deprecated(lstrcatW)
  6340. #pragma deprecated(wsprintfA)
  6341. #pragma deprecated(wsprintfW)
  6342.  
  6343. #pragma deprecated(StrCpyW)
  6344. #pragma deprecated(StrCatW)
  6345. #pragma deprecated(StrNCatA)
  6346. #pragma deprecated(StrNCatW)
  6347. #pragma deprecated(StrCatNA)
  6348. #pragma deprecated(StrCatNW)
  6349. #pragma deprecated(wvsprintfA)
  6350. #pragma deprecated(wvsprintfW)
  6351.  
  6352. #pragma deprecated(strcpy)
  6353. #pragma deprecated(wcscpy)
  6354. #pragma deprecated(strcat)
  6355. #pragma deprecated(wcscat)
  6356. #pragma deprecated(sprintf)
  6357. #pragma deprecated(swprintf)
  6358. #pragma deprecated(vsprintf)
  6359. #pragma deprecated(vswprintf)
  6360. #pragma deprecated(_snprintf)
  6361. #pragma deprecated(_snwprintf)
  6362. #pragma deprecated(_vsnprintf)
  6363. #pragma deprecated(_vsnwprintf)
  6364. #pragma deprecated(gets)
  6365. #pragma deprecated(_getws)
  6366.  
  6367. // Then all the windows.h names - we need to undef and redef based on UNICODE setting
  6368. #undef lstrcpy
  6369. #undef lstrcat
  6370. #undef wsprintf
  6371. #undef wvsprintf
  6372. #pragma deprecated(lstrcpy)
  6373. #pragma deprecated(lstrcat)
  6374. #pragma deprecated(wsprintf)
  6375. #pragma deprecated(wvsprintf)
  6376. #ifdef UNICODE
  6377. #define lstrcpy    lstrcpyW
  6378. #define lstrcat    lstrcatW
  6379. #define wsprintf   wsprintfW
  6380. #define wvsprintf  wvsprintfW
  6381. #else
  6382. #define lstrcpy    lstrcpyA
  6383. #define lstrcat    lstrcatA
  6384. #define wsprintf   wsprintfA
  6385. #define wvsprintf  wvsprintfA
  6386. #endif
  6387.  
  6388. // Then the shlwapi names - they key off UNICODE also.
  6389. #undef StrCpyA
  6390. #undef StrCpy
  6391. #undef StrCatA
  6392. #undef StrCat
  6393. #undef StrNCat
  6394. #undef StrCatN
  6395. #pragma deprecated(StrCpyA)
  6396. #pragma deprecated(StrCatA)
  6397. #pragma deprecated(StrCatN)
  6398. #pragma deprecated(StrCpy)
  6399. #pragma deprecated(StrCat)
  6400. #pragma deprecated(StrNCat)
  6401. #define StrCpyA lstrcpyA
  6402. #define StrCatA lstrcatA
  6403. #define StrCatN StrNCat
  6404. #ifdef UNICODE
  6405. #define StrCpy  StrCpyW
  6406. #define StrCat  StrCatW
  6407. #define StrNCat StrNCatW
  6408. #else
  6409. #define StrCpy  lstrcpyA
  6410. #define StrCat  lstrcatA
  6411. #define StrNCat StrNCatA
  6412. #endif
  6413.  
  6414. // Then all the CRT names - we need to undef/redef based on _UNICODE value.
  6415. #undef _tcscpy
  6416. #undef _ftcscpy
  6417. #undef _tcscat
  6418. #undef _ftcscat
  6419. #undef _stprintf
  6420. #undef _sntprintf
  6421. #undef _vstprintf
  6422. #undef _vsntprintf
  6423. #undef _getts
  6424. #pragma deprecated(_tcscpy)
  6425. #pragma deprecated(_ftcscpy)
  6426. #pragma deprecated(_tcscat)
  6427. #pragma deprecated(_ftcscat)
  6428. #pragma deprecated(_stprintf)
  6429. #pragma deprecated(_sntprintf)
  6430. #pragma deprecated(_vstprintf)
  6431. #pragma deprecated(_vsntprintf)
  6432. #pragma deprecated(_getts)
  6433. #ifdef _UNICODE
  6434. #define _tcscpy     wcscpy
  6435. #define _ftcscpy    wcscpy
  6436. #define _tcscat     wcscat
  6437. #define _ftcscat    wcscat
  6438. #define _stprintf   swprintf
  6439. #define _sntprintf  _snwprintf
  6440. #define _vstprintf  vswprintf
  6441. #define _vsntprintf _vsnwprintf
  6442. #define _getts      _getws
  6443. #else
  6444. #define _tcscpy     strcpy
  6445. #define _ftcscpy    strcpy
  6446. #define _tcscat     strcat
  6447. #define _ftcscat    strcat
  6448. #define _stprintf   sprintf
  6449. #define _sntprintf  _snprintf
  6450. #define _vstprintf  vsprintf
  6451. #define _vsntprintf _vsnprintf
  6452. #define _getts      gets
  6453. #endif
  6454.  
  6455. #else // DEPRECATE_SUPPORTED
  6456.  
  6457. #undef strcpy
  6458. #define strcpy      strcpy_instead_use_StringCbCopyA_or_StringCchCopyA;
  6459.  
  6460. #undef wcscpy
  6461. #define wcscpy      wcscpy_instead_use_StringCbCopyW_or_StringCchCopyW;
  6462.  
  6463. #undef strcat
  6464. #define strcat      strcat_instead_use_StringCbCatA_or_StringCchCatA;
  6465.  
  6466. #undef wcscat
  6467. #define wcscat      wcscat_instead_use_StringCbCatW_or_StringCchCatW;
  6468.  
  6469. #undef sprintf
  6470. #define sprintf     sprintf_instead_use_StringCbPrintfA_or_StringCchPrintfA;
  6471.  
  6472. #undef swprintf
  6473. #define swprintf    swprintf_instead_use_StringCbPrintfW_or_StringCchPrintfW;
  6474.  
  6475. #undef vsprintf
  6476. #define vsprintf    vsprintf_instead_use_StringCbVPrintfA_or_StringCchVPrintfA;
  6477.  
  6478. #undef vswprintf
  6479. #define vswprintf   vswprintf_instead_use_StringCbVPrintfW_or_StringCchVPrintfW;
  6480.  
  6481. #undef _snprintf
  6482. #define _snprintf   _snprintf_instead_use_StringCbPrintfA_or_StringCchPrintfA;
  6483.  
  6484. #undef _snwprintf
  6485. #define _snwprintf  _snwprintf_instead_use_StringCbPrintfW_or_StringCchPrintfW;
  6486.  
  6487. #undef _vsnprintf
  6488. #define _vsnprintf  _vsnprintf_instead_use_StringCbVPrintfA_or_StringCchVPrintfA;
  6489.  
  6490. #undef _vsnwprintf
  6491. #define _vsnwprintf _vsnwprintf_instead_use_StringCbVPrintfW_or_StringCchVPrintfW;
  6492.  
  6493. #undef strcpyA
  6494. #define strcpyA     strcpyA_instead_use_StringCbCopyA_or_StringCchCopyA;
  6495.  
  6496. #undef strcpyW
  6497. #define strcpyW     strcpyW_instead_use_StringCbCopyW_or_StringCchCopyW;
  6498.  
  6499. #undef lstrcpy
  6500. #define lstrcpy     lstrcpy_instead_use_StringCbCopy_or_StringCchCopy;
  6501.  
  6502. #undef lstrcpyA
  6503. #define lstrcpyA    lstrcpyA_instead_use_StringCbCopyA_or_StringCchCopyA;
  6504.  
  6505. #undef lstrcpyW
  6506. #define lstrcpyW    lstrcpyW_instead_use_StringCbCopyW_or_StringCchCopyW;
  6507.  
  6508. #undef StrCpy
  6509. #define StrCpy      StrCpy_instead_use_StringCbCopy_or_StringCchCopy;
  6510.  
  6511. #undef StrCpyA
  6512. #define StrCpyA     StrCpyA_instead_use_StringCbCopyA_or_StringCchCopyA;
  6513.  
  6514. #undef StrCpyW
  6515. #define StrCpyW     StrCpyW_instead_use_StringCbCopyW_or_StringCchCopyW;
  6516.  
  6517. #undef _tcscpy
  6518. #define _tcscpy     _tcscpy_instead_use_StringCbCopy_or_StringCchCopy;
  6519.  
  6520. #undef _ftcscpy
  6521. #define _ftcscpy    _ftcscpy_instead_use_StringCbCopy_or_StringCchCopy;
  6522.  
  6523. #undef lstrcat
  6524. #define lstrcat     lstrcat_instead_use_StringCbCat_or_StringCchCat;
  6525.  
  6526. #undef lstrcatA
  6527. #define lstrcatA    lstrcatA_instead_use_StringCbCatA_or_StringCchCatA;
  6528.  
  6529. #undef lstrcatW
  6530. #define lstrcatW    lstrcatW_instead_use_StringCbCatW_or_StringCchCatW;
  6531.  
  6532. #undef StrCat
  6533. #define StrCat      StrCat_instead_use_StringCbCat_or_StringCchCat;
  6534.  
  6535. #undef StrCatA
  6536. #define StrCatA     StrCatA_instead_use_StringCbCatA_or_StringCchCatA;
  6537.  
  6538. #undef StrCatW
  6539. #define StrCatW     StrCatW_instead_use_StringCbCatW_or_StringCchCatW;
  6540.  
  6541. #undef StrNCat
  6542. #define StrNCat     StrNCat_instead_use_StringCbCatN_or_StringCchCatN;
  6543.  
  6544. #undef StrNCatA
  6545. #define StrNCatA    StrNCatA_instead_use_StringCbCatNA_or_StringCchCatNA;
  6546.  
  6547. #undef StrNCatW
  6548. #define StrNCatW    StrNCatW_instead_use_StringCbCatNW_or_StringCchCatNW;
  6549.  
  6550. #undef StrCatN
  6551. #define StrCatN     StrCatN_instead_use_StringCbCatN_or_StringCchCatN;
  6552.  
  6553. #undef StrCatNA
  6554. #define StrCatNA    StrCatNA_instead_use_StringCbCatNA_or_StringCchCatNA;
  6555.  
  6556. #undef StrCatNW
  6557. #define StrCatNW    StrCatNW_instead_use_StringCbCatNW_or_StringCchCatNW;
  6558.  
  6559. #undef _tcscat
  6560. #define _tcscat     _tcscat_instead_use_StringCbCat_or_StringCchCat;
  6561.  
  6562. #undef _ftcscat
  6563. #define _ftcscat    _ftcscat_instead_use_StringCbCat_or_StringCchCat;
  6564.  
  6565. #undef wsprintf
  6566. #define wsprintf    wsprintf_instead_use_StringCbPrintf_or_StringCchPrintf;
  6567.  
  6568. #undef wsprintfA
  6569. #define wsprintfA   wsprintfA_instead_use_StringCbPrintfA_or_StringCchPrintfA;
  6570.  
  6571. #undef wsprintfW
  6572. #define wsprintfW   wsprintfW_instead_use_StringCbPrintfW_or_StringCchPrintfW;
  6573.  
  6574. #undef wvsprintf
  6575. #define wvsprintf   wvsprintf_instead_use_StringCbVPrintf_or_StringCchVPrintf;
  6576.  
  6577. #undef wvsprintfA
  6578. #define wvsprintfA  wvsprintfA_instead_use_StringCbVPrintfA_or_StringCchVPrintfA;
  6579.  
  6580. #undef wvsprintfW
  6581. #define wvsprintfW  wvsprintfW_instead_use_StringCbVPrintfW_or_StringCchVPrintfW;
  6582.  
  6583. #undef _vstprintf
  6584. #define _vstprintf  _vstprintf_instead_use_StringCbVPrintf_or_StringCchVPrintf;
  6585.  
  6586. #undef _vsntprintf
  6587. #define _vsntprintf _vsntprintf_instead_use_StringCbVPrintf_or_StringCchVPrintf;
  6588.  
  6589. #undef _stprintf
  6590. #define _stprintf   _stprintf_instead_use_StringCbPrintf_or_StringCchPrintf;
  6591.  
  6592. #undef _sntprintf
  6593. #define _sntprintf  _sntprintf_instead_use_StringCbPrintf_or_StringCchPrintf;
  6594.  
  6595. #undef _getts
  6596. #define _getts      _getts_instead_use_StringCbGets_or_StringCchGets;
  6597.  
  6598. #undef gets
  6599. #define gets        _gets_instead_use_StringCbGetsA_or_StringCchGetsA;
  6600.  
  6601. #undef _getws
  6602. #define _getws      _getws_instead_use_StringCbGetsW_or_StringCchGetsW;
  6603.  
  6604. #endif  // !DEPRECATE_SUPPORTED
  6605. #endif  // !STRSAFE_NO_DEPRECATE
  6606.  
  6607. #ifdef _NTSTRSAFE_H_INCLUDED_
  6608. #pragma warning(pop)
  6609. #endif // _NTSTRSAFE_H_INCLUDED_
  6610.  
  6611. #endif  // _STRSAFE_H_INCLUDED_
  6612.