当我尝试将目录从远程驱动器复制到同一驱动器上的新目录时,如何修复 SHFileOperationA 的错误。 WinSysErr 183

How to fix error with SHFileOperationA when I am trying to copy a directory from a remote drive to a new directory on that same drive. WinSysErr 183

当我在我的本地驱动器上使用此方法时,它将按预期工作并将我的预期目录(里面有两个文件)复制到我本地驱动器上的另一个位置。

然而,当尝试在远程驱动器上做同样的事情时,我从 SHFileOperationA( &directory ); 收到一个错误代码,特别是 183,查看 Windows 系统错误我发现:

ERROR_ALREADY_EXISTS 183 (0xB7) Cannot create a file when that file already exists.

关于可能导致此问题的原因有什么想法吗?我知道这个 Q: 驱动器没有 file/folder 限制,因为我能够创建目录,因此,我确信路径名也是正确的。

void Utilities::CopyDirectory(CString from, CString to)
{
SHFILEOPSTRUCTA directory;
/////////////////////////////////test strings
////////////////////////////////from = "Q:\TestFolder"
////////////////////////////////to = "Q:\A\B"
char fromDir[100];
char toDir[100];

strcpy(fromDir, from);
strcpy(toDir, to);

//Last file name is terminated with a double NULL character to indicate end of buffer
//add null character after the last single NULL
fromDir[strlen(fromDir) +1] = 0;
toDir[strlen(toDir) +1] = 0; 

directory.hwnd = NULL; 
directory.wFunc = FO_COPY;
directory.pFrom = fromDir;
directory.pTo = toDir;
directory.fFlags = FOF_RENAMEONCOLLISION | FOF_NOCONFIRMATION | FOF_NOCONFIRMMKDIR | FOF_SILENT;
directory.fAnyOperationsAborted = 0;
directory.hNameMappings = NULL;
directory.lpszProgressTitle = NULL;

int i = SHFileOperationA( &directory );
//i = 0 if success. If not Windows System Error Code
if(i != 0)
    {
    sprintf(gBuf, "Error Occured in copying temp directory to: \n%s\n\n WinSysErrCode: %d", to, i);
    ::MessageBox(NULL, gBuf, "Directory Copy To Outbox Error", MB_OK);
    DeleteDirectory(from);
    return;
    }

//Delete temporary outbox folder after it was sent to Outbox
DeleteDirectory(from);
if(from.Find("QPPR_") >= 0)
    {
    sprintf(gBuf, "Receipt has been sent to the email server outbox.\n\nSent to: %s", to);
    ::MessageBox(NULL, gBuf, "Email Sent", MB_OK);
    }
else if(from.Find("QPP_") >= 0)
    {
    sprintf(gBuf, "Pay Now Request has been sent to the email server outbox.\n\nSent to: %s", to);
    ::MessageBox(NULL, gBuf, "Email Sent", MB_OK);
    }
}

I receive an error code from SHFileOperationA( &directory ); Specifically 183, which looking at Windows System Errors I find this: ERROR_ALREADY_EXISTS 183 (0xB7) Cannot create a file when that file already exists.

这不是错误代码 183 在这种情况下的含义。 SHFileOperation() documentation 对错误 183(十六进制 0xB7)有以下说明:

Return value

Type: int

Returns zero if successful; otherwise nonzero. Applications normally should simply check for zero or nonzero.

...

Do not use GetLastError with the return values of this function.

To examine the nonzero values for troubleshooting purposes, they largely map to those defined in Winerror.h. However, several of its possible return values are based on pre-Win32 error codes, which in some cases overlap the later Winerror.h values without matching their meaning. Those particular values are detailed here, and for these specific values only these meanings should be accepted over the Winerror.h codes. However, these values are provided with these warnings:

These are pre-Win32 error codes and are no longer supported or defined in any public header file. To use them, you must either define them yourself or compare against the numerical value.

These error codes are subject to change and have historically done so.

These values are provided only as an aid in debugging. They should not be regarded as definitive.

Error Code Value Meaning
... ... ...
DE_ERROR_MAX 0xB7 MAX_PATH was exceeded during the operation.
... ... ...

并且,FWIW,您的 fromDirtoDir 缓冲区是等待发生的潜在缓冲区溢出。 MAX_PATH 是 260 个字符,但您的缓冲区每个只能容纳 100 个字符,并且 strcpy() 不执行任何边界检查。至少,您的缓冲区大小应为 MAX_PATH,并且您应该使用 strcpy_s() 来保护它们免受溢出,例如:

char fromDir[MAX_PATH+2]{};
char toDir[MAX_PATH+2]{};

if (strcpy_s(fromDir, from) != 0)
{
    // error...
}

if (strcpy_s(toDir, to) != 0)
{
    // error...
}

...

或者更好的是,将缓冲区动态分配到适当的大小,例如:

int iFromLen = strlen(from);
int iToLen = strlen(to);

char *fromDir = new char[iFromLen+2];
char *toDir = new char[iToLen+2];

strcpy(fromDir, from);
strcpy(toDir, to);

fromDir[iFromLen+1] = '[=11=]';
toDir[iToLen+1] = '[=11=]'; 

...

delete[] fromDir;
delete[] toDir;

或者,由于你是按值传入CString个对象,反正它们已经是副本了,所以直接修改它们然后使用它们就可以了as-is,例如:

...
from += _T('[=12=]');
to += _T('[=12=]');

directory.pFrom = from.c_str();
directory.pTo = to.c_str();
...