views:

121

answers:

2

I have win32 API application in visual c++. I want to create a directory in Application Common Data Directory. I have the code which is generating following error. I have also tried to add '\0' at the end of string, but the same error appears.

Debug Assertion Failed! Expression: (L“String is not NULL terminated” && 0);

code :

TCHAR AppDir[MAX_PATH]; TCHAR SetPath[MAX_PATH];

ITEMIDLIST* pidl; HRESULT hRes = SHGetSpecialFolderLocation( NULL, CSIDL_COMMON_APPDATA|CSIDL_FLAG_CREATE ,&pidl ); if (hRes==NOERROR) { SHGetPathFromIDList(pidl, AppDir); }

strcpy_s(SetPath,AppDir);

::strcat_s(SetPath,"\Keylogger"); ::SHCreateDirectoryExW(hWnd,(LPCWSTR)SetPath,NULL);

::strcat_s(SetPath,"\SnapShot"); ::SHCreateDirectoryExW(hWnd,(LPCWSTR)SetPath,NULL);

A: 

It seems that you are mixing single byte- and unicode string functions.

strcpy_s and strcat_s is used for single byte strings

SHCreateDirectoryExW is used for unicode wide strings.

Try using SHCreateDirectoryEx.

RED SOFT ADAIR
Yeh! you are right, thanks a lot. For your prompt and accurate comment.
Ravi shankar
+1  A: 

Your big problem is the (LPCWSTR) casts in the calls to SHCreateDirectoryExW - these casts are explicitly preventing the compiler telling you what the error is.

A general rule I wish more c++ programmers understood would be, Don't typecast. Unless you understand why. Never typecast to 'fix' a compiler error :- 99% of the time you havn't fixed the error, you've just hidden it.

Analysing the code from the beginning: The use of TCHAR implies that you are writing code that can target UNICODE (text is stored in 16 bit WCHAR fields) or ANSI builds (where text is stored in 8bit CHAR fields). the str prefix in the strxxx_s functions however means you are using string functions that only deal with 8bit strings. The W's on the Shell functions however are how windows APIs advertise the functions are expecting UNICODE strings.

To 'correct' your program you need to pick to either (a) target ANSI, (b) target UNICODE, or (c) target both depending on compiler settings and rewrite it appropriately. The 'both' option would be written:

TCHAR AppDir[MAX_PATH];
TCHAR SetPath[MAX_PATH];
ITEMIDLIST* pidl;
HRESULT hRes = SHGetSpecialFolderLocation( NULL, CSIDL_COMMON_APPDATA|CSIDL_FLAG_CREATE ,&pidl );
SHGetPathFromIDList(pidl, AppDir);
_tcscpy_s(SetPath,AppDir);
_tcscat_s(SetPath,_T("\Keylogger"));
SHCreateDirectoryEx(hWnd,SetPath,NULL);
_tcscat_s(SetPath,_T("\SnapShot"));
SHCreateDirectoryEx(hWnd,SetPath,NULL);

We have dropped the (incorrect) typecasting. Replaced the strxxx_s functions with the _tcsxxx_s versions. And wrapped string literals in the _T() macro that ensures that they are wide strings when _UNICODE is defined, and normal ansi strings otherwise.

Chris Becke
Thanks for your valuable comment.
Ravi shankar