passing double quotes in commandline argument in C++ - c++

How do I pass a string with a double quote as a character as a command line argument?
The string basically has a space in between because of which it was getting treated as two different arguments. So I tried putting them in double quotes, like this.
wstring cmdLineParam = L"\"Test Value=abc\"";
This works perfectly fine in most of the cases.
But now if I have a double quotes as a character in the string, it fails.
wstring cmdLineParam = L"\"Test Value=abc \"test me\"\"";// I want the string to be passed as Value=abc"test me"
Here the argument gets split into two arguments
argv[0] = "Test Value=abc test"
argv[1] = "me"
This is my sample code.
wstring cmdLineParam = L"\"Test Value=abc \"test me\"\""; // Need to pass it as Value = abc "xyz uvw"
wstring path = L"C:\\cmdtest.exe";
BOOL bSuccess = CreateProcess ((LPCWSTR)path.c_str(), (LPWSTR)cmdLineParam.c_str(), NULL, NULL, FALSE, NORMAL_PRIORITY_CLASS,
NULL, NULL, &si, &piProcess);
and as I mentioned, the output is
argv[0] = "Test Value=abc test"
argv[1] = "me"
Kindly guide
Thanks & Regards
Sunil

Related

invalid operands of types 'const char [26]' and 'LPSTR '

My code is
string str = "C:\\Users\\mardare\\Downloads\\config";
LPSTR lp = const_cast<char *>(str.c_str());
MessageBox ( NULL, "The selected folder is : "+lp, "Bye!", MB_OK );
And when I try to build it and run i get this error
invalid operands of types 'const char [26]' and 'LPSTR'
LPSTR represents a char *-type, and string literal "The ..." denotes a const char[26]. You get the error because in your expression "The selected folder is : "+lp, you try to "concatenate" them with operator +, which is not supported for members of type const char* or char *.
Operator + is, however, supported for members of type std::string; So you could work around this by, for example, the following code:
string folder = "The selected folder is : " + str;
MessageBox ( NULL, folder.c_str(), "Bye!", MB_OK );
You are trying to concatenate a char* pointer (obtained from your string variable) to a const char[] array (from your string literal). You can't do that concatenation.
Also, the const_cast is not necessary.
You will have to convert one of the pointers to a string, eg:
string str = "C:\\Users\\mardare\\Downloads\\config";
const char *lp = str.c_str();
MessageBox ( NULL, (string("The selected folder is : ") + lp).c_str(), "Bye!", MB_OK );
Or:
string str = "C:\\Users\\mardare\\Downloads\\config";
const char *lp = str.c_str();
MessageBox ( NULL, ("The selected folder is : " + string(lp)).c_str(), "Bye!", MB_OK );
Alternatively, simply get rid of the char* from the string, you don't actually need it:
string str = "C:\\Users\\mardare\\Downloads\\config";
MessageBox ( NULL, ("The selected folder is : " + str).c_str(), "Bye!", MB_OK );
Or:
string str = "C:\\Users\\mardare\\Downloads\\config";
string msg = "The selected folder is : " + str;
MessageBox ( NULL, msg.c_str(), "Bye!", MB_OK );
Or:
string str = "C:\\Users\\mardare\\Downloads\\config";
ostringstream msg;
msg << "The selected folder is : " << str;
MessageBox ( NULL, msg.str().c_str(), "Bye!", MB_OK );
If you consider the second parameter of MessageBox in this line of code:
MessageBox ( NULL, "The selected folder is : "+lp, "Bye!", MB_OK );
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
You can see a string literal, i.e. "The selected folder is : ", which is a NUL-terminated C-style raw char array (the const char [26] part in your error message); and you are trying to "concatenate" it using the operator + with lp, which you defined as LPSTR (i.e. char*) in your code.
Such operation is not defined, hence the error message.
It's clear that your intent is to concatenate two strings, and print the resulting string calling the MessageBox API.
To do so, consider using a C++ string class. If you are at the Win32 API boundary, I think ATL/MFC CString is very convenient. Or, you can use a standard string class like std::string.
std::string (and CString as well...) conveniently defines proper overloads of operator+(), which make it possible to concatenate strings with a simple syntax, e.g.:
string str = "C:\\Users\\mardare\\Downloads\\config";
string message = "The selected folder is : " + str;
At this point, if you want to pass your message std::string instance to the MessageBox API (which is a C-interface API), you can call the std::string::c_str() method:
MessageBox( NULL, message.c_str(), /* ... other params ... */ );
Note that this code will compile in ANSI/MBCS builds (which is an obsolete build setting; Unicode build has been the default since VS2005, more than 10 years ago).
In your case, the actual Win32 API that gets called is MessageBoxA (note the A suffix).
Your code will fail to compile in VS solutions that use Unicode builds; in those cases, you may want to use the explicit MessageBoxA() call.
EDIT Not directly related to your error message, but might be interesting for you to know: If you are using a recent Visual C++ compiler, you may want to replace NULL with nullptr in your C++ code, and you can use raw string literals to simplify the way you write your paths, like this:
// Was: string str = "C:\\Users\\mardare\\Downloads\\config";
string str = R"(C:\Users\mardare\Downloads\config)";
You cannot add together a const char[26] (that is, your "The selected folder is : " literal) and a char* pointer (that is, your lp variable of type LPSTR, which is char*). Concatenate the strings first and then obtain a const char*, which you can pass to the function:
std::string str = R"(C:\Users\mardare\Downloads\config)"; //don't care about escape sequences, use raw string literals.
MessageBox(nullptr, ("The selected folder is : " + str).c_str(), "Bye!", MB_OK);

C++ LPSTR and string trouble with zero-terminated strings

I'm using GetOpenFileName function from Winapi, and I'm applying filter to the select file dialog.
THIS works perfectly:
LPSTR mfilter = "Filter\0*.PDF\0";
ofn.lpstrFilter = mfilter;
if(GetOpenFileName(&ofn)){
...
THIS fails (dialog opens but no filters apply):
string mfilter = "Filter\0*.PDF\0";
ofn.lpstrFilter = mfilter.c_str();
if(GetOpenFileName(&ofn)){
...
I need to use std:string because I'm getting the file extension via parameters and this type facilitates the concatenation but I'm getting incompatibility issues...
This would be my code if it worked as expected (IT FAILS the same as previous example):
const char * ext = &(4:); //Ampersand parameter (from CA Plex) It contains "PDF"
string mfilter = "Filter\0*." + ext + "\0"; //Final string: Filter\0*.PDF\0;
ofn.lpstrFilter = mfilter.c_str();
When I use this method, I'm getting runtime exception:
string mf;
mf.append("Filter")
.append('\0')
.append("*.pdf")
.append('\0');
ofn.lpstrFilter = mf.c_str();
With
string mfilter = "Filter\0*.PDF\0";
you are calling an std::string contructor, which terminates the string at the first \0.
The following code:
string mfilter = "Filter\0*.PDF\0";
cout << "string:" << mfilter << " len: " << mfilter.length() << endl;
prints
string: Filter len: 6
The string is only constructed until the first \0 terminator. Do the string is only composed of the word "Filter".
The GetOpenFileName function uses TCHARs, and TCHARs become WCHARs in case of UNICODE character set is used.
Here's an example:
std::wstring getOpenFileName(HWND hWnd, const std::wstring& sFilter)
{
wchar_t buffer[MAX_PATH] = L"";
OPENFILENAMEW ofn = {0};
ofn.lStructSize = sizeof(ofn);
ofn.hwndOwner = hWnd;
ofn.lpstrFilter = sFilter.c_str();
ofn.nFilterIndex = 1;
ofn.lpstrFile = buffer;
ofn.nMaxFile = MAX_PATH;
ofn.Flags = OFN_HIDEREADONLY | OFN_FILEMUSTEXIST;
if( !::GetOpenFileNameW( &ofn ) )
return L"";
return buffer;
}
If you want to parametrize lpstrFilter based on std::wstring you can just use wstring::c_str() to get LPCTSTR which is const wchar* in case of UNICODE.
IMPORTANT: The problem is that the std::wstring constructor that takes a const wchar* assumes the input is a C string. C strings are '\0' terminated and thus parsing stops when it reaches the '\0' character. To compensate for this you need to use the constructor that takes two parameters a pointer to the char array and a length.
You can also use string::push_back() method to append NULLs.
std::wstring sFilter = L"PDF Files";
sFilter.push_back('\0');
sFilter.append(L"*.pdf");
sFilter.push_back('\0');
string mfilter = "Filter\0*.PDF\0";
This calls a std::basic_string constructor that uses a null-terminated string. It will stop parsing the string literal at "Filter".
Try this one instead:
string mfilter( "Filter\0*.PDF", 13 ); // need double null at end
This calls a std::basic_string constructor that uses "the first count characters of character string pointed to by s. s can contain null characters."
You have to either count the characters yourself, or write wrapper code if you encounter this problem more often.
Related: std::basic_string constructors.
As for your runtime error:
string mf;
mf.append("Filter")
.append('\0')
.append("*.pdf")
.append('\0');
append() does not have an overload for a single character type. You are probably hitting the const CharT* s overload, with a null pointer.
Use either append( 1, '\0' ) or append( "", 1 ), either of which should append a null byte.

createprocess returning 0 with getlasterror set to 2

I have to execute a class file by providing the jar file path.Below is my program,
But createprocess is returning 0 with getlasterror set to 2.
Tried using sysnative instead of system32 still its not working.
Can anyone point me what is going wrong here:
char *command;
char *cmdname = "c:\\windows\\system32\\cmd.exe /C ";
char *p = " java -cp ";
char *p1 = " com.ge.med.terra.eaaa.server.EA3Server %*";
command = (char *)malloc(50);
env = getenv("GEHC_SECURITY_HOME");
strcpy(command, cmdname);
strcat(command, "\"");
strcat(command, p);
strcat(command, "\"");
strcat(command,env);
strcat(command,"\\eat\\jar\\eat.jar\";");
strcat(command, p1);
strcat(command, "\"");
result = CreateProcessA( NULL, // No module name (use command line)
command, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi ) ;
You tagged this question with c++. For this reason, I would suggest you use C++ std::string class. That way, you can easily concatenate the strings necessary to create you command. It is much more concise, easier to read, all memory management is done by the class in the background (no need for malloc), and you do not need to worry about terminating the string with (maybe not for this example but in general). Here is how you do it:
std::string command = "c:\\windows\\system32\\cmd.exe /C \" java -cp \"" + std::string(env)
+ "\\eat\\jar\\eat.jar\";\"";
result = CreateProcessA(NULL, // No module name (use command line)
command.c_str(), // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
0, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi);
You're overflowing the buffer you allocated. You allocate space for 50 characters, but you write 105 plus whatever is in GEHC_SECURITY_HOME. When this happens, you write into some other allocated block, which will produce unspecified but undesirable behavior.
Using std::string will eliminate this, but the + operator is slow. Using std::stringstream is better if you care about the performance. But to test out whether this is the only problem, you can change your 50 to something like 500 and try again.

Fail to pass command line arguments in CreateProcess

I'm having trouble using CreateProcess with command line arguments. I've read to all the posts I've found but none of the solutions did work.
Here's what I have:
std::string path = "C:\\my\\path\\myfile.exe";
std::wstring stemp = std::wstring(path.begin(), path.end());
LPCWSTR path_lpcwstr = stemp.c_str();
std::string params = " Param1 Param2 Param3";
STARTUPINFO info = { sizeof(info) };
PROCESS_INFORMATION processInfo;
CreateProcess(path_lpcwstr, LPTSTR(params.c_str()), NULL, NULL, TRUE, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &info, &processInfo);
The code works and myfile.exe (a QT Application) is opened, but argc is always 1. I've also tried specifying only the first parameter as "C:\my\path\myfile.exe Param1 Param2 Param3" but that didn't work either.
Any help is greatly appreciated.
Solution:
Using CreateProcessA and change the parameters accordingly fixed the problem pointed out by one of the answers.
STARTUPINFOA info = { sizeof(info) };
PROCESS_INFORMATION processInfo;
std::string path = "C:\\my\\path\\myfile.exe";
std::string params = " Param1 Param2 Param3";
CreateProcessA(path.c_str(), const_cast<char *>(config.c_str()) , NULL, NULL, TRUE, CREATE_NEW_PROCESS_GROUP, NULL, NULL, &info, &processInfo);
There are two versions of CreateProcess (and many other Winapi functions too):
One takes "normal" strings in ASCII/ISO88591/whatever where each character has 1 byte.
"abc" would have the numbers 97 98 99.
The other CreateProcess takes UTF16 strings; each char has 2 or 4 byte there,
and "abc" would have the byte numbers 0 97 0 98 0 99
(UTF16 is a bit more complicated, but in this case, it´s just 0s added).
The advantage is better support for internationalization, because the
old 1-byte charsets are problematic with languages like Russian, Greek etc.
You´re using the second version. path_lpcwstr, ie. the program path and name as first parameter, is correctly provided as UTF16 string by you (std::wstring on Windows and LPCWSTR etc. ...).
However, the second parameter with the arguments for the new process, is not UTF16 in your code (but a one-byte charset) and to avoid a compiler error, you are simply casting a pointer and telling the compiler to treat the not-UTF16 content as UTF16.
The bytes of " Param1 Param2 Param3" understood as UTF16 won´t give any sane string without proper conversion, and to start with, the 2 byte 0 value to terminate the string, as requried by Windows, is nowhere in there. The result is undefined behaviour, any strange things can happen.
Make you parameter string like you did with the path, and everything should be fine.
have you ever try ShellExecuteA()?

CreateProcess doesn't pass command line arguments

Hello I have the following code but it isn't working as expected, can't figure out what the problem is.
Basically, I'm executing a process (a .NET process) and passing it command line arguments, it is executed successfully by CreateProcess() but CreateProcess() isn't passing the command line arguments
What am I doing wrong here??
int main(int argc, char* argv[])
{
PROCESS_INFORMATION ProcessInfo; //This is what we get as an [out] parameter
STARTUPINFO StartupInfo; //This is an [in] parameter
ZeroMemory(&StartupInfo, sizeof(StartupInfo));
StartupInfo.cb = sizeof StartupInfo ; //Only compulsory field
LPTSTR cmdArgs = "name#example.com";
if(CreateProcess("D:\\email\\smtp.exe", cmdArgs,
NULL,NULL,FALSE,0,NULL,
NULL,&StartupInfo,&ProcessInfo))
{
WaitForSingleObject(ProcessInfo.hProcess,INFINITE);
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
printf("Yohoo!");
}
else
{
printf("The process could not be started...");
}
return 0;
}
EDIT: Hey one more thing, if I pass my cmdArgs like this:
// a space as the first character
LPTSTR cmdArgs = " name#example.com";
Then I get the error, then CreateProcess returns TRUE but my target process isn't executed.
Object reference not set to an instance of an object
You should specify also the module name in parameters: LPTSTR cmdArgs = "App name#example.com";
It should be the whole command line (including argv[0]).
If the first parameter to CreateProcess() is non-NULL, it will use that to locate the image to launch.
If it is NULL, it will parser the 2nd argument to try to get the executable to launch from the 1st token.
In either case, the C runtime will use the second argument to populate the argv array. So the first token from that parameter shows up in argv[0].
You probably want something like the following (I've change the smtp.exe program to echoargs.exe - a simple utility I have to help figure out just this kind of issue):
int main(int argc, char* argv[])
{
PROCESS_INFORMATION ProcessInfo; //This is what we get as an [out] parameter
STARTUPINFO StartupInfo; //This is an [in] parameter
char cmdArgs[] = "echoargs.exe name#example.com";
ZeroMemory(&StartupInfo, sizeof(StartupInfo));
StartupInfo.cb = sizeof StartupInfo ; //Only compulsory field
if(CreateProcess("C:\\util\\echoargs.exe", cmdArgs,
NULL,NULL,FALSE,0,NULL,
NULL,&StartupInfo,&ProcessInfo))
{
WaitForSingleObject(ProcessInfo.hProcess,INFINITE);
CloseHandle(ProcessInfo.hThread);
CloseHandle(ProcessInfo.hProcess);
printf("Yohoo!");
}
else
{
printf("The process could not be started...");
}
return 0;
}
Here's the output I get from that program:
echoargs.exe name#example.com
[0]: echoargs.exe
[1]: name#example.com
Yohoo!
It doesn't look like you are using CreateProcess correctly, see http://msdn.microsoft.com/en-us/library/ms682425%28VS.85%29.aspx.
The command line to be executed. The maximum length of this string is 32,768 characters, including the Unicode terminating null character. If lpApplicationName is NULL, the module name portion of lpCommandLine is limited to MAX_PATH characters.
The lpCommandLine parameter can be NULL. In that case, the function uses the string pointed to by lpApplicationName as the command line.
If both lpApplicationName and lpCommandLine are non-NULL, the null-terminated string pointed to by lpApplicationName specifies the module to execute, and the null-terminated string pointed to by lpCommandLine specifies the command line. The new process can use GetCommandLine to retrieve the entire command line. Console processes written in C can use the argc and argv arguments to parse the command line. Because argv[0] is the module name, C programmers generally repeat the module name as the first token in the command line.
So in your case, you need this as the command argument and should probably pass a NULL for the first parameter to get the behaviour your want.
// NOTE THE Null-Terminated string too!
LPTSTR cmdArgs = "D:\\email\\smtp.exe name#example.com\0";
Below is a cut down version of the code used by the Zeus IDE to run external processes:
bool createProcess(const char *pszTitle, const char *pszCommand)
{
STARTUPINFO StartInfo;
memset(&StartInfo, 0, sizeof(StartInfo));
StartInfo.cb = sizeof(StartInfo);
StartInfo.lpTitle = (pszTitle) ? (char *)pszTitle : (char *)pszCommand;
StartInfo.wShowWindow = SW_NORMAL;
StartInfo.dwFlags |= STARTF_USESHOWWINDOW;
if (CreateProcess(0, (char *)pszCommand,
0, 0, TRUE,
CREATE_NEW_PROCESS_GROUP, 0, 0,
&StartInfo, &ProcessInfo))
{
lErrorCode = 0;
}
else
{
lErrorCode = GetLastError();
}
return (lErrorCode == 0);
}
The pszCommand would be the full executable path and file name and arguments so for example:
pszCommand = "D:\\email\\smtp.exe name#example.com";
From what I can tell, the only real difference between the two is that in the Zeus example, the dwCreationFlags argument is set to the CREATE_NEW_PROCESS_GROUP value.
You can add a space as first character of the cmdArgs string:
LPTSTR cmdArgs = " name#example.com";
Apparently Windows appends the 2nd argument string to the application name represented by the first argument, and the result is passed as command line arguments to the executable. So adding a space will properly separate the arguments.
Try this:
LPTSTR cmdArgs = "name#example.com";
CString szcmdline("D:\\email\\smtp.exe");
szcmdline += _T(" ") + cmdArgs ;
//Leave first param empty and pass path + argms in
if(CreateProcess(NULL, szcmdline, second
The Unicode version of this function, CreateProcessW, can modify the contents of this string. Therefore, this parameter cannot be a pointer to read-only memory (such as a const variable or a literal string). If this parameter is a constant string, the function may cause an access violation.
Therefore you can try using LPTSTR cmdArgs = _tcsdup("name#example.com").
Another problem is: how does the target process reads the arguments? using argv[0] as application name? Then you shoud append the application name as the first parameter too.
You are not allocating memory for your string.
Instead of:
LPTSTR cmdArgs = "name#example.com";
try:
TCHAR cmdArgs[] = "name#example.com";
Edit:
then call:
CreateProcess("D:\\email\\smtp.exe", &cmdArgs[0], ...
This will create a local array on the stack and then pass a pointer to that array.