CreateProcess doesn't pass command line arguments - c++

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.

Related

CreateProcess Fails - Error 183

So, code I can't change calls an executable, and I need to give it different commandline args than what the black box code calls. I was figuring I could make an executable to serve as a proxy. proc.exe sits where the black box section is expecting, takes the commandline arguments, modifies them, then calls procReal.exe, the original file.
Unfortunately CreateProcess seems to fail to start, returning status 183. I've looked up everything I can and can't find out much about this. Have tried flipping things around, setting the handle inheritance to true, manually specifying the working directory, not doing either of those things. No luck. I assume there's something going on here with inheriting the proper security context of the calling application so the wrapper works as a proper passthrough, but I can't figure out how to do it...
Code below, irrelevant sections pruned.
EDIT Put the full code here after request. This isn't making any sense anymore. It now will partially work, but only if the fopen section for traceFile isn't there. Not even the fprintfs removed, specifically the whole section has to be cut out.
I've tried to respond to everyone's comments and I think I've ruled out most of those things as an issue, but am left with the current anomalous behavior. What little more I could read up on this says that some forms of copying the strings around could lead to memory overflows, is that possible at all?
#include <iostream>
#include <fstream>
#include <windows.h>
#include <string>
#include <vector>
#include <stdio.h>
#include <tchar.h>
#include <algorithm>
#include <string>
using namespace std;
bool caseInsensitiveStringCompare( const std::string& str1, const std::string& str2 );
int main(int argc, char* argv[]) {
const string path = "E:\\util\\bin\\";
const string procName = "procReal.exe";
const string argToFilter = "-t";
string origValue;
string passedValue;
for(int i = 1; i < argc; i++)
{
origValue.append(" ").append(argv[i]);
}
for(int i = 1; i < argc; i++)
{
if (!caseInsensitiveStringCompare(argv[i],argToFilter))
{
passedValue.append(" ").append(argv[i]);
}
else
{
i++; // skip over argument and it's value
}
}
const LPCTSTR exeModule = (path+procName).c_str();
std::vector<char> chars(passedValue.c_str(), passedValue.c_str() + passedValue.size() + 1u);
LPTSTR exeArgs = &chars[0];
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
GetStartupInfo(&si);
FILE* traceFile;
traceFile = fopen ((path+"lastRun.txt").c_str(), "w"); // This causes exeModule to change value for unknown reasons???
fprintf(traceFile, "orig: %s%s\n", exeModule, origValue.c_str());
fprintf(traceFile, "%s%s\n", exeModule, exeArgs);
SetLastError(0);
// Start the child process.
if( !CreateProcess( exeModule, // use module name with args for exeArgs
exeArgs, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
TRUE, // 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 ) // Pointer to PROCESS_INFORMATION structure
)
{
FILE* myfile;
myfile = fopen ((path+"error.txt").c_str(), "w");
fprintf(myfile, "CreateProcess failed (%d).\n", int(GetLastError()));
fclose(myfile);
}
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
DWORD exit_code;
GetExitCodeProcess(pi.hProcess, &exit_code);
fprintf(traceFile, "Exit Code: %d\n", int(exit_code));
fclose(traceFile);
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
return exit_code;
}
bool caseInsensitiveStringCompare( const std::string& str1, const std::string& str2 ) {
std::string str1Cpy( str1 );
std::string str2Cpy( str2 );
std::transform( str1Cpy.begin(), str1Cpy.end(), str1Cpy.begin(), ::tolower );
std::transform( str2Cpy.begin(), str2Cpy.end(), str2Cpy.begin(), ::tolower );
return ( str1Cpy == str2Cpy );
}
The most obvious problem is that you can't say (path+procName).c_str() because the temporary string object it builds is discarded immediately, invalidating the returned pointer. I'm also very dubious about assuming that the elements of a vector are necessarily consecutive.
The corrected string handling code should look something like this:
string passedValue(procName); // First element of command line MUST be module name
...
const string exeModuleString(path + procName);
const LPCTSTR exeModule = exeModuleString.c_str();
LPTSTR exeArgs = new char[passedValue.size() + 1];
passedValue.copy(exeArgs, passedValue.size());
exeArgs[passedValue.size()] = '\0';
(That might not be the best way to do it; I don't use C++ often. But it should work correctly.)
The corrected error handling code, ensuring that the last error code is read immediately, should look something like this:
{
DWORD err = GetLastError();
FILE* myfile;
myfile = fopen ((path+"error.txt").c_str(), "w");
fprintf(myfile, "CreateProcess failed (%d).\n", int(err));
fclose(myfile);
}
Your code was reporting the wrong error code, because calling fopen() changes it. (When a new file is created that overwrites an existing file, the last error code is set to ERROR_ALREADY_EXISTS.)
There are two broader issues, which may or may not matter in your context. Firstly, you're using argv[] to build the command line for the new process; that means that the command line parsing (as described in Parsing C Command-Line Arguments) will be applied twice (once by your process and once by the child) which may cause trouble if the command line contains any special characters such as quote marks or backslashes. Ideally, in the general case, you would call GetCommandLine() instead. (Granted, this makes parsing the string to remove the extra argument quite a bit harder.)
Secondly, you're obviously building the code in ANSI mode. This may cause problems if the command line ever contains any wide ("Unicode") characters. It is generally accepted that best practice is to always build in Unicode mode. The only major change you'll need to make to the code is to replace string with wstring, so it should be straightforward enough.
I have the same problem.
The problem seems to be there when i call executables with no window.
I found 2 solutions:
1.
Create a bat file with the name of thet exe, followed by the arguments,
and then execute the bat file:
CreateProcess( "temp.bat" , NULL , ....etc
2.
use _spawnl

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()?

passing double quotes in commandline argument in 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

CreateProcess() Error

STARTUPINFO si;
PROCESS_INFORMATION pi;
memset(&si, 0, sizeof(si));
memset(&pi, 0, sizeof(pi));
si.cb = sizeof(si);
LPCWSTR procName =(LPCWSTR)"D:\\test dir 1\\Calc.exe";
LPWSTR procArg =(LPWSTR)"blacknull";
if(CreateProcess(procName,procArg,0,0,0,CREATE_DEFAULT_ERROR_MODE,0,0,&si,&pi))
{
//do some work
}
printf( "CreateProcess failed (%d).\n", GetLastError());
system("Pause");
It keeps throwing Error(2)-> The System cannot find the file specified.
I don't know what's wrong. I also tried to use "Calc.exe" which in the same Dir. but it's not working.
You use the L prefix to make a wide character string:
L"D:\\test dir 1\\Calc.exe";
Casting a string literal to a different character width does not make a string wider.
In addition to the string type issue already pointed out, the second argument (lpCommandLine) must point to a writable buffer, not a constant string. You can do this by declaring it as follows:
WCHAR procArg[] = L"blacknull";
This is documented in MSDN: "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."