Geoff Chappell - Software Analyst
This function copies as much of an input string as will fit in an output buffer, and ensures the output is null-terminated.
LPWSTR StrCpyNW (LPWSTR psz1, LPCWSTR psz2, int cchMax);
The psz1 argument is the address of an output buffer that is to receive as large a copy as possible of the input string.
The psz2 argument is the address of the input string, or is NULL to stand for an empty input string.
The cchMax argument is the capacity of the output buffer, in characters.
The function returns psz1.
Since SHLWAPI version 5.0, this function’s implementation is simply to call StrCpyNXW but return psz1. (The other function usefully returns a pointer to the end of the string in the output buffer, as if to prepare for appending another string.)
Earlier versions have their own implementation, which differs mainly in assuming that an input string is given, i.e., that psz2 is not NULL.
In all versions, the behaviour is better treated as undefined if the input string overlaps the output buffer: the copy is correct if the source is higher in memory than the destination, but the source may be corrupted.
Some time in 2001-02, Microsoft’s documentation of this function started warning that “The copied string is not guaranteed to be null-terminated.” Yet the original coding must be something very like
LPWSTR StrCpyNW (LPWSTR psz1, LPCWSTR psz2, int cchMax) { if (cchMax > 0) { while (-- cchMax > 0) { WCHAR ch = *psz2 ++; *psz1 ++ = ch; if (ch == L'\0') break; } if (cchMax == 0) *psz1 = L'\0'; } return psz1; }
Provided that the output buffer has any capacity to receive a null-terminated string, the output necessarily must be null-terminated. If later versions had their call to StrCpyNXW inlined, the coding would look very like
LPWSTR StrCpyNW (LPWSTR psz1, LPCWSTR psz2, int cchMax) { if (cchMax > 0) { if (psz2 != NULL) { while (-- cchMax > 0) { WCHAR ch = *psz2 ++; *psz1 ++ = ch; if (ch == L'\0') { psz1 --; break; } } } *psz1 = L'\0'; } return psz1; }
which is even harder to mistake as ensuring that the copied string is always null-terminated. Note that Microsoft’s mistaken warning is in a stippled box labelled Security Alert in bold preceded by a warning icon. Are such alerts just for show? This one was evidently not backed up by reference to the source code.
In defence of Microsoft, StrCpyN is documented as if there are both Unicode and ANSI forms. SHLWAPI.DLL provides only the Unicode form as a function, but SHLWAPI.H gives programmers an ANSI form as a macro, expanding just to the KERNEL32 function lstrcpynA. This macro expansion is arguably unwise of Microsoft, since lstrcpynA has (documented) behaviour for ANSI strings that StrCpyNW does not have for Unicode strings. Specifically, lstrcpynA can fail but StrCpyNW cannot. Of course, hardly any explicit calls to lstrcpynA ever will be checked for failure in real-world practice, despite the documentation, but calls made through the StrCpyNA macro won’t ever be checked for failure because of the documentation. Failure, naturally enough, leaves the output buffer undefined. But if this ANSI-specific case is what Microsoft means when warning that StrCpyN is not guaranteed to null-terminate its output, then the warning is far too slight: surely Microsoft ought warn that the function can return without having produced any well-defined output.
The StrCpyNW function is exported by name from SHLWAPI.DLL version 4.70 and higher. A function with the same name but a different coding is also exported by name from NT builds of SHELL32.DLL in version 1.30 and higher, until discontinued in version 6.0 from Windows Vista.
This function has been documented since some time in 1997-98. Though it dates from 1996 in SHLWAPI, and even earlier in SHELL32, it has always been said to require at least SHLWAPI version 4.71.