text: /******************************************************************
  *                                                                 *
  *  strsafe.h -- This module defines safer C library string        *
  *               routine replacements. These are meant to make C   *
  *               a bit more safe in reference to security and      *
  *               robustness                                        *
  *                                                                 *
  *  Copyright (c) Microsoft Corp.  All rights reserved.            *
  *                                                                 *
  ******************************************************************/
  #ifndef _STRSAFE_H_INCLUDED_
  #define _STRSAFE_H_INCLUDED_
  #if (_MSC_VER > 1000)
  #pragma once
  #endif
  
  
  #include <stdio.h>          // for _vsnprintf, _vsnwprintf, getc, getwc
  #include <string.h>         // for memset
  #include <stdarg.h>         // for va_start, etc.
  #include <specstrings.h>    // for _In_, etc.
  #include <winapifamily.h>   // for WINAPI_FAMILY_PARTITION()
  
  #if !defined(_W64)
  #if !defined(__midl) && (defined(_X86_) || defined(_M_IX86) || defined(_ARM_) || defined(_M_ARM)) && (_MSC_VER >= 1300)
  #define _W64 __w64
  #else
  #define _W64
  #endif
  #endif
  
  #if defined(_M_MRX000) || defined(_M_ALPHA) || defined(_M_PPC) || defined(_M_IA64) || defined(_M_AMD64) || defined(_M_ARM) || defined(_M_ARM64)
  #define ALIGNMENT_MACHINE
  #define UNALIGNED __unaligned
  #if defined(_WIN64)
  #define UNALIGNED64 __unaligned
  #else
  #define UNALIGNED64
  #endif
  #else
  #undef ALIGNMENT_MACHINE
  #define UNALIGNED
  #define UNALIGNED64
  #endif
  
  // typedefs
  #ifdef  _WIN64
  typedef unsigned __int64    size_t;
  #else
  typedef _W64 unsigned int   size_t;
  #endif
  
  #ifndef _HRESULT_DEFINED
  #define _HRESULT_DEFINED
  typedef _Return_type_success_(return >= 0) long HRESULT;
  #endif
  
  typedef unsigned long DWORD;
  
  
  // macros
  #define SUCCEEDED(hr)   (((HRESULT)(hr)) >= 0)
  #define FAILED(hr)      (((HRESULT)(hr)) < 0)
  
  #define S_OK            ((HRESULT)0L)
  
  #ifndef SORTPP_PASS
  // compiletime asserts (failure results in error C2118: negative subscript)
  #define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]
  #else
  #define C_ASSERT(e)
  #endif
  
  #ifdef __cplusplus
  #define EXTERN_C    extern "C"
  #else
  #define EXTERN_C    extern
  #endif
  
  // use the new secure crt functions if available
  #ifndef STRSAFE_USE_SECURE_CRT
  #if defined(__GOT_SECURE_LIB__) && (__GOT_SECURE_LIB__ >= 200402L)
  #define STRSAFE_USE_SECURE_CRT 0
  #else
  #define STRSAFE_USE_SECURE_CRT 0
  #endif
  #endif  // !STRSAFE_USE_SECURE_CRT
  
  #ifdef _M_CEE_PURE
  #define STRSAFEAPI      __inline HRESULT __clrcall
  #else
  #define STRSAFEAPI      __inline HRESULT __stdcall
  #endif
  
  #if defined(STRSAFE_LIB_IMPL) || defined(STRSAFE_LIB)
  #define STRSAFEWORKERAPI    EXTERN_C HRESULT __stdcall
  #else
  #define STRSAFEWORKERAPI    static STRSAFEAPI
  #endif
  
  #ifdef STRSAFE_LOCALE_FUNCTIONS
  #if defined(STRSAFE_LOCALE_LIB_IMPL) || defined(STRSAFE_LIB)
  #define STRSAFELOCALEWORKERAPI  EXTERN_C HRESULT __stdcall
  #else
  #define STRSAFELOCALEWORKERAPI  static STRSAFEAPI
  #endif
  #endif // STRSAFE_LOCALE_FUNCTIONS
  
  #if defined(STRSAFE_LIB)
  #pragma comment(lib, "strsafe.lib")
  #endif
  
  #pragma warning(push)
  #pragma warning(disable: 28210) // Because not all PREFast versions like _Always_ equally.
  
  // The user can request no "Cb" or no "Cch" fuctions, but not both
  #if defined(STRSAFE_NO_CB_FUNCTIONS) && defined(STRSAFE_NO_CCH_FUNCTIONS)
  #error cannot specify both STRSAFE_NO_CB_FUNCTIONS and STRSAFE_NO_CCH_FUNCTIONS !!
  #endif
  
  // The user may override STRSAFE_MAX_CCH, but it must always be less than INT_MAX
  #ifndef STRSAFE_MAX_CCH
  #define STRSAFE_MAX_CCH     2147483647  // max buffer size, in characters, that we support (same as INT_MAX)
  #endif
  C_ASSERT(STRSAFE_MAX_CCH <= 2147483647);
  C_ASSERT(STRSAFE_MAX_CCH > 1);
  
  #define STRSAFE_MAX_LENGTH  (STRSAFE_MAX_CCH - 1)   // max buffer length, in characters, that we support
  
  
  // Flags for controling the Ex functions
  //
  //      STRSAFE_FILL_BYTE(0xFF)                         0x000000FF  // bottom byte specifies fill pattern
  #define STRSAFE_IGNORE_NULLS                            0x00000100  // treat null string pointers as TEXT("") -- don't fault on NULL buffers
  #define STRSAFE_FILL_BEHIND_NULL                        0x00000200  // on success, fill in extra space behind the null terminator with fill pattern
  #define STRSAFE_FILL_ON_FAILURE                         0x00000400  // on failure, overwrite pszDest with fill pattern and null terminate it
  #define STRSAFE_NULL_ON_FAILURE                         0x00000800  // on failure, set *pszDest = TEXT('\0')
  #define STRSAFE_NO_TRUNCATION                           0x00001000  // instead of returning a truncated result, copy/append nothing to pszDest and null terminate it
  
  #define STRSAFE_VALID_FLAGS                     (0x000000FF | STRSAFE_IGNORE_NULLS | STRSAFE_FILL_BEHIND_NULL | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE | STRSAFE_NO_TRUNCATION)
  
  // helper macro to set the fill character and specify buffer filling
  #define STRSAFE_FILL_BYTE(x)                    ((DWORD)((x & 0x000000FF) | STRSAFE_FILL_BEHIND_NULL))
  #define STRSAFE_FAILURE_BYTE(x)                 ((DWORD)((x & 0x000000FF) | STRSAFE_FILL_ON_FAILURE))
  
  #define STRSAFE_GET_FILL_PATTERN(dwFlags)       ((int)(dwFlags & 0x000000FF))
  
  
  // error return codes
  #define STRSAFE_E_INSUFFICIENT_BUFFER           ((HRESULT)0x8007007AL)  // 0x7A = 122L = ERROR_INSUFFICIENT_BUFFER
  #define STRSAFE_E_INVALID_PARAMETER             ((HRESULT)0x80070057L)  // 0x57 =  87L = ERROR_INVALID_PARAMETER
  #define STRSAFE_E_END_OF_FILE                   ((HRESULT)0x80070026L)  // 0x26 =  38L = ERROR_HANDLE_EOF
  
  //
  // These typedefs are used in places where the string is guaranteed to
  // be null terminated.
  //
  typedef _Null_terminated_ char* STRSAFE_LPSTR;
  typedef _Null_terminated_ const char* STRSAFE_LPCSTR;
  typedef _Null_terminated_ wchar_t* STRSAFE_LPWSTR;
  typedef _Null_terminated_ const wchar_t* STRSAFE_LPCWSTR;
  typedef _Null_terminated_ const wchar_t UNALIGNED* STRSAFE_LPCUWSTR;
  
  //
  // These typedefs are used in places where the string is NOT guaranteed to
  // be null terminated.
  //
  typedef  const char* STRSAFE_PCNZCH;
  typedef  const wchar_t* STRSAFE_PCNZWCH;
  typedef  const wchar_t UNALIGNED* STRSAFE_PCUNZWCH;
  
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  // prototypes for the worker functions
  
  STRSAFEWORKERAPI
  StringLengthWorkerA(
      _In_reads_or_z_(cchMax) STRSAFE_PCNZCH psz,
      _In_ _In_range_(<=, STRSAFE_MAX_CCH) size_t cchMax,
      _Out_opt_ _Deref_out_range_(<, cchMax) _Deref_out_range_(<=, _String_length_(psz)) size_t* pcchLength);
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEWORKERAPI
  StringLengthWorkerW(
      _In_reads_or_z_(cchMax) STRSAFE_PCNZWCH psz,
      _In_ _In_range_(<=, STRSAFE_MAX_CCH) size_t cchMax,
      _Out_opt_ _Deref_out_range_(<, cchMax) _Deref_out_range_(<=, _String_length_(psz)) size_t* pcchLength);
  
  #ifdef ALIGNMENT_MACHINE
  STRSAFEWORKERAPI
  UnalignedStringLengthWorkerW(
      _In_reads_or_z_(cchMax) STRSAFE_PCUNZWCH psz,
      _In_ _In_range_(<=, STRSAFE_MAX_CCH) size_t cchMax,
      _Out_opt_ _Deref_out_range_(<, cchMax) size_t* pcchLength);
  #endif  // ALIGNMENT_MACHINE
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  _When_(_Old_(*ppszSrc) != NULL, _Unchanged_(*ppszSrc))
  _When_(_Old_(*ppszSrc) == NULL, _At_(*ppszSrc, _Post_z_))
  STRSAFEWORKERAPI
  StringExValidateSrcA(
      _Inout_ _Deref_post_notnull_ STRSAFE_PCNZCH* ppszSrc,
      _Inout_opt_
          _Deref_out_range_(<, cchMax)
          _Deref_out_range_(<=, _Old_(*pcchToRead)) size_t* pcchToRead,
      _In_ const size_t cchMax,
      _In_ DWORD dwFlags);
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  _When_(_Old_(*ppszSrc) != NULL, _Unchanged_(*ppszSrc))
  _When_(_Old_(*ppszSrc) == NULL, _At_(*ppszSrc, _Post_z_))
  STRSAFEWORKERAPI
  StringExValidateSrcW(
      _Inout_ _Deref_post_notnull_ STRSAFE_PCNZWCH* ppszSrc,
      _Inout_opt_
          _Deref_out_range_(<, cchMax)
          _Deref_out_range_(<=, _Old_(*pcchToRead)) size_t* pcchToRead,
      _In_ const size_t cchMax,
      _In_ DWORD dwFlags);
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  _Post_satisfies_(cchDest > 0 && cchDest <= cchMax)
  STRSAFEWORKERAPI
  StringValidateDestA(
      _In_reads_opt_(cchDest) STRSAFE_PCNZCH pszDest,
      _In_ size_t cchDest,
      _In_ const size_t cchMax);
  
  _Post_satisfies_(cchDest > 0 && cchDest <= cchMax)
  STRSAFEWORKERAPI
  StringValidateDestAndLengthA(
      _In_reads_opt_(cchDest) STRSAFE_LPCSTR pszDest,
      _In_ size_t cchDest,
      _Out_ _Deref_out_range_(0, cchDest - 1) size_t* pcchDestLength,
      _In_ const size_t cchMax);
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  _Post_satisfies_(cchDest > 0 && cchDest <= cchMax)
  STRSAFEWORKERAPI
  StringValidateDestW(
      _In_reads_opt_(cchDest) STRSAFE_PCNZWCH pszDest,
      _In_ size_t cchDest,
      _In_ const size_t cchMax);
  
  _Post_satisfies_(cchDest > 0 && cchDest <= cchMax)
  STRSAFEWORKERAPI
  StringValidateDestAndLengthW(
      _In_reads_opt_(cchDest) STRSAFE_LPCWSTR pszDest,
      _In_ size_t cchDest,
      _Out_ _Deref_out_range_(0, cchDest - 1) size_t* pcchDestLength,
      _In_ const size_t cchMax);
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEWORKERAPI
  StringExValidateDestA(
      _In_reads_opt_(cchDest) STRSAFE_PCNZCH pszDest,
      _In_ size_t cchDest,
      _In_ const size_t cchMax,
      _In_ DWORD dwFlags);
  
  STRSAFEWORKERAPI
  StringExValidateDestAndLengthA(
      _In_reads_opt_(cchDest) STRSAFE_LPCSTR pszDest,
      _In_ size_t cchDest,
      _Out_ _Deref_out_range_(0, (cchDest>0?cchDest-1:0)) size_t* pcchDestLength,
      _In_ const size_t cchMax,
      _In_ DWORD dwFlags);
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEWORKERAPI
  StringExValidateDestW(
      _In_reads_opt_(cchDest) STRSAFE_PCNZWCH pszDest,
      _In_ size_t cchDest,
      _In_ const size_t cchMax,
      _In_ DWORD dwFlags);
  
  STRSAFEWORKERAPI
  StringExValidateDestAndLengthW(
      _In_reads_opt_(cchDest) STRSAFE_LPCWSTR pszDest,
      _In_ size_t cchDest,
      _Out_ _Deref_out_range_(0, (cchDest>0?cchDest-1:0)) size_t* pcchDestLength,
      _In_ const size_t cchMax,
      _In_ DWORD dwFlags);
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEWORKERAPI
  StringCopyWorkerA(
      _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
      _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchDest,
      _Always_(_Out_opt_ _Deref_out_range_(<=, (cchToCopy < cchDest) ? cchToCopy : (cchDest - 1))) size_t* pcchNewDestLength,
      _In_reads_or_z_(cchToCopy) STRSAFE_PCNZCH pszSrc,
      _In_ _In_range_(<, STRSAFE_MAX_CCH) size_t cchToCopy);
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEWORKERAPI
  StringCopyWorkerW(
      _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
      _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchDest,
      _Always_(_Out_opt_ _Deref_out_range_(<=, (cchToCopy < cchDest) ? cchToCopy : (cchDest - 1))) size_t* pcchNewDestLength,
      _In_reads_or_z_(cchToCopy) STRSAFE_PCNZWCH pszSrc,
      _In_ _In_range_(<, STRSAFE_MAX_CCH) size_t cchToCopy);
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEWORKERAPI
  StringVPrintfWorkerA(
      _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
      _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchDest,
      _Always_(_Out_opt_ _Deref_out_range_(<=, cchDest - 1)) size_t* pcchNewDestLength,
      _In_ _Printf_format_string_ STRSAFE_LPCSTR pszFormat,
      _In_ va_list argList);
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #ifdef STRSAFE_LOCALE_FUNCTIONS
  STRSAFELOCALEWORKERAPI
  StringVPrintf_lWorkerA(
      _Out_writes_(cchDest) STRSAFE_LPSTR pszDest,
      _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchDest,
      _Out_opt_ _Deref_out_range_(<=, cchDest - 1) size_t* pcchNewDestLength,
      _In_ _Printf_format_string_params_(2) STRSAFE_LPCSTR pszFormat,
      _In_ _locale_t locale,
      _In_ va_list argList);
  #endif  // STRSAFE_LOCALE_FUNCTIONS
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEWORKERAPI
  StringVPrintfWorkerW(
          _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
          _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchDest,
          _Always_(_Out_opt_ _Deref_out_range_(<=, cchDest - 1)) size_t* pcchNewDestLength,
          _In_ _Printf_format_string_ STRSAFE_LPCWSTR pszFormat,
          _In_ va_list argList);
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #ifdef STRSAFE_LOCALE_FUNCTIONS
  STRSAFELOCALEWORKERAPI
  StringVPrintf_lWorkerW(
          _Out_writes_(cchDest) STRSAFE_LPWSTR pszDest,
          _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchDest,
          _Out_opt_ _Deref_out_range_(<=, cchDest - 1) size_t* pcchNewDestLength,
          _In_ _Printf_format_string_params_(2) STRSAFE_LPCWSTR pszFormat,
          _In_ _locale_t locale,
          _In_ va_list argList);
  #endif  // STRSAFE_LOCALE_FUNCTIONS
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #ifndef STRSAFE_LIB_IMPL
  // always run these functions inline always since they use stdin
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
  StringGetsWorkerA(
          _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
          _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchDest,
          _Always_(_Out_opt_ _Deref_out_range_(<, cchDest>0?cchDest:1)) size_t* pcchNewDestLength);
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
  StringGetsWorkerW(
          _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
          _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchDest,
          _Always_(_Out_opt_ _Deref_out_range_(<=, cchDest - 1)) size_t* pcchNewDestLength);
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_LIB_IMPL
  
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEWORKERAPI
  StringExHandleFillBehindNullA(
          _Inout_updates_bytes_(cbRemaining) STRSAFE_LPSTR pszDestEnd,
          _In_ size_t cbRemaining,
          _In_ DWORD dwFlags);
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEWORKERAPI
  StringExHandleFillBehindNullW(
          _Inout_updates_bytes_(cbRemaining) STRSAFE_LPWSTR pszDestEnd,
          _In_ size_t cbRemaining,
          _In_ DWORD dwFlags);
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  _Success_(1)  // always succeeds, no exit tests needed
      STRSAFEWORKERAPI
      StringExHandleOtherFlagsA(
              _Out_writes_bytes_(cbDest) STRSAFE_LPSTR pszDest,
              _In_ _In_range_(1, STRSAFE_MAX_CCH * sizeof(char)) size_t cbDest,
              _In_ _In_range_(0, cbDest>sizeof(char)?(cbDest / sizeof(char)) - 1:0) size_t cchOriginalDestLength,
              _Outptr_result_buffer_(*pcchRemaining) STRSAFE_LPSTR* ppszDestEnd,
              _Out_ _Deref_out_range_(0, cbDest / sizeof(char)) size_t* pcchRemaining,
              _In_ DWORD dwFlags);
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  _Success_(1)  // always succeeds, no exit tests needed
      STRSAFEWORKERAPI
      StringExHandleOtherFlagsW(
              _Out_writes_bytes_(cbDest) STRSAFE_LPWSTR pszDest,
              _In_ _In_range_(1, STRSAFE_MAX_CCH * sizeof(wchar_t)) size_t cbDest,
              _In_ _In_range_(0, cbDest>sizeof(wchar_t)?(cbDest / sizeof(wchar_t)) - 1:0) size_t cchOriginalDestLength,
              _Outptr_result_buffer_(*pcchRemaining) STRSAFE_LPWSTR* ppszDestEnd,
              _Out_ _Deref_out_range_(0, cbDest / sizeof(wchar_t)) size_t* pcchRemaining,
              _In_ DWORD dwFlags);
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  
  // To allow this to stand alone.
  #define __WARNING_CYCLOMATIC_COMPLEXITY 28734
  #define __WARNING_USING_UNINIT_VAR 6001
  #define __WARNING_RETURN_UNINIT_VAR 6101
  #define __WARNING_DEREF_NULL_PTR 6011
  #define __WARNING_MISSING_ZERO_TERMINATION2 6054
  #define __WARNING_INVALID_PARAM_VALUE_1 6387
  #define __WARNING_INCORRECT_ANNOTATION 26007
  #define __WARNING_POTENTIAL_BUFFER_OVERFLOW_HIGH_PRIORITY 26015
  #define __WARNING_PRECONDITION_NULLTERMINATION_VIOLATION 26035
  #define __WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION 26036
  #define __WARNING_HIGH_PRIORITY_OVERFLOW_POSTCONDITION 26045
  #define __WARNING_RANGE_POSTCONDITION_VIOLATION 26061
  #define __WARNING_POTENTIAL_RANGE_POSTCONDITION_VIOLATION 26071
  #define __WARNING_INVALID_PARAM_VALUE_3 28183
  #define __WARNING_RETURNING_BAD_RESULT 28196
  #define __WARNING_BANNED_API_USAGE 28719
  #define __WARNING_POST_EXPECTED 28210
  
  #pragma warning(push)
  #if _MSC_VER <= 1400
  #pragma warning(disable: 4616)  // turn off warning out of range so prefast pragmas won't show
  // show up in build.wrn/build.err
  #endif
  #pragma warning(disable : 4996) // 'function': was declared deprecated
  #pragma warning(disable : 4995) // name was marked as #pragma deprecated
  #pragma warning(disable : 4793) // vararg causes native code generation
  #pragma warning(disable : __WARNING_CYCLOMATIC_COMPLEXITY)
  
  
  #ifndef STRSAFE_LIB_IMPL
  
  #ifndef STRSAFE_NO_CCH_FUNCTIONS
  /*++
  
    STDAPI
    StringCchCopy(
    _Out_writes_(cchDest) _Always_(_Post_z_) LPTSTR  pszDest,
    _In_  size_t  cchDest,
    _In_  LPCTSTR pszSrc
    );
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'strcpy'.
    The size of the destination buffer (in characters) is a parameter and
    this function will not write past the end of this buffer and it will
    ALWAYS null terminate the destination buffer (unless it is zero length).
  
    This routine is not a replacement for strncpy.  That function will pad the
    destination string with extra null termination characters if the count is
    greater than the length of the source string, and it will fail to null
    terminate the destination string if the source string length is greater
    than or equal to the count. You can not blindly use this instead of strncpy:
    it is common for code to use it to "patch" strings and you would introduce
    errors if the code started null terminating in the middle of the string.
  
    This function returns a hresult, and not a pointer.  It returns
    S_OK if the string was copied without truncation and null terminated,
    otherwise it will return a failure code. In failure cases as much of
    pszSrc will be copied to pszDest as possible, and pszDest will be null
    terminated.
  
  Arguments:
  
  pszDest        -   destination string
  
  cchDest        -   size of destination buffer in characters.
  length must be = (_tcslen(src) + 1) to hold all of the
  source including the null terminator
  
  pszSrc         -   source string which must be null terminated
  
  Notes:
  Behavior is undefined if source and destination strings overlap.
  
  pszDest and pszSrc should not be NULL. See StringCchCopyEx if you require
  the handling of NULL values.
  
  Return Value:
  
  S_OK           -   if there was source data and it was all copied and the
  resultant dest string was null terminated
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  STRSAFE_E_INSUFFICIENT_BUFFER /
  HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  -   this return value is an indication that the copy
  operation failed due to insufficient space. When this
  error occurs, the destination buffer is modified to
  contain a truncated version of the ideal result and is
  null terminated. This is useful for situations where
  truncation is ok
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function.
  
  --*/
  
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchCopy  StringCchCopyW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchCopy  StringCchCopyA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCchCopyA(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cchDest,
              _In_ STRSAFE_LPCSTR pszSrc)
  {
      HRESULT hr;
  
      hr = StringValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          hr = StringCopyWorkerA(pszDest,
                  cchDest,
                  NULL,
                  pszSrc,
                  STRSAFE_MAX_LENGTH);
      }
      else if (cchDest > 0)
      {
          *pszDest = '\0';
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCchCopyW(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cchDest,
              _In_ STRSAFE_LPCWSTR pszSrc)
  {
      HRESULT hr;
  
      hr = StringValidateDestW(pszDest, cchDest, STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          hr = StringCopyWorkerW(pszDest,
                  cchDest,
                  NULL,
                  pszSrc,
                  STRSAFE_MAX_LENGTH);
      }
      else if (cchDest > 0)
      {
          *pszDest = L'\0';
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  
  #ifndef STRSAFE_NO_CB_FUNCTIONS
  /*++
  
    STDAPI
    StringCbCopy(
    _Out_writes_bytes_(cbDest) _Always_(_Post_z_) LPTSTR pszDest,
    _In_  size_t cbDest,
    _In_  LPCTSTR pszSrc
    );
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'strcpy'.
    The size of the destination buffer (in bytes) is a parameter and this
    function will not write past the end of this buffer and it will ALWAYS
    null terminate the destination buffer (unless it is zero length).
  
    This routine is not a replacement for strncpy.  That function will pad the
    destination string with extra null termination characters if the count is
    greater than the length of the source string, and it will fail to null
    terminate the destination string if the source string length is greater
    than or equal to the count. You can not blindly use this instead of strncpy:
    it is common for code to use it to "patch" strings and you would introduce
    errors if the code started null terminating in the middle of the string.
  
    This function returns a hresult, and not a pointer.  It returns
    S_OK if the string was copied without truncation and null terminated,
    otherwise it will return a failure code. In failure cases as much of pszSrc
    will be copied to pszDest as possible, and pszDest will be null terminated.
  
  Arguments:
  
  pszDest        -   destination string
  
  cbDest         -   size of destination buffer in bytes.
  length must be = ((_tcslen(src) + 1) * sizeof(TCHAR)) to
  hold all of the source including the null terminator
  
  pszSrc         -   source string which must be null terminated
  
  Notes:
  Behavior is undefined if source and destination strings overlap.
  
  pszDest and pszSrc should not be NULL.  See StringCbCopyEx if you require
  the handling of NULL values.
  
  Return Value:
  
  S_OK           -   if there was source data and it was all copied and the
  resultant dest string was null terminated
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  STRSAFE_E_INSUFFICIENT_BUFFER /
  HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  -   this return value is an indication that the copy
  operation failed due to insufficient space. When this
  error occurs, the destination buffer is modified to
  contain a truncated version of the ideal result and is
  null terminated. This is useful for situations where
  truncation is ok
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function.
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbCopy  StringCbCopyW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbCopy  StringCbCopyA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCbCopyA(
              _Out_writes_bytes_(cbDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cbDest,
              _In_ STRSAFE_LPCSTR pszSrc)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(char);
  
      hr = StringValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          hr = StringCopyWorkerA(pszDest,
                  cchDest,
                  NULL,
                  pszSrc,
                  STRSAFE_MAX_LENGTH);
      }
      else if (cchDest > 0)
      {
          *pszDest = '\0';
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable : __WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION)
  
  STRSAFEAPI
      StringCbCopyW(
              _Out_writes_bytes_(cbDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cbDest,
              _In_ STRSAFE_LPCWSTR pszSrc)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(wchar_t);
  
      hr = StringValidateDestW(pszDest, cchDest, STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          hr = StringCopyWorkerW(pszDest,
                  cchDest,
                  NULL,
                  pszSrc,
                  STRSAFE_MAX_LENGTH);
      }
      else if (cchDest > 0)
      {
          *pszDest = L'\0';
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CB_FUNCTIONS
  
  
  #ifndef STRSAFE_NO_CCH_FUNCTIONS
  /*++
  
    STDAPI
    StringCchCopyEx(
    _Out_writes_(cchDest) _Always_(_Post_z_) LPTSTR  pszDest         OPTIONAL,
    _In_  size_t  cchDest,
    _In_  LPCTSTR pszSrc          OPTIONAL,
    _Outptr_opt_result_buffer_(*pcchRemaining) LPTSTR* ppszDestEnd     OPTIONAL,
    _Out_opt_ size_t* pcchRemaining   OPTIONAL,
    _In_  DWORD   dwFlags
    );
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'strcpy' with
    some additional parameters.  In addition to functionality provided by
    StringCchCopy, this routine also returns a pointer to the end of the
    destination string and the number of characters left in the destination string
    including the null terminator. The flags parameter allows additional controls.
  
  Arguments:
  
  pszDest         -   destination string
  
  cchDest         -   size of destination buffer in characters.
  length must be = (_tcslen(pszSrc) + 1) to hold all of
  the source including the null terminator
  
  pszSrc          -   source string which must be null terminated
  
  ppszDestEnd     -   if ppszDestEnd is non-null, the function will return a
  pointer to the end of the destination string.  If the
  function copied any data, the result will point to the
  null termination character
  
  pcchRemaining   -   if pcchRemaining is non-null, the function will return the
  number of characters left in the destination string,
  including the null terminator
  
  dwFlags         -   controls some details of the string copy:
  
  STRSAFE_FILL_BEHIND_NULL
  if the function succeeds, the low byte of dwFlags will be
  used to fill the uninitialize part of destination buffer
  behind the null terminator
  
  STRSAFE_IGNORE_NULLS
  treat NULL string pointers like empty strings (TEXT("")).
  this flag is useful for emulating functions like lstrcpy
  
  STRSAFE_FILL_ON_FAILURE
  if the function fails, the low byte of dwFlags will be
  used to fill all of the destination buffer, and it will
  be null terminated. This will overwrite any truncated
  string returned when the failure is
  STRSAFE_E_INSUFFICIENT_BUFFER
  
  STRSAFE_NO_TRUNCATION /
  STRSAFE_NULL_ON_FAILURE
  if the function fails, the destination buffer will be set
  to the empty string. This will overwrite any truncated string
  returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
  
  Notes:
  Behavior is undefined if source and destination strings overlap.
  
  pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  is specified.  If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  may be NULL.  An error may still be returned even though NULLS are ignored
  due to insufficient space.
  
  Return Value:
  
  S_OK           -   if there was source data and it was all copied and the
  resultant dest string was null terminated
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  STRSAFE_E_INSUFFICIENT_BUFFER /
  HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  -   this return value is an indication that the copy
  operation failed due to insufficient space. When this
  error occurs, the destination buffer is modified to
  contain a truncated version of the ideal result and is
  null terminated. This is useful for situations where
  truncation is ok.
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchCopyEx  StringCchCopyExW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchCopyEx  StringCchCopyExA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCchCopyExA(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cchDest,
              _In_ STRSAFE_LPCSTR pszSrc,
              _Outptr_opt_result_buffer_(*pcchRemaining) STRSAFE_LPSTR* ppszDestEnd,
              _Out_opt_ size_t* pcchRemaining,
              _In_ DWORD dwFlags)
  {
      HRESULT hr;
  
      hr = StringExValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH, dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPSTR pszDestEnd = pszDest;
          size_t cchRemaining = cchDest;
  
          hr = StringExValidateSrcA(&pszSrc, NULL, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
  
                  if (cchDest != 0)
                  {
                      *pszDest = '\0';
                  }
              }
              else if (cchDest == 0)
              {
                  // only fail if there was actually src data to copy
                  if (*pszSrc != '\0')
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
              }
              else
              {
                  size_t cchCopied = 0;
  
                  hr = StringCopyWorkerA(pszDest,
                          cchDest,
                          &cchCopied,
                          pszSrc,
                          STRSAFE_MAX_LENGTH);
  
                  pszDestEnd = pszDest + cchCopied;
                  cchRemaining = cchDest - cchCopied;
  
                  if (SUCCEEDED(hr)                           &&
                          (dwFlags & STRSAFE_FILL_BEHIND_NULL)    &&
                          (cchRemaining > 1))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
                      cbRemaining = cchRemaining * sizeof(char);
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullA(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
          else
          {
              if (cchDest != 0)
              {
                  *pszDest = '\0';
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cchDest != 0))
          {
              size_t cbDest;
  
              // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
              cbDest = cchDest * sizeof(char);
  
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsA(pszDest,
                      cbDest,
                      0,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcchRemaining)
              {
                  *pcchRemaining = cchRemaining;
              }
          }
      }
      else if (cchDest > 0)
      {
          *pszDest = '\0';
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCchCopyExW(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cchDest,
              _In_ STRSAFE_LPCWSTR pszSrc,
              _Outptr_opt_result_buffer_(*pcchRemaining) STRSAFE_LPWSTR* ppszDestEnd,
              _Out_opt_ size_t* pcchRemaining,
              _In_ DWORD dwFlags)
  {
      HRESULT hr;
  
      hr = StringExValidateDestW(pszDest, cchDest, STRSAFE_MAX_CCH, dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPWSTR pszDestEnd = pszDest;
          size_t cchRemaining = cchDest;
  
          hr = StringExValidateSrcW(&pszSrc, NULL, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
  
                  if (cchDest != 0)
                  {
                      *pszDest = L'\0';
                  }
              }
              else if (cchDest == 0)
              {
                  // only fail if there was actually src data to copy
                  if (*pszSrc != L'\0')
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
              }
              else
              {
                  size_t cchCopied = 0;
  
                  hr = StringCopyWorkerW(pszDest,
                          cchDest,
                          &cchCopied,
                          pszSrc,
                          STRSAFE_MAX_LENGTH);
  
                  pszDestEnd = pszDest + cchCopied;
                  cchRemaining = cchDest - cchCopied;
  
                  if (SUCCEEDED(hr)                           &&
                          (dwFlags & STRSAFE_FILL_BEHIND_NULL)    &&
                          (cchRemaining > 1))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
                      cbRemaining = cchRemaining * sizeof(wchar_t);
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullW(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
          else
          {
              if (cchDest != 0)
              {
                  *pszDest = L'\0';
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cchDest != 0))
          {
              size_t cbDest;
  
              // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
              cbDest = cchDest * sizeof(wchar_t);
  
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsW(pszDest,
                      cbDest,
                      0,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcchRemaining)
              {
                  *pcchRemaining = cchRemaining;
              }
          }
      }
      else if (cchDest > 0)
      {
          *pszDest = L'\0';
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  
  
  #ifndef STRSAFE_NO_CB_FUNCTIONS
  /*++
  
    STDAPI
    StringCbCopyEx(
    _Out_writes_bytes_(cbDest) _Always_(_Post_z_) LPTSTR  pszDest         OPTIONAL,
    _In_  size_t  cbDest,
    _In_  LPCTSTR pszSrc          OPTIONAL,
    _Outptr_opt_result_bytebuffer_(*pcbRemaining) LPTSTR* ppszDestEnd     OPTIONAL,
    _Out_opt_ size_t* pcbRemaining    OPTIONAL,
    _In_  DWORD   dwFlags
    );
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'strcpy' with
    some additional parameters.  In addition to functionality provided by
    StringCbCopy, this routine also returns a pointer to the end of the
    destination string and the number of bytes left in the destination string
    including the null terminator. The flags parameter allows additional controls.
  
  Arguments:
  
  pszDest         -   destination string
  
  cbDest          -   size of destination buffer in bytes.
  length must be ((_tcslen(pszSrc) + 1) * sizeof(TCHAR)) to
  hold all of the source including the null terminator
  
  pszSrc          -   source string which must be null terminated
  
  ppszDestEnd     -   if ppszDestEnd is non-null, the function will return a
  pointer to the end of the destination string.  If the
  function copied any data, the result will point to the
  null termination character
  
  pcbRemaining    -   pcbRemaining is non-null,the function will return the
  number of bytes left in the destination string,
  including the null terminator
  
  dwFlags         -   controls some details of the string copy:
  
  STRSAFE_FILL_BEHIND_NULL
  if the function succeeds, the low byte of dwFlags will be
  used to fill the uninitialize part of destination buffer
  behind the null terminator
  
  STRSAFE_IGNORE_NULLS
  treat NULL string pointers like empty strings (TEXT("")).
  this flag is useful for emulating functions like lstrcpy
  
  STRSAFE_FILL_ON_FAILURE
  if the function fails, the low byte of dwFlags will be
  used to fill all of the destination buffer, and it will
  be null terminated. This will overwrite any truncated
  string returned when the failure is
  STRSAFE_E_INSUFFICIENT_BUFFER
  
  STRSAFE_NO_TRUNCATION /
  STRSAFE_NULL_ON_FAILURE
  if the function fails, the destination buffer will be set
  to the empty string. This will overwrite any truncated string
  returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
  
  Notes:
  Behavior is undefined if source and destination strings overlap.
  
  pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  is specified.  If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  may be NULL.  An error may still be returned even though NULLS are ignored
  due to insufficient space.
  
  Return Value:
  
  S_OK           -   if there was source data and it was all copied and the
  resultant dest string was null terminated
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  STRSAFE_E_INSUFFICIENT_BUFFER /
  HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  -   this return value is an indication that the copy
  operation failed due to insufficient space. When this
  error occurs, the destination buffer is modified to
  contain a truncated version of the ideal result and is
  null terminated. This is useful for situations where
  truncation is ok.
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbCopyEx  StringCbCopyExW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbCopyEx  StringCbCopyExA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCbCopyExA(
              _Out_writes_bytes_(cbDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cbDest,
              _In_ STRSAFE_LPCSTR pszSrc,
              _Outptr_opt_result_bytebuffer_(*pcbRemaining) STRSAFE_LPSTR* ppszDestEnd,
              _Out_opt_ size_t* pcbRemaining,
              _In_ DWORD dwFlags)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(char);
  
      hr = StringExValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH, dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPSTR pszDestEnd = pszDest;
          size_t cchRemaining = cchDest;
  
          hr = StringExValidateSrcA(&pszSrc, NULL, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
  
                  if (cchDest != 0)
                  {
                      *pszDest = '\0';
                  }
              }
              else if (cchDest == 0)
              {
                  // only fail if there was actually src data to copy
                  if (*pszSrc != '\0')
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
                  else
                  {
                      // for consistency with other use in this case...
                      __analysis_assume_nullterminated(pszDest);
                  }
              }
              else
              {
                  size_t cchCopied = 0;
  
                  hr = StringCopyWorkerA(pszDest,
                          cchDest,
                          &cchCopied,
                          pszSrc,
                          STRSAFE_MAX_LENGTH);
  
                  pszDestEnd = pszDest + cchCopied;
                  cchRemaining = cchDest - cchCopied;
  
                  if (SUCCEEDED(hr)                           &&
                          (dwFlags & STRSAFE_FILL_BEHIND_NULL)    &&
                          (cchRemaining > 1))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
                      cbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullA(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
          else
          {
              if (cchDest != 0)
              {
                  *pszDest = '\0';
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cbDest != 0))
          {
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsA(pszDest,
                      cbDest,
                      0,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcbRemaining)
              {
                  // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
                  *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
              }
          }
      }
      else if (cchDest > 0)
      {
          *pszDest = '\0';
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable: __WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION)
  
  STRSAFEAPI
      StringCbCopyExW(
              _Out_writes_bytes_(cbDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cbDest,
              _In_ STRSAFE_LPCWSTR pszSrc,
              _Outptr_opt_result_bytebuffer_(*pcbRemaining) STRSAFE_LPWSTR* ppszDestEnd,
              _Out_opt_ size_t* pcbRemaining,
              _In_ DWORD dwFlags)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(wchar_t);
  
      hr = StringExValidateDestW(pszDest, cchDest, STRSAFE_MAX_CCH, dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPWSTR pszDestEnd = pszDest;
          size_t cchRemaining = cchDest;
  
          hr = StringExValidateSrcW(&pszSrc, NULL, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
  
                  if (cchDest != 0)
                  {
                      *pszDest = L'\0';
                  }
              }
              else if (cchDest == 0)
              {
                  // only fail if there was actually src data to copy
                  if (*pszSrc != L'\0')
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
                  else
                  {
                      // for consistency with other use in this case...
                      __analysis_assume_nullterminated(pszDest);
                  }
              }
              else
              {
                  size_t cchCopied = 0;
  
                  hr = StringCopyWorkerW(pszDest,
                          cchDest,
                          &cchCopied,
                          pszSrc,
                          STRSAFE_MAX_LENGTH);
  
                  pszDestEnd = pszDest + cchCopied;
                  cchRemaining = cchDest - cchCopied;
  
                  if (SUCCEEDED(hr) && (dwFlags & STRSAFE_FILL_BEHIND_NULL))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
                      cbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullW(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
          else
          {
              if (cchDest != 0)
              {
                  *pszDest = L'\0';
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cbDest != 0))
          {
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsW(pszDest,
                      cbDest,
                      0,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcbRemaining)
              {
                  // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
                  *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
              }
          }
      }
      else if (cchDest > 0)
      {
          *pszDest = L'\0';
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CB_FUNCTIONS
  
  
  #ifndef STRSAFE_NO_CCH_FUNCTIONS
  /*++
  
    STDAPI
    StringCchCopyN(
    _Out_writes_(cchDest) _Always_(_Post_z_) LPTSTR  pszDest,
    _In_  size_t  cchDest,
    _In_reads_or_z_(cchToCopy)  LPCTSTR pszSrc,
    _In_  size_t  cchToCopy
    );
  
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'strncpy'.
    The size of the destination buffer (in characters) is a parameter and
    this function will not write past the end of this buffer and it will
    ALWAYS null terminate the destination buffer (unless it is zero length).
  
    This routine is meant as a replacement for strncpy, but it does behave
    differently. This function will not pad the destination buffer with extra
    null termination characters if cchToCopy is greater than the length of pszSrc.
  
    This function returns a hresult, and not a pointer.  It returns
    S_OK if the entire string or the first cchToCopy characters were copied
    without truncation and the resultant destination string was null terminated,
    otherwise it will return a failure code. In failure cases as much of pszSrc
    will be copied to pszDest as possible, and pszDest will be null terminated.
  
  Arguments:
  
  pszDest        -   destination string
  
  cchDest        -   size of destination buffer in characters.
  length must be = (_tcslen(src) + 1) to hold all of the
  source including the null terminator
  
  pszSrc         -   source string
  
  cchToCopy      -   maximum number of characters to copy from source string,
  not including the null terminator.
  
  Notes:
  Behavior is undefined if source and destination strings overlap.
  
  pszDest and pszSrc should not be NULL. See StringCchCopyNEx if you require
  the handling of NULL values.
  
  Return Value:
  
  S_OK           -   if there was source data and it was all copied and the
  resultant dest string was null terminated
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  STRSAFE_E_INSUFFICIENT_BUFFER /
  HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  -   this return value is an indication that the copy
  operation failed due to insufficient space. When this
  error occurs, the destination buffer is modified to
  contain a truncated version of the ideal result and is
  null terminated. This is useful for situations where
  truncation is ok
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function.
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchCopyN  StringCchCopyNW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchCopyN  StringCchCopyNA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCchCopyNA(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cchDest,
              _In_reads_or_z_(cchToCopy) STRSAFE_PCNZCH pszSrc,
              _In_ size_t cchToCopy)
  {
      HRESULT hr;
  
      hr = StringValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          if (cchToCopy > STRSAFE_MAX_LENGTH)
          {
              hr = STRSAFE_E_INVALID_PARAMETER;
  
              *pszDest = '\0';
          }
          else
          {
              hr = StringCopyWorkerA(pszDest,
                      cchDest,
                      NULL,
                      pszSrc,
                      cchToCopy);
          }
      }
      else if (cchDest > 0)
      {
          *pszDest = '\0';
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCchCopyNW(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cchDest,
              _In_reads_or_z_(cchToCopy) STRSAFE_PCNZWCH pszSrc,
              _In_ size_t cchToCopy)
  {
      HRESULT hr;
  
      hr = StringValidateDestW(pszDest, cchDest, STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          if (cchToCopy > STRSAFE_MAX_LENGTH)
          {
              hr = STRSAFE_E_INVALID_PARAMETER;
  
              *pszDest = L'\0';
          }
          else
          {
              hr = StringCopyWorkerW(pszDest,
                      cchDest,
                      NULL,
                      pszSrc,
                      cchToCopy);
          }
      }
      else if (cchDest > 0)
      {
          *pszDest = L'\0';
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  
  
  #ifndef STRSAFE_NO_CB_FUNCTIONS
  /*++
  
    STDAPI
    StringCbCopyN(
    _Out_writes_bytes_(cbDest) LPTSTR  pszDest,
    _In_  size_t  cbDest,
    _In_  LPCTSTR pszSrc,
    _In_  size_t  cbToCopy
    );
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'strncpy'.
    The size of the destination buffer (in bytes) is a parameter and this
    function will not write past the end of this buffer and it will ALWAYS
    null terminate the destination buffer (unless it is zero length).
  
    This routine is meant as a replacement for strncpy, but it does behave
    differently. This function will not pad the destination buffer with extra
    null termination characters if cbToCopy is greater than the size of pszSrc.
  
    This function returns a hresult, and not a pointer.  It returns
    S_OK if the entire string or the first cbToCopy characters were
    copied without truncation and the resultant destination string was null
    terminated, otherwise it will return a failure code. In failure cases as
    much of pszSrc will be copied to pszDest as possible, and pszDest will be
    null terminated.
  
  Arguments:
  
  pszDest        -   destination string
  
  cbDest         -   size of destination buffer in bytes.
  length must be = ((_tcslen(src) + 1) * sizeof(TCHAR)) to
  hold all of the source including the null terminator
  
  pszSrc         -   source string
  
  cbToCopy       -   maximum number of bytes to copy from source string,
  not including the null terminator.
  
  Notes:
  Behavior is undefined if source and destination strings overlap.
  
  pszDest and pszSrc should not be NULL.  See StringCbCopyEx if you require
  the handling of NULL values.
  
  Return Value:
  
  S_OK           -   if there was source data and it was all copied and the
  resultant dest string was null terminated
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  STRSAFE_E_INSUFFICIENT_BUFFER /
  HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  -   this return value is an indication that the copy
  operation failed due to insufficient space. When this
  error occurs, the destination buffer is modified to
  contain a truncated version of the ideal result and is
  null terminated. This is useful for situations where
  truncation is ok
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function.
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbCopyN  StringCbCopyNW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbCopyN  StringCbCopyNA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCbCopyNA(
              _Out_writes_bytes_(cbDest) STRSAFE_LPSTR pszDest,
              _In_ size_t cbDest,
              _In_reads_bytes_(cbToCopy) STRSAFE_PCNZCH pszSrc,
              _In_ size_t cbToCopy)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(char);
  
      hr = StringValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          size_t cchToCopy = cbToCopy / sizeof(char);
  
          if (cchToCopy > STRSAFE_MAX_LENGTH)
          {
              hr = STRSAFE_E_INVALID_PARAMETER;
  
              *pszDest = '\0';
          }
          else
          {
              hr = StringCopyWorkerA(pszDest,
                      cchDest,
                      NULL,
                      pszSrc,
                      cchToCopy);
          }
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable : __WARNING_POTENTIAL_BUFFER_OVERFLOW_HIGH_PRIORITY)
  
  STRSAFEAPI
      StringCbCopyNW(
              _Out_writes_bytes_(cbDest) STRSAFE_LPWSTR pszDest,
              _In_ size_t cbDest,
              _In_reads_bytes_(cbToCopy) STRSAFE_PCNZWCH pszSrc,
              _In_ size_t cbToCopy)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(wchar_t);
  
      hr = StringValidateDestW(pszDest, cchDest, STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          size_t cchToCopy = cbToCopy / sizeof(wchar_t);
  
          if (cchToCopy > STRSAFE_MAX_LENGTH)
          {
              hr = STRSAFE_E_INVALID_PARAMETER;
  
              *pszDest = L'\0';
          }
          else
          {
              hr = StringCopyWorkerW(pszDest,
                      cchDest,
                      NULL,
                      pszSrc,
                      cchToCopy);
          }
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CB_FUNCTIONS
  
  
  #ifndef STRSAFE_NO_CCH_FUNCTIONS
  /*++
  
    STDAPI
    StringCchCopyNEx(
    _Out_writes_(cchDest) _Always_(_Post_z_) LPTSTR  pszDest         OPTIONAL,
    _In_  size_t  cchDest,
    _In_  LPCTSTR pszSrc          OPTIONAL,
    _In_  size_t  cchToCopy,
    _Outptr_opt_result_buffer_(*pcchRemaining) LPTSTR* ppszDestEnd OPTIONAL,
    _Out_opt_ size_t* pcchRemaining OPTIONAL,
    _In_  DWORD   dwFlags
    );
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'strncpy' with
    some additional parameters.  In addition to functionality provided by
    StringCchCopyN, this routine also returns a pointer to the end of the
    destination string and the number of characters left in the destination
    string including the null terminator. The flags parameter allows
    additional controls.
  
    This routine is meant as a replacement for strncpy, but it does behave
    differently. This function will not pad the destination buffer with extra
    null termination characters if cchToCopy is greater than the length of pszSrc.
  
  Arguments:
  
  pszDest         -   destination string
  
  cchDest         -   size of destination buffer in characters.
  length must be = (_tcslen(pszSrc) + 1) to hold all of
  the source including the null terminator
  
  pszSrc          -   source string
  
  cchToCopy       -   maximum number of characters to copy from the source
  string
  
  ppszDestEnd     -   if ppszDestEnd is non-null, the function will return a
  pointer to the end of the destination string.  If the
  function copied any data, the result will point to the
  null termination character
  
  pcchRemaining   -   if pcchRemaining is non-null, the function will return the
  number of characters left in the destination string,
  including the null terminator
  
  dwFlags         -   controls some details of the string copy:
  
  STRSAFE_FILL_BEHIND_NULL
  if the function succeeds, the low byte of dwFlags will be
  used to fill the uninitialize part of destination buffer
  behind the null terminator
  
  STRSAFE_IGNORE_NULLS
  treat NULL string pointers like empty strings (TEXT("")).
  this flag is useful for emulating functions like lstrcpy
  
  STRSAFE_FILL_ON_FAILURE
  if the function fails, the low byte of dwFlags will be
  used to fill all of the destination buffer, and it will
  be null terminated. This will overwrite any truncated
  string returned when the failure is
  STRSAFE_E_INSUFFICIENT_BUFFER
  
  STRSAFE_NO_TRUNCATION /
  STRSAFE_NULL_ON_FAILURE
  if the function fails, the destination buffer will be set
  to the empty string. This will overwrite any truncated string
  returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
  
  Notes:
  Behavior is undefined if source and destination strings overlap.
  
  pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  is specified. If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  may be NULL. An error may still be returned even though NULLS are ignored
  due to insufficient space.
  
  Return Value:
  
  S_OK           -   if there was source data and it was all copied and the
  resultant dest string was null terminated
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  STRSAFE_E_INSUFFICIENT_BUFFER /
  HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  -   this return value is an indication that the copy
  operation failed due to insufficient space. When this
  error occurs, the destination buffer is modified to
  contain a truncated version of the ideal result and is
  null terminated. This is useful for situations where
  truncation is ok.
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchCopyNEx  StringCchCopyNExW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchCopyNEx  StringCchCopyNExA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCchCopyNExA(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cchDest,
              _In_reads_or_z_(cchToCopy) STRSAFE_PCNZCH pszSrc,
              _In_ size_t cchToCopy,
              _Outptr_opt_result_buffer_(*pcchRemaining) STRSAFE_LPSTR* ppszDestEnd,
              _Out_opt_ size_t* pcchRemaining,
              _In_ DWORD dwFlags)
  {
      HRESULT hr;
  
      hr = StringExValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH, dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPSTR pszDestEnd = pszDest;
          size_t cchRemaining = cchDest;
  
          hr = StringExValidateSrcA(&pszSrc, &cchToCopy, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
  
                  if (cchDest != 0)
                  {
                      *pszDest = '\0';
                  }
              }
              else if (cchDest == 0)
              {
                  // only fail if there was actually src data to copy
                  if ((cchToCopy != 0) && (*pszSrc != '\0'))
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
              }
              else
              {
                  size_t cchCopied = 0;
  
                  hr = StringCopyWorkerA(pszDest,
                          cchDest,
                          &cchCopied,
                          pszSrc,
                          cchToCopy);
  
                  pszDestEnd = pszDest + cchCopied;
                  cchRemaining = cchDest - cchCopied;
  
                  if (SUCCEEDED(hr)                           &&
                          (dwFlags & STRSAFE_FILL_BEHIND_NULL)    &&
                          (cchRemaining > 1))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
                      cbRemaining = cchRemaining * sizeof(char);
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullA(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
          else
          {
              if (cchDest != 0)
              {
                  *pszDest = '\0';
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cchDest != 0))
          {
              size_t cbDest;
  
              // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
              cbDest = cchDest * sizeof(char);
  
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsA(pszDest,
                      cbDest,
                      0,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcchRemaining)
              {
                  *pcchRemaining = cchRemaining;
              }
          }
      }
      else if (cchDest > 0)
      {
          *pszDest = '\0';
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCchCopyNExW(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cchDest,
              _In_reads_or_z_(cchToCopy) STRSAFE_PCNZWCH pszSrc,
              _In_ size_t cchToCopy,
              _Outptr_opt_result_buffer_(*pcchRemaining) STRSAFE_LPWSTR* ppszDestEnd,
              _Out_opt_ size_t* pcchRemaining,
              _In_ DWORD dwFlags)
  {
      HRESULT hr;
  
      hr = StringExValidateDestW(pszDest, cchDest, STRSAFE_MAX_CCH, dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPWSTR pszDestEnd = pszDest;
          size_t cchRemaining = cchDest;
  
          hr = StringExValidateSrcW(&pszSrc, &cchToCopy, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
  
                  if (cchDest != 0)
                  {
                      *pszDest = L'\0';
                  }
              }
              else if (cchDest == 0)
              {
                  // only fail if there was actually src data to copy
                  if ((cchToCopy != 0) && (*pszSrc != L'\0'))
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
              }
              else
              {
                  size_t cchCopied = 0;
  
                  hr = StringCopyWorkerW(pszDest,
                          cchDest,
                          &cchCopied,
                          pszSrc,
                          cchToCopy);
  
                  pszDestEnd = pszDest + cchCopied;
                  cchRemaining = cchDest - cchCopied;
  
                  if (SUCCEEDED(hr)                           &&
                          (dwFlags & STRSAFE_FILL_BEHIND_NULL)    &&
                          (cchRemaining > 1))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
                      cbRemaining = cchRemaining * sizeof(wchar_t);
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullW(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
          else
          {
              if (cchDest != 0)
              {
                  *pszDest = L'\0';
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cchDest != 0))
          {
              size_t cbDest;
  
              // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
              cbDest = cchDest * sizeof(wchar_t);
  
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsW(pszDest,
                      cbDest,
                      0,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcchRemaining)
              {
                  *pcchRemaining = cchRemaining;
              }
          }
      }
      else if (cchDest > 0)
      {
          *pszDest = L'\0';
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  
  
  #ifndef STRSAFE_NO_CB_FUNCTIONS
  /*++
  
    STDAPI
    StringCbCopyNEx(
    _Out_writes_bytes_(cbDest) LPTSTR  pszDest         OPTIONAL,
    _In_  size_t  cbDest,
    _In_  LPCTSTR pszSrc          OPTIONAL,
    _In_  size_t  cbToCopy,
    _Outptr_opt_result_bytebuffer_(*pcbRemaining) LPTSTR* ppszDestEnd     OPTIONAL,
    _Out_opt_ size_t* pcbRemaining    OPTIONAL,
    _In_  DWORD   dwFlags
    );
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'strncpy' with
    some additional parameters.  In addition to functionality provided by
    StringCbCopyN, this routine also returns a pointer to the end of the
    destination string and the number of bytes left in the destination string
    including the null terminator. The flags parameter allows additional controls.
  
    This routine is meant as a replacement for strncpy, but it does behave
    differently. This function will not pad the destination buffer with extra
    null termination characters if cbToCopy is greater than the size of pszSrc.
  
  Arguments:
  
  pszDest         -   destination string
  
  cbDest          -   size of destination buffer in bytes.
  length must be ((_tcslen(pszSrc) + 1) * sizeof(TCHAR)) to
  hold all of the source including the null terminator
  
  pszSrc          -   source string
  
  cbToCopy        -   maximum number of bytes to copy from source string
  
  ppszDestEnd     -   if ppszDestEnd is non-null, the function will return a
  pointer to the end of the destination string.  If the
  function copied any data, the result will point to the
  null termination character
  
  pcbRemaining    -   pcbRemaining is non-null,the function will return the
  number of bytes left in the destination string,
  including the null terminator
  
  dwFlags         -   controls some details of the string copy:
  
  STRSAFE_FILL_BEHIND_NULL
  if the function succeeds, the low byte of dwFlags will be
  used to fill the uninitialize part of destination buffer
  behind the null terminator
  
  STRSAFE_IGNORE_NULLS
  treat NULL string pointers like empty strings (TEXT("")).
  this flag is useful for emulating functions like lstrcpy
  
  STRSAFE_FILL_ON_FAILURE
  if the function fails, the low byte of dwFlags will be
  used to fill all of the destination buffer, and it will
  be null terminated. This will overwrite any truncated
  string returned when the failure is
  STRSAFE_E_INSUFFICIENT_BUFFER
  
  STRSAFE_NO_TRUNCATION /
  STRSAFE_NULL_ON_FAILURE
  if the function fails, the destination buffer will be set
  to the empty string. This will overwrite any truncated string
  returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
  
  Notes:
  Behavior is undefined if source and destination strings overlap.
  
  pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  is specified.  If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  may be NULL.  An error may still be returned even though NULLS are ignored
  due to insufficient space.
  
  Return Value:
  
  S_OK           -   if there was source data and it was all copied and the
  resultant dest string was null terminated
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  STRSAFE_E_INSUFFICIENT_BUFFER /
  HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  -   this return value is an indication that the copy
  operation failed due to insufficient space. When this
  error occurs, the destination buffer is modified to
  contain a truncated version of the ideal result and is
  null terminated. This is useful for situations where
  truncation is ok.
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbCopyNEx  StringCbCopyNExW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbCopyNEx  StringCbCopyNExA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCbCopyNExA(
              _Out_writes_bytes_(cbDest) STRSAFE_LPSTR pszDest,
              _In_ size_t cbDest,
              _In_reads_bytes_(cbToCopy) STRSAFE_PCNZCH pszSrc,
              _In_ size_t cbToCopy,
              _Outptr_opt_result_bytebuffer_(*pcbRemaining) STRSAFE_LPSTR* ppszDestEnd,
              _Out_opt_ size_t* pcbRemaining,
              _In_ DWORD dwFlags)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(char);
  
      hr = StringExValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH, dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPSTR pszDestEnd = pszDest;
          size_t cchRemaining = cchDest;
          size_t cchToCopy = cbToCopy / sizeof(char);
  
          hr = StringExValidateSrcA(&pszSrc, &cchToCopy, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
  
                  if (cchDest != 0)
                  {
                      *pszDest = '\0';
                  }
              }
              else if (cchDest == 0)
              {
                  // only fail if there was actually src data to copy
                  if ((cchToCopy != 0) && (*pszSrc != '\0'))
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
                  else
                  {
                      // for consistency with other use in this case...
                      __analysis_assume_nullterminated(pszDest);
                  }
              }
              else
              {
                  size_t cchCopied = 0;
  
                  hr = StringCopyWorkerA(pszDest,
                          cchDest,
                          &cchCopied,
                          pszSrc,
                          cchToCopy);
  
                  pszDestEnd = pszDest + cchCopied;
                  cchRemaining = cchDest - cchCopied;
  
                  if (SUCCEEDED(hr)                           &&
                          (dwFlags & STRSAFE_FILL_BEHIND_NULL)    &&
                          (cchRemaining > 1))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
                      cbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullA(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
          else
          {
              if (cchDest != 0)
              {
                  *pszDest = '\0';
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cbDest != 0))
          {
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsA(pszDest,
                      cbDest,
                      0,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcbRemaining)
              {
                  // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
                  *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
              }
          }
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable : __WARNING_POTENTIAL_BUFFER_OVERFLOW_HIGH_PRIORITY)
  
  STRSAFEAPI
      StringCbCopyNExW(
              _Out_writes_bytes_(cbDest) STRSAFE_LPWSTR pszDest,
              _In_ size_t cbDest,
              _In_reads_bytes_(cbToCopy) STRSAFE_PCNZWCH pszSrc,
              _In_ size_t cbToCopy,
              _Outptr_opt_result_bytebuffer_(*pcbRemaining) STRSAFE_LPWSTR* ppszDestEnd,
              _Out_opt_ size_t* pcbRemaining,
              _In_ DWORD dwFlags)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(wchar_t);
  
      hr = StringExValidateDestW(pszDest, cchDest, STRSAFE_MAX_CCH, dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPWSTR pszDestEnd = pszDest;
          size_t cchRemaining = cchDest;
          size_t cchToCopy = cbToCopy / sizeof(wchar_t);
  
          hr = StringExValidateSrcW(&pszSrc, &cchToCopy, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
  
                  if (cchDest != 0)
                  {
                      *pszDest = L'\0';
                  }
              }
              else if (cchDest == 0)
              {
                  // only fail if there was actually src data to copy
                  if ((cchToCopy != 0) && (*pszSrc != L'\0'))
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
                  else
                  {
                      // for consistency with other use in this case...
                      __analysis_assume_nullterminated(pszDest);
                  }
              }
              else
              {
                  size_t cchCopied = 0;
  
                  hr = StringCopyWorkerW(pszDest,
                          cchDest,
                          &cchCopied,
                          pszSrc,
                          cchToCopy);
  
                  pszDestEnd = pszDest + cchCopied;
                  cchRemaining = cchDest - cchCopied;
  
                  if (SUCCEEDED(hr) && (dwFlags & STRSAFE_FILL_BEHIND_NULL))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
                      cbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullW(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
          else
          {
              if (cchDest != 0)
              {
                  *pszDest = L'\0';
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cbDest != 0))
          {
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsW(pszDest,
                      cbDest,
                      0,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcbRemaining)
              {
                  // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
                  *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
              }
          }
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CB_FUNCTIONS
  
  
  #ifndef STRSAFE_NO_CCH_FUNCTIONS
  /*++
  
    STDAPI
    StringCchCat(
    _Inout_updates_(cchDest) _Always_(_Post_z_) LPTSTR  pszDest,
    _In_     size_t  cchDest,
    _In_     LPCTSTR pszSrc
    );
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'strcat'.
    The size of the destination buffer (in characters) is a parameter and this
    function will not write past the end of this buffer and it will ALWAYS
    null terminate the destination buffer (unless it is zero length).
  
    This function returns a hresult, and not a pointer.  It returns
    S_OK if the string was concatenated without truncation and null terminated,
    otherwise it will return a failure code. In failure cases as much of pszSrc
    will be appended to pszDest as possible, and pszDest will be null
    terminated.
  
  Arguments:
  
  pszDest     -  destination string which must be null terminated
  
  cchDest     -  size of destination buffer in characters.
  length must be = (_tcslen(pszDest) + _tcslen(pszSrc) + 1)
  to hold all of the combine string plus the null
  terminator
  
  pszSrc      -  source string which must be null terminated
  
  Notes:
  Behavior is undefined if source and destination strings overlap.
  
  pszDest and pszSrc should not be NULL.  See StringCchCatEx if you require
  the handling of NULL values.
  
  Return Value:
  
  S_OK           -   if there was source data and it was all concatenated and
  the resultant dest string was null terminated
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  STRSAFE_E_INSUFFICIENT_BUFFER /
  HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  -   this return value is an indication that the operation
  failed due to insufficient space. When this error occurs,
  the destination buffer is modified to contain a truncated
  version of the ideal result and is null terminated. This
  is useful for situations where truncation is ok.
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchCat  StringCchCatW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchCat  StringCchCatA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCchCatA(
              _Inout_updates_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cchDest,
              _In_ STRSAFE_LPCSTR pszSrc)
  {
      HRESULT hr;
      size_t cchDestLength;
  
      hr = StringValidateDestAndLengthA(pszDest,
              cchDest,
              &cchDestLength,
              STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          hr = StringCopyWorkerA(pszDest + cchDestLength,
                  cchDest - cchDestLength,
                  NULL,
                  pszSrc,
                  STRSAFE_MAX_LENGTH);
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCchCatW(
              _Inout_updates_(cchDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cchDest,
              _In_ STRSAFE_LPCWSTR pszSrc)
  {
      HRESULT hr;
      size_t cchDestLength;
  
      hr = StringValidateDestAndLengthW(pszDest,
              cchDest,
              &cchDestLength,
              STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          hr = StringCopyWorkerW(pszDest + cchDestLength,
                  cchDest - cchDestLength,
                  NULL,
                  pszSrc,
                  STRSAFE_MAX_LENGTH);
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  
  
  #ifndef STRSAFE_NO_CB_FUNCTIONS
  /*++
  
    STDAPI
    StringCbCat(
    _Inout_updates_bytes_(cbDest) _Always_(_Post_z_) LPTSTR  pszDest,
    _In_     size_t  cbDest,
    _In_     LPCTSTR pszSrc
    );
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'strcat'.
    The size of the destination buffer (in bytes) is a parameter and this
    function will not write past the end of this buffer and it will ALWAYS
    null terminate the destination buffer (unless it is zero length).
  
    This function returns a hresult, and not a pointer.  It returns
    S_OK if the string was concatenated without truncation and null terminated,
    otherwise it will return a failure code. In failure cases as much of pszSrc
    will be appended to pszDest as possible, and pszDest will be null
    terminated.
  
  Arguments:
  
  pszDest     -  destination string which must be null terminated
  
  cbDest      -  size of destination buffer in bytes.
  length must be = ((_tcslen(pszDest) + _tcslen(pszSrc) + 1) * sizeof(TCHAR)
  to hold all of the combine string plus the null
  terminator
  
  pszSrc      -  source string which must be null terminated
  
  Notes:
  Behavior is undefined if source and destination strings overlap.
  
  pszDest and pszSrc should not be NULL.  See StringCbCatEx if you require
  the handling of NULL values.
  
  Return Value:
  
  S_OK           -   if there was source data and it was all concatenated and
  the resultant dest string was null terminated
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  STRSAFE_E_INSUFFICIENT_BUFFER /
  HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  -   this return value is an indication that the operation
  failed due to insufficient space. When this error occurs,
  the destination buffer is modified to contain a truncated
  version of the ideal result and is null terminated. This
  is useful for situations where truncation is ok.
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbCat  StringCbCatW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbCat  StringCbCatA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCbCatA(
              _Inout_updates_bytes_(cbDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cbDest,
              _In_ STRSAFE_LPCSTR pszSrc)
  {
      HRESULT hr;
      size_t cchDestLength;
      size_t cchDest = cbDest / sizeof(char);
  
      hr = StringValidateDestAndLengthA(pszDest,
              cchDest,
              &cchDestLength,
              STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          hr = StringCopyWorkerA(pszDest + cchDestLength,
                  cchDest - cchDestLength,
                  NULL,
                  pszSrc,
                  STRSAFE_MAX_LENGTH);
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCbCatW(
              _Inout_updates_bytes_(cbDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cbDest,
              _In_ STRSAFE_LPCWSTR pszSrc)
  {
      HRESULT hr;
      size_t cchDestLength;
      size_t cchDest = cbDest / sizeof(wchar_t);
  
      hr = StringValidateDestAndLengthW(pszDest,
              cchDest,
              &cchDestLength,
              STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          hr = StringCopyWorkerW(pszDest + cchDestLength,
                  cchDest - cchDestLength,
                  NULL,
                  pszSrc,
                  STRSAFE_MAX_LENGTH);
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CB_FUNCTIONS
  
  
  #ifndef STRSAFE_NO_CCH_FUNCTIONS
  /*++
  
    STDAPI
    StringCchCatEx(
    _Inout_updates_(cchDest) _Always_(_Post_z_) LPTSTR  pszDest         OPTIONAL,
    _In_     size_t  cchDest,
    _In_     LPCTSTR pszSrc          OPTIONAL,
    _Outptr_opt_result_buffer_(*pcchRemaining)    LPTSTR* ppszDestEnd     OPTIONAL,
    _Out_opt_    size_t* pcchRemaining   OPTIONAL,
    _In_     DWORD   dwFlags
    );
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'strcat' with
    some additional parameters.  In addition to functionality provided by
    StringCchCat, this routine also returns a pointer to the end of the
    destination string and the number of characters left in the destination string
    including the null terminator. The flags parameter allows additional controls.
  
  Arguments:
  
  pszDest         -   destination string which must be null terminated
  
  cchDest         -   size of destination buffer in characters
  length must be (_tcslen(pszDest) + _tcslen(pszSrc) + 1)
  to hold all of the combine string plus the null
  terminator.
  
  pszSrc          -   source string which must be null terminated
  
  ppszDestEnd     -   if ppszDestEnd is non-null, the function will return a
  pointer to the end of the destination string.  If the
  function appended any data, the result will point to the
  null termination character
  
  pcchRemaining   -   if pcchRemaining is non-null, the function will return the
  number of characters left in the destination string,
  including the null terminator
  
  dwFlags         -   controls some details of the string copy:
  
  STRSAFE_FILL_BEHIND_NULL
  if the function succeeds, the low byte of dwFlags will be
  used to fill the uninitialize part of destination buffer
  behind the null terminator
  
  STRSAFE_IGNORE_NULLS
  treat NULL string pointers like empty strings (TEXT("")).
  this flag is useful for emulating functions like lstrcat
  
  STRSAFE_FILL_ON_FAILURE
  if the function fails, the low byte of dwFlags will be
  used to fill all of the destination buffer, and it will
  be null terminated. This will overwrite any pre-existing
  or truncated string
  
  STRSAFE_NULL_ON_FAILURE
  if the function fails, the destination buffer will be set
  to the empty string. This will overwrite any pre-existing or
  truncated string
  
  STRSAFE_NO_TRUNCATION
  if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest
  will not contain a truncated string, it will remain unchanged.
  
  Notes:
  Behavior is undefined if source and destination strings overlap.
  
  pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  is specified.  If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  may be NULL.  An error may still be returned even though NULLS are ignored
  due to insufficient space.
  
  Return Value:
  
  S_OK           -   if there was source data and it was all concatenated and
  the resultant dest string was null terminated
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  STRSAFE_E_INSUFFICIENT_BUFFER /
  HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  -   this return value is an indication that the operation
  failed due to insufficient space. When this error
  occurs, the destination buffer is modified to contain
  a truncated version of the ideal result and is null
  terminated. This is useful for situations where
  truncation is ok.
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchCatEx  StringCchCatExW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchCatEx  StringCchCatExA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCchCatExA(
              _Inout_updates_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cchDest,
              _In_ STRSAFE_LPCSTR pszSrc,
              _Outptr_opt_result_buffer_(*pcchRemaining) STRSAFE_LPSTR* ppszDestEnd,
              _Out_opt_ size_t* pcchRemaining,
              _In_ DWORD dwFlags)
  {
      HRESULT hr;
      size_t cchDestLength;
  
      hr = StringExValidateDestAndLengthA(pszDest,
              cchDest,
              &cchDestLength,
              STRSAFE_MAX_CCH,
              dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPSTR pszDestEnd = pszDest + cchDestLength;
          size_t cchRemaining = cchDest - cchDestLength;
  
          hr = StringExValidateSrcA(&pszSrc, NULL, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
              }
              else if (cchRemaining <= 1)
              {
                  // only fail if there was actually src data to append
                  if (*pszSrc != '\0')
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
              }
              else
              {
                  size_t cchCopied = 0;
  
                  hr = StringCopyWorkerA(pszDestEnd,
                          cchRemaining,
                          &cchCopied,
                          pszSrc,
                          STRSAFE_MAX_LENGTH);
  
                  pszDestEnd = pszDestEnd + cchCopied;
                  cchRemaining = cchRemaining - cchCopied;
  
                  if (SUCCEEDED(hr)                           &&
                          (dwFlags & STRSAFE_FILL_BEHIND_NULL)    &&
                          (cchRemaining > 1))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
                      cbRemaining = cchRemaining * sizeof(char);
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullA(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cchDest != 0))
          {
              size_t cbDest;
  
              // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
              cbDest = cchDest * sizeof(char);
  
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsA(pszDest,
                      cbDest,
                      cchDestLength,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcchRemaining)
              {
                  *pcchRemaining = cchRemaining;
              }
          }
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCchCatExW(
              _Inout_updates_(cchDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cchDest,
              _In_ STRSAFE_LPCWSTR pszSrc,
              _Outptr_opt_result_buffer_(*pcchRemaining) STRSAFE_LPWSTR* ppszDestEnd,
              _Out_opt_ size_t* pcchRemaining,
              _In_ DWORD dwFlags)
  {
      HRESULT hr;
      size_t cchDestLength;
  
      hr = StringExValidateDestAndLengthW(pszDest,
              cchDest,
              &cchDestLength,
              STRSAFE_MAX_CCH,
              dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPWSTR pszDestEnd = pszDest + cchDestLength;
          size_t cchRemaining = cchDest - cchDestLength;
  
          hr = StringExValidateSrcW(&pszSrc, NULL, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
              }
              else if (cchRemaining <= 1)
              {
                  // only fail if there was actually src data to append
                  if (*pszSrc != L'\0')
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
              }
              else
              {
                  size_t cchCopied = 0;
  
                  hr = StringCopyWorkerW(pszDestEnd,
                          cchRemaining,
                          &cchCopied,
                          pszSrc,
                          STRSAFE_MAX_LENGTH);
  
                  pszDestEnd = pszDestEnd + cchCopied;
                  cchRemaining = cchRemaining - cchCopied;
  
                  if (SUCCEEDED(hr)                           &&
                          (dwFlags & STRSAFE_FILL_BEHIND_NULL)    &&
                          (cchRemaining > 1))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
                      cbRemaining = cchRemaining * sizeof(wchar_t);
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullW(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cchDest != 0))
          {
              size_t cbDest;
  
              // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
              cbDest = cchDest * sizeof(wchar_t);
  
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsW(pszDest,
                      cbDest,
                      cchDestLength,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcchRemaining)
              {
                  *pcchRemaining = cchRemaining;
              }
          }
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  
  
  #ifndef STRSAFE_NO_CB_FUNCTIONS
  /*++
  
    STDAPI
    StringCbCatEx(
    _Inout_updates_bytes_(cbDest) _Always_(_Post_z_) LPTSTR  pszDest         OPTIONAL,
    _In_     size_t  cbDest,
    _In_     LPCTSTR pszSrc          OPTIONAL,
    _Outptr_opt_result_bytebuffer_(*pcbRemaining)    LPTSTR* ppszDestEnd     OPTIONAL,
    _Out_opt_    size_t* pcbRemaining    OPTIONAL,
    _In_     DWORD   dwFlags
    );
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'strcat' with
    some additional parameters.  In addition to functionality provided by
    StringCbCat, this routine also returns a pointer to the end of the
    destination string and the number of bytes left in the destination string
    including the null terminator. The flags parameter allows additional controls.
  
  Arguments:
  
  pszDest         -   destination string which must be null terminated
  
  cbDest          -   size of destination buffer in bytes.
  length must be ((_tcslen(pszDest) + _tcslen(pszSrc) + 1) * sizeof(TCHAR)
  to hold all of the combine string plus the null
  terminator.
  
  pszSrc          -   source string which must be null terminated
  
  ppszDestEnd     -   if ppszDestEnd is non-null, the function will return a
  pointer to the end of the destination string.  If the
  function appended any data, the result will point to the
  null termination character
  
  pcbRemaining    -   if pcbRemaining is non-null, the function will return
  the number of bytes left in the destination string,
  including the null terminator
  
  dwFlags         -   controls some details of the string copy:
  
  STRSAFE_FILL_BEHIND_NULL
  if the function succeeds, the low byte of dwFlags will be
  used to fill the uninitialize part of destination buffer
  behind the null terminator
  
  STRSAFE_IGNORE_NULLS
  treat NULL string pointers like empty strings (TEXT("")).
  this flag is useful for emulating functions like lstrcat
  
  STRSAFE_FILL_ON_FAILURE
  if the function fails, the low byte of dwFlags will be
  used to fill all of the destination buffer, and it will
  be null terminated. This will overwrite any pre-existing
  or truncated string
  
  STRSAFE_NULL_ON_FAILURE
  if the function fails, the destination buffer will be set
  to the empty string. This will overwrite any pre-existing or
  truncated string
  
  STRSAFE_NO_TRUNCATION
  if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest
  will not contain a truncated string, it will remain unchanged.
  
  Notes:
  Behavior is undefined if source and destination strings overlap.
  
  pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  is specified.  If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  may be NULL.  An error may still be returned even though NULLS are ignored
  due to insufficient space.
  
  Return Value:
  
  S_OK           -   if there was source data and it was all concatenated
  and the resultant dest string was null terminated
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  STRSAFE_E_INSUFFICIENT_BUFFER /
  HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  -   this return value is an indication that the operation
  failed due to insufficient space. When this error
  occurs, the destination buffer is modified to contain
  a truncated version of the ideal result and is null
  terminated. This is useful for situations where
  truncation is ok.
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbCatEx  StringCbCatExW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbCatEx  StringCbCatExA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCbCatExA(
              _Inout_updates_bytes_(cbDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cbDest,
              _In_ STRSAFE_LPCSTR pszSrc,
              _Outptr_opt_result_bytebuffer_(*pcbRemaining) STRSAFE_LPSTR* ppszDestEnd,
              _Out_opt_ size_t* pcbRemaining,
              _In_ DWORD dwFlags)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(char);
      size_t cchDestLength;
  
      hr = StringExValidateDestAndLengthA(pszDest,
              cchDest,
              &cchDestLength,
              STRSAFE_MAX_CCH,
              dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPSTR pszDestEnd = pszDest + cchDestLength;
          size_t cchRemaining = cchDest - cchDestLength;
  
          hr = StringExValidateSrcA(&pszSrc, NULL, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
              }
              else if (cchRemaining <= 1)
              {
                  // only fail if there was actually src data to append
                  if (*pszSrc != '\0')
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
              }
              else
              {
                  size_t cchCopied = 0;
  
                  hr = StringCopyWorkerA(pszDestEnd,
                          cchRemaining,
                          &cchCopied,
                          pszSrc,
                          STRSAFE_MAX_LENGTH);
  
                  pszDestEnd = pszDestEnd + cchCopied;
                  cchRemaining = cchRemaining - cchCopied;
  
                  if (SUCCEEDED(hr)                           &&
                          (dwFlags & STRSAFE_FILL_BEHIND_NULL)    &&
                          (cchRemaining > 1))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
                      cbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullA(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cbDest != 0))
          {
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsA(pszDest,
                      cbDest,
                      cchDestLength,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcbRemaining)
              {
                  // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
                  *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
              }
          }
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCbCatExW(
              _Inout_updates_bytes_(cbDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cbDest,
              _In_ STRSAFE_LPCWSTR pszSrc,
              _Outptr_opt_result_bytebuffer_(*pcbRemaining) STRSAFE_LPWSTR* ppszDestEnd,
              _Out_opt_ size_t* pcbRemaining,
              _In_ DWORD dwFlags)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(wchar_t);
      size_t cchDestLength;
  
      hr = StringExValidateDestAndLengthW(pszDest,
              cchDest,
              &cchDestLength,
              STRSAFE_MAX_CCH,
              dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPWSTR pszDestEnd = pszDest + cchDestLength;
          size_t cchRemaining = cchDest - cchDestLength;
  
          hr = StringExValidateSrcW(&pszSrc, NULL, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
              }
              else if (cchRemaining <= 1)
              {
                  // only fail if there was actually src data to append
                  if (*pszSrc != L'\0')
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
              }
              else
              {
                  size_t cchCopied = 0;
  
                  hr = StringCopyWorkerW(pszDestEnd,
                          cchRemaining,
                          &cchCopied,
                          pszSrc,
                          STRSAFE_MAX_LENGTH);
  
                  pszDestEnd = pszDestEnd + cchCopied;
                  cchRemaining = cchRemaining - cchCopied;
  
                  if (SUCCEEDED(hr) && (dwFlags & STRSAFE_FILL_BEHIND_NULL))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
                      cbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullW(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cbDest != 0))
          {
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsW(pszDest,
                      cbDest,
                      cchDestLength,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcbRemaining)
              {
                  // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
                  *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
              }
          }
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CB_FUNCTIONS
  
  
  #ifndef STRSAFE_NO_CCH_FUNCTIONS
  /*++
  
    STDAPI
    StringCchCatN(
    _Inout_updates_(cchDest) _Always_(_Post_z_) LPTSTR  pszDest,
    _In_     size_t  cchDest,
    _In_     LPCTSTR pszSrc,
    _In_     size_t  cchToAppend
    );
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'strncat'.
    The size of the destination buffer (in characters) is a parameter as well as
    the maximum number of characters to append, excluding the null terminator.
    This function will not write past the end of the destination buffer and it will
    ALWAYS null terminate pszDest (unless it is zero length).
  
    This function returns a hresult, and not a pointer.  It returns
    S_OK if all of pszSrc or the first cchToAppend characters were appended
    to the destination string and it was null terminated, otherwise it will
    return a failure code. In failure cases as much of pszSrc will be appended
    to pszDest as possible, and pszDest will be null terminated.
  
  Arguments:
  
  pszDest         -   destination string which must be null terminated
  
  cchDest         -   size of destination buffer in characters.
  length must be (_tcslen(pszDest) + min(cchToAppend, _tcslen(pszSrc)) + 1)
  to hold all of the combine string plus the null
  terminator.
  
  pszSrc          -   source string
  
  cchToAppend     -   maximum number of characters to append
  
  Notes:
  Behavior is undefined if source and destination strings overlap.
  
  pszDest and pszSrc should not be NULL. See StringCchCatNEx if you require
  the handling of NULL values.
  
  Return Value:
  
  S_OK           -   if all of pszSrc or the first cchToAppend characters
  were concatenated to pszDest and the resultant dest
  string was null terminated
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  STRSAFE_E_INSUFFICIENT_BUFFER /
  HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  -   this return value is an indication that the operation
  failed due to insufficient space. When this error
  occurs, the destination buffer is modified to contain
  a truncated version of the ideal result and is null
  terminated. This is useful for situations where
  truncation is ok.
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchCatN  StringCchCatNW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchCatN  StringCchCatNA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCchCatNA(
              _Inout_updates_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cchDest,
              _In_reads_or_z_(cchToAppend) STRSAFE_PCNZCH pszSrc,
              _In_ size_t cchToAppend)
  {
      HRESULT hr;
      size_t cchDestLength;
  
      hr = StringValidateDestAndLengthA(pszDest,
              cchDest,
              &cchDestLength,
              STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          if (cchToAppend > STRSAFE_MAX_LENGTH)
          {
              hr = STRSAFE_E_INVALID_PARAMETER;
          }
          else
          {
              hr = StringCopyWorkerA(pszDest + cchDestLength,
                      cchDest - cchDestLength,
                      NULL,
                      pszSrc,
                      cchToAppend);
          }
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCchCatNW(
              _Inout_updates_(cchDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cchDest,
              _In_reads_or_z_(cchToAppend) STRSAFE_PCNZWCH pszSrc,
              _In_ size_t cchToAppend)
  {
      HRESULT hr;
      size_t cchDestLength;
  
      hr = StringValidateDestAndLengthW(pszDest,
              cchDest,
              &cchDestLength,
              STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          if (cchToAppend > STRSAFE_MAX_LENGTH)
          {
              hr = STRSAFE_E_INVALID_PARAMETER;
          }
          else
          {
              hr = StringCopyWorkerW(pszDest + cchDestLength,
                      cchDest - cchDestLength,
                      NULL,
                      pszSrc,
                      cchToAppend);
          }
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  
  
  #ifndef STRSAFE_NO_CB_FUNCTIONS
  /*++
  
    STDAPI
    StringCbCatN(
    _Inout_updates_bytes_(cbDest) _Always_(_Post_z_) LPTSTR  pszDest,
    _In_     size_t  cbDest,
    _In_     LPCTSTR pszSrc,
    _In_     size_t  cbToAppend
    );
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'strncat'.
    The size of the destination buffer (in bytes) is a parameter as well as
    the maximum number of bytes to append, excluding the null terminator.
    This function will not write past the end of the destination buffer and it will
    ALWAYS null terminate pszDest (unless it is zero length).
  
    This function returns a hresult, and not a pointer.  It returns
    S_OK if all of pszSrc or the first cbToAppend bytes were appended
    to the destination string and it was null terminated, otherwise it will
    return a failure code. In failure cases as much of pszSrc will be appended
    to pszDest as possible, and pszDest will be null terminated.
  
  Arguments:
  
  pszDest         -   destination string which must be null terminated
  
  cbDest          -   size of destination buffer in bytes.
  length must be ((_tcslen(pszDest) + min(cbToAppend / sizeof(TCHAR), _tcslen(pszSrc)) + 1) * sizeof(TCHAR)
  to hold all of the combine string plus the null
  terminator.
  
  pszSrc          -   source string
  
  cbToAppend      -   maximum number of bytes to append
  
  Notes:
  Behavior is undefined if source and destination strings overlap.
  
  pszDest and pszSrc should not be NULL. See StringCbCatNEx if you require
  the handling of NULL values.
  
  Return Value:
  
  S_OK           -   if all of pszSrc or the first cbToAppend bytes were
  concatenated to pszDest and the resultant dest string
  was null terminated
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  STRSAFE_E_INSUFFICIENT_BUFFER /
  HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  -   this return value is an indication that the operation
  failed due to insufficient space. When this error
  occurs, the destination buffer is modified to contain
  a truncated version of the ideal result and is null
  terminated. This is useful for situations where
  truncation is ok.
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbCatN  StringCbCatNW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbCatN  StringCbCatNA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCbCatNA(
              _Inout_updates_bytes_(cbDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cbDest,
              _In_reads_bytes_(cbToAppend) STRSAFE_PCNZCH pszSrc,
              _In_ size_t cbToAppend)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(char);
      size_t cchDestLength;
  
      hr = StringValidateDestAndLengthA(pszDest,
              cchDest,
              &cchDestLength,
              STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          size_t cchToAppend = cbToAppend / sizeof(char);
  
          if (cchToAppend > STRSAFE_MAX_LENGTH)
          {
              hr = STRSAFE_E_INVALID_PARAMETER;
          }
          else
          {
              hr = StringCopyWorkerA(pszDest + cchDestLength,
                      cchDest - cchDestLength,
                      NULL,
                      pszSrc,
                      cchToAppend);
          }
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCbCatNW(
              _Inout_updates_bytes_(cbDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cbDest,
              _In_reads_bytes_(cbToAppend) STRSAFE_PCNZWCH pszSrc,
              _In_ size_t cbToAppend)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(wchar_t);
      size_t cchDestLength;
  
      hr = StringValidateDestAndLengthW(pszDest,
              cchDest,
              &cchDestLength,
              STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          size_t cchToAppend = cbToAppend / sizeof(wchar_t);
  
          if (cchToAppend > STRSAFE_MAX_LENGTH)
          {
              hr = STRSAFE_E_INVALID_PARAMETER;
          }
          else
          {
              hr = StringCopyWorkerW(pszDest + cchDestLength,
                      cchDest - cchDestLength,
                      NULL,
                      pszSrc,
                      cchToAppend);
          }
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CB_FUNCTIONS
  
  
  #ifndef STRSAFE_NO_CCH_FUNCTIONS
  /*++
  
    STDAPI
    StringCchCatNEx(
    _Inout_updates_(cchDest) _Always_(_Post_z_) LPTSTR  pszDest         OPTIONAL,
    _In_     size_t  cchDest,
    _In_     LPCTSTR pszSrc          OPTIONAL,
    _In_     size_t  cchToAppend,
    _Outptr_opt_result_buffer_(*pcchRemaining)    LPTSTR* ppszDestEnd     OPTIONAL,
    _Out_opt_    size_t* pcchRemaining   OPTIONAL,
    _In_     DWORD   dwFlags
    );
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'strncat', with
    some additional parameters.  In addition to functionality provided by
    StringCchCatN, this routine also returns a pointer to the end of the
    destination string and the number of characters left in the destination string
    including the null terminator. The flags parameter allows additional controls.
  
  Arguments:
  
  pszDest         -   destination string which must be null terminated
  
  cchDest         -   size of destination buffer in characters.
  length must be (_tcslen(pszDest) + min(cchToAppend, _tcslen(pszSrc)) + 1)
  to hold all of the combine string plus the null
  terminator.
  
  pszSrc          -   source string
  
  cchToAppend     -   maximum number of characters to append
  
  ppszDestEnd     -   if ppszDestEnd is non-null, the function will return a
  pointer to the end of the destination string.  If the
  function appended any data, the result will point to the
  null termination character
  
  pcchRemaining   -   if pcchRemaining is non-null, the function will return the
  number of characters left in the destination string,
  including the null terminator
  
  dwFlags         -   controls some details of the string copy:
  
  STRSAFE_FILL_BEHIND_NULL
  if the function succeeds, the low byte of dwFlags will be
  used to fill the uninitialize part of destination buffer
  behind the null terminator
  
  STRSAFE_IGNORE_NULLS
  treat NULL string pointers like empty strings (TEXT(""))
  
  STRSAFE_FILL_ON_FAILURE
  if the function fails, the low byte of dwFlags will be
  used to fill all of the destination buffer, and it will
  be null terminated. This will overwrite any pre-existing
  or truncated string
  
  STRSAFE_NULL_ON_FAILURE
  if the function fails, the destination buffer will be set
  to the empty string. This will overwrite any pre-existing or
  truncated string
  
  STRSAFE_NO_TRUNCATION
  if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest
  will not contain a truncated string, it will remain unchanged.
  
  Notes:
  Behavior is undefined if source and destination strings overlap.
  
  pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  is specified.  If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  may be NULL.  An error may still be returned even though NULLS are ignored
  due to insufficient space.
  
  Return Value:
  
  S_OK           -   if all of pszSrc or the first cchToAppend characters
  were concatenated to pszDest and the resultant dest
  string was null terminated
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  STRSAFE_E_INSUFFICIENT_BUFFER /
  HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  -   this return value is an indication that the operation
  failed due to insufficient space. When this error
  occurs, the destination buffer is modified to contain
  a truncated version of the ideal result and is null
  terminated. This is useful for situations where
  truncation is ok.
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchCatNEx  StringCchCatNExW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchCatNEx  StringCchCatNExA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCchCatNExA(
              _Inout_updates_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cchDest,
              _In_reads_or_z_(cchToAppend) STRSAFE_PCNZCH pszSrc,
              _In_ size_t cchToAppend,
              _Outptr_opt_result_buffer_(*pcchRemaining) STRSAFE_LPSTR* ppszDestEnd,
              _Out_opt_ size_t* pcchRemaining,
              _In_ DWORD dwFlags)
  {
      HRESULT hr;
      size_t cchDestLength;
  
      hr = StringExValidateDestAndLengthA(pszDest,
              cchDest,
              &cchDestLength,
              STRSAFE_MAX_CCH,
              dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPSTR pszDestEnd = pszDest + cchDestLength;
          size_t cchRemaining = cchDest - cchDestLength;
  
          hr = StringExValidateSrcA(&pszSrc, &cchToAppend, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
              }
              else if (cchRemaining <= 1)
              {
                  // only fail if there was actually src data to append
                  if ((cchToAppend != 0) && (*pszSrc != '\0'))
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
              }
              else
              {
                  size_t cchCopied = 0;
  
                  hr = StringCopyWorkerA(pszDestEnd,
                          cchRemaining,
                          &cchCopied,
                          pszSrc,
                          cchToAppend);
  
                  pszDestEnd = pszDestEnd + cchCopied;
                  cchRemaining = cchRemaining - cchCopied;
  
                  if (SUCCEEDED(hr)                           &&
                          (dwFlags & STRSAFE_FILL_BEHIND_NULL)    &&
                          (cchRemaining > 1))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
                      cbRemaining = cchRemaining * sizeof(char);
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullA(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cchDest != 0))
          {
              size_t cbDest;
  
              // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
              cbDest = cchDest * sizeof(char);
  
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsA(pszDest,
                      cbDest,
                      cchDestLength,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcchRemaining)
              {
                  *pcchRemaining = cchRemaining;
              }
          }
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCchCatNExW(
              _Inout_updates_(cchDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cchDest,
              _In_reads_or_z_(cchToAppend) STRSAFE_PCNZWCH pszSrc,
              _In_ size_t cchToAppend,
              _Outptr_opt_result_buffer_(*pcchRemaining) STRSAFE_LPWSTR* ppszDestEnd,
              _Out_opt_ size_t* pcchRemaining,
              _In_ DWORD dwFlags)
  {
      HRESULT hr;
      size_t cchDestLength;
  
      hr = StringExValidateDestAndLengthW(pszDest,
              cchDest,
              &cchDestLength,
              STRSAFE_MAX_CCH,
              dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPWSTR pszDestEnd = pszDest + cchDestLength;
          size_t cchRemaining = cchDest - cchDestLength;
  
          hr = StringExValidateSrcW(&pszSrc, &cchToAppend, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
              }
              else if (cchRemaining <= 1)
              {
                  // only fail if there was actually src data to append
                  if ((cchToAppend != 0) && (*pszSrc != L'\0'))
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
              }
              else
              {
                  size_t cchCopied = 0;
  
                  hr = StringCopyWorkerW(pszDestEnd,
                          cchRemaining,
                          &cchCopied,
                          pszSrc,
                          cchToAppend);
  
                  pszDestEnd = pszDestEnd + cchCopied;
                  cchRemaining = cchRemaining - cchCopied;
  
                  if (SUCCEEDED(hr)                           &&
                          (dwFlags & STRSAFE_FILL_BEHIND_NULL)    &&
                          (cchRemaining > 1))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
                      cbRemaining = cchRemaining * sizeof(wchar_t);
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullW(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cchDest != 0))
          {
              size_t cbDest;
  
              // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
              cbDest = cchDest * sizeof(wchar_t);
  
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsW(pszDest,
                      cbDest,
                      cchDestLength,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcchRemaining)
              {
                  *pcchRemaining = cchRemaining;
              }
          }
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  
  
  #ifndef STRSAFE_NO_CB_FUNCTIONS
  /*++
  
    STDAPI
    StringCbCatNEx(
    _Inout_updates_bytes_(cbDest) _Always_(_Post_z_) LPTSTR  pszDest         OPTIONAL,
    _In_     size_t  cbDest,
    _In_     LPCTSTR pszSrc          OPTIONAL,
    _In_     size_t  cbToAppend,
    _Outptr_opt_result_bytebuffer_(*pcbRemaining)    LPTSTR* ppszDestEnd     OPTIONAL,
    _Out_opt_    size_t* pcchRemaining   OPTIONAL,
    _In_     DWORD   dwFlags
    );
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'strncat', with
    some additional parameters.  In addition to functionality provided by
    StringCbCatN, this routine also returns a pointer to the end of the
    destination string and the number of bytes left in the destination string
    including the null terminator. The flags parameter allows additional controls.
  
  Arguments:
  
  pszDest         -   destination string which must be null terminated
  
  cbDest          -   size of destination buffer in bytes.
  length must be ((_tcslen(pszDest) + min(cbToAppend / sizeof(TCHAR), _tcslen(pszSrc)) + 1) * sizeof(TCHAR)
  to hold all of the combine string plus the null
  terminator.
  
  pszSrc          -   source string
  
  cbToAppend      -   maximum number of bytes to append
  
  ppszDestEnd     -   if ppszDestEnd is non-null, the function will return a
  pointer to the end of the destination string.  If the
  function appended any data, the result will point to the
  null termination character
  
  pcbRemaining    -   if pcbRemaining is non-null, the function will return the
  number of bytes left in the destination string,
  including the null terminator
  
  dwFlags         -   controls some details of the string copy:
  
  STRSAFE_FILL_BEHIND_NULL
  if the function succeeds, the low byte of dwFlags will be
  used to fill the uninitialize part of destination buffer
  behind the null terminator
  
  STRSAFE_IGNORE_NULLS
  treat NULL string pointers like empty strings (TEXT(""))
  
  STRSAFE_FILL_ON_FAILURE
  if the function fails, the low byte of dwFlags will be
  used to fill all of the destination buffer, and it will
  be null terminated. This will overwrite any pre-existing
  or truncated string
  
  STRSAFE_NULL_ON_FAILURE
  if the function fails, the destination buffer will be set
  to the empty string. This will overwrite any pre-existing or
  truncated string
  
  STRSAFE_NO_TRUNCATION
  if the function returns STRSAFE_E_INSUFFICIENT_BUFFER, pszDest
  will not contain a truncated string, it will remain unchanged.
  
  Notes:
  Behavior is undefined if source and destination strings overlap.
  
  pszDest and pszSrc should not be NULL unless the STRSAFE_IGNORE_NULLS flag
  is specified.  If STRSAFE_IGNORE_NULLS is passed, both pszDest and pszSrc
  may be NULL.  An error may still be returned even though NULLS are ignored
  due to insufficient space.
  
  Return Value:
  
  S_OK           -   if all of pszSrc or the first cbToAppend bytes were
  concatenated to pszDest and the resultant dest string
  was null terminated
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  STRSAFE_E_INSUFFICIENT_BUFFER /
  HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  -   this return value is an indication that the operation
  failed due to insufficient space. When this error
  occurs, the destination buffer is modified to contain
  a truncated version of the ideal result and is null
  terminated. This is useful for situations where
  truncation is ok.
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbCatNEx  StringCbCatNExW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbCatNEx  StringCbCatNExA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCbCatNExA(
              _Inout_updates_bytes_(cbDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cbDest,
              _In_reads_bytes_(cbToAppend) STRSAFE_PCNZCH pszSrc,
              _In_ size_t cbToAppend,
              _Outptr_opt_result_bytebuffer_(*pcbRemaining) STRSAFE_LPSTR* ppszDestEnd,
              _Out_opt_ size_t* pcbRemaining,
              _In_ DWORD dwFlags)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(char);
      size_t cchDestLength;
  
      hr = StringExValidateDestAndLengthA(pszDest,
              cchDest,
              &cchDestLength,
              STRSAFE_MAX_CCH,
              dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPSTR pszDestEnd = pszDest + cchDestLength;
          size_t cchRemaining = cchDest - cchDestLength;
          size_t cchToAppend = cbToAppend / sizeof(char);
  
          hr = StringExValidateSrcA(&pszSrc, &cchToAppend, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
              }
              else if (cchRemaining <= 1)
              {
                  // only fail if there was actually src data to append
                  if ((cchToAppend != 0) && (*pszSrc != '\0'))
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
              }
              else
              {
                  size_t cchCopied = 0;
  
                  hr = StringCopyWorkerA(pszDestEnd,
                          cchRemaining,
                          &cchCopied,
                          pszSrc,
                          cchToAppend);
  
                  pszDestEnd = pszDestEnd + cchCopied;
                  cchRemaining = cchRemaining - cchCopied;
  
                  if (SUCCEEDED(hr)                           &&
                          (dwFlags & STRSAFE_FILL_BEHIND_NULL)    &&
                          (cchRemaining > 1))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
                      cbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullA(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cbDest != 0))
          {
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsA(pszDest,
                      cbDest,
                      cchDestLength,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcbRemaining)
              {
                  // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
                  *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
              }
          }
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable : __WARNING_POTENTIAL_BUFFER_OVERFLOW_HIGH_PRIORITY)
  
  STRSAFEAPI
      StringCbCatNExW(
              _Inout_updates_bytes_(cbDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cbDest,
              _In_reads_bytes_(cbToAppend) STRSAFE_PCNZWCH pszSrc,
              _In_ size_t cbToAppend,
              _Outptr_opt_result_bytebuffer_(*pcbRemaining) STRSAFE_LPWSTR* ppszDestEnd,
              _Out_opt_ size_t* pcbRemaining,
              _In_ DWORD dwFlags)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(wchar_t);
      size_t cchDestLength;
  
      hr = StringExValidateDestAndLengthW(pszDest,
              cchDest,
              &cchDestLength,
              STRSAFE_MAX_CCH,
              dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPWSTR pszDestEnd = pszDest + cchDestLength;
          size_t cchRemaining = cchDest - cchDestLength;
          size_t cchToAppend = cbToAppend / sizeof(wchar_t);
  
          hr = StringExValidateSrcW(&pszSrc, &cchToAppend, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
              }
              else if (cchRemaining <= 1)
              {
                  // only fail if there was actually src data to append
                  if ((cchToAppend != 0) && (*pszSrc != L'\0'))
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
              }
              else
              {
                  size_t cchCopied = 0;
  
                  hr = StringCopyWorkerW(pszDestEnd,
                          cchRemaining,
                          &cchCopied,
                          pszSrc,
                          cchToAppend);
  
                  pszDestEnd = pszDestEnd + cchCopied;
                  cchRemaining = cchRemaining - cchCopied;
  
                  if (SUCCEEDED(hr) && (dwFlags & STRSAFE_FILL_BEHIND_NULL))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
                      cbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullW(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cbDest != 0))
          {
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsW(pszDest,
                      cbDest,
                      cchDestLength,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcbRemaining)
              {
                  // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
                  *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
              }
          }
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CB_FUNCTIONS
  
  
  #ifndef STRSAFE_NO_CCH_FUNCTIONS
  /*++
  
    STDAPI
    StringCchVPrintf(
    _Out_writes_(cchDest) _Always_(_Post_z_) LPTSTR  pszDest,
    _In_  size_t  cchDest,
    _In_ _Printf_format_string_  LPCTSTR pszFormat,
    _In_  va_list argList
    );
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'vsprintf'.
    The size of the destination buffer (in characters) is a parameter and
    this function will not write past the end of this buffer and it will
    ALWAYS null terminate the destination buffer (unless it is zero length).
  
    This function returns a hresult, and not a pointer.  It returns
    S_OK if the string was printed without truncation and null terminated,
    otherwise it will return a failure code. In failure cases it will return
    a truncated version of the ideal result.
  
  Arguments:
  
  pszDest     -  destination string
  
  cchDest     -  size of destination buffer in characters
  length must be sufficient to hold the resulting formatted
  string, including the null terminator.
  
  pszFormat   -  format string which must be null terminated
  
  argList     -  va_list from the variable arguments according to the
  stdarg.h convention
  
  Notes:
  Behavior is undefined if destination, format strings or any arguments
  strings overlap.
  
  pszDest and pszFormat should not be NULL.  See StringCchVPrintfEx if you
  require the handling of NULL values.
  
  Return Value:
  
  S_OK           -   if there was sufficient space in the dest buffer for
  the resultant string and it was null terminated.
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  STRSAFE_E_INSUFFICIENT_BUFFER /
  HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  -   this return value is an indication that the print
  operation failed due to insufficient space. When this
  error occurs, the destination buffer is modified to
  contain a truncated version of the ideal result and is
  null terminated. This is useful for situations where
  truncation is ok.
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchVPrintf  StringCchVPrintfW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchVPrintf  StringCchVPrintfA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable: __WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION)
  
  STRSAFEAPI
      StringCchVPrintfA(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cchDest,
              _In_ _Printf_format_string_ STRSAFE_LPCSTR pszFormat,
              _In_ va_list argList)
  {
      HRESULT hr;
  
      hr = StringValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          hr = StringVPrintfWorkerA(pszDest,
                  cchDest,
                  NULL,
                  pszFormat,
                  argList);
      }
      else if (cchDest > 0)
      {
          *pszDest = '\0';
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable: __WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION)
  
  STRSAFEAPI
      StringCchVPrintfW(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cchDest,
              _In_ _Printf_format_string_ STRSAFE_LPCWSTR pszFormat,
              _In_ va_list argList)
  {
      HRESULT hr;
  
      hr = StringValidateDestW(pszDest, cchDest, STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          hr = StringVPrintfWorkerW(pszDest,
                  cchDest,
                  NULL,
                  pszFormat,
                  argList);
      }
      else if (cchDest > 0)
      {
          *pszDest = L'\0';
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  
  
  #if defined(STRSAFE_LOCALE_FUNCTIONS) && !defined(STRSAFE_NO_CCH_FUNCTIONS)
  /*++
  
    STDAPI
    StringCchVPrintf_l(
    _Out_writes_(cchDest) _Always_(_Post_z_) LPTSTR  pszDest,
    _In_ size_t  cchDest,
    _In_ _Printf_format_string_params_(2)  LPCTSTR pszFormat,
    _In_ locale_t locale,
    _In_ va_list argList
    );
  
    Routine Description:
  
    This routine is a version of StringCchVPrintf that also takes a locale.
    Please see notes for StringCchVPrintf above.
  
    --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchVPrintf_l  StringCchVPrintf_lW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchVPrintf_l  StringCchVPrintf_lA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable: __WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION)
  
  STRSAFEAPI
      StringCchVPrintf_lA(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cchDest,
              _In_ _Printf_format_string_params_(2) STRSAFE_LPCSTR pszFormat,
              _In_ _locale_t locale,
              _In_ va_list argList)
  {
      HRESULT hr;
  
      hr = StringValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          hr = StringVPrintf_lWorkerA(pszDest,
                  cchDest,
                  NULL,
                  pszFormat,
                  locale,
                  argList);
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable: __WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION)
  
  STRSAFEAPI
      StringCchVPrintf_lW(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cchDest,
              _In_ _Printf_format_string_params_(2) STRSAFE_LPCWSTR pszFormat,
              _In_ _locale_t locale,
              _In_ va_list argList)
  {
      HRESULT hr;
  
      hr = StringValidateDestW(pszDest, cchDest, STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          hr = StringVPrintf_lWorkerW(pszDest,
                  cchDest,
                  NULL,
                  pszFormat,
                  locale,
                  argList);
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  //  STRSAFE_LOCALE_FUNCTIONS && !STRSAFE_NO_CCH_FUNCTIONS
  
  
  #ifndef STRSAFE_NO_CB_FUNCTIONS
  /*++
  
    STDAPI
    StringCbVPrintf(
    _Out_writes_bytes_(cbDest) _Always_(_Post_z_) LPTSTR  pszDest,
    _In_ size_t  cbDest,
    _In_ _Printf_format_string_ LPCTSTR pszFormat,
    _In_ va_list argList
    );
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'vsprintf'.
    The size of the destination buffer (in bytes) is a parameter and
    this function will not write past the end of this buffer and it will
    ALWAYS null terminate the destination buffer (unless it is zero length).
  
    This function returns a hresult, and not a pointer.  It returns
    S_OK if the string was printed without truncation and null terminated,
    otherwise it will return a failure code. In failure cases it will return
    a truncated version of the ideal result.
  
  Arguments:
  
  pszDest     -  destination string
  
  cbDest      -  size of destination buffer in bytes
  length must be sufficient to hold the resulting formatted
  string, including the null terminator.
  
  pszFormat   -  format string which must be null terminated
  
  argList     -  va_list from the variable arguments according to the
  stdarg.h convention
  
  Notes:
  Behavior is undefined if destination, format strings or any arguments
  strings overlap.
  
  pszDest and pszFormat should not be NULL.  See StringCbVPrintfEx if you
  require the handling of NULL values.
  
  
  Return Value:
  
  S_OK           -   if there was sufficient space in the dest buffer for
  the resultant string and it was null terminated.
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  STRSAFE_E_INSUFFICIENT_BUFFER /
  HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  -   this return value is an indication that the print
  operation failed due to insufficient space. When this
  error occurs, the destination buffer is modified to
  contain a truncated version of the ideal result and is
  null terminated. This is useful for situations where
  truncation is ok.
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbVPrintf  StringCbVPrintfW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbVPrintf  StringCbVPrintfA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCbVPrintfA(
              _Out_writes_bytes_(cbDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cbDest,
              _In_ _Printf_format_string_ STRSAFE_LPCSTR pszFormat,
              _In_ va_list argList)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(char);
  
      hr = StringValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          hr = StringVPrintfWorkerA(pszDest,
                  cchDest,
                  NULL,
                  pszFormat,
                  argList);
      }
      else if (cchDest > 0)
      {
          *pszDest = '\0';
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable : __WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION)
  
  STRSAFEAPI
      StringCbVPrintfW(
              _Out_writes_bytes_(cbDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cbDest,
              _In_ _Printf_format_string_ STRSAFE_LPCWSTR pszFormat,
              _In_ va_list argList)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(wchar_t);
  
      hr = StringValidateDestW(pszDest, cchDest, STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          hr = StringVPrintfWorkerW(pszDest,
                  cchDest,
                  NULL,
                  pszFormat,
                  argList);
      }
      else if (cchDest > 0)
      {
          *pszDest = '\0';
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CB_FUNCTIONS
  
  
  #if defined(STRSAFE_LOCALE_FUNCTIONS) && !defined(STRSAFE_NO_CB_FUNCTIONS)
  /*++
  
    STDAPI
    StringCbVPrintf_l(
    _Out_writes_bytes_(cbDest) _Always_(_Post_z_) LPTSTR  pszDest,
    _In_ size_t  cbDest,
    _In_ _Printf_format_string_params_(2) LPCTSTR pszFormat,
    _In_ local_t locale,
    _In_ va_list argList
    );
  
    Routine Description:
  
    This routine is a version of StringCbVPrintf that also takes a locale.
    Please see notes for StringCbVPrintf above.
  
    --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbVPrintf_l   StringCbVPrintf_lW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbVPrintf_l   StringCbVPrintf_lA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable: __WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION)
  
  STRSAFEAPI
      StringCbVPrintf_lA(
              _Out_writes_bytes_(cbDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cbDest,
              _In_ _Printf_format_string_params_(2) STRSAFE_LPCSTR pszFormat,
              _In_ _locale_t locale,
              _In_ va_list argList)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(char);
  
      hr = StringValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          hr = StringVPrintf_lWorkerA(pszDest,
                  cchDest,
                  NULL,
                  pszFormat,
                  locale,
                  argList);
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCbVPrintf_lW(
              _Out_writes_bytes_(cbDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cbDest,
              _In_ _Printf_format_string_params_(2) STRSAFE_LPCWSTR pszFormat,
              _In_ _locale_t locale,
              _In_ va_list argList)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(wchar_t);
  
      hr = StringValidateDestW(pszDest, cchDest, STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          hr = StringVPrintf_lWorkerW(pszDest,
                  cchDest,
                  NULL,
                  pszFormat,
                  locale,
                  argList);
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // STRSAFE_LOCALE_FUNCTIONS && !STRSAFE_NO_CB_FUNCTIONS
  
  
  #ifndef _M_CEE_PURE
  
  #ifndef STRSAFE_NO_CCH_FUNCTIONS
  /*++
  
    STDAPI
    StringCchPrintf(
    _Out_writes_(cchDest) _Always_(_Post_z_) LPTSTR  pszDest,
    _In_ size_t  cchDest,
    _In_ _Printf_format_string_  LPCTSTR pszFormat,
    ...
    );
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'sprintf'.
    The size of the destination buffer (in characters) is a parameter and
    this function will not write past the end of this buffer and it will
    ALWAYS null terminate the destination buffer (unless it is zero length).
  
    This function returns a hresult, and not a pointer.  It returns
    S_OK if the string was printed without truncation and null terminated,
    otherwise it will return a failure code. In failure cases it will return
    a truncated version of the ideal result.
  
  Arguments:
  
  pszDest     -  destination string
  
  cchDest     -  size of destination buffer in characters
  length must be sufficient to hold the resulting formatted
  string, including the null terminator.
  
  pszFormat   -  format string which must be null terminated
  
  ...         -  additional parameters to be formatted according to
  the format string
  
  Notes:
  Behavior is undefined if destination, format strings or any arguments
  strings overlap.
  
  pszDest and pszFormat should not be NULL.  See StringCchPrintfEx if you
  require the handling of NULL values.
  
  Return Value:
  
  S_OK           -   if there was sufficient space in the dest buffer for
  the resultant string and it was null terminated.
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  STRSAFE_E_INSUFFICIENT_BUFFER /
  HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  -   this return value is an indication that the print
  operation failed due to insufficient space. When this
  error occurs, the destination buffer is modified to
  contain a truncated version of the ideal result and is
  null terminated. This is useful for situations where
  truncation is ok.
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchPrintf  StringCchPrintfW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchPrintf  StringCchPrintfA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCchPrintfA(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cchDest,
              _In_ _Printf_format_string_ STRSAFE_LPCSTR pszFormat,
              ...)
  {
      HRESULT hr;
  
      hr = StringValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          va_list argList;
  
          va_start(argList, pszFormat);
  
          hr = StringVPrintfWorkerA(pszDest,
                  cchDest,
                  NULL,
                  pszFormat,
                  argList);
  
          va_end(argList);
      }
      else if (cchDest > 0)
      {
          *pszDest = '\0';
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCchPrintfW(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cchDest,
              _In_ _Printf_format_string_ STRSAFE_LPCWSTR pszFormat,
              ...)
  {
      HRESULT hr;
  
      hr = StringValidateDestW(pszDest, cchDest, STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          va_list argList;
  
          va_start(argList, pszFormat);
  
          hr = StringVPrintfWorkerW(pszDest,
                  cchDest,
                  NULL,
                  pszFormat,
                  argList);
  
          va_end(argList);
      }
      else if (cchDest > 0)
      {
          *pszDest = '\0';
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  
  
  #if defined(STRSAFE_LOCALE_FUNCTIONS) && !defined(STRSAFE_NO_CCH_FUNCTIONS)
  /*++
  
    STDAPI
    StringCchPrintf_l(
    _Out_writes_(cchDest) _Always_(_Post_z_) LPTSTR  pszDest,
    _In_ size_t  cchDest,
    _In_ _Printf_format_string_params_(2)  LPCTSTR pszFormat,
    _In_  locale_t locale,
    ...
    );
  
    Routine Description:
  
    This routine is a version of a StringCchPrintf_l that also takes a locale.
    Please see notes for StringCchPrintf above.
  
    --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchPrintf_l   StringCchPrintf_lW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchPrintf_l   StringCchPrintf_lA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable: __WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION)
  
  STRSAFEAPI
      StringCchPrintf_lA(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cchDest,
              _In_ _Printf_format_string_params_(2) STRSAFE_LPCSTR pszFormat,
              _In_ _locale_t locale,
              ...)
  {
      HRESULT hr;
  
      hr = StringValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          va_list argList;
  
          va_start(argList, locale);
  
          hr = StringVPrintf_lWorkerA(pszDest,
                  cchDest,
                  NULL,
                  pszFormat,
                  locale,
                  argList);
  
          va_end(argList);
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable: __WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION)
  
  STRSAFEAPI
      StringCchPrintf_lW(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cchDest,
              _In_ _Printf_format_string_params_(2) STRSAFE_LPCWSTR pszFormat,
              _In_ _locale_t locale,
              ...)
  {
      HRESULT hr;
  
      hr = StringValidateDestW(pszDest, cchDest, STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          va_list argList;
  
          va_start(argList, locale);
  
          hr = StringVPrintf_lWorkerW(pszDest,
                  cchDest,
                  NULL,
                  pszFormat,
                  locale,
                  argList);
  
          va_end(argList);
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // STRSAFE_LOCALE_FUNCTIONS && !STRSAFE_NO_CCH_FUNCTIONS
  
  
  #ifndef STRSAFE_NO_CB_FUNCTIONS
  /*++
  
    STDAPI
    StringCbPrintf(
    _Out_writes_bytes_(cbDest) _Always_(_Post_z_) LPTSTR  pszDest,
    _In_ size_t  cbDest,
    _In_ _Printf_format_string_ LPCTSTR pszFormat,
    ...
    );
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'sprintf'.
    The size of the destination buffer (in bytes) is a parameter and
    this function will not write past the end of this buffer and it will
    ALWAYS null terminate the destination buffer (unless it is zero length).
  
    This function returns a hresult, and not a pointer.  It returns
    S_OK if the string was printed without truncation and null terminated,
    otherwise it will return a failure code. In failure cases it will return
    a truncated version of the ideal result.
  
  Arguments:
  
  pszDest     -  destination string
  
  cbDest      -  size of destination buffer in bytes
  length must be sufficient to hold the resulting formatted
  string, including the null terminator.
  
  pszFormat   -  format string which must be null terminated
  
  ...         -  additional parameters to be formatted according to
  the format string
  
  Notes:
  Behavior is undefined if destination, format strings or any arguments
  strings overlap.
  
  pszDest and pszFormat should not be NULL.  See StringCbPrintfEx if you
  require the handling of NULL values.
  
  
  Return Value:
  
  S_OK           -   if there was sufficient space in the dest buffer for
  the resultant string and it was null terminated.
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  STRSAFE_E_INSUFFICIENT_BUFFER /
  HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  -   this return value is an indication that the print
  operation failed due to insufficient space. When this
  error occurs, the destination buffer is modified to
  contain a truncated version of the ideal result and is
  null terminated. This is useful for situations where
  truncation is ok.
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbPrintf  StringCbPrintfW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbPrintf  StringCbPrintfA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCbPrintfA(
              _Out_writes_bytes_(cbDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cbDest,
              _In_ _Printf_format_string_ STRSAFE_LPCSTR pszFormat,
              ...)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(char);
  
      hr = StringValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          va_list argList;
  
          va_start(argList, pszFormat);
  
          hr = StringVPrintfWorkerA(pszDest,
                  cchDest,
                  NULL,
                  pszFormat,
                  argList);
  
          va_end(argList);
      }
      else if (cchDest > 0)
      {
          *pszDest = '\0';
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable : __WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION)
  
  STRSAFEAPI
      StringCbPrintfW(
              _Out_writes_bytes_(cbDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cbDest,
              _In_ _Printf_format_string_ STRSAFE_LPCWSTR pszFormat,
              ...)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(wchar_t);
  
      hr = StringValidateDestW(pszDest, cchDest, STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          va_list argList;
  
          va_start(argList, pszFormat);
  
          hr = StringVPrintfWorkerW(pszDest,
                  cchDest,
                  NULL,
                  pszFormat,
                  argList);
  
          va_end(argList);
      }
      else if (cchDest > 0)
      {
          *pszDest = L'\0';
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CB_FUNCTIONS
  
  
  #if defined(STRSAFE_LOCALE_FUNCTIONS) && !defined(STRSAFE_NO_CB_FUNCTIONS)
  /*++
  
    STDAPI
    StringCbPrintf_l(
    _Out_writes_bytes_(cbDest) _Always_(_Post_z_) LPTSTR  pszDest,
    _In_ size_t  cbDest,
    _In_ _Printf_format_string_params_(2) LPCTSTR pszFormat,
    _In_ locale_t locale,
    ...
    );
  
    Routine Description:
  
    This routine is a version of StringCbPrintf that also takes a locale.
    Please see notes for StringCbPrintf above.
  
    --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbPrintf_l    StringCbPrintf_lW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbPrintf_l    StringCbPrintf_lA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable: __WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION)
  
  STRSAFEAPI
      StringCbPrintf_lA(
              _Out_writes_bytes_(cbDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cbDest,
              _In_ _Printf_format_string_params_(2) STRSAFE_LPCSTR pszFormat,
              _In_ _locale_t locale,
              ...)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(char);
  
      hr = StringValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          va_list argList;
  
          va_start(argList, locale);
  
          hr = StringVPrintf_lWorkerA(pszDest,
                  cchDest,
                  NULL,
                  pszFormat,
                  locale,
                  argList);
  
          va_end(argList);
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCbPrintf_lW(
              _Out_writes_bytes_(cbDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cbDest,
              _In_ _Printf_format_string_params_(2) STRSAFE_LPCWSTR pszFormat,
              _In_ _locale_t locale,
              ...)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(wchar_t);
  
      hr = StringValidateDestW(pszDest, cchDest, STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          va_list argList;
  
          va_start(argList, locale);
  
          hr = StringVPrintf_lWorkerW(pszDest,
                  cchDest,
                  NULL,
                  pszFormat,
                  locale,
                  argList);
  
          va_end(argList);
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // STRSAFE_LOCALE_FUNCTIONS && !STRSAFE_NO_CB_FUNCTIONS
  
  
  #ifndef STRSAFE_NO_CCH_FUNCTIONS
  /*++
  
    STDAPI
    StringCchPrintfEx(
    _Out_writes_(cchDest) _Always_(_Post_z_) LPTSTR  pszDest         OPTIONAL,
    _In_  size_t  cchDest,
    _Outptr_opt_result_buffer_(*pcchRemaining) LPTSTR* ppszDestEnd     OPTIONAL,
    _Out_opt_ size_t* pcchRemaining   OPTIONAL,
    _In_ DWORD   dwFlags,
    _In_ _Printf_format_string_ LPCTSTR pszFormat       OPTIONAL,
    ...
    );
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'sprintf' with
    some additional parameters.  In addition to functionality provided by
    StringCchPrintf, this routine also returns a pointer to the end of the
    destination string and the number of characters left in the destination string
    including the null terminator. The flags parameter allows additional controls.
  
  Arguments:
  
  pszDest         -   destination string
  
  cchDest         -   size of destination buffer in characters.
  length must be sufficient to contain the resulting
  formatted string plus the null terminator.
  
  ppszDestEnd     -   if ppszDestEnd is non-null, the function will return a
  pointer to the end of the destination string.  If the
  function printed any data, the result will point to the
  null termination character
  
  pcchRemaining   -   if pcchRemaining is non-null, the function will return
  the number of characters left in the destination string,
  including the null terminator
  
  dwFlags         -   controls some details of the string copy:
  
  STRSAFE_FILL_BEHIND_NULL
  if the function succeeds, the low byte of dwFlags will be
  used to fill the uninitialize part of destination buffer
  behind the null terminator
  
  STRSAFE_IGNORE_NULLS
  treat NULL string pointers like empty strings (TEXT(""))
  
  STRSAFE_FILL_ON_FAILURE
  if the function fails, the low byte of dwFlags will be
  used to fill all of the destination buffer, and it will
  be null terminated. This will overwrite any truncated
  string returned when the failure is
  STRSAFE_E_INSUFFICIENT_BUFFER
  
  STRSAFE_NO_TRUNCATION /
  STRSAFE_NULL_ON_FAILURE
  if the function fails, the destination buffer will be set
  to the empty string. This will overwrite any truncated string
  returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
  
  pszFormat       -   format string which must be null terminated
  
  ...             -   additional parameters to be formatted according to
  the format string
  
  Notes:
  Behavior is undefined if destination, format strings or any arguments
  strings overlap.
  
  pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS
  flag is specified.  If STRSAFE_IGNORE_NULLS is passed, both pszDest and
  pszFormat may be NULL.  An error may still be returned even though NULLS
  are ignored due to insufficient space.
  
  Return Value:
  
  S_OK           -   if there was sufficient space in the dest buffer for
  the resultant string and it was null terminated.
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  STRSAFE_E_INSUFFICIENT_BUFFER /
  HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  -   this return value is an indication that the print
  operation failed due to insufficient space. When this
  error occurs, the destination buffer is modified to
  contain a truncated version of the ideal result and is
  null terminated. This is useful for situations where
  truncation is ok.
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchPrintfEx  StringCchPrintfExW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchPrintfEx  StringCchPrintfExA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable : __WARNING_INCORRECT_ANNOTATION)
  
  STRSAFEAPI
      StringCchPrintfExA(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cchDest,
              _Outptr_opt_result_buffer_(*pcchRemaining) STRSAFE_LPSTR* ppszDestEnd,
              _Out_opt_ size_t* pcchRemaining,
              _In_ DWORD dwFlags,
              _In_ _Printf_format_string_ STRSAFE_LPCSTR pszFormat,
              ...)
  {
      HRESULT hr;
  
      hr = StringExValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH, dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPSTR pszDestEnd = pszDest;
          size_t cchRemaining = cchDest;
  
          hr = StringExValidateSrcA(&pszFormat, NULL, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
  
                  if (cchDest != 0)
                  {
                      *pszDest = '\0';
                  }
              }
              else if (cchDest == 0)
              {
                  // only fail if there was actually a non-empty format string
                  if (*pszFormat != '\0')
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
              }
              else
              {
                  size_t cchNewDestLength = 0;
                  va_list argList;
  
                  va_start(argList, pszFormat);
  
                  hr = StringVPrintfWorkerA(pszDest,
                          cchDest,
                          &cchNewDestLength,
                          pszFormat,
                          argList);
  
                  va_end(argList);
  
                  pszDestEnd = pszDest + cchNewDestLength;
                  cchRemaining = cchDest - cchNewDestLength;
  
                  if (SUCCEEDED(hr)                           &&
                          (dwFlags & STRSAFE_FILL_BEHIND_NULL)    &&
                          (cchRemaining > 1))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
                      cbRemaining = cchRemaining * sizeof(char);
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullA(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
          else
          {
              if (cchDest != 0)
              {
                  *pszDest = '\0';
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cchDest != 0))
          {
              size_t cbDest;
  
              // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
              cbDest = cchDest * sizeof(char);
  
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsA(pszDest,
                      cbDest,
                      0,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcchRemaining)
              {
                  *pcchRemaining = cchRemaining;
              }
          }
      }
      else if (cchDest > 0)
      {
          *pszDest = '\0';
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable : __WARNING_INCORRECT_ANNOTATION)
  
  STRSAFEAPI
      StringCchPrintfExW(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cchDest,
              _Outptr_opt_result_buffer_(*pcchRemaining) STRSAFE_LPWSTR* ppszDestEnd,
              _Out_opt_ size_t* pcchRemaining,
              _In_ DWORD dwFlags,
              _In_ _Printf_format_string_ STRSAFE_LPCWSTR pszFormat,
              ...)
  {
      HRESULT hr;
  
      hr = StringExValidateDestW(pszDest, cchDest, STRSAFE_MAX_CCH, dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPWSTR pszDestEnd = pszDest;
          size_t cchRemaining = cchDest;
  
          hr = StringExValidateSrcW(&pszFormat, NULL, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
  
                  if (cchDest != 0)
                  {
                      *pszDest = L'\0';
                  }
              }
              else if (cchDest == 0)
              {
                  // only fail if there was actually a non-empty format string
                  if (*pszFormat != L'\0')
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
              }
              else
              {
                  size_t cchNewDestLength = 0;
                  va_list argList;
  
                  va_start(argList, pszFormat);
  
                  hr = StringVPrintfWorkerW(pszDest,
                          cchDest,
                          &cchNewDestLength,
                          pszFormat,
                          argList);
  
                  va_end(argList);
  
                  pszDestEnd = pszDest + cchNewDestLength;
                  cchRemaining = cchDest - cchNewDestLength;
  
                  if (SUCCEEDED(hr)                           &&
                          (dwFlags & STRSAFE_FILL_BEHIND_NULL)    &&
                          (cchRemaining > 1))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
                      cbRemaining = cchRemaining * sizeof(wchar_t);
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullW(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
          else
          {
              if (cchDest != 0)
              {
                  *pszDest = L'\0';
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cchDest != 0))
          {
              size_t cbDest;
  
              // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
              cbDest = cchDest * sizeof(wchar_t);
  
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsW(pszDest,
                      cbDest,
                      0,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcchRemaining)
              {
                  *pcchRemaining = cchRemaining;
              }
          }
      }
      else if (cchDest > 0)
      {
          *pszDest = L'\0';
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  
  
  #if defined(STRSAFE_LOCALE_FUNCTIONS) && !defined(STRSAFE_NO_CCH_FUNCTIONS)
  /*++
  
    STDAPI
    StringCchPrintf_lEx(
    _Out_writes_(cchDest) _Always_(_Post_z_) LPTSTR  pszDest         OPTIONAL,
    _In_ size_t  cchDest,
    _Outptr_opt_result_buffer_(*pcchRemaining) LPTSTR* ppszDestEnd     OPTIONAL,
    _Out_opt_ size_t* pcchRemaining   OPTIONAL,
    _In_ DWORD   dwFlags,
    _In_ _Printf_format_string_params_(2) LPCTSTR pszFormat       OPTIONAL,
    _In_ locale_t locale,
    ...
    );
  
    Routine Description:
  
    This routine is a version of StringCchPrintfEx that also takes a locale.
    Please see notes for StringCchPrintfEx above.
  
    --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchPrintf_lEx StringCchPrintf_lExW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchPrintf_lEx StringCchPrintf_lExA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable: __WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION)
  
  STRSAFEAPI
      StringCchPrintf_lExA(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cchDest,
              _Outptr_opt_result_buffer_(*pcchRemaining) STRSAFE_LPSTR* ppszDestEnd,
              _Out_opt_ size_t* pcchRemaining,
              _In_ DWORD dwFlags,
              _In_ _Printf_format_string_params_(2) STRSAFE_LPCSTR pszFormat,
              _In_ _locale_t locale,
              ...)
  {
      HRESULT hr;
  
      hr = StringExValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH, dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPSTR pszDestEnd = pszDest;
          size_t cchRemaining = cchDest;
  
          hr = StringExValidateSrcA(&pszFormat, NULL, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
  
                  if (cchDest != 0)
                  {
                      *pszDest = '\0';
                  }
              }
              else if (cchDest == 0)
              {
                  // only fail if there was actually a non-empty format string
                  if (*pszFormat != '\0')
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
              }
              else
              {
                  size_t cchNewDestLength = 0;
                  va_list argList;
  
                  va_start(argList, locale);
  
                  hr = StringVPrintf_lWorkerA(pszDest,
                          cchDest,
                          &cchNewDestLength,
                          pszFormat,
                          locale,
                          argList);
  
                  va_end(argList);
  
                  pszDestEnd = pszDest + cchNewDestLength;
                  cchRemaining = cchDest - cchNewDestLength;
  
                  if (SUCCEEDED(hr)                           &&
                          (dwFlags & STRSAFE_FILL_BEHIND_NULL)    &&
                          (cchRemaining > 1))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
                      cbRemaining = cchRemaining * sizeof(char);
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullA(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
          else
          {
              if (cchDest != 0)
              {
                  *pszDest = '\0';
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cchDest != 0))
          {
              size_t cbDest;
  
              // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
              cbDest = cchDest * sizeof(char);
  
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsA(pszDest,
                      cbDest,
                      0,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcchRemaining)
              {
                  *pcchRemaining = cchRemaining;
              }
          }
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable: __WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION)
  
  STRSAFEAPI
      StringCchPrintf_lExW(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cchDest,
              _Outptr_opt_result_buffer_(*pcchRemaining) STRSAFE_LPWSTR* ppszDestEnd,
              _Out_opt_ size_t* pcchRemaining,
              _In_ DWORD dwFlags,
              _In_ _Printf_format_string_params_(2) STRSAFE_LPCWSTR pszFormat,
              _In_ _locale_t locale,
              ...)
  {
      HRESULT hr;
  
      hr = StringExValidateDestW(pszDest, cchDest, STRSAFE_MAX_CCH, dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPWSTR pszDestEnd = pszDest;
          size_t cchRemaining = cchDest;
  
          hr = StringExValidateSrcW(&pszFormat, NULL, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
  
                  if (cchDest != 0)
                  {
                      *pszDest = L'\0';
                  }
              }
              else if (cchDest == 0)
              {
                  // only fail if there was actually a non-empty format string
                  if (*pszFormat != L'\0')
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
              }
              else
              {
                  size_t cchNewDestLength = 0;
                  va_list argList;
  
                  va_start(argList, locale);
  
                  hr = StringVPrintf_lWorkerW(pszDest,
                          cchDest,
                          &cchNewDestLength,
                          pszFormat,
                          locale,
                          argList);
  
                  va_end(argList);
  
                  pszDestEnd = pszDest + cchNewDestLength;
                  cchRemaining = cchDest - cchNewDestLength;
  
                  if (SUCCEEDED(hr)                           &&
                          (dwFlags & STRSAFE_FILL_BEHIND_NULL)    &&
                          (cchRemaining > 1))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
                      cbRemaining = cchRemaining * sizeof(wchar_t);
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullW(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
          else
          {
              if (cchDest != 0)
              {
                  *pszDest = L'\0';
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cchDest != 0))
          {
              size_t cbDest;
  
              // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
              cbDest = cchDest * sizeof(wchar_t);
  
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsW(pszDest,
                      cbDest,
                      0,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcchRemaining)
              {
                  *pcchRemaining = cchRemaining;
              }
          }
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // STRSAFE_LOCALE_FUNCTIONS && !STRSAFE_NO_CCH_FUNCTIONS
  
  
  #ifndef STRSAFE_NO_CB_FUNCTIONS
  /*++
  
    STDAPI
    StringCbPrintfEx(
    _Out_writes_bytes_(cbDest) _Always_(_Post_z_) LPTSTR  pszDest         OPTIONAL,
    _In_ size_t  cbDest,
    _Outptr_opt_result_bytebuffer_(*pcbRemaining) LPTSTR* ppszDestEnd     OPTIONAL,
    _Out_opt_ size_t* pcbRemaining    OPTIONAL,
    _In_ DWORD   dwFlags,
    _In_ _Printf_format_string_ LPCTSTR pszFormat       OPTIONAL,
    ...
    );
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'sprintf' with
    some additional parameters.  In addition to functionality provided by
    StringCbPrintf, this routine also returns a pointer to the end of the
    destination string and the number of bytes left in the destination string
    including the null terminator. The flags parameter allows additional controls.
  
  Arguments:
  
  pszDest         -   destination string
  
  cbDest          -   size of destination buffer in bytes.
  length must be sufficient to contain the resulting
  formatted string plus the null terminator.
  
  ppszDestEnd     -   if ppszDestEnd is non-null, the function will return a
  pointer to the end of the destination string.  If the
  function printed any data, the result will point to the
  null termination character
  
  pcbRemaining    -   if pcbRemaining is non-null, the function will return
  the number of bytes left in the destination string,
  including the null terminator
  
  dwFlags         -   controls some details of the string copy:
  
  STRSAFE_FILL_BEHIND_NULL
  if the function succeeds, the low byte of dwFlags will be
  used to fill the uninitialize part of destination buffer
  behind the null terminator
  
  STRSAFE_IGNORE_NULLS
  treat NULL string pointers like empty strings (TEXT(""))
  
  STRSAFE_FILL_ON_FAILURE
  if the function fails, the low byte of dwFlags will be
  used to fill all of the destination buffer, and it will
  be null terminated. This will overwrite any truncated
  string returned when the failure is
  STRSAFE_E_INSUFFICIENT_BUFFER
  
  STRSAFE_NO_TRUNCATION /
  STRSAFE_NULL_ON_FAILURE
  if the function fails, the destination buffer will be set
  to the empty string. This will overwrite any truncated string
  returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
  
  pszFormat       -   format string which must be null terminated
  
  ...             -   additional parameters to be formatted according to
  the format string
  
  Notes:
  Behavior is undefined if destination, format strings or any arguments
  strings overlap.
  
  pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS
  flag is specified.  If STRSAFE_IGNORE_NULLS is passed, both pszDest and
  pszFormat may be NULL.  An error may still be returned even though NULLS
  are ignored due to insufficient space.
  
  Return Value:
  
  S_OK           -   if there was source data and it was all concatenated and
  the resultant dest string was null terminated
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  STRSAFE_E_INSUFFICIENT_BUFFER /
  HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  -   this return value is an indication that the print
  operation failed due to insufficient space. When this
  error occurs, the destination buffer is modified to
  contain a truncated version of the ideal result and is
  null terminated. This is useful for situations where
  truncation is ok.
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbPrintfEx  StringCbPrintfExW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbPrintfEx  StringCbPrintfExA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable : __WARNING_INCORRECT_ANNOTATION)
  
  STRSAFEAPI
      StringCbPrintfExA(
              _Out_writes_bytes_(cbDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cbDest,
              _Outptr_opt_result_bytebuffer_(*pcbRemaining) STRSAFE_LPSTR* ppszDestEnd,
              _Out_opt_ size_t* pcbRemaining,
              _In_ DWORD dwFlags,
              _In_ _Printf_format_string_ STRSAFE_LPCSTR pszFormat,
              ...)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(char);
  
      hr = StringExValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH, dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPSTR pszDestEnd = pszDest;
          size_t cchRemaining = cchDest;
  
          hr = StringExValidateSrcA(&pszFormat, NULL, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
  
                  if (cchDest != 0)
                  {
                      *pszDest = '\0';
                  }
              }
              else if (cchDest == 0)
              {
                  // only fail if there was actually a non-empty format string
                  if (*pszFormat != '\0')
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
                  else
                  {
                      // for consistency with other use in this case...
                      __analysis_assume_nullterminated(pszDest);
                  }
              }
              else
              {
                  size_t cchNewDestLength = 0;
                  va_list argList;
  
                  va_start(argList, pszFormat);
  
                  hr = StringVPrintfWorkerA(pszDest,
                          cchDest,
                          &cchNewDestLength,
                          pszFormat,
                          argList);
  
                  va_end(argList);
  
                  pszDestEnd = pszDest + cchNewDestLength;
                  cchRemaining = cchDest - cchNewDestLength;
  
                  if (SUCCEEDED(hr)                           &&
                          (dwFlags & STRSAFE_FILL_BEHIND_NULL)    &&
                          (cchRemaining > 1))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
                      cbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullA(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
          else
          {
              if (cchDest != 0)
              {
                  *pszDest = '\0';
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cbDest != 0))
          {
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsA(pszDest,
                      cbDest,
                      0,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcbRemaining)
              {
                  // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
                  *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
              }
          }
      }
      else if (cchDest > 0)
      {
          *pszDest = '\0';
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable : __WARNING_INCORRECT_ANNOTATION)
  #pragma warning(disable: __WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION)
  
  STRSAFEAPI
      StringCbPrintfExW(
              _Out_writes_bytes_(cbDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cbDest,
              _Outptr_opt_result_bytebuffer_(*pcbRemaining) STRSAFE_LPWSTR* ppszDestEnd,
              _Out_opt_ size_t* pcbRemaining,
              _In_ DWORD dwFlags,
              _In_ _Printf_format_string_ STRSAFE_LPCWSTR pszFormat,
              ...)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(wchar_t);
  
      hr = StringExValidateDestW(pszDest, cchDest, STRSAFE_MAX_CCH, dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPWSTR pszDestEnd = pszDest;
          size_t cchRemaining = cchDest;
  
          hr = StringExValidateSrcW(&pszFormat, NULL, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
  
                  if (cchDest != 0)
                  {
                      *pszDest = L'\0';
                  }
              }
              else if (cchDest == 0)
              {
                  // only fail if there was actually a non-empty format string
                  if (*pszFormat != L'\0')
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
                  else
                  {
                      // for consistency with other use in this case...
                      __analysis_assume_nullterminated(pszDest);
                  }
              }
              else
              {
                  size_t cchNewDestLength = 0;
                  va_list argList;
  
                  va_start(argList, pszFormat);
  
                  hr = StringVPrintfWorkerW(pszDest,
                          cchDest,
                          &cchNewDestLength,
                          pszFormat,
                          argList);
  
                  va_end(argList);
  
                  pszDestEnd = pszDest + cchNewDestLength;
                  cchRemaining = cchDest - cchNewDestLength;
  
                  if (SUCCEEDED(hr) && (dwFlags & STRSAFE_FILL_BEHIND_NULL))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
                      cbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullW(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
          else
          {
              if (cchDest != 0)
              {
                  *pszDest = L'\0';
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cbDest != 0))
          {
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsW(pszDest,
                      cbDest,
                      0,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcbRemaining)
              {
                  // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
                  *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
              }
          }
      }
      else if (cchDest > 0)
      {
          *pszDest = L'\0';
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CB_FUNCTIONS
  
  
  #if defined(STRSAFE_LOCALE_FUNCTIONS) && !defined(STRSAFE_NO_CB_FUNCTIONS)
  /*++
  
    STDAPI
    StringCbPrintf_lEx(
    _Out_writes_bytes_(cbDest) _Always_(_Post_z_) LPTSTR  pszDest         OPTIONAL,
    _In_ size_t  cbDest,
    _Outptr_opt_result_bytebuffer_(*pcbRemaining) LPTSTR* ppszDestEnd     OPTIONAL,
    _Out_opt_ size_t* pcbRemaining    OPTIONAL,
    _In_ DWORD   dwFlags,
    _In_ _Printf_format_string_params_(2) LPCTSTR pszFormat       OPTIONAL,
    _In_ locale_t locale,
    ...
    );
  
    Routine Description:
  
    This routine is a version of StringCbPrintfEx that also takes a locale.
    Please seee notes for StringCbPrintfEx above.
  
    --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbPrintf_lEx  StringCbPrintf_lExW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbPrintf_lEx  StringCbPrintf_lExA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable: __WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION)
  
  STRSAFEAPI
      StringCbPrintf_lExA(
              _Out_writes_bytes_(cbDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cbDest,
              _Outptr_opt_result_bytebuffer_(*pcbRemaining) STRSAFE_LPSTR* ppszDestEnd,
              _Out_opt_ size_t* pcbRemaining,
              _In_ DWORD dwFlags,
              _In_ _Printf_format_string_params_(2) STRSAFE_LPCSTR pszFormat,
              _In_ _locale_t locale,
              ...)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(char);
  
      hr = StringExValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH, dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPSTR pszDestEnd = pszDest;
          size_t cchRemaining = cchDest;
  
          hr = StringExValidateSrcA(&pszFormat, NULL, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
  
                  if (cchDest != 0)
                  {
                      *pszDest = '\0';
                  }
              }
              else if (cchDest == 0)
              {
                  // only fail if there was actually a non-empty format string
                  if (*pszFormat != '\0')
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
              }
              else
              {
                  size_t cchNewDestLength = 0;
                  va_list argList;
  
                  va_start(argList, locale);
  
                  hr = StringVPrintf_lWorkerA(pszDest,
                          cchDest,
                          &cchNewDestLength,
                          pszFormat,
                          locale,
                          argList);
  
                  va_end(argList);
  
                  pszDestEnd = pszDest + cchNewDestLength;
                  cchRemaining = cchDest - cchNewDestLength;
  
                  if (SUCCEEDED(hr)                           &&
                          (dwFlags & STRSAFE_FILL_BEHIND_NULL)    &&
                          (cchRemaining > 1))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
                      cbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullA(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
          else
          {
              if (cchDest != 0)
              {
                  *pszDest = '\0';
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cbDest != 0))
          {
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsA(pszDest,
                      cbDest,
                      0,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcbRemaining)
              {
                  // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
                  *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
              }
          }
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable: __WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION)
  
  STRSAFEAPI
      StringCbPrintf_lExW(
              _Out_writes_bytes_(cbDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cbDest,
              _Outptr_opt_result_bytebuffer_(*pcbRemaining) STRSAFE_LPWSTR* ppszDestEnd,
              _Out_opt_ size_t* pcbRemaining,
              _In_ DWORD dwFlags,
              _In_ _Printf_format_string_params_(2) STRSAFE_LPCWSTR pszFormat,
              _In_ _locale_t locale,
              ...)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(wchar_t);
  
      hr = StringExValidateDestW(pszDest, cchDest, STRSAFE_MAX_CCH, dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPWSTR pszDestEnd = pszDest;
          size_t cchRemaining = cchDest;
  
          hr = StringExValidateSrcW(&pszFormat, NULL, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
  
                  if (cchDest != 0)
                  {
                      *pszDest = L'\0';
                  }
              }
              else if (cchDest == 0)
              {
                  // only fail if there was actually a non-empty format string
                  if (*pszFormat != L'\0')
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
              }
              else
              {
                  size_t cchNewDestLength = 0;
                  va_list argList;
  
                  va_start(argList, locale);
  
                  hr = StringVPrintf_lWorkerW(pszDest,
                          cchDest,
                          &cchNewDestLength,
                          pszFormat,
                          locale,
                          argList);
  
                  va_end(argList);
  
                  pszDestEnd = pszDest + cchNewDestLength;
                  cchRemaining = cchDest - cchNewDestLength;
  
                  if (SUCCEEDED(hr) && (dwFlags & STRSAFE_FILL_BEHIND_NULL))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
                      cbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullW(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
          else
          {
              if (cchDest != 0)
              {
                  *pszDest = L'\0';
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cbDest != 0))
          {
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsW(pszDest,
                      cbDest,
                      0,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcbRemaining)
              {
                  // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
                  *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
              }
          }
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // STRSAFE_LOCALE_FUNCTIONS && !STRSAFE_NO_CB_FUNCTIONS
  
  #endif  // !_M_CEE_PURE
  
  
  #ifndef STRSAFE_NO_CCH_FUNCTIONS
  /*++
  
    STDAPI
    StringCchVPrintfEx(
    _Out_writes_(cchDest) _Always_(_Post_z_) LPTSTR  pszDest         OPTIONAL,
    _In_ size_t  cchDest,
    _Outptr_opt_result_buffer_(*pcchRemaining) LPTSTR* ppszDestEnd     OPTIONAL,
    _Out_opt_ size_t* pcchRemaining   OPTIONAL,
    _In_ DWORD   dwFlags,
    _In_ _Printf_format_string_ LPCTSTR pszFormat       OPTIONAL,
    _In_ va_list argList
    );
  
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'vsprintf' with
    some additional parameters.  In addition to functionality provided by
    StringCchVPrintf, this routine also returns a pointer to the end of the
    destination string and the number of characters left in the destination string
    including the null terminator. The flags parameter allows additional controls.
  
  Arguments:
  
  pszDest         -   destination string
  
  cchDest         -   size of destination buffer in characters.
  length must be sufficient to contain the resulting
  formatted string plus the null terminator.
  
  ppszDestEnd     -   if ppszDestEnd is non-null, the function will return a
  pointer to the end of the destination string.  If the
  function printed any data, the result will point to the
  null termination character
  
  pcchRemaining   -   if pcchRemaining is non-null, the function will return
  the number of characters left in the destination string,
  including the null terminator
  
  dwFlags         -   controls some details of the string copy:
  
  STRSAFE_FILL_BEHIND_NULL
  if the function succeeds, the low byte of dwFlags will be
  used to fill the uninitialize part of destination buffer
  behind the null terminator
  
  STRSAFE_IGNORE_NULLS
  treat NULL string pointers like empty strings (TEXT(""))
  
  STRSAFE_FILL_ON_FAILURE
  if the function fails, the low byte of dwFlags will be
  used to fill all of the destination buffer, and it will
  be null terminated. This will overwrite any truncated
  string returned when the failure is
  STRSAFE_E_INSUFFICIENT_BUFFER
  
  STRSAFE_NO_TRUNCATION /
  STRSAFE_NULL_ON_FAILURE
  if the function fails, the destination buffer will be set
  to the empty string. This will overwrite any truncated string
  returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
  
  pszFormat       -   format string which must be null terminated
  
  argList         -   va_list from the variable arguments according to the
  stdarg.h convention
  
  Notes:
  Behavior is undefined if destination, format strings or any arguments
  strings overlap.
  
  pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS
  flag is specified.  If STRSAFE_IGNORE_NULLS is passed, both pszDest and
  pszFormat may be NULL.  An error may still be returned even though NULLS
  are ignored due to insufficient space.
  
  Return Value:
  
  S_OK           -   if there was source data and it was all concatenated and
  the resultant dest string was null terminated
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  STRSAFE_E_INSUFFICIENT_BUFFER /
  HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  -   this return value is an indication that the print
  operation failed due to insufficient space. When this
  error occurs, the destination buffer is modified to
  contain a truncated version of the ideal result and is
  null terminated. This is useful for situations where
  truncation is ok.
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchVPrintfEx  StringCchVPrintfExW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchVPrintfEx  StringCchVPrintfExA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable: __WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION)
  #pragma warning(disable : __WARNING_INCORRECT_ANNOTATION)
  
  STRSAFEAPI
      StringCchVPrintfExA(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cchDest,
              _Outptr_opt_result_buffer_(*pcchRemaining) STRSAFE_LPSTR* ppszDestEnd,
              _Out_opt_ size_t* pcchRemaining,
              _In_ DWORD dwFlags,
              _In_ _Printf_format_string_ STRSAFE_LPCSTR pszFormat,
              _In_ va_list argList)
  {
      HRESULT hr;
  
      hr = StringExValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH, dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPSTR pszDestEnd = pszDest;
          size_t cchRemaining = cchDest;
  
          hr = StringExValidateSrcA(&pszFormat, NULL, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
  
                  if (cchDest != 0)
                  {
                      *pszDest = '\0';
                  }
              }
              else if (cchDest == 0)
              {
                  // only fail if there was actually a non-empty format string
                  if (*pszFormat != '\0')
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
              }
              else
              {
                  size_t cchNewDestLength = 0;
  
                  hr = StringVPrintfWorkerA(pszDest,
                          cchDest,
                          &cchNewDestLength,
                          pszFormat,
                          argList);
  
                  pszDestEnd = pszDest + cchNewDestLength;
                  cchRemaining = cchDest - cchNewDestLength;
  
                  if (SUCCEEDED(hr)                           &&
                          (dwFlags & STRSAFE_FILL_BEHIND_NULL)    &&
                          (cchRemaining > 1))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
                      cbRemaining = cchRemaining * sizeof(char);
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullA(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
          else
          {
              if (cchDest != 0)
              {
                  *pszDest = '\0';
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cchDest != 0))
          {
              size_t cbDest;
  
              // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
              cbDest = cchDest * sizeof(char);
  
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsA(pszDest,
                      cbDest,
                      0,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcchRemaining)
              {
                  *pcchRemaining = cchRemaining;
              }
          }
      }
      else if (cchDest > 0)
      {
          *pszDest = '\0';
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable: __WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION)
  #pragma warning(disable : __WARNING_INCORRECT_ANNOTATION)
  
  STRSAFEAPI
      StringCchVPrintfExW(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cchDest,
              _Outptr_opt_result_buffer_(*pcchRemaining) STRSAFE_LPWSTR* ppszDestEnd,
              _Out_opt_ size_t* pcchRemaining,
              _In_ DWORD dwFlags,
              _In_ _Printf_format_string_ STRSAFE_LPCWSTR pszFormat,
              _In_ va_list argList)
  {
      HRESULT hr;
  
      hr = StringExValidateDestW(pszDest, cchDest, STRSAFE_MAX_CCH, dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPWSTR pszDestEnd = pszDest;
          size_t cchRemaining = cchDest;
  
          hr = StringExValidateSrcW(&pszFormat, NULL, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
  
                  if (cchDest != 0)
                  {
                      *pszDest = L'\0';
                  }
              }
              else if (cchDest == 0)
              {
                  // only fail if there was actually a non-empty format string
                  if (*pszFormat != L'\0')
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
              }
              else
              {
                  size_t cchNewDestLength = 0;
  
                  hr = StringVPrintfWorkerW(pszDest,
                          cchDest,
                          &cchNewDestLength,
                          pszFormat,
                          argList);
  
                  pszDestEnd = pszDest + cchNewDestLength;
                  cchRemaining = cchDest - cchNewDestLength;
  
                  if (SUCCEEDED(hr)                           &&
                          (dwFlags & STRSAFE_FILL_BEHIND_NULL)    &&
                          (cchRemaining > 1))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
                      cbRemaining = cchRemaining * sizeof(wchar_t);
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullW(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
          else
          {
              if (cchDest != 0)
              {
                  *pszDest = L'\0';
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cchDest != 0))
          {
              size_t cbDest;
  
              // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
              cbDest = cchDest * sizeof(wchar_t);
  
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsW(pszDest,
                      cbDest,
                      0,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcchRemaining)
              {
                  *pcchRemaining = cchRemaining;
              }
          }
      }
      else if (cchDest > 0)
      {
          *pszDest = L'\0';
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  
  
  #if defined(STRSAFE_LOCALE_FUNCTIONS) && !defined(STRSAFE_NO_CCH_FUNCTIONS)
  /*++
  
    STDAPI
    StringCchVPrintf_lEx(
    _Out_writes_(cchDest) _Always_(_Post_z_) LPTSTR  pszDest         OPTIONAL,
    _In_ size_t  cchDest,
    _Outptr_opt_result_buffer_(*pcchRemaining) LPTSTR* ppszDestEnd     OPTIONAL,
    _Out_opt_ size_t* pcchRemaining   OPTIONAL,
    _In_ DWORD   dwFlags,
    _In_ _Printf_format_string_params_(2) LPCTSTR pszFormat       OPTIONAL,
    _In_ locale_t locale,
    _In_ va_list argList
    );
  
    Routine Description:
  
    This routine is a version of StringCchVPrintfEx that also takes a locale.
    Please see notes for StringCchVPrintfEx above.
  
    --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchVPrintf_lEx    StringCchVPrintf_lExW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchVPrintf_lEx    StringCchVPrintf_lExA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable: __WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION)
  
  STRSAFEAPI
      StringCchVPrintf_lExA(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cchDest,
              _Outptr_opt_result_buffer_(*pcchRemaining) STRSAFE_LPSTR* ppszDestEnd,
              _Out_opt_ size_t* pcchRemaining,
              _In_ DWORD dwFlags,
              _In_ _Printf_format_string_params_(2) STRSAFE_LPCSTR pszFormat,
              _In_ _locale_t locale,
              _In_ va_list argList)
  {
      HRESULT hr;
  
      hr = StringExValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH, dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPSTR pszDestEnd = pszDest;
          size_t cchRemaining = cchDest;
  
          hr = StringExValidateSrcA(&pszFormat, NULL, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
  
                  if (cchDest != 0)
                  {
                      *pszDest = '\0';
                  }
              }
              else if (cchDest == 0)
              {
                  // only fail if there was actually a non-empty format string
                  if (*pszFormat != '\0')
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
              }
              else
              {
                  size_t cchNewDestLength = 0;
  
                  hr = StringVPrintf_lWorkerA(pszDest,
                          cchDest,
                          &cchNewDestLength,
                          pszFormat,
                          locale,
                          argList);
  
                  pszDestEnd = pszDest + cchNewDestLength;
                  cchRemaining = cchDest - cchNewDestLength;
  
                  if (SUCCEEDED(hr)                           &&
                          (dwFlags & STRSAFE_FILL_BEHIND_NULL)    &&
                          (cchRemaining > 1))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
                      cbRemaining = cchRemaining * sizeof(char);
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullA(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
          else
          {
              if (cchDest != 0)
              {
                  *pszDest = '\0';
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cchDest != 0))
          {
              size_t cbDest;
  
              // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
              cbDest = cchDest * sizeof(char);
  
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsA(pszDest,
                      cbDest,
                      0,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcchRemaining)
              {
                  *pcchRemaining = cchRemaining;
              }
          }
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable: __WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION)
  
  STRSAFEAPI
      StringCchVPrintf_lExW(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cchDest,
              _Outptr_opt_result_buffer_(*pcchRemaining) STRSAFE_LPWSTR* ppszDestEnd,
              _Out_opt_ size_t* pcchRemaining,
              _In_ DWORD dwFlags,
              _In_ _Printf_format_string_params_(2) STRSAFE_LPCWSTR pszFormat,
              _In_ _locale_t locale,
              _In_ va_list argList)
  {
      HRESULT hr;
  
      hr = StringExValidateDestW(pszDest, cchDest, STRSAFE_MAX_CCH, dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPWSTR pszDestEnd = pszDest;
          size_t cchRemaining = cchDest;
  
          hr = StringExValidateSrcW(&pszFormat, NULL, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
  
                  if (cchDest != 0)
                  {
                      *pszDest = L'\0';
                  }
              }
              else if (cchDest == 0)
              {
                  // only fail if there was actually a non-empty format string
                  if (*pszFormat != L'\0')
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
              }
              else
              {
                  size_t cchNewDestLength = 0;
  
                  hr = StringVPrintf_lWorkerW(pszDest,
                          cchDest,
                          &cchNewDestLength,
                          pszFormat,
                          locale,
                          argList);
  
                  pszDestEnd = pszDest + cchNewDestLength;
                  cchRemaining = cchDest - cchNewDestLength;
  
                  if (SUCCEEDED(hr)                           &&
                          (dwFlags & STRSAFE_FILL_BEHIND_NULL)    &&
                          (cchRemaining > 1))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
                      cbRemaining = cchRemaining * sizeof(wchar_t);
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullW(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
          else
          {
              if (cchDest != 0)
              {
                  *pszDest = L'\0';
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cchDest != 0))
          {
              size_t cbDest;
  
              // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
              cbDest = cchDest * sizeof(wchar_t);
  
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsW(pszDest,
                      cbDest,
                      0,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcchRemaining)
              {
                  *pcchRemaining = cchRemaining;
              }
          }
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // STRSAFE_LOCALE_FUNCTIONS && !STRSAFE_NO_CCH_FUNCTIONS
  
  
  #ifndef STRSAFE_NO_CB_FUNCTIONS
  /*++
  
    STDAPI
    StringCbVPrintfEx(
    _Out_writes_bytes_(cbDest) LPTSTR  pszDest         OPTIONAL,
    _In_ size_t  cbDest,
    _Outptr_opt_result_bytebuffer_(*pcbRemaining) LPTSTR* ppszDestEnd     OPTIONAL,
    _Out_opt_ size_t* pcbRemaining    OPTIONAL,
    _In_ DWORD   dwFlags,
    _In_ _Printf_format_string_ LPCTSTR pszFormat       OPTIONAL,
    _In_ va_list argList
    );
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'vsprintf' with
    some additional parameters.  In addition to functionality provided by
    StringCbVPrintf, this routine also returns a pointer to the end of the
    destination string and the number of characters left in the destination string
    including the null terminator. The flags parameter allows additional controls.
  
  Arguments:
  
  pszDest         -   destination string
  
  cbDest          -   size of destination buffer in bytes.
  length must be sufficient to contain the resulting
  formatted string plus the null terminator.
  
  ppszDestEnd     -   if ppszDestEnd is non-null, the function will return
  a pointer to the end of the destination string.  If the
  function printed any data, the result will point to the
  null termination character
  
  pcbRemaining    -   if pcbRemaining is non-null, the function will return
  the number of bytes left in the destination string,
  including the null terminator
  
  dwFlags         -   controls some details of the string copy:
  
  STRSAFE_FILL_BEHIND_NULL
  if the function succeeds, the low byte of dwFlags will be
  used to fill the uninitialize part of destination buffer
  behind the null terminator
  
  STRSAFE_IGNORE_NULLS
  treat NULL string pointers like empty strings (TEXT(""))
  
  STRSAFE_FILL_ON_FAILURE
  if the function fails, the low byte of dwFlags will be
  used to fill all of the destination buffer, and it will
  be null terminated. This will overwrite any truncated
  string returned when the failure is
  STRSAFE_E_INSUFFICIENT_BUFFER
  
  STRSAFE_NO_TRUNCATION /
  STRSAFE_NULL_ON_FAILURE
  if the function fails, the destination buffer will be set
  to the empty string. This will overwrite any truncated string
  returned when the failure is STRSAFE_E_INSUFFICIENT_BUFFER.
  
  pszFormat       -   format string which must be null terminated
  
  argList         -   va_list from the variable arguments according to the
  stdarg.h convention
  
  Notes:
  Behavior is undefined if destination, format strings or any arguments
  strings overlap.
  
  pszDest and pszFormat should not be NULL unless the STRSAFE_IGNORE_NULLS
  flag is specified.  If STRSAFE_IGNORE_NULLS is passed, both pszDest and
  pszFormat may be NULL.  An error may still be returned even though NULLS
  are ignored due to insufficient space.
  
  Return Value:
  
  S_OK           -   if there was source data and it was all concatenated and
  the resultant dest string was null terminated
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  STRSAFE_E_INSUFFICIENT_BUFFER /
  HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  -   this return value is an indication that the print
  operation failed due to insufficient space. When this
  error occurs, the destination buffer is modified to
  contain a truncated version of the ideal result and is
  null terminated. This is useful for situations where
  truncation is ok.
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbVPrintfEx  StringCbVPrintfExW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbVPrintfEx  StringCbVPrintfExA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable : __WARNING_INCORRECT_ANNOTATION)
  
  STRSAFEAPI
      StringCbVPrintfExA(
              _Out_writes_bytes_(cbDest) STRSAFE_LPSTR pszDest,
              _In_ size_t cbDest,
              _Outptr_opt_result_bytebuffer_(*pcbRemaining) STRSAFE_LPSTR* ppszDestEnd,
              _Out_opt_ size_t* pcbRemaining,
              _In_ DWORD dwFlags,
              _In_ _Printf_format_string_ STRSAFE_LPCSTR pszFormat,
              _In_ va_list argList)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(char);
  
      hr = StringExValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH, dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPSTR pszDestEnd = pszDest;
          size_t cchRemaining = cchDest;
  
          hr = StringExValidateSrcA(&pszFormat, NULL, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
  
                  if (cchDest != 0)
                  {
                      *pszDest = '\0';
                  }
              }
              else if (cchDest == 0)
              {
                  // only fail if there was actually a non-empty format string
                  if (*pszFormat != '\0')
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
                  else
                  {
                      // for consistency with other use in this case...
                      __analysis_assume_nullterminated(pszDest);
                  }
              }
              else
              {
                  size_t cchNewDestLength = 0;
  
                  hr = StringVPrintfWorkerA(pszDest,
                          cchDest,
                          &cchNewDestLength,
                          pszFormat,
                          argList);
  
                  pszDestEnd = pszDest + cchNewDestLength;
                  cchRemaining = cchDest - cchNewDestLength;
  
                  if (SUCCEEDED(hr)                           &&
                          (dwFlags & STRSAFE_FILL_BEHIND_NULL)    &&
                          (cchRemaining > 1))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
                      cbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullA(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
          else
          {
              if (cchDest != 0)
              {
                  *pszDest = '\0';
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cbDest != 0))
          {
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsA(pszDest,
                      cbDest,
                      0,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcbRemaining)
              {
                  // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
                  *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
              }
          }
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable : __WARNING_INCORRECT_ANNOTATION)
  
  STRSAFEAPI
      StringCbVPrintfExW(
              _Out_writes_bytes_(cbDest) STRSAFE_LPWSTR pszDest,
              _In_ size_t cbDest,
              _Outptr_opt_result_bytebuffer_(*pcbRemaining) STRSAFE_LPWSTR* ppszDestEnd,
              _Out_opt_ size_t* pcbRemaining,
              _In_ DWORD dwFlags,
              _In_ _Printf_format_string_ STRSAFE_LPCWSTR pszFormat,
              _In_ va_list argList)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(wchar_t);
  
      hr = StringExValidateDestW(pszDest, cchDest, STRSAFE_MAX_CCH, dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPWSTR pszDestEnd = pszDest;
          size_t cchRemaining = cchDest;
  
          hr = StringExValidateSrcW(&pszFormat, NULL, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
  
                  if (cchDest != 0)
                  {
                      *pszDest = L'\0';
                  }
              }
              else if (cchDest == 0)
              {
                  // only fail if there was actually a non-empty format string
                  if (*pszFormat != L'\0')
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
                  else
                  {
                      // for consistency with other use in this case...
                      __analysis_assume_nullterminated(pszDest);
                  }
              }
              else
              {
                  size_t cchNewDestLength = 0;
  
                  hr = StringVPrintfWorkerW(pszDest,
                          cchDest,
                          &cchNewDestLength,
                          pszFormat,
                          argList);
  
                  pszDestEnd = pszDest + cchNewDestLength;
                  cchRemaining = cchDest - cchNewDestLength;
  
                  if (SUCCEEDED(hr) && (dwFlags & STRSAFE_FILL_BEHIND_NULL))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
                      cbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullW(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
          else
          {
              if (cchDest != 0)
              {
                  *pszDest = L'\0';
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cbDest != 0))
          {
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsW(pszDest,
                      cbDest,
                      0,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcbRemaining)
              {
                  // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
                  *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
              }
          }
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CB_FUNCTIONS
  
  
  #if defined(STRSAFE_LOCALE_FUNCTIONS) && !defined(STRSAFE_NO_CB_FUNCTIONS)
  /*++
  
    STDAPI
    StringCbVPrintf_lEx(
    _Out_writes_bytes_(cbDest) LPTSTR  pszDest         OPTIONAL,
    _In_ size_t  cbDest,
    _Outptr_opt_result_bytebuffer_(*pcbRemaining) LPTSTR* ppszDestEnd     OPTIONAL,
    _Out_opt_ size_t* pcbRemaining    OPTIONAL,
    _In_ DWORD   dwFlags,
    _In_ _Printf_format_string_params_(2) LPCTSTR pszFormat       OPTIONAL,
    _In_ locale_t locale,
    _In_ va_list argList
    );
  
    Routine Description:
  
    This routine is a version of StringCbVPrintfEx that also takes a locale.
    Please see notes for StringCbVPrintfEx above.
  
    --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbVPrintf_lEx StringCbVPrintf_lExW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbVPrintf_lEx StringCbVPrintf_lExA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCbVPrintf_lExA(
              _Out_writes_bytes_(cbDest) STRSAFE_LPSTR pszDest,
              _In_ size_t cbDest,
              _Outptr_opt_result_bytebuffer_(*pcbRemaining) STRSAFE_LPSTR* ppszDestEnd,
              _Out_opt_ size_t* pcbRemaining,
              _In_ DWORD dwFlags,
              _In_ _Printf_format_string_params_(2) STRSAFE_LPCSTR pszFormat,
              _In_ _locale_t locale,
              _In_ va_list argList)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(char);
  
      hr = StringExValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH, dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPSTR pszDestEnd = pszDest;
          size_t cchRemaining = cchDest;
  
          hr = StringExValidateSrcA(&pszFormat, NULL, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
  
                  if (cchDest != 0)
                  {
                      *pszDest = '\0';
                  }
              }
              else if (cchDest == 0)
              {
                  // only fail if there was actually a non-empty format string
                  if (*pszFormat != '\0')
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
              }
              else
              {
                  size_t cchNewDestLength = 0;
  
                  hr = StringVPrintf_lWorkerA(pszDest,
                          cchDest,
                          &cchNewDestLength,
                          pszFormat,
                          locale,
                          argList);
  
                  pszDestEnd = pszDest + cchNewDestLength;
                  cchRemaining = cchDest - cchNewDestLength;
  
                  if (SUCCEEDED(hr)                           &&
                          (dwFlags & STRSAFE_FILL_BEHIND_NULL)    &&
                          (cchRemaining > 1))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
                      cbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullA(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
          else
          {
              if (cchDest != 0)
              {
                  *pszDest = '\0';
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cbDest != 0))
          {
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsA(pszDest,
                      cbDest,
                      0,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcbRemaining)
              {
                  // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
                  *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
              }
          }
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable: __WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION)
  
  STRSAFEAPI
      StringCbVPrintf_lExW(
              _Out_writes_bytes_(cbDest) STRSAFE_LPWSTR pszDest,
              _In_ size_t cbDest,
              _Outptr_opt_result_bytebuffer_(*pcbRemaining) STRSAFE_LPWSTR* ppszDestEnd,
              _Out_opt_ size_t* pcbRemaining,
              _In_ DWORD dwFlags,
              _In_ _Printf_format_string_params_(2) STRSAFE_LPCWSTR pszFormat,
              _In_ _locale_t locale,
              _In_ va_list argList)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(wchar_t);
  
      hr = StringExValidateDestW(pszDest, cchDest, STRSAFE_MAX_CCH, dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPWSTR pszDestEnd = pszDest;
          size_t cchRemaining = cchDest;
  
          hr = StringExValidateSrcW(&pszFormat, NULL, STRSAFE_MAX_CCH, dwFlags);
  
          if (SUCCEEDED(hr))
          {
              if (dwFlags & (~STRSAFE_VALID_FLAGS))
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
  
                  if (cchDest != 0)
                  {
                      *pszDest = L'\0';
                  }
              }
              else if (cchDest == 0)
              {
                  // only fail if there was actually a non-empty format string
                  if (*pszFormat != L'\0')
                  {
                      if (pszDest == NULL)
                      {
                          hr = STRSAFE_E_INVALID_PARAMETER;
                      }
                      else
                      {
                          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
                      }
                  }
              }
              else
              {
                  size_t cchNewDestLength = 0;
  
                  hr = StringVPrintf_lWorkerW(pszDest,
                          cchDest,
                          &cchNewDestLength,
                          pszFormat,
                          locale,
                          argList);
  
                  pszDestEnd = pszDest + cchNewDestLength;
                  cchRemaining = cchDest - cchNewDestLength;
  
                  if (SUCCEEDED(hr) && (dwFlags & STRSAFE_FILL_BEHIND_NULL))
                  {
                      size_t cbRemaining;
  
                      // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
                      cbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
  
                      // handle the STRSAFE_FILL_BEHIND_NULL flag
                      StringExHandleFillBehindNullW(pszDestEnd, cbRemaining, dwFlags);
                  }
              }
          }
          else
          {
              if (cchDest != 0)
              {
                  *pszDest = L'\0';
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cbDest != 0))
          {
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsW(pszDest,
                      cbDest,
                      0,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr) || (hr == STRSAFE_E_INSUFFICIENT_BUFFER))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcbRemaining)
              {
                  // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
                  *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
              }
          }
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // STRSAFE_LOCALE_FUNCTIONS && !STRSAFE_NO_CB_FUNCTIONS
  
  
  #ifndef STRSAFE_LIB_IMPL
  
  #ifndef STRSAFE_NO_CCH_FUNCTIONS
  /*++
  
    STDAPI
    StringCchGets(
    _Out_writes_(cchDest) _Always_(_Post_z_) LPTSTR  pszDest,
    _In_ size_t  cchDest
    );
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'gets'.
    The size of the destination buffer (in characters) is a parameter and
    this function will not write past the end of this buffer and it will
    ALWAYS null terminate the destination buffer (unless it is zero length).
  
    This routine is not a replacement for fgets.  That function does not replace
    newline characters with a null terminator.
  
    This function returns a hresult, and not a pointer.  It returns
    S_OK if any characters were read from stdin and copied to pszDest and
    pszDest was null terminated, otherwise it will return a failure code.
  
  Arguments:
  
  pszDest     -   destination string
  
  cchDest     -   size of destination buffer in characters.
  
  Notes:
  pszDest should not be NULL. See StringCchGetsEx if you require the handling
  of NULL values.
  
  cchDest must be > 1 for this function to succeed.
  
  Return Value:
  
  S_OK           -   data was read from stdin and copied, and the resultant
  dest string was null terminated
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  STRSAFE_E_END_OF_FILE /
  HRESULT_CODE(hr) == ERROR_HANDLE_EOF
  -   this return value indicates an error or end-of-file
  condition, use feof or ferror to determine which one has
  occured.
  
  STRSAFE_E_INSUFFICIENT_BUFFER /
  HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  -   this return value is an indication that there was
  insufficient space in the destination buffer to copy any
  data
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function.
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchGets  StringCchGetsW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchGets  StringCchGetsA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCchGetsA(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cchDest)
  {
      HRESULT hr;
  
      hr = StringValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          hr = StringGetsWorkerA(pszDest, cchDest, NULL);
      }
      else if (cchDest > 0)
      {
          *pszDest = '\0';
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCchGetsW(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cchDest)
  {
      HRESULT hr;
  
      hr = StringValidateDestW(pszDest, cchDest, STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          hr = StringGetsWorkerW(pszDest, cchDest, NULL);
      }
      else if (cchDest > 0)
      {
          *pszDest = L'\0';
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  
  
  #ifndef STRSAFE_NO_CB_FUNCTIONS
  /*++
  
    STDAPI
    StringCbGets(
    _Out_writes_bytes_(cbDest) _Always_(_Post_z_) LPTSTR  pszDest,
    _In_ size_t  cbDest
    );
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'gets'.
    The size of the destination buffer (in bytes) is a parameter and
    this function will not write past the end of this buffer and it will
    ALWAYS null terminate the destination buffer (unless it is zero length).
  
    This routine is not a replacement for fgets.  That function does not replace
    newline characters with a null terminator.
  
    This function returns a hresult, and not a pointer.  It returns
    S_OK if any characters were read from stdin and copied to pszDest
    and pszDest was null terminated, otherwise it will return a failure code.
  
  Arguments:
  
  pszDest     -   destination string
  
  cbDest      -   size of destination buffer in bytes.
  
  Notes:
  pszDest should not be NULL. See StringCbGetsEx if you require the handling
  of NULL values.
  
  cbDest must be > sizeof(TCHAR) for this function to succeed.
  
  Return Value:
  
  S_OK           -   data was read from stdin and copied, and the resultant
  dest string was null terminated
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  STRSAFE_E_END_OF_FILE /
  HRESULT_CODE(hr) == ERROR_HANDLE_EOF
  -   this return value indicates an error or end-of-file
  condition, use feof or ferror to determine which one has
  occured.
  
  STRSAFE_E_INSUFFICIENT_BUFFER /
  HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  -   this return value is an indication that there was
  insufficient space in the destination buffer to copy any
  data
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function.
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbGets  StringCbGetsW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbGets  StringCbGetsA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCbGetsA(
              _Out_writes_bytes_(cbDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cbDest)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(char);
  
      hr = StringValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          hr = StringGetsWorkerA(pszDest, cchDest, NULL);
      }
      else if (cchDest > 0)
      {
          *pszDest = '\0';
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCbGetsW(
              _Out_writes_bytes_(cbDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cbDest)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(wchar_t);
  
      hr = StringValidateDestW(pszDest, cchDest, STRSAFE_MAX_CCH);
  
      if (SUCCEEDED(hr))
      {
          hr = StringGetsWorkerW(pszDest, cchDest, NULL);
      }
      else if (cchDest > 0)
      {
          *pszDest = L'\0';
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CB_FUNCTIONS
  
  
  #ifndef STRSAFE_NO_CCH_FUNCTIONS
  /*++
  
    STDAPI
    StringCchGetsEx(
    _Out_writes_(cchDest) _Always_(_Post_z_) LPTSTR  pszDest         OPTIONAL,
    _In_ size_t  cchDest,
    _Outptr_opt_result_buffer_(*pcchRemaining) LPTSTR* ppszDestEnd     OPTIONAL,
    _Out_opt_ size_t* pcchRemaining   OPTIONAL,
    _In_ DWORD   dwFlags
    );
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'gets' with
    some additional parameters. In addition to functionality provided by
    StringCchGets, this routine also returns a pointer to the end of the
    destination string and the number of characters left in the destination string
    including the null terminator. The flags parameter allows additional controls.
  
  Arguments:
  
  pszDest         -   destination string
  
  cchDest         -   size of destination buffer in characters.
  
  ppszDestEnd     -   if ppszDestEnd is non-null, the function will return a
  pointer to the end of the destination string.  If the
  function copied any data, the result will point to the
  null termination character
  
  pcchRemaining   -   if pcchRemaining is non-null, the function will return the
  number of characters left in the destination string,
  including the null terminator
  
  dwFlags         -   controls some details of the string copy:
  
  STRSAFE_FILL_BEHIND_NULL
  if the function succeeds, the low byte of dwFlags will be
  used to fill the uninitialize part of destination buffer
  behind the null terminator
  
  STRSAFE_IGNORE_NULLS
  treat NULL string pointers like empty strings (TEXT("")).
  
  STRSAFE_FILL_ON_FAILURE
  if the function fails, the low byte of dwFlags will be
  used to fill all of the destination buffer, and it will
  be null terminated.
  
  STRSAFE_NO_TRUNCATION /
  STRSAFE_NULL_ON_FAILURE
  if the function fails, the destination buffer will be set
  to the empty string.
  
  Notes:
  pszDest should not be NULL unless the STRSAFE_IGNORE_NULLS flag is specified.
  If STRSAFE_IGNORE_NULLS is passed and pszDest is NULL, an error may still be
  returned even though NULLS are ignored
  
  cchDest must be > 1 for this function to succeed.
  
  Return Value:
  
  S_OK           -   data was read from stdin and copied, and the resultant
  dest string was null terminated
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  STRSAFE_E_END_OF_FILE /
  HRESULT_CODE(hr) == ERROR_HANDLE_EOF
  -   this return value indicates an error or end-of-file
  condition, use feof or ferror to determine which one has
  occured.
  
  STRSAFE_E_INSUFFICIENT_BUFFER /
  HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  -   this return value is an indication that there was
  insufficient space in the destination buffer to copy any
  data
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function.
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchGetsEx  StringCchGetsExW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchGetsEx  StringCchGetsExA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCchGetsExA(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cchDest,
              _Outptr_opt_result_buffer_(*pcchRemaining) STRSAFE_LPSTR* ppszDestEnd,
              _Out_opt_ size_t* pcchRemaining,
              _In_ DWORD dwFlags)
  {
      HRESULT hr;
  
      hr = StringExValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH, dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPSTR pszDestEnd = pszDest;
          size_t cchRemaining = cchDest;
  
          if (dwFlags & (~STRSAFE_VALID_FLAGS))
          {
              hr = STRSAFE_E_INVALID_PARAMETER;
  
              if (cchDest != 0)
              {
                  *pszDest = '\0';
              }
          }
          else if (cchDest == 0)
          {
              if (pszDest == NULL)
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
              }
              else
              {
                  hr = STRSAFE_E_INSUFFICIENT_BUFFER;
              }
          }
          else
          {
              size_t cchNewDestLength = 0;
  
              hr = StringGetsWorkerA(pszDest, cchDest, &cchNewDestLength);
  
              pszDestEnd = pszDest + cchNewDestLength;
              cchRemaining = cchDest - cchNewDestLength;
  
              if (SUCCEEDED(hr)                           &&
                      (dwFlags & STRSAFE_FILL_BEHIND_NULL)    &&
                      (cchRemaining > 1))
              {
                  size_t cbRemaining;
  
                  // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
                  cbRemaining = cchRemaining * sizeof(char);
  
                  // handle the STRSAFE_FILL_BEHIND_NULL flag
                  StringExHandleFillBehindNullA(pszDestEnd, cbRemaining, dwFlags);
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cchDest != 0))
          {
              size_t cbDest;
  
              // safe to multiply cchDest * sizeof(char) since cchDest < STRSAFE_MAX_CCH and sizeof(char) is 1
              cbDest = cchDest * sizeof(char);
  
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsA(pszDest,
                      cbDest,
                      0,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr)                           ||
                  (hr == STRSAFE_E_INSUFFICIENT_BUFFER)   ||
                  (hr == STRSAFE_E_END_OF_FILE))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcchRemaining)
              {
                  *pcchRemaining = cchRemaining;
              }
          }
      }
      else if (cchDest > 0)
      {
          *pszDest = '\0';
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCchGetsExW(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cchDest,
              _Outptr_opt_result_buffer_(*pcchRemaining) STRSAFE_LPWSTR* ppszDestEnd,
              _Out_opt_ size_t* pcchRemaining,
              _In_ DWORD dwFlags)
  {
      HRESULT hr;
  
      hr = StringExValidateDestW(pszDest, cchDest, STRSAFE_MAX_CCH, dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPWSTR pszDestEnd = pszDest;
          size_t cchRemaining = cchDest;
  
          if (dwFlags & (~STRSAFE_VALID_FLAGS))
          {
              hr = STRSAFE_E_INVALID_PARAMETER;
  
              if (cchDest != 0)
              {
                  *pszDest = L'\0';
              }
          }
          else if (cchDest == 0)
          {
              if (pszDest == NULL)
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
              }
              else
              {
                  hr = STRSAFE_E_INSUFFICIENT_BUFFER;
              }
          }
          else
          {
              size_t cchNewDestLength = 0;
  
              hr = StringGetsWorkerW(pszDest, cchDest, &cchNewDestLength);
  
              pszDestEnd = pszDest + cchNewDestLength;
              cchRemaining = cchDest - cchNewDestLength;
  
              if (SUCCEEDED(hr)                           &&
                      (dwFlags & STRSAFE_FILL_BEHIND_NULL)    &&
                      (cchRemaining > 1))
              {
                  size_t cbRemaining;
  
                  // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
                  cbRemaining = cchRemaining * sizeof(wchar_t);
  
                  // handle the STRSAFE_FILL_BEHIND_NULL flag
                  StringExHandleFillBehindNullW(pszDestEnd, cbRemaining, dwFlags);
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cchDest != 0))
          {
              size_t cbDest;
  
              // safe to multiply cchDest * sizeof(wchar_t) since cchDest < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
              cbDest = cchDest * sizeof(wchar_t);
  
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsW(pszDest,
                      cbDest,
                      0,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr)                           ||
                  (hr == STRSAFE_E_INSUFFICIENT_BUFFER)   ||
                  (hr == STRSAFE_E_END_OF_FILE))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcchRemaining)
              {
                  *pcchRemaining = cchRemaining;
              }
          }
      }
      else if (cchDest > 0)
      {
          *pszDest = L'\0';
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  
  
  #ifndef STRSAFE_NO_CB_FUNCTIONS
  /*++
  
    STDAPI
    StringCbGetsEx(
    _Out_writes_bytes_(cbDest) _Always_(_Post_z_) LPTSTR  pszDest         OPTIONAL,
    _In_ size_t  cbDest,
    _Outptr_opt_result_bytebuffer_(*pcbRemaining) LPTSTR* ppszDestEnd     OPTIONAL,
    _Out_opt_ size_t* pcbRemaining    OPTIONAL,
    _In_ DWORD   dwFlags
    );
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'gets' with
    some additional parameters. In addition to functionality provided by
    StringCbGets, this routine also returns a pointer to the end of the
    destination string and the number of characters left in the destination string
    including the null terminator. The flags parameter allows additional controls.
  
  Arguments:
  
  pszDest         -   destination string
  
  cbDest          -   size of destination buffer in bytes.
  
  ppszDestEnd     -   if ppszDestEnd is non-null, the function will return a
  pointer to the end of the destination string.  If the
  function copied any data, the result will point to the
  null termination character
  
  pcbRemaining    -   if pcbRemaining is non-null, the function will return the
  number of bytes left in the destination string,
  including the null terminator
  
  dwFlags         -   controls some details of the string copy:
  
  STRSAFE_FILL_BEHIND_NULL
  if the function succeeds, the low byte of dwFlags will be
  used to fill the uninitialize part of destination buffer
  behind the null terminator
  
  STRSAFE_IGNORE_NULLS
  treat NULL string pointers like empty strings (TEXT("")).
  
  STRSAFE_FILL_ON_FAILURE
  if the function fails, the low byte of dwFlags will be
  used to fill all of the destination buffer, and it will
  be null terminated.
  
  STRSAFE_NO_TRUNCATION /
  STRSAFE_NULL_ON_FAILURE
  if the function fails, the destination buffer will be set
  to the empty string.
  
  Notes:
  pszDest should not be NULL unless the STRSAFE_IGNORE_NULLS flag is specified.
  If STRSAFE_IGNORE_NULLS is passed and pszDest is NULL, an error may still be
  returned even though NULLS are ignored
  
  cbDest must be > sizeof(TCHAR) for this function to succeed
  
  Return Value:
  
  S_OK           -   data was read from stdin and copied, and the resultant
  dest string was null terminated
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  STRSAFE_E_END_OF_FILE /
  HRESULT_CODE(hr) == ERROR_HANDLE_EOF
  -   this return value indicates an error or end-of-file
  condition, use feof or ferror to determine which one has
  occured.
  
  STRSAFE_E_INSUFFICIENT_BUFFER /
  HRESULT_CODE(hr) == ERROR_INSUFFICIENT_BUFFER
  -   this return value is an indication that there was
  insufficient space in the destination buffer to copy any
  data
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function.
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbGetsEx  StringCbGetsExW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbGetsEx  StringCbGetsExA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringCbGetsExA(
              _Out_writes_bytes_(cbDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ size_t cbDest,
              _Outptr_opt_result_bytebuffer_(*pcbRemaining) STRSAFE_LPSTR* ppszDestEnd,
              _Out_opt_ size_t* pcbRemaining,
              _In_ DWORD dwFlags)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(char);
  
      hr = StringExValidateDestA(pszDest, cchDest, STRSAFE_MAX_CCH, dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPSTR pszDestEnd = pszDest;
          size_t cchRemaining = cchDest;
  
          if (dwFlags & (~STRSAFE_VALID_FLAGS))
          {
              hr = STRSAFE_E_INVALID_PARAMETER;
  
              if (cchDest != 0)
              {
                  *pszDest = '\0';
              }
          }
          else if (cchDest == 0)
          {
              if (pszDest == NULL)
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
              }
              else
              {
                  hr = STRSAFE_E_INSUFFICIENT_BUFFER;
              }
          }
          else
          {
              size_t cchNewDestLength = 0;
  
              hr = StringGetsWorkerA(pszDest, cchDest, &cchNewDestLength);
  
              pszDestEnd = pszDest + cchNewDestLength;
              cchRemaining = cchDest - cchNewDestLength;
  
              if (SUCCEEDED(hr)                           &&
                      (dwFlags & STRSAFE_FILL_BEHIND_NULL)    &&
                      (cchRemaining > 1))
              {
                  size_t cbRemaining;
  
                  // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
                  cbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
  
                  // handle the STRSAFE_FILL_BEHIND_NULL flag
                  StringExHandleFillBehindNullA(pszDestEnd, cbRemaining, dwFlags);
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cbDest != 0))
          {
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsA(pszDest,
                      cbDest,
                      0,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr)                           ||
                  (hr == STRSAFE_E_INSUFFICIENT_BUFFER)   ||
                  (hr == STRSAFE_E_END_OF_FILE))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcbRemaining)
              {
                  // safe to multiply cchRemaining * sizeof(char) since cchRemaining < STRSAFE_MAX_CCH and sizeof(char) is 1
                  *pcbRemaining = (cchRemaining * sizeof(char)) + (cbDest % sizeof(char));
              }
          }
      }
      else if (cchDest > 0)
      {
          *pszDest = '\0';
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable: __WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION)
  
  STRSAFEAPI
      StringCbGetsExW(
              _Out_writes_bytes_(cbDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ size_t cbDest,
              _Outptr_opt_result_bytebuffer_(*pcbRemaining) STRSAFE_LPWSTR* ppszDestEnd,
              _Out_opt_ size_t* pcbRemaining,
              _In_ DWORD dwFlags)
  {
      HRESULT hr;
      size_t cchDest = cbDest / sizeof(wchar_t);
  
      hr = StringExValidateDestW(pszDest, cchDest, STRSAFE_MAX_CCH, dwFlags);
  
      if (SUCCEEDED(hr))
      {
          STRSAFE_LPWSTR pszDestEnd = pszDest;
          size_t cchRemaining = cchDest;
  
          if (dwFlags & (~STRSAFE_VALID_FLAGS))
          {
              hr = STRSAFE_E_INVALID_PARAMETER;
  
              if (cchDest != 0)
              {
                  *pszDest = L'\0';
              }
          }
          else if (cchDest == 0)
          {
              if (pszDest == NULL)
              {
                  hr = STRSAFE_E_INVALID_PARAMETER;
              }
              else
              {
                  hr = STRSAFE_E_INSUFFICIENT_BUFFER;
              }
          }
          else
          {
              size_t cchNewDestLength = 0;
  
              hr = StringGetsWorkerW(pszDest, cchDest, &cchNewDestLength);
  
              pszDestEnd = pszDest + cchNewDestLength;
              cchRemaining = cchDest - cchNewDestLength;
  
              if (SUCCEEDED(hr) && (dwFlags & STRSAFE_FILL_BEHIND_NULL))
              {
                  size_t cbRemaining;
  
                  // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
                  cbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
  
                  // handle the STRSAFE_FILL_BEHIND_NULL flag
                  StringExHandleFillBehindNullW(pszDestEnd, cbRemaining, dwFlags);
              }
          }
  
          if (FAILED(hr)                                                                              &&
                  (dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE)) &&
                  (cbDest != 0))
          {
              // handle the STRSAFE_FILL_ON_FAILURE, STRSAFE_NULL_ON_FAILURE, and STRSAFE_NO_TRUNCATION flags
              StringExHandleOtherFlagsW(pszDest,
                      cbDest,
                      0,
                      &pszDestEnd,
                      &cchRemaining,
                      dwFlags);
          }
  
          if (SUCCEEDED(hr)                           ||
                  (hr == STRSAFE_E_INSUFFICIENT_BUFFER)   ||
                  (hr == STRSAFE_E_END_OF_FILE))
          {
              if (ppszDestEnd)
              {
                  *ppszDestEnd = pszDestEnd;
              }
  
              if (pcbRemaining)
              {
                  // safe to multiply cchRemaining * sizeof(wchar_t) since cchRemaining < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
                  *pcbRemaining = (cchRemaining * sizeof(wchar_t)) + (cbDest % sizeof(wchar_t));
              }
          }
      }
      else if (cchDest > 0)
      {
          *pszDest = L'\0';
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CB_FUNCTIONS
  
  #endif  // !STRSAFE_LIB_IMPL
  
  #ifndef STRSAFE_NO_CCH_FUNCTIONS
  /*++
  
    STDAPI
    StringCchLength(
    _In_reads_or_z_(cchMax) LPCTSTR psz,
    _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t  cchMax,
    _Out_opt_ _Deref_out_range_(<, cchMax) _Deref_out_range_(<=, _String_length_(psz)) size_t* pcchLength  OPTIONAL
    );
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'strlen'.
    It is used to make sure a string is not larger than a given length, and
    it optionally returns the current length in characters not including
    the null terminator.
  
    This function returns a hresult, and not a pointer.  It returns
    S_OK if the string is non-null and the length including the null
    terminator is less than or equal to cchMax characters.
  
  Arguments:
  
  psz         -   string to check the length of
  
  cchMax      -   maximum number of characters including the null terminator
  that psz is allowed to contain
  
  pcch        -   if the function succeeds and pcch is non-null, the current length
  in characters of psz excluding the null terminator will be returned.
  This out parameter is equivalent to the return value of strlen(psz)
  
  Notes:
  psz can be null but the function will fail
  
  cchMax should be greater than zero or the function will fail
  
  Return Value:
  
  S_OK           -   psz is non-null and the length including the null
  terminator is less than or equal to cchMax characters
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function.
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchLength  StringCchLengthW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCchLength  StringCchLengthA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable:__WARNING_POTENTIAL_RANGE_POSTCONDITION_VIOLATION)
  
  _Must_inspect_result_
  STRSAFEAPI
      StringCchLengthA(
              _In_reads_or_z_(cchMax) STRSAFE_PCNZCH psz,
              _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchMax,
              _Out_opt_ _Deref_out_range_(<, cchMax) _Deref_out_range_(<=, _String_length_(psz)) size_t* pcchLength)
  {
      HRESULT hr;
  
      if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
      {
          hr = STRSAFE_E_INVALID_PARAMETER;
      }
      else
      {
          hr = StringLengthWorkerA(psz, cchMax, pcchLength);
      }
  
      if (FAILED(hr) && pcchLength)
      {
          *pcchLength = 0;
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable:__WARNING_POTENTIAL_RANGE_POSTCONDITION_VIOLATION)
  
  _Must_inspect_result_
  STRSAFEAPI
      StringCchLengthW(
              _In_reads_or_z_(cchMax) STRSAFE_PCNZWCH psz,
              _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchMax,
              _Out_opt_ _Deref_out_range_(<, cchMax) _Deref_out_range_(<=, _String_length_(psz)) size_t* pcchLength)
  {
      HRESULT hr;
  
      if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
      {
          hr = STRSAFE_E_INVALID_PARAMETER;
      }
      else
      {
          hr = StringLengthWorkerW(psz, cchMax, pcchLength);
      }
  
      if (FAILED(hr) && pcchLength)
      {
          *pcchLength = 0;
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  
  
  #ifndef STRSAFE_NO_CB_FUNCTIONS
  /*++
  
    STDAPI
    StringCbLength(
    _In_reads_or_z_(cbMax) LPCTSTR psz,
    _In_ _In_range_(1, STRSAFE_MAX_CCH * sizeof(TCHAR)) size_t  cbMax,
    _Out_opt_ _Deref_out_range_(<, cbMax) size_t* pcbLength   OPTIONAL
    );
  
    Routine Description:
  
    This routine is a safer version of the C built-in function 'strlen'.
    It is used to make sure a string is not larger than a given length, and
    it optionally returns the current length in bytes not including
    the null terminator.
  
    This function returns a hresult, and not a pointer.  It returns
    S_OK if the string is non-null and the length including the null
    terminator is less than or equal to cbMax bytes.
  
  Arguments:
  
  psz         -   string to check the length of
  
  cbMax       -   maximum number of bytes including the null terminator
  that psz is allowed to contain
  
  pcb         -   if the function succeeds and pcb is non-null, the current length
  in bytes of psz excluding the null terminator will be returned.
  This out parameter is equivalent to the return value of strlen(psz) * sizeof(TCHAR)
  
  Notes:
  psz can be null but the function will fail
  
  cbMax should be greater than or equal to sizeof(TCHAR) or the function will fail
  
  Return Value:
  
  S_OK           -   psz is non-null and the length including the null
  terminator is less than or equal to cbMax bytes
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function.
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbLength  StringCbLengthW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define StringCbLength  StringCbLengthA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  _Must_inspect_result_
  STRSAFEAPI
      StringCbLengthA(
              _In_reads_or_z_(cbMax) STRSAFE_PCNZCH psz,
              _In_ _In_range_(1, STRSAFE_MAX_CCH * sizeof(char)) size_t cbMax,
              _Out_opt_ _Deref_out_range_(<, cbMax) size_t* pcbLength)
  {
      HRESULT hr;
      size_t cchMax = cbMax / sizeof(char);
      size_t cchLength = 0;
  
      if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
      {
          hr = STRSAFE_E_INVALID_PARAMETER;
      }
      else
      {
          hr = StringLengthWorkerA(psz, cchMax, &cchLength);
      }
  
      if (pcbLength)
      {
          if (SUCCEEDED(hr))
          {
              // safe to multiply cchLength * sizeof(char) since cchLength < STRSAFE_MAX_CCH and sizeof(char) is 1
              *pcbLength = cchLength * sizeof(char);
          }
          else
          {
              *pcbLength = 0;
          }
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  _Must_inspect_result_
  STRSAFEAPI
      StringCbLengthW(
              _In_reads_or_z_(cbMax / sizeof(wchar_t)) STRSAFE_PCNZWCH psz,
              _In_ _In_range_(1, STRSAFE_MAX_CCH * sizeof(wchar_t)) size_t cbMax,
              _Out_opt_ _Deref_out_range_(<, cbMax - 1) size_t* pcbLength)
  {
      HRESULT hr;
      size_t cchMax = cbMax / sizeof(wchar_t);
      size_t cchLength = 0;
  
      if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
      {
          hr = STRSAFE_E_INVALID_PARAMETER;
      }
      else
      {
          hr = StringLengthWorkerW(psz, cchMax, &cchLength);
      }
  
      if (pcbLength)
      {
          if (SUCCEEDED(hr))
          {
              // safe to multiply cchLength * sizeof(wchar_t) since cchLength < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
              *pcbLength = cchLength * sizeof(wchar_t);
          }
          else
          {
              *pcbLength = 0;
          }
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CB_FUNCTIONS
  
  #ifndef STRSAFE_NO_CCH_FUNCTIONS
  /*++
  
    STDAPI
    UnalignedStringCchLength(
    _In_ LPCUTSTR    psz,
    _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t  cchMax,
    _Out_opt_ _Deref_out_range_(<, cchMax) size_t*     pcchLength  OPTIONAL
    );
  
    Routine Description:
  
    This routine is a version of StringCchLength that accepts an unaligned string pointer.
  
    This function returns a hresult, and not a pointer.  It returns
    S_OK if the string is non-null and the length including the null
    terminator is less than or equal to cchMax characters.
  
  Arguments:
  
  psz         -   string to check the length of
  
  cchMax      -   maximum number of characters including the null terminator
  that psz is allowed to contain
  
  pcch        -   if the function succeeds and pcch is non-null, the current length
  in characters of psz excluding the null terminator will be returned.
  This out parameter is equivalent to the return value of strlen(psz)
  
  Notes:
  psz can be null but the function will fail
  
  cchMax should be greater than zero or the function will fail
  
  Return Value:
  
  S_OK           -   psz is non-null and the length including the null
  terminator is less than or equal to cchMax characters
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function.
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define UnalignedStringCchLength    UnalignedStringCchLengthW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define UnalignedStringCchLength    StringCchLengthA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #ifdef ALIGNMENT_MACHINE
  _Must_inspect_result_
  STRSAFEAPI
      UnalignedStringCchLengthW(
              _In_reads_or_z_(cchMax) STRSAFE_PCUNZWCH psz,
              _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchMax,
              _Out_opt_ _Deref_out_range_(<, cchMax) size_t* pcchLength)
  {
      HRESULT hr;
  
      if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
      {
          hr = STRSAFE_E_INVALID_PARAMETER;
      }
      else
      {
          hr = UnalignedStringLengthWorkerW(psz, cchMax, pcchLength);
      }
  
      if (FAILED(hr) && pcchLength)
      {
          *pcchLength = 0;
      }
  
      return hr;
  }
  
  #else
  #define UnalignedStringCchLengthW   StringCchLengthW
  #endif  // !ALIGNMENT_MACHINE
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CCH_FUNCTIONS
  
  #ifndef STRSAFE_NO_CB_FUNCTIONS
  /*++
  
    STDAPI
    UnalignedStringCbLength(
    _In_reads_or_z_(cbMax) LPCUTSTR    psz,
    _In_ _In_range_(1, STRSAFE_MAX_CCH * sizeof(TCHAR)) size_t  cbMax,
    _Out_opt_ _Deref_out_range_(<, cbMax) size_t*   pcbLength   OPTIONAL
    );
  
    Routine Description:
  
    This routine is a version of StringCbLength that accepts an unaligned string pointer.
  
    This function returns a hresult, and not a pointer.  It returns
    S_OK if the string is non-null and the length including the null
    terminator is less than or equal to cbMax bytes.
  
  Arguments:
  
  psz         -   string to check the length of
  
  cbMax       -   maximum number of bytes including the null terminator
  that psz is allowed to contain
  
  pcb         -   if the function succeeds and pcb is non-null, the current length
  in bytes of psz excluding the null terminator will be returned.
  This out parameter is equivalent to the return value of strlen(psz) * sizeof(TCHAR)
  
  Notes:
  psz can be null but the function will fail
  
  cbMax should be greater than or equal to sizeof(TCHAR) or the function will fail
  
  Return Value:
  
  S_OK           -   psz is non-null and the length including the null
  terminator is less than or equal to cbMax bytes
  
  failure        -   you can use the macro HRESULT_CODE() to get a win32
  error code for all hresult failure cases
  
  It is strongly recommended to use the SUCCEEDED() / FAILED() macros to test the
  return value of this function.
  
  --*/
  #ifdef UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #define UnalignedStringCbLength UnalignedStringCbLengthW
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #else
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #define UnalignedStringCbLength StringCbLengthA
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif // !UNICODE
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #ifdef ALIGNMENT_MACHINE
  _Must_inspect_result_
  STRSAFEAPI
      UnalignedStringCbLengthW(
              _In_reads_or_z_(cbMax / sizeof(wchar_t)) STRSAFE_PCUNZWCH psz,
              _In_ _In_range_(1, STRSAFE_MAX_CCH * sizeof(wchar_t)) size_t cbMax,
              _Out_opt_ _Deref_out_range_(<, cbMax - 1) size_t* pcbLength)
  {
      HRESULT hr;
      size_t cchMax = cbMax / sizeof(wchar_t);
      size_t cchLength = 0;
  
      if ((psz == NULL) || (cchMax > STRSAFE_MAX_CCH))
      {
          hr = STRSAFE_E_INVALID_PARAMETER;
      }
      else
      {
          hr = UnalignedStringLengthWorkerW(psz, cchMax, &cchLength);
      }
  
      if (pcbLength)
      {
          if (SUCCEEDED(hr))
          {
              // safe to multiply cchLength * sizeof(wchar_t) since cchLength < STRSAFE_MAX_CCH and sizeof(wchar_t) is 2
              *pcbLength = cchLength * sizeof(wchar_t);
          }
          else
          {
              *pcbLength = 0;
          }
      }
  
      return hr;
  }
  #else
  #define UnalignedStringCbLengthW    StringCbLengthW
  
  #endif  // !ALIGNMENT_MACHINE
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_NO_CB_FUNCTIONS
  
  
  #endif  // !STRSAFE_LIB_IMPL
  
  // Below here are the worker functions that actually do the work
  
  #if defined(STRSAFE_LIB_IMPL) || !defined(STRSAFE_LIB)
  
  #pragma warning(push)
  #pragma warning(disable:__WARNING_RETURNING_BAD_RESULT)
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEWORKERAPI
      StringLengthWorkerA(
              _In_reads_or_z_(cchMax) STRSAFE_PCNZCH psz,
              _In_ _In_range_(<=, STRSAFE_MAX_CCH) size_t cchMax,
              _Out_opt_ _Deref_out_range_(<, cchMax) _Deref_out_range_(<=, _String_length_(psz)) size_t* pcchLength)
  {
      HRESULT hr = S_OK;
      size_t cchOriginalMax = cchMax;
  
      while (cchMax && (*psz != '\0'))
      {
          psz++;
          cchMax--;
      }
  
      if (cchMax == 0)
      {
          // the string is longer than cchMax
          hr = STRSAFE_E_INVALID_PARAMETER;
      }
  
      if (pcchLength)
      {
          if (SUCCEEDED(hr))
          {
              *pcchLength = cchOriginalMax - cchMax;
          }
          else
          {
              *pcchLength = 0;
          }
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEWORKERAPI
      StringLengthWorkerW(
              _In_reads_or_z_(cchMax) STRSAFE_PCNZWCH psz,
              _In_ _In_range_(<=, STRSAFE_MAX_CCH) size_t cchMax,
              _Out_opt_ _Deref_out_range_(<, cchMax) _Deref_out_range_(<=, _String_length_(psz)) size_t* pcchLength)
  {
      HRESULT hr = S_OK;
      size_t cchOriginalMax = cchMax;
  
      while (cchMax && (*psz != L'\0'))
      {
          psz++;
          cchMax--;
      }
  
      if (cchMax == 0)
      {
          // the string is longer than cchMax
          hr = STRSAFE_E_INVALID_PARAMETER;
      }
  
      if (pcchLength)
      {
          if (SUCCEEDED(hr))
          {
              *pcchLength = cchOriginalMax - cchMax;
          }
          else
          {
              *pcchLength = 0;
          }
      }
  
      return hr;
  }
  
  #ifdef ALIGNMENT_MACHINE
  STRSAFEWORKERAPI
      UnalignedStringLengthWorkerW(
              _In_reads_or_z_(cchMax) STRSAFE_PCUNZWCH psz,
              _In_ _In_range_(<=, STRSAFE_MAX_CCH) size_t cchMax,
              _Out_opt_ _Deref_out_range_(<, cchMax) size_t* pcchLength)
  {
      HRESULT hr = S_OK;
      size_t cchOriginalMax = cchMax;
  
      while (cchMax && (*psz != L'\0'))
      {
          psz++;
          cchMax--;
      }
  
      if (cchMax == 0)
      {
          // the string is longer than cchMax
          hr = STRSAFE_E_INVALID_PARAMETER;
      }
  
      if (pcchLength)
      {
          if (SUCCEEDED(hr))
          {
              *pcchLength = cchOriginalMax - cchMax;
          }
          else
          {
              *pcchLength = 0;
          }
      }
  
      return hr;
  }
  #endif  // ALIGNMENT_MACHINE
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma warning(pop)
  
  // Intentionally allow null deref when STRSAFE_IGNORE_NULLS is not present.
  #pragma warning(push)
  #pragma warning(disable : __WARNING_DEREF_NULL_PTR)
  #pragma warning(disable : __WARNING_INVALID_PARAM_VALUE_1)
  #pragma warning(disable : __WARNING_INVALID_PARAM_VALUE_3)
  #pragma warning(disable : __WARNING_RETURNING_BAD_RESULT)
  #pragma warning(disable : __WARNING_MISSING_ZERO_TERMINATION2)
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
      _When_(_Old_(*ppszSrc) != NULL, _Unchanged_(*ppszSrc))
  _When_(_Old_(*ppszSrc) == NULL, _At_(*ppszSrc, _Post_z_))
      STRSAFEWORKERAPI
      StringExValidateSrcA(
              _Inout_ _Deref_post_notnull_ STRSAFE_PCNZCH* ppszSrc,
              _Inout_opt_
              _Deref_out_range_(<, cchMax)
              _Deref_out_range_(<=, _Old_(*pcchToRead)) size_t* pcchToRead,
              _In_ const size_t cchMax,
              _In_ DWORD dwFlags)
  {
      HRESULT hr = S_OK;
  
      if (pcchToRead && (*pcchToRead >= cchMax))
      {
          hr = STRSAFE_E_INVALID_PARAMETER;
      }
      else if ((dwFlags & STRSAFE_IGNORE_NULLS) && (*ppszSrc == NULL))
      {
          *ppszSrc = "";
  
          if (pcchToRead)
          {
              *pcchToRead = 0;
          }
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
      _When_(_Old_(*ppszSrc) != NULL, _Unchanged_(*ppszSrc))
  _When_(_Old_(*ppszSrc) == NULL, _At_(*ppszSrc, _Post_z_))
      STRSAFEWORKERAPI
      StringExValidateSrcW(
              _Inout_ _Deref_post_notnull_ STRSAFE_PCNZWCH* ppszSrc,
              _Inout_opt_
              _Deref_out_range_(<, cchMax)
              _Deref_out_range_(<=, _Old_(*pcchToRead)) size_t* pcchToRead,
              _In_ const size_t cchMax,
              _In_ DWORD dwFlags)
  {
      HRESULT hr = S_OK;
  
      if (pcchToRead && (*pcchToRead >= cchMax))
      {
          hr = STRSAFE_E_INVALID_PARAMETER;
      }
      else if ((dwFlags & STRSAFE_IGNORE_NULLS) && (*ppszSrc == NULL))
      {
          *ppszSrc = L"";
  
          if (pcchToRead)
          {
              *pcchToRead = 0;
          }
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma warning(pop)    // allow null deref
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable : 4100) // Unused parameter (pszDest)
  _Post_satisfies_(cchDest > 0 && cchDest <= cchMax)
      STRSAFEWORKERAPI
      StringValidateDestA(
              _In_reads_opt_(cchDest) STRSAFE_PCNZCH pszDest,
              _In_ size_t cchDest,
              _In_ const size_t cchMax)
  {
      HRESULT hr = S_OK;
  
      if ((cchDest == 0) || (cchDest > cchMax))
      {
          hr = STRSAFE_E_INVALID_PARAMETER;
      }
  
      return hr;
  }
  #pragma warning(pop)
  
  // Intentionally allow null deref when STRSAFE_IGNORE_NULLS is not present.
  #pragma warning(push)
  #pragma warning(disable : __WARNING_DEREF_NULL_PTR)
  #pragma warning(disable : __WARNING_INVALID_PARAM_VALUE_1)
  #pragma warning(disable : __WARNING_RANGE_POSTCONDITION_VIOLATION)
  
  _Post_satisfies_(cchDest > 0 && cchDest <= cchMax)
      STRSAFEWORKERAPI
      StringValidateDestAndLengthA(
              _In_reads_opt_(cchDest) STRSAFE_LPCSTR pszDest,
              _In_ size_t cchDest,
              _Out_ _Deref_out_range_(0, cchDest - 1) size_t* pcchDestLength,
              _In_ const size_t cchMax)
  {
      HRESULT hr;
  
      hr = StringValidateDestA(pszDest, cchDest, cchMax);
  
      if (SUCCEEDED(hr))
      {
          hr = StringLengthWorkerA(pszDest, cchDest, pcchDestLength);
      }
      else
      {
          *pcchDestLength = 0;
      }
  
      return hr;
  }
  // End intentionally allow null deref.
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #pragma warning(push)
  #pragma warning(disable : 4100) // Unused parameter (pszDest)
  _Post_satisfies_(cchDest > 0 && cchDest <= cchMax)
      STRSAFEWORKERAPI
      StringValidateDestW(
              _In_reads_opt_(cchDest) STRSAFE_PCNZWCH pszDest,
              _In_ size_t cchDest,
              _In_ const size_t cchMax)
  {
      HRESULT hr = S_OK;
  
      if ((cchDest == 0) || (cchDest > cchMax))
      {
          hr = STRSAFE_E_INVALID_PARAMETER;
      }
  
      return hr;
  }
  #pragma warning(pop)
  
  // Intentionally allow null deref when STRSAFE_IGNORE_NULLS is not present.
  #pragma warning(push)
  #pragma warning(disable : __WARNING_DEREF_NULL_PTR)
  #pragma warning(disable : __WARNING_INVALID_PARAM_VALUE_1)
  #pragma warning(disable : __WARNING_RANGE_POSTCONDITION_VIOLATION)
  
  _Post_satisfies_(cchDest > 0 && cchDest <= cchMax)
      STRSAFEWORKERAPI
      StringValidateDestAndLengthW(
              _In_reads_opt_(cchDest) STRSAFE_LPCWSTR pszDest,
              _In_ size_t cchDest,
              _Out_ _Deref_out_range_(0, cchDest - 1) size_t* pcchDestLength,
              _In_ const size_t cchMax)
  {
      HRESULT hr;
  
      hr = StringValidateDestW(pszDest, cchDest, cchMax);
  
      if (SUCCEEDED(hr))
      {
          hr = StringLengthWorkerW(pszDest, cchDest, pcchDestLength);
      }
      else
      {
          *pcchDestLength = 0;
      }
  
      return hr;
  }
  // End intentionally allow null deref.
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEWORKERAPI
      StringExValidateDestA(
              _In_reads_opt_(cchDest) STRSAFE_PCNZCH pszDest,
              _In_ size_t cchDest,
              _In_ const size_t cchMax,
              _In_ DWORD dwFlags)
  {
      HRESULT hr = S_OK;
  
      if (dwFlags & STRSAFE_IGNORE_NULLS)
      {
          if (((pszDest == NULL) && (cchDest != 0))   ||
                  (cchDest > cchMax))
          {
              hr = STRSAFE_E_INVALID_PARAMETER;
          }
      }
      else
      {
          hr = StringValidateDestA(pszDest, cchDest, cchMax);
      }
  
      return hr;
  }
  
  // Intentionally allow null deref when STRSAFE_IGNORE_NULLS is not present.
  #pragma warning(push)
  #pragma warning(disable : __WARNING_DEREF_NULL_PTR)
  #pragma warning(disable : __WARNING_INVALID_PARAM_VALUE_1)
  STRSAFEWORKERAPI
      StringExValidateDestAndLengthA(
              _In_reads_opt_(cchDest) STRSAFE_LPCSTR pszDest,
              _In_ size_t cchDest,
              _Out_ _Deref_out_range_(0, (cchDest>0?cchDest-1:0)) size_t* pcchDestLength,
              _In_ const size_t cchMax,
              _In_ DWORD dwFlags)
  {
      HRESULT hr;
  
      if (dwFlags & STRSAFE_IGNORE_NULLS)
      {
          hr = StringExValidateDestA(pszDest, cchDest, cchMax, dwFlags);
  
          if (FAILED(hr) || (cchDest == 0))
          {
              *pcchDestLength = 0;
          }
          else
          {
              hr = StringLengthWorkerA(pszDest, cchDest, pcchDestLength);
          }
      }
      else
      {
          hr = StringValidateDestAndLengthA(pszDest,
                  cchDest,
                  pcchDestLength,
                  cchMax);
      }
  
      return hr;
  }
  // End intentionally allow null deref.
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEWORKERAPI
      StringExValidateDestW(
              _In_reads_opt_(cchDest) STRSAFE_PCNZWCH pszDest,
              _In_ size_t cchDest,
              _In_ const size_t cchMax,
              _In_ DWORD dwFlags)
  {
      HRESULT hr = S_OK;
  
      if (dwFlags & STRSAFE_IGNORE_NULLS)
      {
          if (((pszDest == NULL) && (cchDest != 0))   ||
                  (cchDest > cchMax))
          {
              hr = STRSAFE_E_INVALID_PARAMETER;
          }
      }
      else
      {
          hr = StringValidateDestW(pszDest, cchDest, cchMax);
      }
  
      return hr;
  }
  
  // Intentionally allow null deref when STRSAFE_IGNORE_NULLS is not present.
  #pragma warning(push)
  #pragma warning(disable : __WARNING_DEREF_NULL_PTR)
  #pragma warning(disable : __WARNING_INVALID_PARAM_VALUE_1)
  STRSAFEWORKERAPI
      StringExValidateDestAndLengthW(
              _In_reads_opt_(cchDest) STRSAFE_LPCWSTR pszDest,
              _In_ size_t cchDest,
              _Out_ _Deref_out_range_(0, (cchDest>0?cchDest-1:0)) size_t* pcchDestLength,
              _In_ const size_t cchMax,
              _In_ DWORD dwFlags)
  {
      HRESULT hr;
  
      if (dwFlags & STRSAFE_IGNORE_NULLS)
      {
          hr = StringExValidateDestW(pszDest, cchDest, cchMax, dwFlags);
  
          if (FAILED(hr) || (cchDest == 0))
          {
              *pcchDestLength = 0;
          }
          else
          {
              hr = StringLengthWorkerW(pszDest, cchDest, pcchDestLength);
          }
      }
      else
      {
          hr = StringValidateDestAndLengthW(pszDest,
                  cchDest,
                  pcchDestLength,
                  cchMax);
      }
  
      return hr;
  }
  // End intentionally allow null deref.
  #pragma warning(pop)
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma warning(push)
  #pragma warning(disable:__WARNING_RETURNING_BAD_RESULT)
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEWORKERAPI
      StringCopyWorkerA(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchDest,
              _Always_(_Out_opt_ _Deref_out_range_(<=, (cchToCopy < cchDest) ? cchToCopy : (cchDest - 1))) size_t* pcchNewDestLength,
              _In_reads_or_z_(cchToCopy) STRSAFE_PCNZCH pszSrc,
              _In_ _In_range_(<, STRSAFE_MAX_CCH) size_t cchToCopy)
  {
      HRESULT hr = S_OK;
      size_t cchNewDestLength = 0;
  
      // ASSERT(cchDest != 0);
  
      while (cchDest && cchToCopy && (*pszSrc != '\0'))
      {
          *pszDest++ = *pszSrc++;
          cchDest--;
          cchToCopy--;
  
          cchNewDestLength++;
      }
  
      if (cchDest == 0)
      {
          // we are going to truncate pszDest
          pszDest--;
          cchNewDestLength--;
  
          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
      }
  
      *pszDest = '\0';
  
      if (pcchNewDestLength)
      {
          *pcchNewDestLength = cchNewDestLength;
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEWORKERAPI
      StringCopyWorkerW(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchDest,
              _Always_(_Out_opt_ _Deref_out_range_(<=, (cchToCopy < cchDest) ? cchToCopy : (cchDest - 1))) size_t* pcchNewDestLength,
              _In_reads_or_z_(cchToCopy) STRSAFE_PCNZWCH pszSrc,
              _In_ _In_range_(<, STRSAFE_MAX_CCH) size_t cchToCopy)
  {
      HRESULT hr = S_OK;
      size_t cchNewDestLength = 0;
  
      // ASSERT(cchDest != 0);
  
      while (cchDest && cchToCopy && (*pszSrc != L'\0'))
      {
          *pszDest++ = *pszSrc++;
          cchDest--;
          cchToCopy--;
  
          cchNewDestLength++;
      }
  
      if (cchDest == 0)
      {
          // we are going to truncate pszDest
          pszDest--;
          cchNewDestLength--;
  
          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
      }
  
      *pszDest = L'\0';
  
      if (pcchNewDestLength)
      {
          *pcchNewDestLength = cchNewDestLength;
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma warning(pop)
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEWORKERAPI
      StringVPrintfWorkerA(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchDest,
              _Always_(_Out_opt_ _Deref_out_range_(<=, cchDest - 1)) size_t* pcchNewDestLength,
              _In_ _Printf_format_string_ STRSAFE_LPCSTR pszFormat,
              _In_ va_list argList)
  {
      HRESULT hr = S_OK;
      int iRet;
      size_t cchMax;
      size_t cchNewDestLength = 0;
  
      // leave the last space for the null terminator
      cchMax = cchDest - 1;
  
  #if (STRSAFE_USE_SECURE_CRT == 1) && !defined(STRSAFE_LIB_IMPL)
      iRet = _vsnprintf_s(pszDest, cchDest, cchMax, pszFormat, argList);
  #else
  #pragma warning(push)
  #pragma warning(disable: __WARNING_BANNED_API_USAGE)// "STRSAFE not included"
      iRet = _vsnprintf(pszDest, cchMax, pszFormat, argList);
  #pragma warning(pop)
  #endif
      // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
  
      if ((iRet < 0) || (((size_t)iRet) > cchMax))
      {
          // need to null terminate the string
          pszDest += cchMax;
          *pszDest = '\0';
  
          cchNewDestLength = cchMax;
  
          // we have truncated pszDest
          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
      }
      else if (((size_t)iRet) == cchMax)
      {
          // need to null terminate the string
          pszDest += cchMax;
          *pszDest = '\0';
  
          cchNewDestLength = cchMax;
      }
      else
      {
          cchNewDestLength = (size_t)iRet;
      }
  
      if (pcchNewDestLength)
      {
          *pcchNewDestLength = cchNewDestLength;
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  #ifdef STRSAFE_LOCALE_FUNCTIONS
  
  #pragma warning(push)
  #pragma warning(disable: __WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION)
  
  STRSAFELOCALEWORKERAPI
      StringVPrintf_lWorkerA(
              _Out_writes_(cchDest) STRSAFE_LPSTR pszDest,
              _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchDest,
              _Out_opt_ _Deref_out_range_(<=, cchDest - 1) size_t* pcchNewDestLength,
              _In_ _Printf_format_string_params_(2) STRSAFE_LPCSTR pszFormat,
              _In_ _locale_t locale,
              _In_ va_list argList)
  {
      HRESULT hr = S_OK;
      int iRet;
      size_t cchMax;
      size_t cchNewDestLength = 0;
  
      // leave the last space for the null terminator
      cchMax = cchDest - 1;
  
  #if (STRSAFE_USE_SECURE_CRT == 1) && !defined(STRSAFE_LIB_IMPL)
      iRet = _vsnprintf_s_l(pszDest, cchDest, cchMax, pszFormat, locale, argList);
  #else
      iRet = _vsnprintf_l(pszDest, cchMax, pszFormat, locale, argList);
  #endif
      // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
  
      if ((iRet < 0) || (((size_t)iRet) > cchMax))
      {
          // need to null terminate the string
          pszDest += cchMax;
          *pszDest = '\0';
  
          cchNewDestLength = cchMax;
  
          // we have truncated pszDest
          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
      }
      else if (((size_t)iRet) == cchMax)
      {
          // need to null terminate the string
          pszDest += cchMax;
          *pszDest = '\0';
  
          cchNewDestLength = cchMax;
      }
      else
      {
          cchNewDestLength = (size_t)iRet;
      }
  
      if (pcchNewDestLength)
      {
          *pcchNewDestLength = cchNewDestLength;
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif  // STRSAFE_LOCALE_FUNCTIONS
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEWORKERAPI
      StringVPrintfWorkerW(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchDest,
              _Always_(_Out_opt_ _Deref_out_range_(<=, cchDest - 1)) size_t* pcchNewDestLength,
              _In_ _Printf_format_string_ STRSAFE_LPCWSTR pszFormat,
              _In_ va_list argList)
  {
      HRESULT hr = S_OK;
      int iRet;
      size_t cchMax;
      size_t cchNewDestLength = 0;
  
      // leave the last space for the null terminator
      cchMax = cchDest - 1;
  
  #if (STRSAFE_USE_SECURE_CRT == 1) && !defined(STRSAFE_LIB_IMPL)
      iRet = _vsnwprintf_s(pszDest, cchDest, cchMax, pszFormat, argList);
  #else
  #pragma warning(push)
  #pragma warning(disable: __WARNING_BANNED_API_USAGE)// "STRSAFE not included"
      iRet = _vsnwprintf(pszDest, cchMax, pszFormat, argList);
  #pragma warning(pop)
  #endif
      // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
  
      if ((iRet < 0) || (((size_t)iRet) > cchMax))
      {
          // need to null terminate the string
          pszDest += cchMax;
          *pszDest = L'\0';
  
          cchNewDestLength = cchMax;
  
          // we have truncated pszDest
          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
      }
      else if (((size_t)iRet) == cchMax)
      {
          // need to null terminate the string
          pszDest += cchMax;
          *pszDest = L'\0';
  
          cchNewDestLength = cchMax;
      }
      else
      {
          cchNewDestLength = (size_t)iRet;
      }
  
      if (pcchNewDestLength)
      {
          *pcchNewDestLength = cchNewDestLength;
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  #ifdef STRSAFE_LOCALE_FUNCTIONS
  
  #pragma warning(push)
  #pragma warning(disable: __WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION)
  
  STRSAFELOCALEWORKERAPI
      StringVPrintf_lWorkerW(
              _Out_writes_(cchDest) STRSAFE_LPWSTR pszDest,
              _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchDest,
              _Out_opt_ _Deref_out_range_(<=, cchDest - 1) size_t* pcchNewDestLength,
              _In_ _Printf_format_string_params_(2) STRSAFE_LPCWSTR pszFormat,
              _In_ _locale_t locale,
              _In_ va_list argList)
  {
      HRESULT hr = S_OK;
      int iRet;
      size_t cchMax;
      size_t cchNewDestLength = 0;
  
      // leave the last space for the null terminator
      cchMax = cchDest - 1;
  
  #if (STRSAFE_USE_SECURE_CRT == 1) && !defined(STRSAFE_LIB_IMPL)
      iRet = _vsnwprintf_s_l(pszDest, cchDest, cchMax, pszFormat, locale, argList);
  #else
      iRet = _vsnwprintf_l(pszDest, cchMax, pszFormat, locale, argList);
  #endif
      // ASSERT((iRet < 0) || (((size_t)iRet) <= cchMax));
  
      if ((iRet < 0) || (((size_t)iRet) > cchMax))
      {
          // need to null terminate the string
          pszDest += cchMax;
          *pszDest = L'\0';
  
          cchNewDestLength = cchMax;
  
          // we have truncated pszDest
          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
      }
      else if (((size_t)iRet) == cchMax)
      {
          // need to null terminate the string
          pszDest += cchMax;
          *pszDest = L'\0';
  
          cchNewDestLength = cchMax;
      }
      else
      {
          cchNewDestLength = (size_t)iRet;
      }
  
      if (pcchNewDestLength)
      {
          *pcchNewDestLength = cchNewDestLength;
      }
  
      return hr;
  }
  
  #pragma warning(pop)
  
  #endif  // STRSAFE_LOCALE_FUNCTIONS
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // defined(STRSAFE_LIB_IMPL) || !defined(STRSAFE_LIB)
  
  #ifndef STRSAFE_LIB_IMPL
  // the StringGetsWorkerA/W functions always run inline since we do not want to
  // have a different strsafe lib versions each type of c runtime (eg msvcrt,
  // libcmt, etc..)
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringGetsWorkerA(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPSTR pszDest,
              _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchDest,
              _Always_(_Out_opt_ _Deref_out_range_(<, cchDest>0?cchDest:1)) size_t* pcchNewDestLength)
  {
      HRESULT hr = S_OK;
      size_t cchNewDestLength = 0;
  
      if (cchDest == 1)
      {
          *pszDest = '\0';
  
          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
      }
      else
      {
          while (cchDest > 1)
          {
              char ch;
              int i = getc(stdin);
  
              if (i == EOF)
              {
                  if (cchNewDestLength == 0)
                  {
                      // we failed to read anything from stdin
                      hr = STRSAFE_E_END_OF_FILE;
                  }
  
                  break;
              }
  
              ch = (char)i;
  
              if (ch == '\n')
              {
                  break;
              }
  
              *pszDest++ = ch;
              cchDest--;
  
              cchNewDestLength++;
          }
  
          *pszDest = '\0';
      }
  
      if (pcchNewDestLength)
      {
          *pcchNewDestLength = cchNewDestLength;
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEAPI
      StringGetsWorkerW(
              _Out_writes_(cchDest) _Always_(_Post_z_) STRSAFE_LPWSTR pszDest,
              _In_ _In_range_(1, STRSAFE_MAX_CCH) size_t cchDest,
              _Always_(_Out_opt_ _Deref_out_range_(<=, cchDest - 1)) size_t* pcchNewDestLength)
  {
      HRESULT hr = S_OK;
      size_t cchNewDestLength = 0;
  
      if (cchDest == 1)
      {
          *pszDest = '\0';
  
          hr = STRSAFE_E_INSUFFICIENT_BUFFER;
      }
      else
      {
          while (cchDest > 1)
          {
              wchar_t ch = getwc(stdin);
              // ASSERT(sizeof(wchar_t) == sizeof(wint_t));
  
              if (ch == WEOF)
              {
                  if (cchNewDestLength == 0)
                  {
                      // we failed to read anything from stdin
                      hr = STRSAFE_E_END_OF_FILE;
                  }
  
                  break;
              }
  
              if (ch == L'\n')
              {
                  break;
              }
  
              *pszDest++ = ch;
              cchDest--;
  
              cchNewDestLength++;
          }
  
          *pszDest = L'\0';
      }
  
      if (pcchNewDestLength)
      {
          *pcchNewDestLength = cchNewDestLength;
      }
  
      return hr;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // !STRSAFE_LIB_IMPL
  
  #if defined(STRSAFE_LIB_IMPL) || !defined(STRSAFE_LIB)
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEWORKERAPI
      StringExHandleFillBehindNullA(
              _Inout_updates_bytes_(cbRemaining) STRSAFE_LPSTR pszDestEnd,
              _In_ size_t cbRemaining,
              _In_ DWORD dwFlags)
  {
      if (cbRemaining > sizeof(char))
      {
          memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), cbRemaining - sizeof(char));
      }
  
      return S_OK;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  STRSAFEWORKERAPI
      StringExHandleFillBehindNullW(
              _Inout_updates_bytes_(cbRemaining) STRSAFE_LPWSTR pszDestEnd,
              _In_ size_t cbRemaining,
              _In_ DWORD dwFlags)
  {
      if (cbRemaining > sizeof(wchar_t))
      {
          memset(pszDestEnd + 1, STRSAFE_GET_FILL_PATTERN(dwFlags), cbRemaining - sizeof(wchar_t));
      }
  
      return S_OK;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  // ignore false positives due to complexity of bitflag usage
  #pragma warning(push)
  #pragma warning(disable : __WARNING_USING_UNINIT_VAR)
  #pragma warning(disable : __WARNING_RETURN_UNINIT_VAR)
  #pragma warning(disable : __WARNING_MISSING_ZERO_TERMINATION2)
  #pragma warning(disable : __WARNING_POSTCONDITION_NULLTERMINATION_VIOLATION)
  #pragma warning(disable:__WARNING_POTENTIAL_RANGE_POSTCONDITION_VIOLATION)
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  _Success_(1)  // always succeeds, no exit tests needed
      STRSAFEWORKERAPI
      StringExHandleOtherFlagsA(
              _Out_writes_bytes_(cbDest) STRSAFE_LPSTR pszDest,
              _In_ _In_range_(1, STRSAFE_MAX_CCH * sizeof(char)) size_t cbDest,
              _In_ _In_range_(0, cbDest>sizeof(char)?(cbDest / sizeof(char)) - 1:0) size_t cchOriginalDestLength,
              _Outptr_result_buffer_(*pcchRemaining) STRSAFE_LPSTR* ppszDestEnd,
              _Out_ _Deref_out_range_(0, cbDest / sizeof(char)) size_t* pcchRemaining,
              _In_ DWORD dwFlags)
  {
      size_t cchDest = cbDest / sizeof(char);
  
      _Analysis_assume_(dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE));
  
      if ((cchDest > 0) && (dwFlags & STRSAFE_NO_TRUNCATION))
      {
          char* pszOriginalDestEnd;
  
          pszOriginalDestEnd = pszDest + cchOriginalDestLength;
  
          *ppszDestEnd = pszOriginalDestEnd;
          *pcchRemaining = cchDest - cchOriginalDestLength;
  
          // null terminate the end of the original string
          *pszOriginalDestEnd = '\0';
      }
  
      if (dwFlags & STRSAFE_FILL_ON_FAILURE)
      {
          memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  
          if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
          {
              *ppszDestEnd = pszDest;
              *pcchRemaining = cchDest;
              _Analysis_assume_(*pszDest == '\0');
          }
          else if (cchDest > 0)
          {
              char* pszDestEnd;
  
              pszDestEnd = pszDest + cchDest - 1;
  
              *ppszDestEnd = pszDestEnd;
              *pcchRemaining = 1;
  
              // null terminate the end of the string
              *pszDestEnd = L'\0';
          }
      }
  
      if ((cchDest > 0) && (dwFlags & STRSAFE_NULL_ON_FAILURE))
      {
          *ppszDestEnd = pszDest;
          *pcchRemaining = cchDest;
  
          // null terminate the beginning of the string
          *pszDest = '\0';
      }
  
      return S_OK;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  _Success_(1)  // always succeeds, no exit tests needed
      STRSAFEWORKERAPI
      StringExHandleOtherFlagsW(
              _Out_writes_bytes_(cbDest) STRSAFE_LPWSTR pszDest,
              _In_ _In_range_(1, STRSAFE_MAX_CCH * sizeof(wchar_t)) size_t cbDest,
              _In_ _In_range_(0, cbDest>sizeof(wchar_t)?(cbDest / sizeof(wchar_t)) - 1:0) size_t cchOriginalDestLength,
              _Outptr_result_buffer_(*pcchRemaining) STRSAFE_LPWSTR* ppszDestEnd,
              _Out_ _Deref_out_range_(0, cbDest / sizeof(wchar_t)) size_t* pcchRemaining,
              _In_ DWORD dwFlags)
  {
      size_t cchDest = cbDest / sizeof(wchar_t);
  
      _Analysis_assume_(dwFlags & (STRSAFE_NO_TRUNCATION | STRSAFE_FILL_ON_FAILURE | STRSAFE_NULL_ON_FAILURE));
  
      if ((cchDest > 0) && (dwFlags & STRSAFE_NO_TRUNCATION))
      {
          wchar_t* pszOriginalDestEnd;
  
          pszOriginalDestEnd = pszDest + cchOriginalDestLength;
  
          *ppszDestEnd = pszOriginalDestEnd;
          *pcchRemaining = cchDest - cchOriginalDestLength;
  
          // null terminate the end of the original string
          *pszOriginalDestEnd = L'\0';
      }
  
      if (dwFlags & STRSAFE_FILL_ON_FAILURE)
      {
          memset(pszDest, STRSAFE_GET_FILL_PATTERN(dwFlags), cbDest);
  
          if (STRSAFE_GET_FILL_PATTERN(dwFlags) == 0)
          {
              *ppszDestEnd = pszDest;
              *pcchRemaining = cchDest;
              _Analysis_assume_(cchDest == 0 || *pszDest == L'\0');
          }
          else if (cchDest > 0)
          {
              wchar_t* pszDestEnd;
  
              pszDestEnd = pszDest + cchDest - 1;
  
              *ppszDestEnd = pszDestEnd;
              *pcchRemaining = 1;
  
              // null terminate the end of the string
              *pszDestEnd = L'\0';
          }
      }
  
      if ((cchDest > 0) && (dwFlags & STRSAFE_NULL_ON_FAILURE))
      {
          *ppszDestEnd = pszDest;
          *pcchRemaining = cchDest;
  
          // null terminate the beginning of the string
          *pszDest = L'\0';
      }
  
      return S_OK;
  }
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma warning(pop)   // ignore false positives due to complexity of bitflag usage
  
  #pragma region Desktop Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM)
  
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #endif  // defined(STRSAFE_LIB_IMPL) || !defined(STRSAFE_LIB)
  
  #pragma region Application Family
  #if WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM)
  
  // Do not call these functions, they are worker functions for internal use within this file
  #ifdef DEPRECATE_SUPPORTED
  #pragma deprecated(StringLengthWorkerA)
  #pragma deprecated(StringLengthWorkerW)
  #pragma deprecated(UnalignedStringLengthWorkerW)
  #pragma deprecated(StringExValidateSrcA)
  #pragma deprecated(StringExValidateSrcW)
  #pragma deprecated(StringValidateDestA)
  #pragma deprecated(StringValidateDestAndLengthA)
  #pragma deprecated(StringValidateDestW)
  #pragma deprecated(StringValidateDestAndLengthW)
  #pragma deprecated(StringExValidateDestA)
  #pragma deprecated(StringExValidateDestAndLengthA)
  #pragma deprecated(StringExValidateDestW)
  #pragma deprecated(StringExValidateDestAndLengthW)
  #pragma deprecated(StringCopyWorkerA)
  #pragma deprecated(StringCopyWorkerW)
  #pragma deprecated(StringVPrintfWorkerA)
  #pragma deprecated(StringVPrintfWorkerW)
  #pragma deprecated(StringGetsWorkerA)
  #pragma deprecated(StringGetsWorkerW)
  #pragma deprecated(StringExHandleFillBehindNullA)
  #pragma deprecated(StringExHandleFillBehindNullW)
  #pragma deprecated(StringExHandleOtherFlagsA)
  #pragma deprecated(StringExHandleOtherFlagsW)
  #else
  #define StringLengthWorkerA             StringLengthWorkerA_instead_use_StringCchLengthA_or_StringCbLengthA
  #define StringLengthWorkerW             StringLengthWorkerW_instead_use_StringCchLengthW_or_StringCbLengthW
  #define UnalignedStringLengthWorkerW    UnalignedStringLengthWorkerW_instead_use_UnalignedStringCchLengthW
  #define StringExValidateSrcA            StringExValidateSrcA_do_not_call_this_function
  #define StringExValidateSrcW            StringExValidateSrcW_do_not_call_this_function
  #define StringValidateDestA             StringValidateDestA_do_not_call_this_function
  #define StringValidateDestAndLengthA    StringValidateDestAndLengthA_do_not_call_this_function
  #define StringValidateDestW             StringValidateDestW_do_not_call_this_function
  #define StringValidateDestAndLengthW    StringValidateDestAndLengthW_do_not_call_this_function
  #define StringExValidateDestA           StringExValidateDestA_do_not_call_this_function
  #define StringExValidateDestAndLengthA  StringExValidateDestAndLengthA_do_not_call_this_function
  #define StringExValidateDestW           StringExValidateDestW_do_not_call_this_function
  #define StringExValidateDestAndLengthW  StringExValidateDestAndLengthW_do_not_call_this_function
  #define StringCopyWorkerA               StringCopyWorkerA_instead_use_StringCchCopyA_or_StringCbCopyA
  #define StringCopyWorkerW               StringCopyWorkerW_instead_use_StringCchCopyW_or_StringCbCopyW
  #define StringVPrintfWorkerA            StringVPrintfWorkerA_instead_use_StringCchVPrintfA_or_StringCbVPrintfA
  #define StringVPrintfWorkerW            StringVPrintfWorkerW_instead_use_StringCchVPrintfW_or_StringCbVPrintfW
  #define StringGetsWorkerA               StringGetsWorkerA_instead_use_StringCchGetsA_or_StringCbGetsA
  #define StringGetsWorkerW               StringGetsWorkerW_instead_use_StringCchGetsW_or_StringCbGetsW
  #define StringExHandleFillBehindNullA   StringExHandleFillBehindNullA_do_not_call_this_function
  #define StringExHandleFillBehindNullW   StringExHandleFillBehindNullW_do_not_call_this_function
  #define StringExHandleOtherFlagsA       StringExHandleOtherFlagsA_do_not_call_this_function
  #define StringExHandleOtherFlagsW       StringExHandleOtherFlagsW_do_not_call_this_function
  #endif // !DEPRECATE_SUPPORTED
  
  #endif /* WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP | WINAPI_PARTITION_SYSTEM) */
  #pragma endregion
  
  #pragma warning(pop)
  #pragma warning(pop)
  
  #endif  // _STRSAFE_H_INCLUDED_
  