如何将 SHFileOperation() 与 CString 路径一起使用

How to use SHFileOperation() with CString paths

本文关键字:路径 CString 一起 SHFileOperation      更新时间:2023-10-16

我正在尝试将CString转换为LPCWSTR并且效果很好。但是在代码的处理中出现了一些问题。

我想将目录复制到另一个路径,所以我正在使用SHFILEOPSTRUCT

HWND console = GetConsoleWindow();
SHFILEOPSTRUCT s = { 0 };
s.hwnd = console;
s.wFunc = FO_COPY;
s.fFlags = FOF_SILENT;
CString _folderName("a6_töüst-Oa5Z.OZS-CI5O5235"),
firstPath("C:\ORTIM-Daten\a5Pc 2.0.3\Temp\"),
lastPart("\Documents\*"),
firstPathDest("C:\ORTIM-Daten\a5Pc 2.0.3\"),
lastPartDest("Documents\"),
_folderNameDest("a6_töüst-Oa5Z.OZS-CI5O5235");
CString cstrTemp = firstPath + _folderName + lastPart,
cstrTempDest = firstPathDest + lastPartDest + _folderNameDest;
s.pTo   = cstrTempDest /*_TEXT("C:\ORTIM-Daten\a5Pc 2.0.3\Documents\a6_töüst-Oa5Z.OZS-CI5O5235")*/;
s.pFrom = cstrTemp     /*_TEXT("C:\ORTIM-Daten\a5Pc 2.0.3\Temp\a6_töüst-Oa5Z.OZS-CI5O5235\Documents\*")*/;
SHFileOperation(&s);

当我直接使用CString时,复制操作不起作用,但是当我使用_TEXT()宏(如注释中所示(在结构中分配LPCWSTR成员时,一切正常。

编辑 1

在源路径和目标路径的变体中,代码都会编译。

在此变体中,代码编译并执行复制操作:

s.pTo   = _TEXT("C:\ORTIM-Daten\a5Pc 2.0.3\Documents\a6_töüst-Oa5Z.OZS-CI5O5235");
s.pFrom = _TEXT("C:\ORTIM-Daten\a5Pc 2.0.3\Temp\a6_töüst-Oa5Z.OZS-CI5O5235\Documents\*");

在我实际需要的另一个变体中,代码也可以编译,但不会发生复制操作:

s.pTo   = cstrTempDest;
s.pFrom = cstrTemp;

>SHFILEOPSTRUCT需要以两个NUL 字符结尾的字符串,但根据定义,NUL 终止的字符串以1结尾,并且任何其他 NUL 字符都将被不接受显式长度参数CString方法忽略。

您可以通过手动添加一个来强制双 NULL:

CString cstrTempDest = firstPathDest + lastPartDest + _folderNameDest;
// *** Add NUL manually ***
cstrTempDest.AppendChar( 0 );
s.pTo = cstrTempDest;
// For debuging - verify resulting string with example.
TCHAR* test = _TEXT("C:\ORTIM-Daten\a5Pc 2.0.3\Documents\a6_töüst-Oa5Z.OZS-CI5O5235");
// +2 because we want to check two NULs at end.
ASSERT( memcmp( s.pTo, test, (_tcslen(test)+2)*sizeof(TCHAR) ) == 0 );

替代解决方案可以使用具有显式长度参数的方法:

CString cstrTempDest = firstPathDest + lastPartDest
+ CString(_folderNameDest, _tcslen(_folderNameDest)+1);

 
如果项目配置为使用 unicode 字符集,请使用宽字符串调用CString构造函数:

CString _folderName(_T("a6_töüst-Oa5Z.OZS-CI5O5235")),
firstPath(_T("C:\ORTIM-Daten\a5Pc 2.0.3\Temp\"))
...

Unicode 模式下的CString会自动将窄字符串转换为宽字符串,但当运行时代码页和开发代码页之间存在差异时,它可能会失败。如果你打算使用 Unicode 并且永不回头,扔掉_TEXTTEXT_T宏,只使用宽文字:

CString _folderName( L"a6_töüst-Oa5Z.OZS-CI5O5235" ),
firstPath( L"C:\ORTIM-Daten\a5Pc 2.0.3\Temp\" )
...

 
您还应该检查SHFileOperation返回值。

用户 msp0815 关于创建双空结尾 CString 的答案解决了您的问题。

// strings must be double-null terminated
CString from(cstrTemp + (TCHAR)'');
PCZZTSTR szzFrom= from;
s.pFrom= szzFrom;
CString dest(cstrTempDest + (TCHAR)'');
PCZZTSTR szzDest= dest;
s.pTo= szzDest;

我通常不会经常使用 LPCWSTR,但这是我的想法:

CString TestCSTR = "Hello world";
LPCWSTR TestLPC;
TestLPC = (LPCWSTR)_TEXT(TestCSTR.GetString());

事实上,它按预期工作,变量TestLPC包含"Hello world",或者更准确地说,是指向它的长指针。应该可以在没有后果的情况下删除_TEXT但我不确定,顺便说一句,结果是一样的。