Environment: Windows 9x/NT/2K, Version 4.00 (or later) of Shell32.dll
Introduction
The function
, enables you to copy, move or delete a file system object. As you can see, this function takes as its sole parameter a pointer to a
structure (also shown below).
// SHFileOperation syntax
WINSHELLAPI int WINAPI SHFileOperation(LPSHFILEOPSTRUCT lpFileOp);
// SHFILEOPSTRUCT layout
typedef struct _SHFILEOPSTRUCT{
HWND hwnd;
UINT wFunc;
LPCSTR pFrom;
LPCSTR pTo;
FILEOP_FLAGS fFlags;
BOOL fAnyOperationsAborted;
LPVOID hNameMappings;
LPCSTR lpszProgressTitle;
} SHFILEOPSTRUCT, FAR *LPSHFILEOPSTRUCT;
|
Unfortunately, despite this function’s obvious usefulness, the Microsoft documentation is very ambiguous regarding the
structure and how to fill it out. In fact, there are several pitfalls when using this structure. Therefore, in this article, I’ll attempt to address these issues so that those of you using this function for the first time can benefit from my experience as to how to take advantage of this very handy function.
Name Collision Resolution and the hNameMappings member
is (almost always) an input-only member of
In fact, after the call to
has returned successfully, this value will be actually be set to
. The only time that this value will be changed by the
function is if you have specified the flags
|
in the
member. Then if there were files that had to be renamed due to a name collision, assign a name mapping object will containing their old and new names to the hNameMappings member.
This member can be treated as a void pointer to a continuous memory block. This memory block in turn can be treated as some kind of the structure with int as a first member. Value of this integer indicates how many SHNAMEMAPPING structures follows. This way you can retrieve needed info.
File Name Retrieval
Another pitfall that you need to know about deals with retrieving the names of files.
and
members are declared as
.
However, they are laid out as
; not
! Therefore, any string copying function available fails to successfully copy the path strings.
Sample Code
Here is a code snippet illustrating these issues. It can be done differently and is not posted for the purpose of code review. Treat it rather as a suggestion.
CString OldPath;
CString NewPath;
SHFILEOPSTRUCT shFileOp;
//after filling other members:
shFileOp.fFlags = FOF_WANTMAPPINGHANDLE
| FOF_RENAMEONCOLLISION;
shFileOp.lpszProgressTitle = "Test";
shFileOp.fAnyOperationsAborted = FALSE;
SHFileOperation(&shFileOp);
if(!shFileOp.hNameMappings)
return; //there is nothing further to do, no file collision
struct TMPMAP
{
int Indx;
SHNAMEMAPPING *pMapping;
};
//this will give you a pointer to the beginning of the
//array of SHNAMEMAPPING structures
TMPMAP *pTmpMap = (TMPMAP*)shFileOp.hNameMappings;
for(int in = 0; in < pTmpMap->Indx; in++)
{
SHNAMEMAPPING *pMap = &pTmpMap->pMapping[in];
//do the same thing for csOldPath
/*********************************************************/
char *buf = csNewPath.GetBufferSetLength(pMap->cchNewPath);
strcpy(buf, (char*)pMap->pszOldPath); //see the result of
this,
for(int dw = 0 ; dw < 2 * pMap->cchNewPath - 1 ; dw+=2)
{
*buf = (pMap->pszNewPath[dw]);
buf++;
}
buf = 0;
csNewPath.ReleaseBuffer(); //and see the result of this.
/**********************************************************/
}
//always free it if requested
SHFreeNameMappings(shFileOp.hNameMappings);
|