为何重复调用SHFileOperationW会创建文件夹而非移动文件?
问题:重复调用自定义Move函数时后续操作异常
我基于SHFileOperationW实现了自定义的文件/文件夹移动函数,代码如下:
int MoveItem(string strSourcePath, string strDestinationDirectory, string strNewName, bool bAllowOverwrite, bool bCreateDestinationDirectoryIfNotExist) { int intPositionOfLastSlash; int intResult = 0; SHFILEOPSTRUCTW sfosMove; string strNewPath; string strOldName; wchar_t a_wcNewPath[MAX_PATH] = {0}; wchar_t a_wcSourcePath[MAX_PATH] = {0}; wstring wsNewPath; wstring wsSourcePath; if((IsFileExist(strSourcePath) == false) && (IsFolderExist(strSourcePath) == false)) { intResult = 0x7C; } else { if(IsFolderExist(strDestinationDirectory) == false) { if(bCreateDestinationDirectoryIfNotExist == false) { intResult = 0x7C; } } } if(intResult == 0) { intPositionOfLastSlash = strSourcePath.find_last_of("\\"); strOldName = strSourcePath.substr(intPositionOfLastSlash + 1); if(strNewName == "") { strNewPath = strDestinationDirectory + "\\" + strOldName; } else { strNewPath = strDestinationDirectory + "\\" + strNewName; } if(bAllowOverwrite == false) { if(IsFileExist(strNewPath) == true) { intResult = 0x7E; } else if(IsFolderExist(strNewPath) == true) { intResult = 0x80; } } } if(intResult == 0) { /*- Source Path -*/ wsSourcePath = Utf8StringToWstring(strSourcePath); StrCpyW(a_wcSourcePath, wsSourcePath.c_str()); CopyMemory(a_wcSourcePath + lstrlenW(a_wcSourcePath), L"\0\0", 2); /*---------------*/ /*- New Path -*/ wsNewPath = Utf8StringToWstring(strNewPath); StrCpyW(a_wcNewPath, wsNewPath.c_str()); CopyMemory(a_wcNewPath + lstrlenW(a_wcNewPath), L"\0\0", 2); /*-------------------------*/ /*- Move Item -*/ sfosMove.fFlags = FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_SILENT; sfosMove.pFrom = a_wcSourcePath; sfosMove.pTo = a_wcNewPath; sfosMove.wFunc = FO_MOVE; intResult = SHFileOperationW(&sfosMove); /*-------------*/ } return intResult; }
但重复调用该函数时,只有第一个文件能正常移动,后续调用会创建与文件名同名的文件夹。例如:第一个文件abc.txt可正常移动到目标目录,第二个文件def.txt未被移动,反而在目标目录下生成了名为def.txt的文件夹。调用示例如下:
// "example_folder" 已存在于D盘 int intResult; intResult = MoveItem("C:\\ProgramData\\abc.txt", "D:\\example_folder", "", true, false); if(intResult == 0) { intResult = MoveItem("C:\\ProgramData\\def.txt", "D:\\example_folder", "", true, false); }
问题原因
核心问题是SHFILEOPSTRUCTW结构体未被初始化。第一次调用SHFileOperationW后,结构体中未显式赋值的成员(如hwnd、hNameMappings等)会残留垃圾值,这些残留值会干扰后续调用的逻辑,导致SHFileOperationW误将目标路径解析为需要创建的文件夹,而非文件的目标路径。
解决方法
在使用sfosMove结构体前,用ZeroMemory将其初始化为全0,确保每次调用时结构体的所有成员都处于已知的初始状态:
修改代码中定义sfosMove的部分,添加初始化代码:
SHFILEOPSTRUCTW sfosMove; ZeroMemory(&sfosMove, sizeof(SHFILEOPSTRUCTW)); // 新增初始化逻辑
此外,目标路径的拼接逻辑本身无问题,但结构体初始化是解决重复调用异常的关键。
内容的提问来源于stack exchange,提问作者Çağatay KAYA
相关产品推荐
相关产品推荐

