Как использовать 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 без последствий, но я не уверен, результат тот же, кстати.

Другие вопросы по тегам