why argv in createProcess() is different from normal c++ program - c++

this is my code, and i found the first output is "thisProgram.exe"
and the second output is "a".
why?
i read the doc in msdn, however i don't quite clear why the argv[0] can be "a", is there something different in windows when using createProcess. Could someone please tell me the difference from lpApplicationName and lpCommandline? thanks
int main( int argc, char *argv[] ) {
cout << argv[0] << endl;
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
// Start the child process.
if (!CreateProcess("thisProgram.exe", // No module name (use command line)
"a b c", // 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) // Pointer to PROCESS_INFORMATION structure
) {
printf("CreateProcess failed (%d).\n", GetLastError());
return 1;
}
// Wait until child process exits.
WaitForSingleObject(pi.hProcess, INFINITE);
// Close process and thread handles.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
return 0;
}

CreateProcess passes the second argument (the command line) to the new process as its command line. CreateProcess will not prepend the module name. If you want the application name to appear as argv[0] you must repeat the application name in the command line argument.
The documentation says it like this:
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.
It's generally simplest to pass NULL for the application name, and for the command line pass the application name and the arguments concatenated together.

Related

c++ can't pass an argument with CreateProcess [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
This question does not appear to be about programming within the scope defined in the help center.
Closed 4 months ago.
Improve this question
i have to pass a string into my process, but for some reason i can't
i've tried to pass a path and an argument in function, i've tried to put a \0 after the argument, i've tried to pass an argument or space + an argument but it doesn't passes.
could you please help me?
#include <stdio.h>
#include <tchar.h>
#include <iostream>
#include <string>
using namespace std;
void _tmain(int argc, TCHAR* argv[])
{
cout << "we are here!\n";
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
string first = "C:\\Users\\User\\source\\repos\\1\\x64\\Debug\\1.exe"; //Initializing a name of our file
wstring temp = wstring(first.begin(), first.end()); // Initializing an object of wstring
LPCWSTR file_name = temp.c_str(); // Applying c_str() method on temp
string s1 = " 1.exe 1\0";
LPWSTR cl1 = (LPWSTR)s1.c_str();
// Start the child process.
if (!CreateProcess(file_name, // No module name (use command line)
cl1, // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
CREATE_NEW_CONSOLE, // Creating console for our application
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
)
{
printf("CreateProcess failed (%d).\n", GetLastError());
return;
}
// Wait until child process exits.
WaitForSingleObject(pi.hProcess, INFINITE);
// Close process and thread handles.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
cout << "we are done!\n";
}
thanks for your help in advance
Are you compiling in Unicode or Multibyte (MBCS)?
Assuming you are compiling in Unicode you can avoid the use of string objects and use wstring objects instead.
To initialize a wstring you have to prefix the double quoted string with an L, i.e.
wstring first(L"C:\\Users\\User\\source\\repos\\1\\x64\\Debug\\1.exe");
So, you can avoid the use of temp variable.
Note: Is more efficient to initialize a (w)string using the constructor instead of the assignment operator.
Also, the cast in
string s1 = " 1.exe 1\0";
LPWSTR cl1 = (LPWSTR)s1.c_str();
is nos valid, as s1.c_str() return type is const char* (or LPCSTR).
Instead, you can declare
wstring s1(L" 1.exe 1\0");
LPCWSTR cl1 = s1.c_str();
In fact, you don't need to assign the result of c_str() to another variable. You can call to c_str() when you are calling to CreateProcess. The code could be something as:
//Initializing a name of our file
wstring first(L"C:\\Users\\User\\source\\repos\\1\\x64\\Debug\\1.exe");
wstring s1(L" 1.exe 1\0");
// Start the child process.
if (!CreateProcess(first.c_str(), // No module name (use command line)
const_cast<LPWSTR>(s1.c_str()), // Command line
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
FALSE, // Set handle inheritance to FALSE
CREATE_NEW_CONSOLE, // Creating console for our application
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi) // Pointer to PROCESS_INFORMATION structure
)
{
printf("CreateProcess failed (%d).\n", GetLastError());
return;
}
If you are compiling with MBCS you should change wstring by string and remove the L prefix when initializing strings. The rest of the code could remain the same.

How can I use CreateProcess method to refer to other 'ini' file to start 'exe' program?

I'm currently trying to execute 'ClientProc.exe'. This program uses 'SA_Client.ini' file from a same directory as a reference.
I'm using CreateProcess method to execute the .exe program as belows.
STARTUPINFO si;
PROCESS_INFORMATION pi;
// set the size of the structures
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
LPCSTR lpApplicationName = "C:\\projects\\Client\\ClientProc.exe";
LPSTR cmd = (char*)"./";
if (!CreateProcess(lpApplicationName, // the path
cmd, // 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 // Pointer to PROCESS_INFORMATION structure (removed extra parentheses)
))
{
printf("CreateProcess failed (%d).\n", GetLastError());
return;
}
// Wait until child process exits.
WaitForSingleObject(pi.hProcess, INFINITE);
// Close process and thread handles.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
The problem is that I don't know how to make CreateProcess to refer to the 'ini' file even though the file exists in the same directory.
I've checked Microsoft document or other StackOverflow comments but couldn't find anything useful.
Does anyone know how to do it?
Thank you in advance!
--Edit--
I've also tried setting the lpCurrentDirectory parameter where ini file exists.
CreateProcess(lpApplicationName, // the path
NULL, // 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
"C:\\projects\\Client", // Use parent's starting directory
&si, // Pointer to STARTUPINFO structure
&pi // Pointer to PROCESS_INFORMATION structure (removed extra parentheses)
)
Then, I've got an error 267 which stands for 'ERROR_DIRECTORY'. I'm sure that the file exists in the directory. What am I doing wrong?

using the CreateProcess function

I'm trying to create something similar to a cmd with Microsoft Visual Studio Express 2013 for Windows Desktop in c++ and one of my function should start a process like open skype by typing "skype.exe". I searched in the internet and found the CreateProcess function that should do the work for me. when I created a function that receives a class value that I created called Line (the name of the class but it doesn't really metter) and used the CreateProcess function in the way that is shown bellow I have to type in my cmd "start skype.exe" but I want it to work like in the regular cmd by writing only "skype.exe", how can I do it?
(the l.parameter is just a string that contains the word skype)
void execute(Line l){
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
LPSTR s = const_cast<char *>(l.parameter.c_str());
if (!CreateProcess(NULL, s, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi))
{
printf("CreateProcess failed (%d).\n", GetLastError());
return;
}
// Wait until child process exits.
WaitForSingleObject(pi.hProcess, INFINITE);
// Close process and thread handles.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);}
First thing is that:
LPSTR s = const_cast<char *>(l.parameter.c_str());
is bad idea, CreateFile accepts for lpCommandLine non const buffer for a reason - it might modify it:
The system adds a terminating null character to the command-line string to separate the file name from the arguments. This divides the original string into two strings for internal processing.
so you should pass an array, for example:
TCHAR szCmd[MAX_PATH] = {0};
then to your question, if "start skype.exe" works for you and you want to enter only skype.exe at the command line - then why not concatenate strings? for example:
_tcscat(szCmd, _T("start "));
_tcscat(szCmd, parameter.c_str());
and pass szCmd to CreateProcess
the question is whether you use UNICODE build, if yes then make sure parameter is std::wstring, otherwise if you use non-UNICODE build (and it looks like thats true) then std::string is fine.
start is not an executable, it is a feature of cmd.exe, so to invoke start skype.exe via CreateProcess(), you would have to specify cmd.exe as the command and /C start skype.exe as its parameter.
Line l;
line.parameter = "cmd.exe /C start skype.exe";
execute(l);
But that is overkill in this situation, as start is not actually needed, despite what you claim. It is perfectly valid and preferable to invoke skype.exe directly as the command.
However, you have to provide the full path to skype.exe (same if you were to invoke start), otherwise CreateProcess() won't be able to find it, as Skype does not register its .exe file path in the App Paths key of the Registry, or the path to its Phone subfolder (where skype.exe resides) on the system's %PATH% environment variable.
For example:
Line l;
line.parameter = "C:\\Program Files (x86)\\Skype\\Phone\\Skype.exe";
execute(l);
Fortunately, Skype does store the full path to skype.exe in the Registry, specifically in the following key:
HKEY_CURRENT_USER\Software\Skype\Phone
It is stored in a REG_SZ value named "SkypePath".
std::string GetSkypePath()
{
std::string sPath;
HKEY hKey;
if (RegOpenKeyExA(HKEY_CURRENT_USER, "Software\\Skype\\Phone", 0, KEY_QUERY_VALUE, &hKey) == 0)
{
char szPath[MAX_PATH+1] = {0};
DWORD dwPathLen = MAX_PATH;
if (RegQueryValueExA(hKey, "SkypePath", NULL, NULL, (LPBYTE)szPath, &dwPathLen) == 0)
sPath = szPath;
RegCloseKey(hKey);
}
return sPath;
}

Beginner C++ CreateProcess () Error 2

I am trying to create a process that send command to cmd.exe and receive Error 2,
Why? It's posible? How?
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
String pathexe = "C:\Windows\system32\cmd.exe";
String command= "notepad.exe";
if(!CreateProcess(
pathexe.c_str(), // lpApplicationName
command.c_str(), // lpCommandLine
NULL, // lpProcessAttributes
NULL, // lpThreadAttributes
FALSE, // bInheritHandles
0, // dwCreationFlags
NULL, // lpEnvironment
NULL, // lpCurrentDirectory
&si, // lpStartupInfo
&pi // lpProcessInformation
))
{
AnsiString error = GetLastError();
ShowMessage("Error: " + error);
}
WaitForSingleObject( pi.hProcess, INFINITE );
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
PD: 1) It is assumed that you can use CreateProcess () for this purpose, I should not do it with ShellExecute () or system().
2) I have read about it in the forum and can not find a solution to this error, there are many answers to similar questions but do not address the error, other functions are proposed, or mix with the route command.
3) I do not think that issue permits because I built while the manifest.
4) I currently use C ++ Builder, in win7, 32bits but not important.
5) I guess the issue will be voted as negative and duplicate (as usual) but the proposed testing examples also receive errors.
Thanks to all
FIRST CONCLUSIONS:
Error 2: The system cannot find the file specified.
Link funtion: https://msdn.microsoft.com/es-es/library/windows/desktop/ms679360(v=vs.85).aspx
Link error: https://msdn.microsoft.com/es-es/library/windows/desktop/ms681382(v=vs.85).aspx
With error 2: check syntax, file path and existence.
works:
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
String command = "notepad.exe";
if(!CreateProcess(
NULL, // lpApplicationName
commmand.c_str(), // lpCommandLine
NULL, // lpProcessAttributes
NULL, // lpThreadAttributes
FALSE, // bInheritHandles
0, // dwCreationFlags
NULL, // lpEnvironment
NULL, // lpCurrentDirectory
&si, // lpStartupInfo
&pi // lpProcessInformation
))
{
AnsiString error = GetLastError();
ShowMessage("Error: " + error);
}
WaitForSingleObject( pi.hProcess, INFINITE );
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
This example works also for exe
String command = "cd C:\\sample\\calc.exe";
But no with cmd´s general commands, there must be a way to send commands to cmd as:
notepad.exe && cd C:\sample\ && sample1.txt
THANKS TO ALL
You're trying to run this command:
cmd notepad
(You aren't doing that quite right, either; the lpCommandLine argument should include the entire string, not just notepad, and you haven't quoted the backslashes properly.)
But even once you fix those problems, it won't work, because you've got the syntax wrong. You'll find it won't work if typed on the command line either!
Instead, try:
String pathexe = "C:\\Windows\\system32\\cmd.exe";
String command= "cmd /c notepad.exe";
The /c option means "run this command". You can use /k instead if you want the command window to stay open after the command has finished, though it's unusual for a program to do so.
One final note: I'm assuming here than notepad is just a stand-in for a more complicated command. If you actually want to run notepad, or any other executable, you shouldn't be invoking cmd.exe at all:
String command= "notepad";
if(!CreateProcess(
NULL, // lpApplicationName
command.c_str(), // lpCommandLine
...
You only need to call on cmd.exe if you need to run a built-in command, or a composite command line.
(Actually, calling cmd.exe is considered poor practice even in those cases; in Windows, you are generally expected do that sort of thing for yourself via the API rather than farming out the job to the command interpreter. But there are edge cases, and your mileage may vary.)

Format String C++ in CreateProcess

ello all I hope someone can help me with this issue I am using the following example from msdn for createprocess function.
#include <windows.h>
#include <stdio.h>
#include <tchar.h>
void _tmain( int argc, TCHAR *argv[] )
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory( &si, sizeof(si) );
si.cb = sizeof(si);
ZeroMemory( &pi, sizeof(pi) );
if( argc != 2 )
{
printf("Usage: %s [cmdline]\n", argv[0]);
return;
}
// Start the child process.
if( !CreateProcess( NULL, // No module name (use command line)
argv[1], // 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 ) // Pointer to PROCESS_INFORMATION structure
)
{
printf( "CreateProcess failed (%d).\n", GetLastError() );
return;
}
// Wait until child process exits.
WaitForSingleObject( pi.hProcess, INFINITE );
// Close process and thread handles.
CloseHandle( pi.hProcess );
CloseHandle( pi.hThread );
}
This is accessed via dos and works perfectly using this command in command prompt. When I type this
this.exe "my.exe test" > result.txt
The my.exe is another console application that takes the input test and the > result.txt is for my output log. I am trying to remove the need for the command line so I am trying to feed the path into the createprocess function call. This is where I get stuck here is what I am trying
if( !CreateProcess( NULL, // No module name (use command line)
"\"my.exe test \" > result.txt", // this.exe "my.exe test" > result.txt
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
still doesnt work I thought \" would give me the result I needed but it doesnt seem to work, will parse the my.exe and test part but not the > result.txt output. However it works from the command prompt fine if i pass it to argv[1].
Any help much appreciated.
So in summary
In console I can parse
this.exe "my.exe test" > result.txt // Works fine via cmd.exe
To app I tried
my.exe test > result.txt // Not work but missing ""
and
\"my.exe test \" > result.txt // work for first section
CreateProcess only does basic command line parsing by breaking up the words into individual arguments -- it doesn't understand file redirection or anything. If you pass it "> result.txt", it tries to parse that as two arguments named literally ">" and "result.txt".
If you want to redirect the output of the command, you have two options:
Do the redirection yourself. To do that, you'd first open the file with CreateFile (passing in security attributes which make the handle inheritable), and then assign the resulting handle to the hStdOut member of the STARTUPINFO structure you pass in. Then, remember to close the file after CreateProcess returns, since otherwise you'd leak a handle.
Use another program to do the redirection. When you type in commands on the command line, it's cmd.exe which parses your command line and does the file redirection. So instead of creating a my.exe process, you could instead create a cmd.exe process with a command line something like this:
cmd.exe "my.exe test > result.txt"
CreateProcess only expects an executable name and some arguments. The redirection is actually not a program argument. That is interpreted by the shell (cmd.exe).
What is happening when you invoke your own program is as follows...
cmd> this.exe "my.exe test" > result.txt
argv[0] = "this.exe"
argv[1] = "my.exe test"
Output is sent to result.txt by the shell
Now, your one that doesn't work:
cmd> this.exe my.exe test > result.txt
argv[0] = "this.exe"
argv[1] = "my.exe"
argv[2] = "test"
Output is sent to result.txt by the shell
You'll see that because you only send argv[1] to CreateProcess, the behaviour is not as you expected.
Now, as I mentioned, CreateProcess does not actually redirect output. To do that, you should use the system call which invokes cmd.exe or whatever command interpreter the system uses:
system( "my.exe test > result.txt" );
See: http://msdn.microsoft.com/en-us/library/277bwbdz(v=vs.80).aspx