I want to properly close any application (not kill) running in system tray. I have tried SendKeys() but it fails. Sending Alt+F4, Alt+F then x all fail because tray applications have no main window. Any idea how to do that? the objective to to properly exit an application that performs some inner tasks upon exiting, running in system tray without terminating, just like when its titlebar exit button is clicked.
There is no simple answer to this. Each and every application has its own way of controlling life time. You can even write Forms application that does not respond to [Alt F4] to shut it down.
The only way you can an arbitrary process of which you know nothing (other than that it has put an icon into the system tray), is to terminate the process. And that, as Gian Paolo pointed out, is just not cricket.
From what you have written on the comments on the other answers, it sounds like you merely want to close a specific app. You can do this with the taskkill utility.
Related
I have installed a program ("CmisSync.exe") that runs as a small icon in the Windows system tray.
From C# I want to start it, and then exit it gracefully (as if a user had clicked "Exit" in the program's menu). Here is my attempt:
Process process = Process.Start(#"C:\Programs\CmisSync\CmisSync.exe");
// Wait for CmisSync's configuration/UI to start properly.
Thread.Sleep(5000);
// Close as if the user had clicked "Exit".
process.CloseMainWindow();
// Wait for CmisSync to finish what it is doing and exit normally.
// This might take a few minutes if a big sync is going on.
process.WaitForExit();
Unfortunately, CloseMainWindow does not make the program stop.
Maybe it is due to the program not actually have a main window? It only runs in the tray.
Close does not make the program stop either, by design.
Kill is not graceful, it does not let the program finish its current UI loop. Unlike the UNIX equivalent, the command does not seem to accept arguments indicating how brutal the kill should be.
The tray icon is implemented using System.Windows.Forms.Form
Yes, as you have discovered Process.CloseMainWindow only closes a program with a main window i.e you will most likely find the MainWindowHandle will be IntPtr.Zero
Process.CloseMainWindow Method ()
Closes a process that has a user interface by sending a close
message to its main window
Additionally, AFAIK WM_CLOSE or any other message wont help you either
However, you could create a message only window, or have your mainwindow set to invisible so you could message it in standard ways or call Process.CloseMainWindow.
However there are also many other IPC techniques you could use to the same affect, or even WCF. Anyway, since you're in control of the sync tray icon program, you can employ anything really (well except techniques that require a window evidently)
Interprocess Communications
Update
Since its open source, you can either edit as desired or have a look at the internals of it and you might find a way to gracefully close it.
I've written a WPF/C#-based "shell" which launches WPF apps or other apps.
What would be the best method for checking if the process is finally fully launched or no longer "busy"? I've noticed that the mouse cursor for the launched process stays at the busy cursor from initial launch until I can finally see the UI for the process. Could I use User32.SetCapture API to set the mouse capture to the external process, then somehow check if the mouse cursor is the busy cursor? Or perhaps there's a mechanism in the System.Diagnostics.Process class that I'm unaware of?
As some of the launched apps are pre-compiled third-party apps, I absolutely cannot implement a mechanism in the external processes to message if it is finally ready, such as: Microsoft PowerPoint 2010 Viewer, Adobe Acrobat, or Adobe Flash Player Standalone.
I can't just check if the process has been created, because then I have a blank, unresponding window and a busy cursor. I hope to hide my WPF app the moment the external process is done launching.
The WaitForInputIdle Win32 APi function will wait until given process enters the message loop (with no input pending).
Quote: "Before trying to communicate with the child process, the parent process can use the WaitForInputIdle function to determine when the child's initialization has been completed."
You can call it via P/Invoke.
Not very cear what do you mean saying "beasy", but hear are several considerations:
There is no known (clear) way, at least that I'm aware of, that can let you do something like that. The thing is that process is perfectly isolated OS kernel citizen. So you can not write something that works for all type processes, especially if they are 3rd part binaries.
What you can try to do, is get the MainWindow of the process (if there is any), get its handle, and filter OS messages untill you get for example WM_ACTIVATED.
But even if this could work in certain situations, in others can measurably fail. For example, process loaded but the program is not active, cause for some reason License window of the application appeared.
Let's see what others suggest, in my opinion, there is no generic and no single solution to cover minority of possible cases.
Good luck
I'm starting a external application with System.Diagnostics.Process, this external process at one moment opens up a dialog where user has type something and then click OK. What i need is to wait with my application(the one where i started the external process) until the user has inserted something and clicked OK. After that OK i have to do some more task on that external process and then close it.
Yes, it's possible. There are a number of ways to get window information starting with a process handle and/or ID. See this question and responses for getting started. You will most likely end up using P/Invoke to the Win32 API to get this accomplished but there are dozens of good examples for getting this done.
Once you have the window handle you can use a timer polling scheme to test for the presence, or in your case, presence and then the disappearance of a window.
This is possible but there are some work behind it. First you need to run your code as unmanaged code as you will need to hook on Windows OS events with the Win32 API.
So an option would be to have a loop looking for the dialog to open, pause what ever your code are doing and continue when the dialog are gone.
If the application you are starting exists after the user interacts with the dialog, then you can just call Process.WaitFroExit() and your code will not continue until the process you started has quit.
There are quite a few helpful functions for interacting with processes in the System.Diagnostics.Process class (that I assume you are using to start this external application)
I doubt this is even possible. So your app is running and user decides to End Process via Task Manager. Is there a method/action to save data during process.kill? I doubt there is but I had to ask.
Also, if a user shuts down/restarts PC (as in windows update/manual restart), what action would the app execute? Window_Unloaded? On this second question, I would like to find a way to ensure my app does not show up as a 'if you want to restart, kill this app' situation and want to save needed data.
Your two cents is greatly appreciated!
It's not possible to do what you want unless you have two processes; one monitoring the other one's status and do some stuff upon its termination. The watchdog process might be a Windows Service Application without GUI.
Windows sends a quit message to every opened application when normal shutdown occurs. You can run some code (usually housekeeping stuff) upon receiving the message and exit the application. It shouldn't take long or Windows will automatically ask user if they want to kill the application.
Force shutdown kills all processes immediately (in no particular/predictable order). So you can't (easily) detect it.
I suggest you to save everything needed as soon as possible to prevent data loss when the application process gets killed.
If something terminates your running app, then you don't get an opportunity to do anything, just die. You modify your app such that all data is always saved to some persistent location, so if the app dies, the persisted data remains. Obviously you have to design for this. Then if the user does a "save", you commit to the "real" datastore.
If Windows is going to reboot, it should send a message to your app, which you can handle. Not sure if this works for all GUI/console/service -type apps however.
What is the best and cleanest way to close a console application on windows mobile?
The application by default is invisible and you cannot see it in the running programs, which is great for running a background process, but sometimes the user might need to close it..
Exit Main. Seriously. If you need someone to be able to exit is manually, there needs to be some mechanism like a shell icon and menu or a program in the Programs folder of something. How else would the user even know it's running? Any one of those visual cues would then set a named system event, and inside your Console app you'd have something listening for the same event (likely a worker). When it gets set, you take the actions required to shut down.
How would a user be able to close it if the application is not visible in the UI?
That's a great question. I once spent a long time trying to figure this out. Of course, we are assuming you can not (easily) return from Main. The correct answer on the desktop is System.Environment.Exit; But that method is conveniently not supported on CF.
An apparent second option is Application.Exit. That is on CF, but only applies to WinForms, and is in fact not guaranteed to exit your application.
So, throw an unhandled exception. ;)
EDIT: To kill it programatically from another app, you can look at Process.GetProcessById, and Process.Kill. Both of these are available on CF. You will have to somehow let the "killer" app figure out the "victim"'s ID. More convenient methods like Process.GetProcessesByName are not available on CF.
This technique isn't that elegant, though, and there may be permissions issues.
You could also consider some kind of IPC (inter-process communication), perhaps one overviewed in this previous Windows Mobile answer.
I decided to to read a boolean (keep alive) in the config file and have another application set it to false when I want to exit.
Its not that responsive but at least I can exit cleanly..