2

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))
codeLover
  • 3,720
  • 10
  • 65
  • 121
  • You can use `GetCurrentDirectory` to get it as a wide string in the first place. You should also use a variant of `PathCombine` to add the filename onto the path. – chris Aug 13 '14 at 13:07

3 Answers3

4

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.

David Heffernan
  • 601,492
  • 42
  • 1,072
  • 1,490
  • Thanks for this usefulinfo. Is there a way wherein I can write this code portable for both Unicode and ANSCI (MultiByteCharc) ? – codeLover Aug 13 '14 at 14:11
  • @codeLover You only want to do that if you are coding for Windows 95/98/ME which don't support Unicode. I doubt you are. In which case make your life simple and code for the native character set of Windows, UTF-16 Unicode. – David Heffernan Aug 13 '14 at 14:16
  • Sure good suggestion. Just curious to understand, 2 things :: 1) If the VS project settings is set to "Unicode" & if I use ANSCII functions like, CreateProcessA, char[], strcpy, getcwd() etc.. willit cause any issue ? What is the whole point of selecting Unicode if I use ANSCII functions and datatypes. 2) Is there any advantage of having "MultiByte CharacterSet" (ANSCII) as the setting in VS project setting over Unicode. Then why does VS provide ANSCII as default setting even if Unicode is native for windows. Is there any memory related advatage ANSCII has over UNicode ? – codeLover Aug 13 '14 at 14:23
  • 1) No issues. If you use entirely ANSI, then don't target Unicode. But are you sure you don't want to support international text, use long file names etc. 2) Choose MBCS or Unicode depending on which character set you want to have as your default. MBCS is default setting (at least in older VS versions) for historical reasons. Using ANSI has greater memory and perf requirements because the native API is Unicode and so the Windows API ANSI functions have to convert between ANSI and Unicode because the underlying APIs are all Unicode. – David Heffernan Aug 13 '14 at 16:00
  • I think there are plenty of good topics on the web and at MSDN that cover these issues. I'm not sure that there's much more I can offer regarding your original question. – David Heffernan Aug 13 '14 at 16:01
  • It is worth pointing out that the MSVC build settings don't distinguish between ANSI and MBCS. When you pick a non-Unicode configuration, you get an ANSI build. Which, on certain systems, uses a multi-byte character set (MBCS). On US English systems (and I believe most Western European systems, too), you get a single-byte character set (SBCS). But really, don't write applications in the year 2014 that use anything but Unicode. Do whatever it takes to obtain a Unicode string in the first place; for example, by calling `GetCurrentDirectory`. Avoid the `A`-suffixed API functions. (cc @code) – Cody Gray - on strike Aug 13 '14 at 23:12
  • By using unicode solution mentioned above I could resolve teh issue but the CReateProcesss() is causing an unhandled exception & crashing the code. I've taken care to not provide const as the 1st and 2nd parameter to CReateProcess() API and also other params are correct . NOt sure what is causing this crash. Any inputs to this would be helpful. – codeLover Aug 14 '14 at 05:43
  • That sounds like another question since we can no longer know what your modified code is – David Heffernan Aug 14 '14 at 05:46
  • Most of the time the fact is I wont use static string like `L"\\pwrtest.exe /sleep /c:1"` . So I need a way to convert a dynamic character array to LPTSTR . Is it mandatory to use TCHAR everywhere in my project if I want to create a child process based on user input(plain string) ? – KRoy Apr 26 '18 at 15:43
2

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>.

Christophe
  • 68,716
  • 7
  • 72
  • 138
2

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.

Cody Gray - on strike
  • 239,200
  • 50
  • 490
  • 574
  • This answers my question correctly, I needed a `dynamic ascii-c-string` to be converted to LPTSTR . – KRoy Apr 26 '18 at 15:46