VS2015, Unicode: Getting the "Could Not Find the Path Specified" error running the following code in a listbox:
wchar_t *currPath, *cumPath;
int listTotal = 5;
int pathLength = 32760;
listTotal = SendMessageW(hList, LB_GETCOUNT, 0, 0);
wcscpy_s(cumPath, pathLength, L"\\\\?\\C:\\");
//wcscpy_s(cumPath, pathLength, L"C:\\"); //Tried this, no difference
wcscpy_s(currPath, MAX_PATH - 3, L"");
for (int i = 0; i < listTotal; i++) {
SendMessageW(hList, LB_GETTEXT, i, (LPARAM) currPath); //"My Nested Path" picked up from textbox OK
wcscat_s(cumPath, pathLength, (wchar_t *) currPath);
\\OK but doubled backslashes
wcscat_s(cumPath, MAX_PATH - 3, __TEXT("\\"));
\\appear in debugger variable contents
}
int errorcode = CreateDirectoryW(cumPath, NULL);
if (errorcode == 0) {
ErrorExit(TEXT("CreateDirectoryW"));
//GetLastError courtesy [MSDN][1]
}
Meh, have I missed something fundamental here?
The double backslash is not parsed out of the variable name. Is there a way to construct a macro using a verbatim or "as is" prefix that works in conjunction with TEXT or L?
Edit1 The following two lines preceded the code:
currPath = (wchar_t *)calloc(pathLength, sizeof(wchar_t));
cumPath = (wchar_t *)calloc(pathLength, sizeof(wchar_t));
Both these vars are declared module wide. However, prior to entry on this sub there was:
currPath = (wchar_t *)calloc(pathLength, sizeof(wchar_t));
...
free(currPath);
Would the "re-calloc" of currPath have upset anything?
Edit2: No, tried with another variable. The value of cumPath before CreateDirectoryW is as expected?
cumPath = 0x005b4fe8 L"\\\\?\\C:\\My Nested Path\\My Nested Path\\My Nested Path\\My Nested Path\\My Nested Path\\"
Eureka! commenting out this line, the function worked!
//wcscat_s(cumPath, MAX_PATH - 3, __TEXT("\\"));
But now there are no nested directories, as was the original requirement.
cumPath = 0x00644fe8 L"\\?\C:\My Nested PathMy Nested PathMy Nested PathMy Nested PathMy Nested Path"
the first problem is that cumPath is not pointed to any allocated memory.
and the wcscpy_s() function expects the destination to be a char array large enough to hold the source bytes
here is a relevant extract from the wcscpy() man page
DESCRIPTION
The wcscpy() function is the wide-character equivalent of the strcpy(3)
function. It copies the wide-character string pointed to by src,
including the terminating null wide character (L'\0'), to the array
pointed to by dest.
The strings may not overlap.
The programmer must ensure that there is room for at least
wcslen(src)+1 wide characters at dest.
It appears that something is broken in the way the system handles the C compiled nested directory strings.
There is no similar problem in C++ apparently.
The solution here is to change the current directory with each new directory iteration:
#include <Windows.h>
#include <Strsafe.h>
void ErrorExit(LPCTSTR lpszFunction)
{
DWORD dww = 0;
LPVOID lpMsgBuf;
LPVOID lpDisplayBuf;
dww = GetLastError();
FormatMessage(
FORMAT_MESSAGE_ALLOCATE_BUFFER |
FORMAT_MESSAGE_FROM_SYSTEM |
FORMAT_MESSAGE_IGNORE_INSERTS,
NULL,
dww,
MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), (LPTSTR)&lpMsgBuf,0, NULL);
lpDisplayBuf = (LPVOID)LocalAlloc(LMEM_ZEROINIT, (lstrlen((LPCTSTR)lpMsgBuf) + lstrlen((LPCTSTR)lpszFunction) + 40) * sizeof(TCHAR));
StringCchPrintf((LPTSTR)lpDisplayBuf, LocalSize(lpDisplayBuf) / sizeof(TCHAR), TEXT("%s failed with error %lu: %s"), lpszFunction, dww, lpMsgBuf);
MessageBox(NULL, (LPCTSTR)lpDisplayBuf, "Error", MB_OK);
LocalFree(lpDisplayBuf);
LocalFree(lpMsgBuf);
}
int main()
{
wchar_t *currPathW, *cumPathW;
int listTotal = 2;
int errorcode;
int pathLength = MAX_PATH - 3;
int stripLen;
currPathW = (wchar_t *)calloc(pathLength, sizeof(wchar_t));
cumPathW = (wchar_t *)calloc(pathLength, sizeof(wchar_t));
wcscpy_s(cumPathW, pathLength, L"\\\\?\\C:\\");
wcscpy_s(currPathW, MAX_PATH - 3, L"NestedPath");
for (int i = 0; i < listTotal; i++) {
wcscat_s(cumPathW, pathLength, (wchar_t *) currPathW);
//OK but doubled backslashes
wcscat_s(cumPathW, MAX_PATH - 3, L"\\");
//appear in debugger variable contents
int errorcode = CreateDirectoryW(cumPathW, NULL);
if (errorcode == 0) ErrorExit("Failed: ");
}
//wchar_t * currPathWtmp = (wchar_t *)calloc(pathLength, sizeof(wchar_t));
wchar_t * currPathWtmp;
currPathWtmp = cumPathW;
stripLen = wcslen(currPathWtmp)- wcslen(L"NestedPath") - 1;
for (int i = 0; i < listTotal; i++) {
int errorcode = RemoveDirectoryW(currPathWtmp);
if (errorcode == 0) ErrorExit("Failed: ");
currPathWtmp [stripLen] = 0;
}
//currPathWtmp = NULL;
free(currPathW);
free(cumPathW);
}
Edit: The function failed with "Could Not Find the Path Specified" again on the 256 char barrier, so it looks like jumping a few more coding hoops to get it actually working as advertised.
Edit2: Changing PreprocessorDefinitions from _WIN32 to WIN64 (_AMD64 in this case) didn't make any difference.
Edit3: Should compile this out of the box now. All working! In actual fact it works for many values of listTotal. Something else going on.