4

I need to create a variable to use in the CreateProcess:

CreateProcess(z7Cmdline, z7Arg, NULL, NULL, FALSE, NULL, NULL, NULL, &startInfo, &processInfo);

The variable z7Arg is a argument list for 7 -zip which contains a file name based on the current date ie: 2017-12-13.zip.

string buArg = "-o""c:\\moshe"" a " + buDir + buFileName + "c:\\moshe\\*.pdf";

I want to copy buArg into z7Arg as a LPTSTR to use in the CreateProcess routine

How do I go about it?

I am new at coding in C++, 30 years ago I programed in IBM Fortran & Assembly language for Grumman Aerospace, but have done little coding since then.

tadman
  • 208,517
  • 23
  • 234
  • 262
MosheMaurice
  • 41
  • 1
  • 2
  • 3
    A `std::string` is based on the string type being `char`. An `LPTSTR` is not the same thing. It is either based on `char` if the build is not a Unicode build, or `wchar_t` if it is a Unicode build. You need to get your string types straightened out and understood first before knowing exactly how to convert. – PaulMcKenzie Dec 14 '17 at 23:22
  • Basically, you want `strcpy(buArg.c_str(),z7Arg)` – Octopus Dec 14 '17 at 23:25
  • Also `std::string -> LPSTR -> LPTSTR (non-Unicode build)` and `std::wstring -> LPWSTR -> LPTSTR (Unicode build)`. Confusing, but that basically what the "compatibility tree" looks like. – PaulMcKenzie Dec 14 '17 at 23:29

3 Answers3

7

You have to do 2 things:

  1. Convert const char* to const TCHAR*, where TCHAR may be either char or wchar_t depending on whether Unicode is enabled for your project.
  2. Remove const because CreateProcess requires TCHAR*, not const TCHAR*. You can't just use const_cast, you need a writable buffer that you'll pass to CreateProcess.

For that you may use convenient string conversion macros from ATL or MFC. Use it the following way:

CA2T param(buArg.c_str());
CreateProcess(..., param, ...);

or just

CreateProcess(..., CA2T(buArg.c_str()), ...);

Read more about string conversion macros here.

If you don't have access to ATL or MFC in your project and you have Unicode enabled, you'll need to manually convert char* to wchar_t* using MultibyteToWideChar.

Paul
  • 13,042
  • 3
  • 41
  • 59
  • 1
    @orhtej2 I know MFC is included, I believe ATL is too. – Mark Ransom Dec 14 '17 at 23:29
  • @orhtej2 I don't know if it's available in Community Edition. OP did not specify what is available for him, so I edited the answer to clarify ATL or MFC is needed for those macros. – Paul Dec 14 '17 at 23:31
  • This will break in unicode build, as the argument string has to write-able, while `.c_str()` is const, so it's not enough just to cast it. (overall using macros in age of C++14 is ... weird ... then again, programming for windows is obsolete either, so why do I bother...) (a more robust code should copy it to simple char array and use that) – Ped7g Dec 14 '17 at 23:32
  • 1
    @Ped7g Note, that it is `CA2T`, not `CA2CT`. It will allocate a writable buffer (or use static one if the result will fit into it). Those are not "cast macros", they are "conversion macros". Read about them on MSDN. If you have more elegant solution _in age of C++14_ go ahead and post it. – Paul Dec 14 '17 at 23:36
  • @Paul then I'm sorry, but it's not obvious from MS docs (it's marked as bad code in the first example, literally *"It should be stressed that the following is not good code"*).. and basically this chat is the very reason why I would avoid macros, it's even less clear to what they will compile, than with classes. Saving just few chars of typing instead of allocating own char array + strncpy(...), making it more cryptic ... not in my code. :) – Ped7g Dec 14 '17 at 23:40
  • 1
    There is an explanation why that code is not good code - because the memory would be freed earlier than user may expect. This won't happen in case `CreateProcess(..., CA2T(...), ...)` - in this case the memory will not be freed before `CreateProcess` returns. There is also an example of how good code should look. – Paul Dec 14 '17 at 23:46
  • What do I define param as? if I put in CA2T param(buArg.c_str()); I get an error _identifier "param" is undefined_ – MosheMaurice Dec 15 '17 at 01:18
  • @MosheMaurice What version of Visual Studio do you have? It's possible you don't have ATL 7.0 conversion classes and only ATL 3.0 conversion macros, in this case you should use `CreateProcess(..., CA2T(buArg.c_str()), ...)`. – Paul Dec 15 '17 at 01:21
3

When compiling for Unicode, TCHAR-based APIs map to wchar_t-based functions, and when compiling for ANSI/MCBS, they map to char-based functions instead.

So, in your case, the TCHAR-based CreateProcess() macro maps to either CreateProcessA() taking char* strings, or CreateProcessW() taking wchar_t* strings.

std::string operates with char only, and std::wstring operates with wchar_t only.

So, the simplest solution to your issue is to just call CreateProcessA() directly, eg:

std::string z7Cmdline = ...;
std::string z7Arg = ...;
STARTUPINFOA si = {};
... 
CreateProcessA(z7Cmdline.c_str(), & z7Arg[0], ..., &si, ...);

If you want to call CreateProcessW(), use std::wstring instead:

std::wstring z7Cmdline = ;
std::wstring z7Arg = ...;
STARTUPINFOW si = {};
... 
CreateProcessW(z7Cmdline.c_str(), & z7Arg[0], ..., &si, ...);

In this latter case, if your input must be std:string, then you have to use a runtime conversion, via MultiByteToWideChar(), std::wstring_convert, etc.

Or, you could use std::basic_string<TCHAR> instead:

std::basic_string<TCHAR> z7Cmdline = ;
std::basic_string<TCHAR> z7Arg = ...;
STARTUPINFO si = {};
... 
CreateProcess(z7Cmdline.c_str(), & z7Arg[0], ..., &si, ...);
Remy Lebeau
  • 555,201
  • 31
  • 458
  • 770
  • I tried using CreateProcessA and the following two errors now pop up argument of type "const char *" is incompatible with parameter of type "LPSTR" argument of type "STARTUPINFO *" is incompatible with parameter of type "LPSTARTUPINFOA" – MosheMaurice Dec 15 '17 at 01:09
0
string buArg = "-o""c:\\moshe"" a " + buDir + buFileName + "c:\\moshe\\*.pdf";
LPTSTR lpt = new TCHAR[31];
lpt = (LPTSTR) buArg.c_str();

tested by MinGW 6.3.0

Saleh Shekari
  • 41
  • 1
  • 4
  • 1
    Hi, please add a brief explanation as to "how" your solution solves the problem, rather than just code. – natn2323 Oct 22 '18 at 14:09
  • This code will cause a memory leak. Line 2 allocates memory for a 31-element array, and then saves the address of that array in `lpt`. Then line 3 overwrites the value in `lpt` with the address returned from `c_str()`. It does _not_ copy the contents of the value returned from `c_str()` into the array allocated on line 2. – Kurt Hutchinson Oct 25 '18 at 06:52