I want to write a program in C++ that can open a .exe program and I want to know when it's close by the user. I know that I can open a program by this code:
system ("start C:\\AAA.exe");
However I don't know how can I check if the program closed.
On Windows if you use CreateProcess() instead of system() to start a new process. Simplified code:
PROCESS_INFORMATION processInformation;
CreateProcess(..., &processInformation);
In PPROCESS_INFORMATION you find its handle. With its handle you can wait it's terminated (to mimic how system() works):
WaitForSingleObject(processInformation.hProcess, INFINITE);
Or periodically check its status getting its exit code (if any, see also How to determine if a Windows Process is running?) if your code has to run together with child process:
DWORD exitCode;
BOOL isActive = STILL_ACTIVE == GetExitCodeProcess(processInformation.hProcess, &exitCode);
Don't forget to close handle (even if process already terminated):
CloseHandle(processInformation.hProcess);
Note that with that code you don't know the reason process terminated. It may be because user closed its window, because it terminated by itself or because it crashed. For a GUI application you can hook its main window messages looking for WM_CLOSE (to detect user actions), WM_QUIT (application did it) and attaching an handler with SetUnhandledExceptionFilter() (to detect unhandled errors). It's not 100% reliable but it may be material for another question...
Calling system ("C:\AAA.exe"); you can block until process AAA.exe finished.
If it is not acceptable, you can call system ("C:\AAA.exe"); in separate thread, and check is it finished or not.
#include <thread>
void threadRoutine()
{
::system("C:\AAA.exe");
}
int main()
{
std::thread systemCall(threadRoutine);
//do some work here
systemCall.join();
//you are sure that AAA.exe is finished
return 0;
}
Related
I'm working on an implementation to force the exit of a process by PID in QT. The only way I found to solve this problem is using the following lines of code:
QString processToKill = "taskkill /F /PID " + QString(getAppPid());
system(processToKill.toStdString().c_str());
These lines do their job and works well, the only detail I have found is that when executing this command a console opens and closes quickly (a flicker). Is there any way to prevent this behavior?
If you are using system() you cannot avoid the occasional flash of the console window. Were you to use any other program you might even see its window flash.
I won’t go into any detail about the security flaws inherent to using system().
The correct way to do this with the Windows API.
Even so, you are taking a sledgehammer approach. You should first signal the process to terminate gracefully. If it hasn’t done so after a second or two, only then should you crash it.
The SO question “How to gracefully terminate a process” details several options to properly ask a process to terminate.
If that fails, then you can simply kill a process using the TerminateProcess() Windows API function (which is what taskkill /f does). Here is a good example of how to do that: https://github.com/malcomvetter/taskkill
The relevant code has the following function:
BOOL TerminateProcess(int pid)
{
WORD dwDesiredAccess = PROCESS_TERMINATE;
BOOL bInheritHandle = FALSE;
HANDLE hProcess = OpenProcess(dwDesiredAccess, bInheritHandle, pid);
if (hProcess == NULL)
return FALSE;
BOOL result = TerminateProcess(hProcess, 1);
CloseHandle(hProcess);
return(TRUE);
}
Microsoft has a page all about Terminating a Process that you may wish to review as well.
If this is a windows program create a program that uses a WinMain entry point rather than main, and set the linker subsystem to windows rather than console.
Just because it uses WinMain does not mean that you must create a window, it merely means you don't automatically get a console.
Suppose we have small program, written in C++, which looks like below.
This program itself intentionally does NOT perform signal handling via WinAPI call SetConsoleCtrlHandler - it's important part of question.
#include <stdio.h>
#include <stdlib.h>
int main() {
while(true) {
int status = system("EXTERNAL COMMAND");
printf("RESULT STATUS = %d\n", status);
}
}
When Ctrl+C key combination have been pressed in terminal, program above have quite different behavior depend on which "EXTERNAL COMMAND" had been invoked
1) If external command is pause, program will stand in infinite loop, invoking pause command step by step, and will print "RESULT STATUS = 0" many times, while not terminated forced via process kill.
2) If external command in choice, program will terminate immediately after Ctrl+C pressure. It will not print anything and does not return from system call.
3) If external command is set /P VAR=, program has much interesting behavior. When Ctrl+C pressed, program prints `"RESULT STATUS = 1" and continue working until first async call is performed.
First and second case can be explained in following manner. Terminal windows is proxt between user input and target program, so when user presses Ctrl+C, terminal window perform dispatch signal itself to target process.
So some subprocesses can take manually terminal handler via hConsole = GetStdHandle(STD_OUTPUT_HANDLE) and perform own signal handling. Another subprocess does not do this, so signal passed into parent process and terminate it.
But third case causes big question. If child process intercepts SIGINT, why parent process perform terminating after first async call. If not, why it does not terminate immediately and why and how it prints `"RESULT STATUS = 1" and continue working.
Thanks
There are no Unix signals in Windows, at least not from the kernel. That said, Windows and the Windows API are fundamentally based on the C programming language, which, having been developed in tandem with Unix, does require six signals. The C runtime in Windows emulates SIGABRT and SIGTERM within process (e.g. for use with C raise). For SIGSEGV, SIGILL, and SIGFPE it uses an OS exception handler. In a console application, standardSIGINT and non-standard SIGBREAK are associated with the C runtime's console control handler, which is usually the first handler registered via SetConsoleCtrlHandler. CTRL_C_EVENT is mapped to the SIGINT signal handler, and all others (CTRL_BREAK_EVENT, CTRL_CLOSE_EVENT) are mapped to the SIGBREAK handler.
Console control events are sent by the console host (conhost.exe), which implements this by having the session server (csrss.exe) create a thread in a client process. This thread begins at the undocumented CtrlRoutine function in kernelbase.dll, which walks the registered control handlers until one of them handles the event by returning true. If none of them handles the event, the default handler calls ExitProcess(STATUS_CONTROL_C_EXIT). Note that SetConsoleCtrlHandler(NULL, TRUE) sets a flag that makes CtrlRoutine ignore CTRL_C_EVENT, and this flag is inherited by child processes and enabled by default when a process is created with the flag CREATE_NEW_PROCESS_GROUP. Also, for CTRL_CLOSE_EVENT, the session server gives each process 5 seconds to handle the event and exit on its own, else it terminates the process forcefully.
To understand what's happening with CMD's internal PAUSE command, see SetConsoleMode, and, in particular, ENABLE_PROCESSED_INPUT. PAUSE calls C _getch, which temporarily sets the console input mode to 0. With the processed-input mode disabled, Ctrl+C is simply read as "\x03" instead of generating a CTRL_C_EVENT.
I have a Win32 program. This program creates a process with CreateProcess function to run another program. I want to parent process to be closed, if the child process was closed or crashed for any reason.
How can I do it?
You can use the WaitForSingleObject function on the created process' handle, like so:
STARTUPINFO si {sizeof(si)};
PROCESS_INFORMATION pi {};
CreateProcessW(/*your arguments here*/);
WaitForSingleObject(pi.hProcess, INFINITE);
Note that if you do use INFINITE as the wait time, the function blocks until the process terminates. If you want the parent process to be doing other things in the mean time, it's best to have that code in a separate thread.
If you want the parent process to be a complete wrapper for the created process, use GetExitCodeProcess when you're done to obtain the child process' exit code.
DWORD dwExit;
GetExitCodeProcess(pi.hProcess, &dwExit);
This code was just a simple example. All three functions I mentioned in my answer can fail, and robust code would check their return values and act accordingly in the case of failure.
I have a program (runs as a background process) in which I installed a hook to capture EVENT_SYSTEM_FOREGROUND events (i.e - when the user switches between windows). The callback which is registered for the hook basically logs what application (process exe filename) the user has switched from and which they have switched to.
I want to add some code to check if the application they have switched from is still active (if not we assume they have closed it and that is what has brought a new window into the foreground). I am testing for it's existence by trying to create a handle to the previous PID using OpenProcess
//Check prev pid still exists - if not, assume the previous app has been closed
HANDLE hPrevProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,false,g_prevPid);
if (hPrevProc==NULL){
prevProcStillRunning=false;
}
else{
CloseHandle(hPrevProc);
}
Assumptions with the code above:
g_prevPid is populated with a PID - I have verified this
prevProcStillRunning has been initialized to true
The problem with the code above is that for some reason, even when the user has exited an app (say notepad.exe for example). For up to 10 seconds after they have exited, this test still passes (i.e - hPrevProc gets initialised). Even though I can see in the task manager that the Notepad.exe process has dissapeared (and yes I only have one instance of it opened), somehow, the OpenProcess line still can get a handle on that PID. I am guessing that somehow the PID actually still exists but it may be in a state where its terminating. I have found that if this code is called a few more times, eventually it will return null.
I would like to find out a better way I can test whether hPrevProc is still acitive.
I tried to test this using the GetExitCodeProcess function but this seems to just give me the PID and I'm not even sure if that's the right approach in any case.
Any help appreciated.
The process subsists in the system after it terminates at least while there is an open handle to it.
The only foolproof method to know whether a process is still active is:
make sure the process cannot exit with code STILL_ACTIVE (259)
try to open the process (OpenProcess)-> if you cannot is is terminated
read the exit process code (GetExitCodeProcess) -> if it is not STILL_ACTIVE the process is terminated.
You code could become:
//Check prev pid still exists - if not, assume the previous app has been closed
HANDLE hPrevProc = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ,false,g_prevPid);
if (hPrevProc==NULL){
prevProcStillRunning=false;
}
else{
DWORD cr;
if ((GetExitCodeProcess(hPrevProc, &cr) == 0) || (cr != STILL_ACTIVE)) {
prevProcStillRunning=false;
}
CloseHandle(hPrevProc);
}
Anyway, closing a GUI application involves different steps:
the GUI elements are destroyed
the message loop ends
eventually the application could do background operations (save state to file, etc.)
the main procedure returns an exit code
the system knows that the application is terminated
The event will be sent as soon as the main window will be closed, which can happen some time before the application actually stops. A good example for that is Firefox. If you close the window and immediately try to start a new process, you will get an error because even if the UI is gone, the process is not still terminated. What is worse, is that you can find applications that simply go into background when you close the UI, and allow user to open UI again through an action on an icon in the status area of the taskbar (Shell_NotifyIcon and its callback). This is common for services of other application working in background (network servers, firewalls, etc.). In that case, the UI is gone but the process will not terminate.
TL/DR: the time between the disparition of the UI and the termination of the process owning it is variable and depends on the system load and the background activity of the process after closing the UI. You can try to use a delay for that but I cannon guarantee anything about it...
Probably some process (maybe yours?) still holds a valid handle to this process. Until CloseHandle was called on all handles, system maintains internal record which allow to access its process data. This is important because as you say it must be possible to call GetExitCodeProcess on closed process, also someone might want to wait for it to stop with WaitForSingleObject.
Also be carefull with PIDs, they can be reused - so in theory you might call OpenProcess on some other newly opened process.
As for checking if given process is not a zombie, you might try enumerating top level windows with EnumWindows, and checking if any of them is associated with given PID (to get window's PID use GetWindowThreadProcessID).
I am going to open game process from my trainer app and write some values to memory. I have no problems with opening a process and writing a value to memory. But I can't realize how to monitor the game process availability. For example I opened a running process, user closed it and opened again. How can I track this in my code? OpenProcess handle is valid even after the process is closed (until CloseHandle called). Thank you.
You can use the GetExitCodeProcess function to see if the handle you have points to a running process.
DWORD exitCode=0;
::GetExitCodeProcess(hProcess, &exitCode);
if (exitCode==STILL_ACTIVE)
; //process is alive
MSDN link
Or else, if it's more suitable for your application to have the process termination event signalled to you (process is a waitable object):
::WaitForSingleObject(hProcess, dwTimeout);