the Program entry point function is WinMain
and it doesn't create a Window so it runs in the background.
I want to get a notification when the program is closed like: by the user through task manager or through system shutdown so I can save some progress.
something like the windows messages WM_QUITE but I can't access that as far as I know cuz i don't create a window
If there is no window, you may consider modifying the program registration as a DLL service plug-in.
The service also has no window and executes in the background.
The process is closed. Only the kernel callback knows that a process is killed. There will be no event whether the R3 process is closed.
Unless you have another process intermittently scanning the process list continuously.
Registering as a service at least you can receive event callbacks when your service is stopped by others.
CreateServiceW
https://learn.microsoft.com/zh-cn/windows/win32/services/installing-a-service
Is the background program something that your own code started, using CreateProcess()? If so, you can use the process handle (hProcess in the PROCESS_INFORMATION structure) in functions like WaitForSingleObject() etc. to check if the process still runs.
Related
Basically what the title says I need to detect when my program is ending like when someones clicks on end task in the task manager or something. Can anyone point me to some kind of event that handles this with an example or something? Thanks for any help given
You need to open this process. This way you will retrieve its handle. After that you can simply wait on this handle.
HANDLE h = OpenProcess(....);
WaitForSingleObject(h);
Handles of the processes and threads in many ways look like Windows event handles. Once this process or thread finishes, they get signaled.
It depends on how your app is terminated and what type of app it is.
For apps with an UI:
If the user clicks "End Task" in the task manager, you will actually receive WM_DESTROY and even WM_CLOSE messages to your message handler.
If the user simply clicks the X button of your app, obviously the above also applies.
If the user logs off or shuts down the PC, you'll receive WM_QUERYENDSESSION and WM_ENDSESSION messages.
For console apps, you can use the SetConsoleCtrlHandler function to be notified of most cases of app termination (I don't have any experience with this so can't give many details).
For services, you can use the RegisterServiceCtrlHandler function in much the same way.
For all types of apps, if the app is terminated forcibly by another process via the TerminateProcess function, there is no way to get notified:
If a process is terminated by TerminateProcess, all threads of the process are terminated immediately with no chance to run additional code. This means that the thread does not execute code in termination handler blocks. In addition, no attached DLLs are notified that the process is detaching.
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).
if a user decides to force close my application(like through the task manager) is there a way i can quickly execute some clean up code before the application closes? i'm coding in c++ btw
It depends on how the process is instructed to close. It is possible to do this upon graceful exit, but not for anything forcefully closed.
If the process is closed via TerminateProcess or ExitProcess, you won't be able to perform any graceful cleanup. TerminateProcess is how Task Manager and utilities like Sysinternals pskill end a target process. ExitProcess is called within a process but is not typically used to exit.
If the process has a message pump on one thread (typically the first thread in the process) and no other threads running that are running code whose lifetimes are independent of activity in that thread, then a WM_QUIT message will signal that the process should close (semantically, that the app should close, your process might conceivably stick around for a while for other reasons), and you can run cleanup code upon receiving the message. Depending on your needs, in a windowed app you might consider performing cleanup operations as early as WM_CLOSE or WM_DESTROY.
If you have written code in a DLL, there are notifications that you can handle in DllMain that will allow you to perform last-chance cleanup (DLL_PROCESS_DETACH), which can potentially cover the case of a process exiting without having a message pump. However, this is not a great way to perform cleanup for code that strictly relies on any C/C++ runtime (or any other DLL), as the runtime might be unloaded first.
Last, for any graceful close where you control what runs in WinMain or main, you can always do whatever cleanup you need to do before either function returns, sending control back to the windows subsystem. This is preferred and usually safest for most application needs.
If you are using a message pump, handle the WM_QUIT message.
Also: What is the difference between WM_QUIT, WM_CLOSE, and WM_DESTROY in a windows program?
EDIT
Im sorry, I read over the fact that you want to handle termination, eg by the task manager.
This might help you though: How to catch event when Task manager kill your C++ application
Is it possible to create a windows service to create and maintain another process? Like I'm writing a program, and say a virus killed the process, could I have my window service running and basically 'watching' it? I already have the code for a regular application that stays running and executes a program if it's not currently running, to keep it running.
I've never written a service before, but would it be that hard to just write this simple program, which basically runs a check to see if the process is running, if not, it executes it and sleeps for a few minutes?
Thanks.
Yes, it is possible. It is not uncommon to see third-party apps have watchdog services to keep them running in case of crashes. A service can enumerate running processes using EnumProcesses(), and if the desired executable is not running then start a new copy of it using CreateProcessAsUser().
If the service is the one starting the executable process in the first place, or can find it after an enumeration, one optimization would be to keep an open handle to the process (returned by CreateProcess...(), or use OpenProcess() on the process ID an enumeration returns), and then use a wait function, like WaitForSingleObject(), to detect when the process stops running. That way, you don't have to enumerate processes to find out if the intended process is still running or not.
I am creating an application in C++ gtk and if I press a button a threading process will start and I need to run the application if the window is closed also is it possible?
Under a Unix system (and since Windows 10), you create another process using the fork() function. To run a program you then use the execve() or similar.
However, that means you need to communicate with that other process using a pipe (see pipe() or pipe2()) or via the network.
Using a thread instead of a process allows you to run in the same memory & process and you can very easily shared everything between multiple threads.
As far as I know, the gtk loop just returns once the user selects the "Close Window" or similar exit function. It would be up for your main() function to make sure that it waits for all the threads to be done before exiting. For threads, this is usually done with a "join()". It will depend on the library you use to run your background process.
Note that in most cases people expect processes to exit whenever they ask the process to exit. Showing a window saying that your process is still running in the background (is busy) is a good idea for a process which runs a GUI. Especially, if you run your process from the console, it would not exit immediately after you closed the window, so letting the user know what's happening is important otherwise they are likely to hit Ctrl-C and kill the whole thing.
If you'd like the main to return but be able to keep the background threads running, it's a tad bit more complicated, but it uses both of the solutions I just mentioned:
create a pipe()
fork() (but no execve())
from within the forked app. (child) open Gtk window, background thread, etc.
when last Gtk window is closed, send message over pipe
parent process receives message and quits immediately
child process still attempts a "join()" to wait for the background thread
This way, the background process with threads created in (3) can continue to run (your function still needs to wait for all the threads to end with the "join()" call), however, the use has a sense of "the app. is done" since it returns to the next line on the prompt in your console even though a background process is still running.
The pipe() and wait on a message on the pipe() is not required if you don't mind having your application always running in the background.
Note: that usage of fork() is most often seen when creating processes that want to run in the background (i.e. services, often called servers under Unix). That's how they get their PPID set to 1.
On Windows, you need to create a Windows/Linux/Mac Service or run the process in background. On Linux you need to create a daemon service or run the process in the background. Services allow to automatically start the process on boot.