How to duplicate current process? - c++

What's the easiest way to duplicate the current process, to spawn another instance in Windows? I know Linux has fork(), but all I need is to run main in the same process again, probably using CreateProcess() with the correct arguments.

As #DavidHeffernan commented:
STARTUPINFO si;
::memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
PROCESS_INFORMATION pi;
::CreateProcess(NULL, ::GetCommandLine(), NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi);

Cygwin implements fork() within its managed environment, but even that is an intricate square dance in getting the child to catch up with the parent to accurately replicate POSIX behavior.
It seems like you don't need to emulate fork(), but fork()/exec(). For that, gathering the environment variables, program parameters and passing them to CreateProcess() should be enough. There are options to copy the file descriptors to the child too. See CreateProcess's documentation.

Related

C++ - CreateProcess failed code 2

I am trying to use the CreateProcess() function in order to launch an .exe application that is in a folder in my root directory (the directory where my VS solution is). Seems simple right? It probably is but I can't for the life of me notice what I have done wrong. Every time I try to launch the .exe I get the error message "CreateProcess failed code 2" which means that the .exe file I am trying to launch cant be found.
My code:
void HavNetProfiler::LaunchClumsy()
{
STARTUPINFO si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
si.cb = sizeof(si);
ZeroMemory(&pi, sizeof(pi));
// Start the child process.
if (!CreateProcess((LPCTSTR)"Clumsy\\clumsy.exe", // No module name (use command line)
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
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);
}
Am I using this function wrong? Have I misunderstood how it works or have I simply missed some minor detail? I am calling the function LaunchClumsy() in a file that is placed in a different folder (that folder exists in the root folder just like the "Clumsy" folder though). Would that make a difference?
Thanks!
There are 2 immediate bugs in the code:
The LPCTSTR cast is wrong. If your code does not compile without that cast, you have passed an argument with the wrong character encoding. Change it to L"Clumsy\\clumsy.exe" to explicitly pass a wide-character string.
Using a relative path is very likely to fail. The system searches starting from the current working directory. That is a process-wide property, that can be altered by any thread, at any time. Use an absolute path instead.

Win32 C API: Alternative to broken execl*() family of functions?

So, on Windows, it seems execl() is broken in different ways across different versions of windows. I've spent a lot of time narrowing it down and debugging, and it doesn't really make sense, and I can only think there's something wrong with Microsoft's implementation of execl() (actually execlp() for me).
The only Windows version execlp() seems to work correctly on is 7.
On Windows 10, it works fine, until I compile with -mwindows in MinGW.
Then it just makes my program terminate with a zero exit code.
On Windows XP, it interprets spaces in argument parameters as separate arguments, despite the actual number of arguments being clearly specified by the nature of the function's prototype...
So, looks like I'll have to use some Windows native function and wrap it in "#ifdef WIN32"s.
What I really need is execl() (execlp isn't necessary) like behavior on Windows, in that it replaces the current process image with a new one, and keeps network descriptors open like execl() will.
I'm really at a loss as to what good options are, and while CreateProcess seems somewhat able to do some of it, I can't find enough info on what I'm trying to do.
Any help is appreciated. Thanks!
Unfortunately, you will need a completely different code path on windows, because in the win32 subsystem, creating a process is coupled together with loading and running a new image in a single call: CreateProcess().
In a typical posix scenario, you would fork() your new process, set up things like e.g. file descriptors and then exec*() the new binary. To achieve something similar in Windows, you must rely on the possibilities you get from CreateProcess(). For open files (or sockets), win32 uses "handles" and these can be marked inheritable, for example I do the following for a pipe:
HANDLE pin, pout;
SECURITY_ATTRIBUTES sa;
sa.nLength = sizeof(sa);
sa.lpSecurityDescriptor = 0;
sa.bInheritHandle = 1;
if (!CreatePipe(&pin, &pout, &sa, 0))
{
fprintf(stderr, "Error creating pipe: %lu\n", GetLastError());
return;
}
This way, the pipe's handles are inheritable. Then, when calling CreateProcess(), by passing 1 (or TRUE) for bInheritHandles, the new process inherits all handles marked this way. In this example, I do the following:
STARTUPINFO si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
si.hStdInput = nul;
si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
si.dwFlags |= STARTF_USESTDHANDLES;
// simple example, my production code looks different, e.g. quoting the command:
char cmdline[1024];
strcpy(cmdline, exename);
strcat(cmdline, " ");
snprintf(cmdline + strlen(cmdline), 1024 - strlen(cmdline), "%" PRIxPTR, (uintptr_t)pout);
// [...]
PROCESS_INFORMATION pi;
CreateProcess(0, cmdline, 0, 0, 1, 0, 0, 0, &si, &pi);
In the child, the pipe could be used like that:
uintptr_t testPipeHandleValue;
if (sscanf(argv[1], "%" SCNxPTR, &testPipeHandleValue) != 1)
{
exit(EXIT_FAILURE);
}
int testPipeFd = _open_osfhandle(
(intptr_t)testPipeHandleValue, _O_APPEND | _O_WRONLY);
FILE *testPipe = _fdopen(testPipeFd, "a");
setvbuf(testPipe, 0, _IONBF, 0);
Of course this will look different for a network socket, but I hope the general idea helps.

System() to start a process, but using CreateProcess fails?

So, curious problem, I'm trying to create a process, and then resume it, mostly exploring the Windows API. I've noticed that if I do this:
system("C:\\Windows\\System32\\calc.exe");
It will open a calculator exe, however if I try to do the same thing using CreateProcessA, I get this:
STARTUPINFO starting_info;
PROCESS_INFORMATION process_info;
// let's try and make a process
if (!CreateProcessA(NULL, "C:\\Windows\\System32\\calc.exe", NULL, NULL, FALSE, CREATE_SUSPENDED, NULL, NULL, &starting_info, &process_info)) {
return;
}
// resume thread
NtResumeThread(process_info.hThread, NULL);
This for some reason throws an error of 0xc0000142 most of the times when it "creates" the process, else it just fails.
What's going on?
See the following MSDN sample code for creating a process:
https://msdn.microsoft.com/en-us/library/windows/desktop/ms682512(v=vs.85).aspx
You need to zero out the si and pi structs, also set
si.cb = sizeof(si);
In the end, close process and thread handles.
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);

How to open a program and make it run on the currently open console app in C++ [duplicate]

When I call CreateProcess in Windows, the new process doesn't seem to inherit the console of the calling process. I made a test program that runs "ruby xtest", xtest being a script that writes "hello" to standard output. I ran this test program from Emacs, and get no output. I also tried the following code calling GetStdHandle, but again, no output. Then I tried passing CREATE_NEW_CONSOLE in dwCreationFlags to CreateProcess, which made a whole new window with the Ruby output. Finally, I made a simple fork/exec
test program and compiled it using Cygwin's GCC. This program worked: the Ruby output showed up in Emacs as expected. I tried to decipher the Cygwin source code in http://cygwin.com/cgi-bin/cvsweb.cgi/src/winsup/cygwin/spawn.cc?rev=1.268&content-type=text/x-cvsweb-markup&cvsroot=src but failed. So, how do you make the new process inherit the console of the parent process such that the output from the child shows up as expected?
STARTUPINFO si;
PROCESS_INFORMATION pi;
memset(&si, 0, sizeof(si));
memset(&pi, 0, sizeof(pi));
si.dwFlags |= STARTF_USESTDHANDLES;
si.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
si.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
si.hStdError = GetStdHandle(STD_ERROR_HANDLE);
if(!CreateProcess(0, "ruby xtest", 0, 0, 1, 0, 0, 0, &si, &pi)) die("CreateProcess");
I know, this thread is rather old, however, I just ran into the same problem.
Just as for the TS, the console handle was inherited and working fine under Cygwin, but not on a Windows console. Instead, the output on stdout was neither shown, nor any error was reported. Inherited Pipe handles worked still fine.
I took me some time to identify the (now obvious) problem: CreateProcess() was called with CREATE_NO_WINDOW. Dropping this flag, console output is fine. (Though, according to the code of the TS, they never set this flag in the first place.)
Hope this might be helpful for people who also stumble across this thread, like myself.
According to Microsoft documentation, lpCommandLine (2. parameter):
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.
When I stopped using a constant here it worked for me. I didn't need the STARTF_USESTDHANDLES and GetStdHandle thing.
This code from a console prg runs and outputs another console exe in the same console:
FillChar(SI, SizeOf(SI), 0);
SI.cb:=SizeOf(SI);
FillChar(PI, SizeOf(PI), 0);
if CreateProcess(nil, CmdLineVar, nil, nil, False, 0, nil, nil, SI, PI) then ...
I've done this by passing in pipes for hStdInput, hStdOutput, and hStdError and manually routing data from the hStdOutput and hStdError pipes to the console.
Not sure if debeige ever solved this, but I needed the same thing, but starting up another thread to listen to stdout output, just to put it on stdout seemed nuts to me.
The following works for me, and is slightly different than what he originally posted. I thought at first it wouldn't work if you don't set si.cb, but when I commented that in mine, it still worked, so... YMMV.
STARTUPINFO siStartInfo;
ZeroMemory( &siStartInfo, sizeof(STARTUPINFO) );
siStartInfo.cb = sizeof(STARTUPINFO);
siStartInfo.hStdError = GetStdHandle(STD_OUTPUT_HANDLE);
siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
siStartInfo.hStdInput = g_hChildStd_IN_Rd; // my outgoing pipe
siStartInfo.dwFlags |= STARTF_USESTDHANDLES;
// Create the child process.
bSuccess = CreateProcess(
NULL,
szCmdline,
NULL,
NULL,
TRUE,
0,
NULL,
NULL,
&siStartInfo,
&piProcInfo);

How to set PROCESS_SET_QUOTA to process?

I want to use SetProcessWorkingSetSize function, and on MSDN i see this:
"The handle must have the PROCESS_SET_QUOTA access right. For more information, see Process Security and Access Rights."
So, how can i set PROCESS_SET_QUOTA to process handle?
I want to write program that runs executable with working set limits, so there is main piece of code:
STARTUPINFO si;
memset(&si, 0, sizeof(si));
si.cb = sizeof(si);
GetStartupInfo(&si);
si.dwFlags = 0;
PROCESS_INFORMATION pi;
if (!CreateProcess(
exePath.c_str(),
cmdParametersBuffer,
NULL,
NULL,
FALSE,
NORMAL_PRIORITY_CLASS,
NULL,
NULL,
&si,
&pi))
{
cout << "error" << endl;
}
SetProcessWorkingSetSize(pi.hProcess, 20 * 4 * 1024, 100*1024*1024);
Did you actually try the code you have showed and it is not working for you? If so, what error is GetLastError() reporting?
If you read the documentation, it says:
Process Security and Access Rights
PROCESS_ALL_ACCESS
All possible access rights for a process object.
...
The handle returned by the CreateProcess function has PROCESS_ALL_ACCESS access to the process object
So you should be able to call SetProcessWorkingSetSize() after CreateProcess() exits, exactly like you have showed, without doing anything extra to enable PROCESS_SET_QUOTA rights, as it should already be enabled.
Your example code is calling SetProcessWorkingSetSize() successfully, as the error you get is 0. If you got an error like 0x522 ERROR_PRIVILEGE_NOT_HELD then you'd know the call failed.
It might help to know that an app is expected to be able to allocate more memory than its the working set size. The OS will page out memory from RAM. If you use Task Manager to view the Working Set for your process, is it actually exceeding the quota you set?
You might also need to use SetProcessWorkingSetSizeEx wth flag QUOTA_LIMITS_HARDWS_MAX_ENABLE to force the OS to actually apply your setting.