I want to use the Win API CreateProcess for which accepts 2nd parameter as "LPTSTR".
But I've the path to my exe in a char array. My VS2013 project (static library) is Unicode encoding type.
Code snippert below.
IN this line
"appPath = (LPTSTR)TestEXEPath;"
of the below code snippet where the type cast is happening, I see that the characters in "appPath" gets converted to some junk characters whereas the RHS of this expression "TestEXEPath" does have valid characters.
However tehre is no compilation error here. It is at run time this characters get corrupted in "appPath".
I know this typecast is creating this problem. But how do I solve this, how do I type cast this char array to LPTSTR typr which is needed by "CreateProcess() API.
Or is there any better way of doing this so as to avoid the char array itself.
LPTSTR appPath;
char cwd[_MAX_PATH];
getcwd(cwd, _MAX_PATH);
char TestEXEPath[_MAX_PATH];
strcpy(TestEXEPath, cwd);
strcat(TestEXEPath, "\\pwrtest.exe /sleep /c:1");
appPath = (LPTSTR)TestEXEPath; // The characters in this gets converted to some junk characters.
.......................
......................
CreateProcess(NULL, appPath, NULL, NULL, FALSE, 0, NULL, workingDir, &sI, &pI))
You are compiling for Unicode, so LPTSTR expands to wchar_t*. But you have ANSI data, char*. In that case it is simplest to call CreateProcessA and pass the ANSI data.
BOOL retval = CreateProcessA(..., TestExePath, ...));
If you want to avoid using ANSI functions then you can stick to wchar_t arrays.
whar_t exepath[MAX_PATH + 100]; // enough room for cwd and the rest of command line
GetCurrentDirectory(MAX_PATH, exepath);
wcscat(exepath, L"\\pwrtest.exe /sleep /c:1");
BOOL retval = CreateProcess(..., exepath, ...);
Note that I switched from getcwd to GetCurrentDirectory in order to get a wide char version of the working directory.
Note also that your code should check for errors. I neglected to do that here due to laze. But in your real code, you should not be as lazy as I have been.
The fact that you had to cast should have set off warning signals for you. Well, judging from the question, it probably did. When you write:
appPath = (LPTSTR)TestEXEPath;
That simply tells the compiler to treat TestEXEPath as LPTSTR whether or not it really is. And the fact that the program won't compile without the cast tells you that TestEXEPath is not LPTSTR. The cast does not change that reality, it merely shuts the compiler up. Always a bad move.
With unicode, LPTSTR points to an array of wchar_t and not an array of char.
Here some additional explantions.
Try with:
TCHAR TestExePath[_MAX_PATH];
And use wcscat() and wcscpy() and the other wide c-string handling functions in <cwchar>.
Also take a look at the very convenient ATL conversion classes here: http://msdn.microsoft.com/en-us/library/87zae4a3.aspx
LPTSTR str = CA2T(TestEXEPath);
Or even easier just
CreateProcess(NULL, CA2T(TestEXEPath), NULL, NULL, FALSE, 0, NULL, workingDir, &sI, &pI))
No destruction is needed.
Related
In the following code, RegSetValueEx is only writing the first letter of my string. I've tried changing the sizes to just about anything I can think of, and I only ever get the first string. Any help is appreciated.
LPCWSTR path = L"Test String";
size_t size = wclsen(path) * sizeof(wchar_t);
DWORD dwResult = RegSetValueEx(HKEY_LOCAL_MACHINE,
"SOFTWARE\\My App",
0,
REG_SZ,
(LPBYTE)path,
test);
I've tried using path.size() * sizeof(wchar_t) and any number of other sizes I could think of, but nothing seems to work right. Any ideas?
RegSetValueEx() expects REG_SZ data to be provided as const TCHAR*, which in your case is const CHAR* per your compiler settings - as evident by the fact that you are able to pass a char* to the second parameter, which means you are actually calling RegSetValueExA(). Since you are providing a const WCHAR* to RegSetValueExA(), the first 0x00 byte gets interpreted as a null terminator, hence only a single character value gets written.
Your options are:
RegSetValueExW(..., (const BYTE*) path, ...
CString sPath(path); RegSetValueEx(..., (const BYTE*) (LPCTSTR) sPath, ...
Switch project settings to Unicode build
Sounds like you haven't defined UNICODE/_UNICODE before compiling, so the zero-byte in your wide string is being interpreted as signaling the end of the string.
Try using RegSetValueExW (and L"SOFTWARE\\My App") instead.
Dealing with these insane strings and arrays is giving me a headache...
Here's my code so far
wchar_t mypath[MAX_PATH];
wchar_t temppath[MAX_PATH];
GetModuleFileName(0, mypath, MAX_PATH);
GetTempPath(MAX_PATH, temppath);
CreateDirectory(???, NULL);
The first two windows API functions use the LPWSTR variable. The third uses LPCWSTR. What's the major difference? After I get the path for the TEMP directory, I want to create a new directory inside it called "test". This means I need to append (L"test") to my "temppath" variable. Can someone give me some tips on how to use these arrays. This is what makes C++ a pain. Why couldn't everyone just settle on one data type for strings. How is wchar_t even useful? It's so hard to use and manipulate.
Thanks guys!
The first two windows API functions use the LPWSTR variable. The third uses LPCWSTR. What's the major difference?
LPCWSTR is a const version of LPWSTR:
From LPCWSTR:
typedef const wchar_t* LPCWSTR;
From LPWSTR:
typedef wchar_t* LPWSTR, *PWSTR;
I want to create a new directory inside it called "test". This means I need to append (L"test") to my "temppath" variable.
Use a std::wostringstream:
std::wostringstream wos;
wos << temppath << L"\\test";
std::wstring fullpath(wos.str());
or just a std::wstring (as suggested by chris in the comments):
std::wstring fullpath(std::wstring(temppath) + L"\\test");
to produce a concatenated version. Then use c_str() as the argument to CreateDirectory():
if (CreateDirectory(fullpath.c_str(), NULL) ||
ERROR_ALREADY_EXISTS == GetLastError())
{
// Directory created or already existed.
}
else
{
// Failed to create directory.
}
Use PathCombine(), eg:
wchar_t temppath[MAX_PATH+1] = {0};
GetTempPath(MAX_PATH, temppath);
wchar_t mypath[MAX_PATH+8] = {0};
PathCombineW(mypath, temppath, L"test");
CreateDirectoryW(mypath, NULL);
I am trying to convert a program for multibyte character to Unicode.
I have gone through the program and preceded the string literals with L so they look like L"string".
This has worked but I am now left with a C style string that won't conform. I have tried the L and putting it in TEXT() but the L gets added to the variable name -- not the string -- if I use TEXT().
I have tried making it a TCHAR but then it complains that it cannot convert a TCHAR to a char *.
What options am I left with?
I know C and C++ are different. It is an old in-house C library that has been used in C++ projects for several years now.
The std::mbstowcs function is what you are looking for:
char text[] = "something";
wchar_t wtext[20];
mbstowcs(wtext, text, strlen(text)+1);//Plus null
LPWSTR ptr = wtext;
for strings,
string text = "something";
wchar_t wtext[20];
mbstowcs(wtext, text.c_str(), text.length());//includes null
LPWSTR ptr = wtext;
--> ED: The "L" prefix only works on string literals, not variables. <--
The clean way to use mbstowcs is to call it twice to find the length of the result:
const char * cs = <your input char*>
size_t wn = mbsrtowcs(NULL, &cs, 0, NULL);
// error if wn == size_t(-1)
wchar_t * buf = new wchar_t[wn + 1](); // value-initialize to 0 (see below)
wn = mbsrtowcs(buf, &cs, wn + 1, NULL);
// error if wn == size_t(-1)
assert(cs == NULL); // successful conversion
// result now in buf, return e.g. as std::wstring
delete[] buf;
Don't forget to call setlocale(LC_CTYPE, ""); at the beginning of your program!
The advantage over the Windows MultiByteToWideChar is that this is entirely standard C, although on Windows you might prefer the Windows API function anyway.
I usually wrap this method, along with the opposite one, in two conversion functions string->wstring and wstring->string. If you also add trivial overloads string->string and wstring->wstring, you can easily write code that compiles with the Winapi TCHAR typedef in any setting.
[Edit:] I added zero-initialization to buf, in case you plan to use the C array directly. I would usually return the result as std::wstring(buf, wn), though, but do beware if you plan on using C-style null-terminated arrays.[/]
In a multithreaded environment you should pass a thread-local conversion state to the function as its final (currently invisible) parameter.
Here is a small rant of mine on this topic.
I'm using the following in VC++ and it works like a charm for me.
CA2CT(charText)
This version, using the Windows API function MultiByteToWideChar(), handles the memory allocation for arbitrarily long input strings.
int lenA = lstrlenA(input);
int lenW = ::MultiByteToWideChar(CP_ACP, 0, input, lenA, NULL, 0);
if (lenW>0)
{
output = new wchar_t[lenW];
::MultiByteToWideChar(CP_ACP, 0, input, lenA, output, lenW);
}
You may use CString, CStringA, CStringW to do automatic conversions and convert between these types. Further, you may also use CStrBuf, CStrBufA, CStrBufW to get RAII pattern modifiable strings
Im creating a DLL that shares memory between different applications.
The code that creates the shared memory looks like this:
#define NAME_SIZE 4
HANDLE hSharedFile;
create(char[NAME_SIZE] name)
{
hSharedFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 1024, (LPCSTR)name);
(...) //Other stuff that maps the view of the file etc.
}
It does not work. However if I replace name with a string it works:
SharedFile = CreateFileMapping(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, 1024, (LPCSTR)"MY_TEST_NAME");
How can I get this to work with the char array?
I have a java background where you would just use string all the time, what is a LPCSTR? And does this relate to whether my MS VC++ project is using Unicode or Multi-Byte character set
I suppose you should increase NAME_SIZE value.
Do not forget that array must be at least number of chars + 1 to hold \0 char at the end, which shows the end of the line.
LPCSTR is a pointer to a constant null-terminated string of 8-bit Windows (ANSI) characters and defined as follows:
LPCSTR defined as typedef __nullterminated CONST CHAR *LPCSTR;
For example even if you have "Hello world" constant and it has 11 characters it will take 12 bytes in the memory.
If you are passing a string constant as an array you must add '\0' to the end like {'T','E','S','T', '\0'}
If you look at the documentation, you'll find that most Win32 functions take an LPCTSTR, which represents a string of TCHAR. Depending on whether you use Unicode (the default) or ANSI, TCHAR will expand to either wchar_t or char. Also, LPCWSTR and LPCSTR explicitly represent Unicode and ANSI strings respectively.
When you're developing for Win32, in most cases, it's best to follow suit and use LPCTSTR wherever you need strings, instead of explicit char arrays/pointers. Also, use the TEXT("...") macro to create the correct kind of string literals instead of just "...".
In your case though, I doubt this is causing a problem, since both your examples use only LPCSTR. You have also defined NAME_SIZE to be 4, could it be that your array is too small to hold the string you want?
This is my procedure:
bool Open(std::string filename)
{
...
HANDLE hFile = CreateFile(filename.c_str(), GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
...
}
Error:'CreateFileW' : cannot convert parameter 1 from 'const char *' to 'LPCWSTR'
Types pointed to are unrelated; conversion requires reinterpret_cast, C-style cast or function-style cast
Where is the problem?
A std::string consists of an array of char's, and so the c_str function returns a const char*.
A LPCWSTR is a Long Pointer to a Constant Wide String, or in other words, const wchar_t*.
So you have a couple of options. Either get the filename as a wide string (std::wstring), or specify that you want the non-wide version of CreateFile instead. That can be done either by calling CreateFileA or disabling UNICODE in your project settings.
CreateFile is a macro which either resolves to CreateFileA (the char version) or CreateFileW (the wide char version) depending on whether or not unicode is enabled.
You have specified std::string, whose character type is char. And the code you're using CreateFile() in must be being compiled under the definition of the pre-processor symbol UNICODE, since that selects the actual underlying function CreateFileW().
Either get rid of the UNICODE definition, or explicitly use CreateFileA().
It looks like you are compiling with Unicode support turned on. You may want to turn it off, or if not use std::wstring instead of std::string.
As others have suggested, you could call CreateFileA directly, but I'd strongly suggest you not do this - you will end up with an unmaintanable collection of Unicode and non-Unicode function calls.
The problem is you are trying to pass char* to a function requiring wchar_t*
You could write a function to convert string into wstring:
wstring Widen( const string& str );
Then you could call CreateFile like this:
HANDLE hFile = CreateFile( Widen(filename).c_str(), etc. );
Another technique I've seen used is to conditionally define tstring to be either string or wstring depending on the Unicode setting, and use tstring everywhere in your code.
bool Open(tstring filename)
{
...
HANDLE hFile = CreateFile( filename.c_str(), etc. );
...
}
It's a bit of a thorny issue I'm afraid and the best solution for you is something only you can decide. However, I'd agree with Neil and steer clear of directly calling CreateFileA as that will leave you in a mess eventually.