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.
Related
I want to watch a process (in another application) that might fail and relaunch it if it fail. It's working if the process is exited. But if the window that say the programe not seem to respond terminate now or wait is open.
My process is dead but as long as i don't click on close program i don't get any information about this.
My process are on multiple VM it's a process that update my client application and i try to not force my support to connect in every client to click on Close program every time a little bug happend.
Is their any event that can tell me window ask to close this process?
Is their a way to achive this? Right know I'm thinking about making a ping with my process using some message. But i would like a solution that don't involve modify both app and only the watcher app. Plus i'm not sure if a process is in "Close now" State have all thread stop or if my read message thread will continu to respond while my main thread will be dead.
I want to close another program that does not have a main window.
It runs in background.
So process.CloseMainWindow() will not work,
And using process.kill() will lose some data.
Is there a graceful way to close this kind of program without losing data for example by means of SendMessage or something else?
It's just a small program puts a tray icon in task bar not a windows service
In that case it must have a message pump and so you can post a Windows WM_QUIT message to the process. When the target process processes it message pump and encounters this message, it will gracefully quit. Alternatively, you may post WM_CLOSE but then you need to know which window (it still works if the window is invisible).
I have tried solving this, but the only solution was to make a window that is visible to the user (even making it 0x0 still makes it visible in the Alt-Tab switcher).
When I mean hidden, I want it hidden from Alt-Tab, Win-Tab, Ctrl-Tab, the Taskbar, and the "Apps" section of Task Manager.
Any workaround? I only need to detect an unexpected stop from Task Manager, but I need a window to receive events from SetWinEventHook().
Kind of a catch-22. You need a window to receive WinEvents. You could create a message-only window for that, which is hidden from the system.
But, hiding a window from the system also means hiding it from Task Manager. If Task Manager doesn't see a visible window (doesn't show it in "Apps"), it will not try to close the window gracefully, it will just kill the process abortively, and there is no signal sent to the process when that happens.
To get a graceful close, you can't hide the window from the system, but then you have to accept the other side effects that go along with it.
The only option I can think of in this situation is to create a separate process that monitors your main process. If the main process disappears unexpectedly, the watcher process can react accordingly. You could make the watcher be a service so non-admin users can't kill it in Task Manager.
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.
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