How to gracefully end a process without using CloseMainWindow - c#

Is there a way to gracefully end a process without using Process.CloseMainWindow()?
I have a bunch of processes in a list which I want to end. The process should be ended without Process.Kill() to make sure they clean up and end their child processes as well.
I tried CloseMainWindow, but unfortunately it will make my process pop up a messagebox with "Do you really want to end the programm?"[Yes][No] which I want to avoid.
The processes have a message handler for WM_QUERYENDSESSION but when I tried to send a WM_QUERYENDSESSION message to the process, it didn't react on it. It just reacts on WM_QUIT, but the behaviour looks like the one when calling Process.Kill().
I couldn't find a proper solution yet. Hopefully I didn't overlooked things in here...

Sending the WM_CLOSE message is pretty much the same as clicking the close button on a window. Applications will be able to block this request or put up a "Save your changes" confirmation dialog.
Anything beyond this and you risk loosing data. WM_QUIT is not something you should be sending.
WM_QUERYENDSESSION is a query, you would send that first and then WM_ENDSESSION but not all applications will handle these messages.
Win32 does not have a main-window property, it is a .NET concept.
Another thing you should look into is the restart manager feature if you plan on restarting these applications again when you are done with whatever you are doing.

Well after a while I admit that there seems to be no real answer to this explicit problem.
Since I got control of both parts I just removed the "Do you really want to quit?" pop up like IInspectable assumed and send a message via the opened pipe to the child process like Sefe assumed.

Related

Detecting when a Process (GUI) is "Done" even though it doesn't Exit?

I'm writing a console app that detects USB drives, formats them, and then runs a program called UnetBootin to write an ISO to the drives. Everything works fine, but the issue is UNetbootin doesn't simply "exit" so .WaitForExit() doesn't work unless the user clicks the "Exit" button.
The only way I can imagine to solve this is either by checking for that button to appear or trying to guess if the process is idling somehow. In either case, I wouldn't know where to start.
This is going to be ugly no matter how you slice it. I 'm not aware of a better approach, so here is one that would work AFAIK:
Get the PID of your target process (you already have that if you can call WaitForExit)
Get handles to all windows of that process
Use GetWindowText to get the text of each and every window from step 2
If any window has text equal to "Reboot Now", you know you 're done
WARNING: At this point I should mention that GetWindowText should be considered extremely dangerous because it can do evil things to your thread, including hanging it, due to no fault of your own. In practice it won't happen, but it's something you should know.

how to close a window from a different process

I have a c# application which I want to instruct to shutdown nicely, from a different process.
I also want to be able to ask it to open its main window.
I have a reference to its main window handle.
I know I can do it using elaborate schemes such as remoting or WCF.
the question is can I do it using simpler mechanisms such as window messages, or the OnClose event handlers of the window in the c# application
Pinvoke SendMessage() to send the WM_CLOSE message to the app's main window. Asking it to open its main window is probably going to be quite difficult, you cannot obtain the window handle until the window is created. Process.Start() would be the normal way.
A low cost alternative to WCF and superior to pinvoke is a named pipe or a socket to interface with the app. This requires being able to modify the source code of the app.
Process.CloseMainWindow
http://msdn.microsoft.com/en-us/library/system.diagnostics.process.closemainwindow.aspx
I think that you could probably use FindWindow to find the correct child window and then SendMessage or PostMessage to send a WM_CLOSE.
Here's another StackOverflow question that deals with doing this in C#.
Edit: Though as the other answer says in that question, you might be able to use Process.CloseMainWindow instead.
I would first make my target application "aware" of the fact that some other process might like to trigger its closing or opening of a window or doing any action. This should be implemented similar to calling any method on another process through the target app's api or public methods. ..unless you are trying to do something with 3rd party applications, I think you shouldn't attempt to directly send them messages to close or shutdown.

FindWindow doesn't return IntPtr.Zero, although the window is already closed

I'm trying to control a Java application from my C# program. Before the program begins to input data, it checks if there are any pervious data input windows, and tries to close them.
The code for checking if a window exists is:
public static bool WindowExists(string WindowName)
{
IntPtr hWnd = FindWindow(null, WindowName);
return (hWnd != IntPtr.Zero);
}
Until now, I simply used this method in a while loop (sending Alt+F4 to the windows), until there was no open input window left.
A while ago the Java application got an update, and this method no longer works. For some reason, WindowExists keeps returning true, even after the data input window is closed. This only happens if the input window existed at least once.
I even tried to add Thread.Sleep() to the loop, to make sure this isn't caused by some latency in the Java app, but it didn't work.
Sometimes simply calling WindowExists crashes the input window.
There's no problem with the code, because it has worked before, and it still works with other programs, so it must be a problem with the update in the Java program.
Is there any alternative/more reliable way to check if a window exists?
Changing sending Alt+F4 to "close window event" might also worth a try, but I have no idea how to send this event to another program's window.
I'm a newbie, so please keep the answer simple.
Thanks in advance.
I would use Spy++ to watch the window handle of the Java app, and see if you can figure out what else is going on - I agree there has to be a way to tell that it is closed.
I assume watching the process list is out of the question...
I would hazard a guess that whilst the Java app is running and consequently, the JVM, the 'handle' to the window has not yet been garbaged collected and as such appears to the underlying pointer mechanism as still being valid.
If it was me writing that stuff (and if I was able to change the Java code) I'd probably add a means of querying the java app to see if its windows are showing.
A sockets interface or something.
My guess is that either the window hasn't been completely disposed of by the Java code/VM, or it's handling Alt+F4 in some special way (i.e. maybe making itself invisible rather than closing).
Creation/deletion of windows is out of your control. If you want to reliably detect the presence of 'someone else' using the same resource a you want, have that other party communicate it explicitly.
The other party may signal it's presence by creating a file, opening a port, whatever, and can release/delete/close it on it's exit.
Try to make additional check using IsWindow API, on hWnd value returned by FindWindow.

"Gracefully" killing a process

Right now I am using Process.Kill() to kill a process. Is there a way though, instead of just killing it immediately, that I can like send a message to the process instructing it to close so that it can gracefully clean up and shut down. Basically, I'm looking for the equivlent to just clicking the red X in the upper right hand corner, which I believe DOES send a message to the application requesting a shut down.
If the process has a windows interface (as you refer to the red "X"), you can try Process.CloseMainWindow(). If it fails, you can fallback to Process.Kill().
Killing can not be graceful, perhaps you can signal the process to commit suicide.
For signaling you have many options.
SendMessage
NamedPipes
Named Mutex
Sockets
It would depend on the process you're killing. As stated at on the relevant page for Process.Kill, "Kill is the only way to terminate processes that do not have graphical interfaces." If there is a graphical window, then go with the answer by lc above; Process.CloseMainWindow functions as the red X you referred to.

Prevent Process 'A' from spawning Process 'B' which then shows up on top of what should be the "TopMost" Process 'C'

I have a windows form application which needs to be the TopMost. I've set my form to be the TopMost and my application works as I'd like it to except for in one case.
There is a 3rd party application (referred to as player.exe) that displays SWF movie files on a portion of the screen that popup on top of my application.
Using Process Monitor I determined that player.exe application calls
flash.exe <PositionX> <PositionY> <Width> <Height> <MovieFile>
in my case:
flash.exe 901 96 379 261 somemovie.swf
Since flash.exe is being spawned in a new process after my form has been set to the TopMost it is appearing on top of my application.
First thing I did was make my application minimize the player.exe main application window hoping that this would prevent the Flash from appearing also. But, unfortunately it doesn't... even with the window minimized whenever the flash movie starts it shows up at the pixel location (901,96). I then tried creating a timer to keep setting the form.TopMost property to true every 10ms. This sort of works but you still see a very quick blip of the swf file.
Is there some type of Windows API call which can be used to temporarily prevent player.exe from spawning child processes which are visible? I admit it sounds a little far fetched. But, curious if anyone else has had a similar problem.
Addendum:
This addendum is to provide a reply to some of the suggestions layed out in Mathew's post below.
For the emergency situation described in the comments, I would look at possible solutions along these lines:
1) How does the third party application normally get started and
stopped? Am I permitted to close it
the same way? If it is a service, the
Service Control Manager can stop it.
If it is a regular application,
sending an escape keystroke (with
SendInput() perhaps) or WM_CLOSE
message to its main window may work.
Easiest way to close the app is to CTRL-ALT-DEL, then kill process. -OR-
The proper way is to Hold ESC while clicking the left mouse button... then input your username and password, navigate some menu's to stop the player.
There is no PAUSE command... believe it or not.
I don't think using WM_CLOSE will help since minimizing the application doesn't. Would that kill the process also? If not, how do you reopen it.
2) If I can't close it nicely, am I permitted to kill it? If so,
TerminateProcess() should work.
I can't kill the process for two reasons. 1) Upon relaunch you need to supply username/password credentials... There may be a way to get around this since it doesn't prompt when the machine is rebooted but... 2) Whenever I kill the process in task manager it doesn't die gracefully and asks if you want to send an error report.
3) If I absolutely have to leave the other process running, I would try
to see if I can programmatically
invoke fast user switching to take me
to a different session (in which there
will be no competing topmost windows).
I don't know where in the API to start
with this one. (Peter Ruderman
suggests SwitchDesktop() for this
purpose in his answer.)
I got really excited by this idea... I found this article on CodeProject which provides a lot of the API Wrapper methods. I stopped implementing it because I think that in order for desktop's to work you must have explorer.exe running (which I do not).
EDIT2: On second thought... maybe explorer.exe isn't needed. I'll give it a try and report back.
Edit3: Was unable to get the code in that article working. Will have to put this on hold for a moment.
Answer Summary
As one might have expected, there is no simple answer to this problem. The best solution would be to problematically switch to a different desktop when you need to guarantee nothing will appear over it. I was unable to find a simple C# implementation of desktop switching that worked and I had a looming doubt that I would just be opening a whole new set of worms once it was implemented. Therefore, I decided not to implement the desktop switching. I did find a C++ Implementation that works well. Please post working C# virtual desktop implementations for others.
Setting the TopMost property (or adding the WS_EX_TOPMOST style to a window) does not make it unique in the system. Any number of topmost windows may be created by any number of applications; the only guarantee is that all topmost windows will be drawn 'above' all non-topmost windows. If there are two or more topmost windows, the Z-order still applies. From your description, I suspect that flash.exe is also creating a topmost window.
Aside from periodically forcing your window to the top of the Z-order, I think there is little you can do. Be warned, however, that this approach is dangerous: if two or more windows are simultaneously trying to force themselves to the top of the Z-order, the result will be a flickering mess that the user will likely have to use the task manager to escape.
I recommend that your program not attempt to meddle with other processes on the computer (unless that is its explicit purpose, e.g. a task manager clone). The computer belongs to the user, and he may not value your program more highly than all others.
Addendum:
For the emergency situation described in the comments, I would look at possible solutions along these lines:
How does the third party application normally get started and stopped? Am I permitted to close it the same way? If it is a service, the Service Control Manager can stop it. If it is a regular application, sending an escape keystroke (with SendInput() perhaps) or WM_CLOSE message to its main window may work.
If I can't close it nicely, am I permitted to kill it? If so, TerminateProcess() should work.
If I absolutely have to leave the other process running, I would try to see if I can programmatically invoke fast user switching to take me to a different session (in which there will be no competing topmost windows). I don't know where in the API to start with this one. (Peter Ruderman suggests SwitchDesktop() for this purpose in his answer.)
You can use the Process class to start flash.exe directly - and use an appropriate ProcessStartInfo settings to show the window in a hidden state - or with a WindowStyle of hidden or minimized.
You could also consider using the SetWindowsHookEx API to intercept the process start API calls, and when the process is flash.exe run some code to restore you window to top-most status.
Matthew's answer is excellent, but I suspect you may be asking the wrong question. Why does your application need to be topmost? If you're trying to create a kiosk or some such, then topmost is not the way to go.
Edit: After reading your response to Matthew's comment, I'd suggest creating a new desktop and switching to it before displaying your alert. (See CreateDesktop and SwitchDesktop in MSDN.)

Categories

Resources