Как использовать SHFileOperation() с путями CString
Я пытаюсь конвертировать 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\\*\0"),
firstPathDest("C:\\ORTIM-Daten\\a5Pc 2.0.3\\"),
lastPartDest("Documents\\"),
_folderNameDest("a6_töüst-Oa5Z.OZS-CI5O5235\0");
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\0")*/;
s.pFrom = cstrTemp /*_TEXT("C:\\ORTIM-Daten\\a5Pc 2.0.3\\Temp\\a6_töüst-Oa5Z.OZS-CI5O5235\\Documents\\*\0")*/;
SHFileOperation(&s);
Когда я использую CString
напрямую, операция копирования не работает, но когда я использую _TEXT()
макрос (как в комментариях), чтобы назначить LPCWSTR
члены в структуре все работает.
РЕДАКТИРОВАТЬ 1
В обоих вариантах исходного и целевого путей код компилируется.
В этом варианте код компилируется и выполняет операцию копирования:
s.pTo = _TEXT("C:\\ORTIM-Daten\\a5Pc 2.0.3\\Documents\\a6_töüst-Oa5Z.OZS-CI5O5235\0");
s.pFrom = _TEXT("C:\\ORTIM-Daten\\a5Pc 2.0.3\\Temp\\a6_töüst-Oa5Z.OZS-CI5O5235\\Documents\\*\0");
В другом варианте, который мне действительно нужен, код тоже компилируется, но операция копирования не происходит:
s.pTo = cstrTempDest;
s.pFrom = cstrTemp;
3 ответа
SHFILEOPSTRUCT
ожидает строки, заканчивающиеся двумя символами NUL, но строки, оканчивающиеся NUL, по определению заканчиваются одним, а любые дополнительные символы NUL игнорируются CString
методы, которые не принимают явный аргумент длины.
Вы можете принудительно установить двойной NUL, добавив его вручную:
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\0");
// +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\\"))
...
CString
в режиме Unicode автоматически преобразует узкие строки в широкие, но может потерпеть неудачу, если существует несоответствие между кодовыми страницами времени выполнения и разработки. Если вы планируете перейти на Unicode и никогда не оглядываться назад, выбросьте _TEXT
, TEXT
а также _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)'\0');
PCZZTSTR szzFrom= from;
s.pFrom= szzFrom;
CString dest(cstrTempDest + (TCHAR)'\0');
PCZZTSTR szzDest= dest;
s.pTo= szzDest;
Я обычно не использую LPCWSTR, но вот моя идея:
CString TestCSTR = "Hello world";
LPCWSTR TestLPC;
TestLPC = (LPCWSTR)_TEXT(TestCSTR.GetString());
Он работает, как и ожидалось, на самом деле переменная TestLPC содержит "Hello world" или, точнее, длинный указатель на нее. Должно быть возможно удалить _TEXT без последствий, но я не уверен, результат тот же, кстати.