I need to start a process and run it as a detached process. I have some sort of starter application which purpose is to run another exe and immediately exit. What is a best way to achieve that?
I read CreateProcess documentation several times but still have questions. Documentation says that I need to call CloseHandle after I finish. But my parent app shouldn't wait for a child to exit. Another part of documentation says that I can leave handles alone - the system will close them when the parent process terminates. Does that means that child application exits immediately after parent? It seems not true - I close a starter but my child process still runs.
There's a DETACHED_PROCESS flag that seem what I'm looking for. But documentation says something about console. What console? I don't care about console.
DETACHED_PROCESS flag documentation states
For console processes, the new process does not inherit its parent's console (the default)
that means: if you have a console process and you start a new one, it will not inherit its parent's console.
If you don't have a console process you don't have to worry about it.
CreateProcess creates a child process but does not wait for the child process to finish, so you're already all set.
If you wanted to wait for the child process to complete, you should have called CreateProcess and then WaitForSingleObject
To summarize:
// Version 1) Launch and wait for a child process completion
STARTUPINFO info = { sizeof(info) };
PROCESS_INFORMATION processInfo;
if (CreateProcess(L"C:\\myapp.exe", L"", NULL, NULL, TRUE, 0, NULL, NULL, &info, &processInfo)) {
::WaitForSingleObject(processInfo.hProcess, INFINITE); // DO WAIT for the child to exit
CloseHandle(processInfo.hProcess);
CloseHandle(processInfo.hThread);
}
// ----------------------------------------------------------------
// Version 2) Launch and do NOT wait for a child process completion
STARTUPINFO info = { sizeof(info) };
PROCESS_INFORMATION processInfo;
if (CreateProcess(L"C:\\myapp.exe", L"", NULL, NULL, TRUE, 0, NULL, NULL, &info, &processInfo)) {
CloseHandle(processInfo.hProcess); // Cleanup since you don't need this
CloseHandle(processInfo.hThread); // Cleanup since you don't need this
}
notice that version 2 will not terminate your child process. Only resources which are no longer needed will be released.
I read CreateProcess documentation several times but still have questions. Documentation says that I need to call CloseHandle after I finish. But my parent app shouldn't wait for a child to exit.
Okay, then don't wait. You can call CloseHandle immediately in the parent.
Another part of documentation says that I can leave handles alone - the system will close them when the parent process terminates. Does that means that child application exits immediately after parent? It seems not true - I close a starter but my child process still runs.
No, it doesn't. I'm not sure how you got that from the documentation, but that's not what it means.
There's a DETACHED_PROCESS flag that seem what I'm looking for. But documentation says something about console. What console? I don't care about console.
If you don't care, then don't worry about it.
Related
I have a Win32 C++ application. I'm trying to launch one or several child processes with CreateProcess. I want the children to close when the parent does.
I achieved this by creating a job and enabling JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE:
HANDLE hJob = CreateJobObject(NULL, NULL);
JOBOBJECT_EXTENDED_LIMIT_INFORMATION extendedInfo;
ZeroMemory(&extendedInfo, sizeof(extendedInfo));
extendedInfo.BasicLimitInformation.LimitFlags =
JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE;
SetInformationJobObject(
hJob, JOBOBJECTINFOCLASS::JobObjectExtendedLimitInformation,
&extendedInfo, sizeof(extendedInfo));
Then adding the current (parent) and created (child) process to this job:
// assign parent to job
AssignProcessToJobObject(hJob, GetCurrentProcess());
// launch child with no inherited handles
PROCESS_INFORMATION procInfo;
ZeroMemory(&procInfo, sizeof(procInfo));
STARTUPINFOA startInfo;
ZeroMemory(&startInfo, sizeof(startInfo));
startInfo.cb = sizeof(startInfo);
startInfo.dwFlags |= STARTF_USESTDHANDLES;
bool success = CreateProcessA(NULL,
"test.exe", // command line
NULL, // process security attributes
NULL, // primary thread security attributes
FALSE, // handles are inherited
0, // creation flags
NULL, // use parent's environment
NULL, // use parent's current directory
&startInfo, // STARTUPINFO pointer
&procInfo); // receives PROCESS_INFORMATION
// assign child to job
AssignProcessToJobObject(hJob, procInfo.hProcess);
This works, but the parent app and the child app (main.exe and test.exe) show up as two unrelated processes in the task manager:
(Even though closing main.exe will close test.exe).
What am I doing differently than, say, Microsoft Teams or Chrome, which both have nested processes?
Exactly what Task manager is doing is not documented.
In Windows 8 it does not group child processes, it only organizes based on a process having a window or by being "special".
How does Task Manager categorize processes as App, Background Process, or Windows Process?:
These are terms that Task Manager simply made up. The system itself doesn’t really care what kind of processes they are.
If the process has a visible window, then Task Manager calls it an “App”.
If the process is marked as critical, then Task Manager calls it a “Windows Process”.
Otherwise, Task Manager calls it a “Background Process”.
(I don't believe this is 100% accurate, it clearly knows about services and I suspect it might hard-code some names)
In Windows 10 it tries harder to group things together but I don't exactly know what it is doing.
It is often (but not always) able to tie the conhost.exe child to its parent console application.
The new fancy store/packaged versions of Notepad and Paint have all their processes in a single group. The same does not happen with Notepad2 even though it has a Application Model ID set. Neither does it apply to Wordpad (even when one is a child of the other). I also tried setting an AMUI in a little test application and neither process wide AMUI nor per-HWND AMUI seems to trigger the grouping.
A job object does not seem to enable grouping.
Depending on your version, Edge might use a special API to tell Task manager about its processes.
In conclusion, I don't know what exactly what it is looking for but Packaged applications and App Containers seem to often trigger it.
To make it visible as a child process in the task manager, you have to set the CreateNoWindow property to false and UseShellExecute property to false in the StartInfo property before starting the process.
startInfo.CreateNoWindow = false;
startInfo.UseShellExecute = false;
This tells the process to create a new window for the child process and to use the command line to start the process instead of using the shell to start the process.
This will now create the child process as a new visible process in the task manager, and it will be shown under the tree of the main process.
I've accidentally created a program that continues to call CreateProcess on itself - resulting in an infinite loop.
How would I go about killing this program once it's started to run? I have attempted killing this through the task manager, but because the program calls itself to start and immediately dies, it continues to disappear and reappear in the task manager making it 'unstoppable'.
The only way to stop this seems to be a reboot of the PC, which can be very inconvenient.
int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, PWSTR pCmdLine, int nCmdShow )
{
using namespace std;
CreateProcess( L"self.exe",
NULL, // No command line arguments
NULL, // Process handle not inheritable
NULL, // Thread handle not inheritable
NULL, // Set handle inheritance to NULL
NULL, // No creation flags
NULL, // Use parent's environment block
NULL, // Use parent's starting directory
&lpStartupInfo, // Pointer to STARTUPINFO structure
&lpProcessInfo // Pointer to PROCESS_INFORMATION structure
);
return 0;
//return (int)msg.wParam;
}
From a end-users point of view, the easy solution is to press Ctrl+Alt+Del and log off. If you want to keep the session alive the only solution to a fork-bomb like this is to use a tool that understands the process tree. taskkill /T /IM self.exe as suggested in the comments or the "Kill process tree" feature in Process Explorer. Child processes might still be able to sneak past so you might have to execute the kill command multiple times.
If I was programming a kill tool for this I would enumerate the processes and when a target process is found you open a handle to it and try to associate it with a job object. A job object allows you to deny the creation of child processes and allows easy termination of all processes in the job. Just call TerminateProcess if the process could not be added to a job.
You need to run this enumeration code in a loop until you have killed all the desired processes.
I'm trying to open "mspaint" and find handle of it right after it has been initialized. But FindWindow returns NULL if I call WaitForInputIdle. If I try to use the function Sleep(1000) it works. But I don't think it's a right way to wait for the program to be ready. Is there a solution for this code?
CString strWindowDirectory;
GetSystemDirectory(strWindowDirectory.GetBuffer(MAX_PATH), MAX_PATH);
SHELLEXECUTEINFO sei = { 0 };
sei.cbSize = sizeof(SHELLEXECUTEINFO);
sei.fMask = SEE_MASK_NOCLOSEPROCESS;
sei.lpVerb = L"open";
sei.lpFile = L"mspaint";
sei.lpDirectory = strWindowDirectory;
sei.nShow = SW_SHOWNORMAL;
HWND hPaint = NULL;
if(ShellExecuteEx(&sei))
{
int r = ::WaitForInputIdle(sei.hProcess, INFINITE);
ATLTRACE(L"WaitForInputIdle %d\n", r);
if (sei.hProcess == NULL) return;
hPaint = ::FindWindow(L"MSPaintApp", NULL);
ATLTRACE(L"Handle %d\n", hPaint);
if (!hPaint) return;
}
else
{
MessageBox(L"Couldn't find mspaint program");
return;
}
WaitForInputIdle works, but not the way you assume it does. This is largely, because the documentation is misleading (or at least not as explicit as it should be):
Waits until the specified process has finished processing its initial input and is waiting for user input with no input pending, or until the time-out interval has elapsed.
This is almost criminally inaccurate. While the Remarks section notes, that WaitForInputIdle waits at most once per process, it never mentions significant details. Specifically:
WaitForInputIdle returns, as soon as the initial startup has come to a point, where any thread in the process is ready to process messages. Those messages need not be user input.
WaitForInputIdle was invented to allow a process to communicate with a child process using a message-based protocol. The specific scenario addressed was DDE, which no one1) uses anymore.
WaitForInputIdle cannot be used as a reliable solution to your problem: Waiting for a child process' UI to show up. You really need to wait for the UI show up.
The system offers two solutions you can use:
A global CBT hook, and wait for the HCBT_CREATEWND callback. You can inspect the CREATESTRUCT's lpszClass and/or lpszName members to filter out the window you are interested in.
Use WinEvents and respond to the EVENT_OBJECT_CREATE event.
The global CBT hook is called, whenever a window is about to be created. The kernel structures that the HWND references have been fully populated, but the client calling CreateWindow[Ex] may still terminate window creation. In contrast, the WinEvent is issued, after the window has been fully constructed, and is ready for interaction.
In general, a solution based on a CBT hook is used, when an application needs to update certain aspects of a window before the caller of CreateWindowEx gets to see the HWND for the first time. WinEvents, instead, are usually the tool of choice when implementing accessibility or UI automation solutions.
Additional resources:
WaitForInputIdle should really be called WaitForProcessStartupComplete
WaitForInputIdle waits for any thread, which might not be the thread you care about
1) Yes, I know, some applications might still use DDE. But if Raymond Chen suggested in 2007, that we should feel free to stop using DDE, I'll just pass that on as authoritative guidance.
I have created a process using CreateProcess(). This is the code:
STARTUPINFO si = {0};
PROCESS_INFORMATION pi = {0};
result = CreateProcess("C:\\AP\\DatabaseBase\\dbntsrv.exe", NULL, NULL, NULL, FALSE, 0, NULL, "C:\\ADP\\SQLBase", &si, &pi)
How can I get the Handle and processId of this specific process? And eventually use it to close this process?
Thank You.
In the struct pi you get:
typedef struct _PROCESS_INFORMATION {
HANDLE hProcess;
HANDLE hThread;
DWORD dwProcessId;
DWORD dwThreadId;
} PROCESS_INFORMATION, *LPPROCESS_INFORMATION;
The first parameter is the handle to the process.
You can use that handle to end the process:
BOOL WINAPI TerminateProcess(
__in HANDLE hProcess,
__in UINT uExitCode
);
hProcess [in]
A handle to the process to be terminated.
The handle must have the PROCESS_TERMINATE access right. For more information, see Process Security and Access Rights.
uExitCode [in]
The exit code to be used by the process and threads terminated as a result of this call. Use the GetExitCodeProcess function to retrieve a process's exit value. Use the GetExitCodeThread function to retrieve a thread's exit value.
A handle to the process is returned in the PROCESS_INFORMATION structure, pi variable.
The TerminateProcess() function can be used to terminate the process. However, you should consider why you need to kill the process and why a graceful shutdown is not possible.
Note you need to set the cb member of si before calling CreateProcess():
si.cb = sizeof(STARTUPINFO);
EDIT:
To suppress the console window specify CREATE_NO_WINDOW, as the creation flag (the sixth argument) in the CreateProcess() call.
EDIT (2):
To suppress the window try setting following members of STARTUPINFO structure prior to calling CreateProcess():
STARTUPINFO si = {0};
si.cb = sizeof(STARTUPINFO);
si.dwFlags = STARTF_USESHOWWINDOW;
si.wShowWindow = FALSE;
Closing the process cleanly
To close the process cleanly, you should send a close signal first:
How To Terminate an Application "Cleanly" in Win32.
If you absolutely must shut down a process, follow these steps:
Post a WM_CLOSE to all Top-Level windows owned by the process that you want to shut down. Many Windows applications respond to this message by shutting down.
NOTE: A console application's response to WM_CLOSE depends on whether or not it has installed a control handler.
Use EnumWindows() to find the handles to your target windows. In your callback function, check to see if the windows' process ID matches the process you want to shut down. You can do this by calling GetWindowThreadProcessId(). Once you have established a match, use PostMessage() or SendMessageTimeout() to post the WM_CLOSE message to the window.
Use WaitForSingleObject() to wait for the handle of the process. Make sure you wait with a timeout value, because there are many situations in which the WM_CLOSE will not shut down the application. Remember to make the timeout long enough (either with WaitForSingleObject(), or with SendMessageTimeout()) so that a user can respond to any dialog boxes that were created in response to the WM_CLOSE message.
If the return value is WAIT_OBJECT_0, then the application closed itself down cleanly. If the return value is WAIT_TIMEOUT, then you must use TerminateProcess() to shutdown the application.
NOTE: If you are getting a return value from WaitForSingleObject() other then WAIT_OBJECT_0 or WAIT_TIMEOUT, use GetLastError() to determine the cause.
By following these steps, you give the application the best possible chance to shutdown cleanly (aside from IPC or user-intervention).
See this answer for code.
Terminating the process
If you don't care about clean shutdown, you can use TerminateProcess(). However, it is important to note that TerminateProcess() is asynchronous; it initiates termination and returns immediately. If you have to be sure the process has terminated, call the WaitForSingleObject() function with a handle to the process.
Note: Access rights PROCESS_TERMINATE and SYNCHRONIZE are required.
TerminateProcess(pi.hProcess, 0);
// 500 ms timeout; use INFINITE for no timeout
const DWORD result = WaitForSingleObject(pi.hProcess, 500);
if (result == WAIT_OBJECT_0) {
// Success
}
else {
// Timed out or an error occurred
}
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
Not closing, just wait until finished
If the process will finish on its own, instead of terminating you can wait until it has finished.
WaitForSingleObject(pi.hProcess, INFINITE);
CloseHandle(pi.hProcess);
CloseHandle(pi.hThread);
This is explained thoroughly in MSDN:
If result is non-zero (which means that it succeeded) you will get the handle and processid in the pi structure.
In order to kill the process you can use TerminateProcess
I have an application that is essentially a "helper" application that wraps another app.
The app that the user interacts with is a process that is created by the "helper" app like so:
PROCESS_INFORMATION processInfo;
STARTUPINFO startupInfo;
memset(&processInfo, 0, sizeof(processInfo));
memset(&startupInfo, 0, sizeof(startupInfo));
startupInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
startupInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
startupInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
startupInfo.dwFlags = STARTF_USESTDHANDLES;
startupInfo.cb = sizeof(startupInfo);
int retval = CreateProcess(cmd, cmdLine, NULL, NULL, false,
CREATE_NO_WINDOW, NULL, NULL, &startupInfo,
&processInfo);
This process is an executable that I do not have the source code to and cannot make changes to.
The "helper" application does a few things based mainly on network traffic from the other app. At one point I want to display a file browse dialog from the helper app based on something the user does in the started UI process.
When I show the file dialog from the helper app, it's shown behind the UI of the process that was created, which isn't ideal. I tried calling SetForegroundWindow() from the helper app but it fails the criteria specified for SetForegroundWindow in the MSDN docs ( http://msdn.microsoft.com/en-us/library/windows/desktop/ms633539%28v=vs.85%29.aspx ), namely:
The process is not the foreground process.
The process was not started by the foreground process.
(even though the process created the foreground process).
Is there a way to call CreateProcess() with a flag or setting that works like calling AllowSetForegroundWindow() from that process? Or a flag that can be used to make Windows think the started process is "the same" as the process that started it for purposes of SetForegroundWindow permissions?
Or is there another way I can show the dialog generated by the helper app on top of the created process' dialogs?
The only solution I could think of off the top of my head would be to do remote thread injection into the child process, and then have your injected thread call AllowSetForegroundWindow with the appropriate parameters to allow the parent process to steal foreground-ness back.
I have not tested this though.