Important You must ensure that the source and destination paths are double-null terminated. A normal string ends in just a single null character. If you pass that value in either the source or destination members, the function will not realize when it has reached the end of the string and will continue to read on in memory until it comes to a random double null value. This can at least lead to a buffer overrun, and possibly the unintended deletion of unrelated data.
// WRONG
LPTSTR pszSource = L"C:\\Windows\\*";
// RIGHT
LPTSTR pszSource = L"C:\\Windows\\*\0";
To account for the two terminating null characters, be sure to create buffers large enough to hold MAX_PATH (which normally includes the single terminating null character) plus 1.
It cannot be overstated that your paths should always be full paths. If the
pFrom or
pTo members are unqualified names, the current directories are taken from the global current drive and directory settings as managed by the
GetCurrentDirectory and
SetCurrentDirectory functions.
If you do not provide a full path, the following facts become pertinent:
- The lack of a path before a file name does not indicate to SHFileOperation that this file resides in the root of the current directory.
- The PATH environment variable is not used by SHFileOperation to determine a valid path.
- SHFileOperation cannot be relied on to use the directory that is the current directory when it begins executing. The directory seen as the current directory is process-wide, and it can be changed from another thread while the operation is executing. If that were to happen, the results of SHFileOperation would be unpredictable.
If pFrom is set to a file name without a full path, deleting the file with FO_DELETE does not move it to the Recycle Bin, even if the FOF_ALLOWUNDO flag is set. You must provide a full path to delete the file to the Recycle Bin.
SHFileOperation fails on any path prefixed with "\\?\".
There are two versions of this structure, an ANSI version (SHFILEOPSTRUCTA) and a Unicode version (SHFILEOPSTRUCTW). The Unicode version is identical to the ANSI version, except that wide character strings (
LPCWSTR) are used in place of ANSI character strings (
LPCSTR). On Microsoft Windows 98 and earlier, only the ANSI version is supported. On Microsoft Windows NT 4.0 and later, both the ANSI and Unicode versions of this structure are supported. SHFILEOPSTRUCTW and SHFILEOPTSTRUCTA should never be used directly; the appropriate structure is redefined as
SHFILEOPSTRUCT by the precompiler depending on whether the application is compiled for ANSI or Unicode.
SHNAMEMAPPING has similar ANSI and Unicode versions. For ANSI applications, hNameMappings points to an int followed by an array of ANSI SHNAMEMAPPING structures. For Unicode applications, hNameMappings points to an int followed by an array of Unicode SHNAMEMAPPING structures. However, on Windows NT 4.0 and later, SHFileOperation always returns a handle to a Unicode set of SHNAMEMAPPING structures. If you want applications to be functional with all versions of Windows, the application must employ conditional code to deal with name mappings. For example:
x = SHFileOperation(&shop);
if (fWin9x)
HandleAnsiNameMappings(shop.hNameMappings);
else
HandleUnicodeNameMappings(shop.hNameMappings);
Treat
hNameMappings as a pointer to a structure whose members are a
UINT value followed by a pointer to an array of
SHNAMEMAPPING structures, as seen in its declaration:
struct HANDLETOMAPPINGS
{
UINT uNumberOfMappings; // Number of mappings in the array.
LPSHNAMEMAPPING lpSHNameMapping; // Pointer to the array of mappings.
};
The UINT value indicates the number of SHNAMEMAPPING structures in the array. Each SHNAMEMAPPING structure contains the old and new path for one of the renamed files.
Note The handle must be freed with SHFreeNameMappings.
For a complete application that uses the SHFILEOPSTRUCT structure and explains how to set up the SHNAMEMAPPING structure, see the Knowledge Base Article Q151799 at http://support.microsoft.com/support/kb/articles/Q151/7/99.asp.