SHFileOperation 这个API函数怎么用起来结果飘忽不定?

starytx 2014-01-10 06:13:08
环境:vs2005.我的一个复制文件夹的函数如下:
// 将原路径srcDir中的文件/文件夹(不包括srcDir本身),拷贝到目标路径desDir下,存在的话覆盖
bool copyForder(const char * srcDir,const char *desDir)
{
SHFILEOPSTRUCT fop;
ZeroMemory(&fop, sizeof(fop));
fop.fFlags = FOF_SILENT | FOF_NOCONFIRMATION | FOF_NOERRORUI | FOF_NOCONFIRMMKDIR |FOF_MULTIDESTFILES;
fop.wFunc = FO_COPY;
fop.pFrom = _T(srcDir);
fop.pTo = _T(desDir);

int nResult = SHFileOperation(&fop);
if(0 == nResult)
{
return true;
}

return false;
}

测试代码如下:
	string src="D:\\source\\";
string des = "D:\\dest\\aaa\\";
if(!copyForder(src.c_str() ,des.c_str()))
printf("文件夹拷贝失败!\n");
else
printf("文件夹拷贝成功!\n");
好像文件夹路径最后加不加那个斜杠会影响结果?之前试的时候从source往dest中复制的话怎么折腾都成功,现在往dest下的aaa文件夹里放感觉有时候就会失败,nResult返回值有时候是123,有时候是87,有墙,还查不到更多的信息,有时候复制成功但是又吧source本身都复制过去了,好混乱啊,到底怎么正确使用呢?
...全文
272 7 打赏 收藏 转发到动态 举报
写回复
用AI写文章
7 条回复
切换为时间正序
请发表友善的回复…
发表回复
starytx 2014-01-11
  • 打赏
  • 举报
回复
这函数真不好用,运行的时候一会儿失败一会儿成功的,哎,还是递归复制算了。
vipcxj 2014-01-10
  • 打赏
  • 举报
回复
引用 5 楼 starytx 的回复:
[quote=引用 2 楼 vipcxj 的回复:] 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. 如果非要说LZ有啥问题,你的源路径和目标路径都必须是双null结尾,因为这个API支持多个路径放一起,用null隔开,所以双null才是标志路径结束。 example

// WRONG
LPTSTR pszSource = L"C:\\Windows\\*";

// RIGHT
LPTSTR pszSource = L"C:\\Windows\\*\0";
我看过网上说的,末尾也加上"\0\0"了,还是不稳定[/quote] 应该是多一个"\0",因为字符串本身就有一个"\0",不过感觉这貌似不是问题,LZ可以试试把FOF_NOERRORUI这个flag去掉,看看错误到底是啥~ 还有我上面给的示例代码就是msdn提供的,或许它就是不支持末尾是"\\"的,你干脆再弄个函数,一旦末尾源路径末尾是"\\",你就改成"\\*\0",这应该不难吧~
starytx 2014-01-10
  • 打赏
  • 举报
回复
引用 2 楼 vipcxj 的回复:
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. 如果非要说LZ有啥问题,你的源路径和目标路径都必须是双null结尾,因为这个API支持多个路径放一起,用null隔开,所以双null才是标志路径结束。 example

// WRONG
LPTSTR pszSource = L"C:\\Windows\\*";

// RIGHT
LPTSTR pszSource = L"C:\\Windows\\*\0";
我看过网上说的,末尾也加上"\0\0"了,还是不稳定
vipcxj 2014-01-10
  • 打赏
  • 举报
回复
引用 3 楼 starytx 的回复:
[quote=引用 1 楼 vipcxj 的回复:] http://msdn.microsoft.com/en-us/library/windows/desktop/bb775771(v=vs.85).aspx 微软更推荐用IFileOperation
怎么用啊?比较紧急啊,没有多少时间来自己研究了,或者有其他好用的赋值文件夹的代码也可以。xcopy命令行的就算了,现有的就是这个,用其他的来替换的。[/quote] 我刚刚又看了下IFileOperation要求windows最低版本wista,实在有点坑,LZ,你试试我说的在字符串结尾在加个"\0"吧,这是msdn说滴 其实copy文件,boost提供了一个跨平台的支持,就是FileSystem库,不过这个库是需要编译的。用法和Java里的File类很像,并且提供文件拷贝,复制,删除等等操作~
starytx 2014-01-10
  • 打赏
  • 举报
回复
引用 1 楼 vipcxj 的回复:
http://msdn.microsoft.com/en-us/library/windows/desktop/bb775771(v=vs.85).aspx 微软更推荐用IFileOperation
怎么用啊?比较紧急啊,没有多少时间来自己研究了,或者有其他好用的赋值文件夹的代码也可以。xcopy命令行的就算了,现有的就是这个,用其他的来替换的。
vipcxj 2014-01-10
  • 打赏
  • 举报
回复
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. 如果非要说LZ有啥问题,你的源路径和目标路径都必须是双null结尾,因为这个API支持多个路径放一起,用null隔开,所以双null才是标志路径结束。 example

// WRONG
LPTSTR pszSource = L"C:\\Windows\\*";

// RIGHT
LPTSTR pszSource = L"C:\\Windows\\*\0";
vipcxj 2014-01-10
  • 打赏
  • 举报
回复
http://msdn.microsoft.com/en-us/library/windows/desktop/bb775771(v=vs.85).aspx 微软更推荐用IFileOperation
API功能详解: 使用API函数SHFileOperation,这个函数可以同时拷贝、删除、改名或移动多个文件,甚至整个目录。如果你愿意,还可以显示相应的动画对话框,功能十分强大。SHFileOperation的参数是一个SHFILEOPSSTRUCT结构。这个结构中各成员的含义如下: - hwnd - 显示文件操作对话框的窗口句柄 - wFunc - 表示要进行的操作,可以取以下值: - FO_COPY - 拷贝文件。所要拷贝的文件由pFrom成员指定,目的地址有pTo成员指定。 - FO_DELETE - 删除pFrom指定的文件。(pTo 被忽略。) - FO_MOVE - 移动文件。所要移动的文件由pFrom成员指定,目的地址有pTo成员指定。 - FO_RENAME - 改名pFrom指定的文件。 - pFrom - 指定文件名的缓冲区的地址。必须以Chr(0)结尾。如果包括多个文件以Chr(0)分割。 - pTo - 指定目的文件名或目录的缓冲区的地址。必须以Chr(0)结尾。如果使用了FOF_MULTIDESTFILES标志,可以包括多个文件名,文件名之间以Chr(0)分割。 - fFlags - 标志: - FOF_ALLOWUNDO - 允许恢复 - FOF_FILESONLY - 如果使用了*.*,只操作文件。 - FOF_MULTIDESTFILES - pTo成员可以为多个目的文件。 - FOF_NOCONFIRMATION - 不显示确认对话框。 - FOF_NOCONFIRMMKDIR - 不确认是否建立目录。 - FOF_NOERRORUI - 如果有错误,不显示用户界面。 - FOF_RENAMEONCOLLISION - 如果目的文件已经存在,给要处理的文件一个新名字。 - FOF_SILENT - 不显示进度对话框。 - FOF_SIMPLEPROGRESS - 显示进度框,但不显示文件名。 - fAnyOperationsAborted -如果用户退出,该成员为TRUE,否则为FALSE。 - lpszProgressTitle - 进度框的标题,只有选择了FOF_SIMPLEPROGRESS标志才有效。
VB拦截Windows Explorer删除进程,内含API HOOK,源代码:倒霉蛋儿,程序有时候也会窗口勾挂失败!   勾住了SHFileOperation函数,DLL用Delphi写的C会的太少,查了半天才知道原来explorer是用SHFileOperation删除文件,经过测试很稳定,没有出现崩溃的情况,由于只勾住了SHFileOperation函数,所以别的程序要是调用DeleteFile删除文件,拦截不到,要是想拦截DeleteFile自己接着写吧。      mod_Inject.bas类的注释摘录:   Dim MyAddr As Long ‘执行远程线程代码的起始地址。这里等于LoadLibraryA的地址   ‘dll文件路径   MyDllFileLength = LenB(StrConv(MyDllFileName, vbFromUnicode)) + 1    ‘这里把dll文件名从Unicode转换成Ansi,否则英文字母是2个字节。 _   顺便说一下,学过C的应该知道字符串要以/0标志结尾,所以dll文件名长度要加上1个字节存放Chr(0)   ‘得到进程的句柄   在目标进程中申请分配一块空白内存区域。内存的起始地址保存在MyDllFileBuffer中。 _   这块内存区域我们用来存放dll文件路径,并作为参数传递给LoadLibraryA。   在分配出来的内存区域中写入dll路径径。注意第二个参数传递的是MyDllFileBuffer的内容, _   而不是MyDllFileBuffer的内存地址?   If MyReturn = 0 Then Inject = False   MyAddr = GetProcAddress(GetModuleHandle("Kernel32"), "LoadLibraryA")   ‘得到LoadLibraryA函数的起始地址。他的参数就是我们刚才写入的dll路径。但是LoadLibraryA本身是不知道参数在哪里的。 _   接下来我们就用CreateRemoteThread函数告诉他参数放在哪里了? If MyAddr = 0 Then Inject = False   MyResult = CreateRemoteThread(ProcessHandle, 0, 0, MyAddr, MyDllFileBuffer, 0, 0)   好了,现在用CreateRemoteThread在目标进程创建一个线程,线程起始地址指向LoadLibraryA, _   参数就是MyDllFileBuffer中保存的dll路径?    If MyResult = 0 Then    Inject = False    Else    Inject = True    End If    ‘接下来你可以使用WaitForSingleObject等待线程执行完毕。 _    并用GetExitCodeThread得到线程的退出代码,用来判断时候正确执行了dll中的代码。    CloseHandle MyResult    CloseHandle ProcessHandle    ‘扫地工作   End Function

64,637

社区成员

发帖
与我相关
我的任务
社区描述
C++ 语言相关问题讨论,技术干货分享,前沿动态等
c++ 技术论坛(原bbs)
社区管理员
  • C++ 语言社区
  • encoderlee
  • paschen
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
  1. 请不要发布与C++技术无关的贴子
  2. 请不要发布与技术无关的招聘、广告的帖子
  3. 请尽可能的描述清楚你的问题,如果涉及到代码请尽可能的格式化一下

试试用AI创作助手写篇文章吧