How to close a WPF application running in system t

2019-09-12 09:19发布

问题:

I'm developing an application which has 2 parts:

1) A WPF application which runs from the system tray. It does have a GUI window, which can be brought up by right-clicking the sys-tray icon & choosing an option on the context menu, but it is not needed very frequently & the app will run from the sys-tray most of the time. Moreover, I've changed the Closing() event of the MainWindow, so as to minimize the app, if the user tries to close it.

2) A console application which runs without displaying a console & its purpose is to poll for launch/close of another application. As soon as the other application is launched/closed, the console application launches/closes the WPF application too. (Please don't tell me to do this using a Windows Service. I've already explored the route before. It doesn't work for me due to several reasons, which I won't enlist here).

PROBLEM: I am not able to close the WPF application from the console application. What I'm doing is as follows. First I obtain the process for my WPF application:

Process AppProcess = Process.GetProcessById((int)AppID);

After this I've tried a lot of options as follows:

1) Killing the process: AppProcess.Kill();

This is the only one which worked, but is very unelegant. It also leaves the SysTray icon undisposed, so it is not acceptable.

2) AppProcess.Close();

Doesn't work at all & I don't know why.

3) AppProcess.Dispose();

Doesn't work at all & I don't know why.

4) AppProcess.CloseMainWindow();

This only works if the user has kept the GUI of the WPF app opened, which is very rarely the case as I mentioned before. So, normally this also doesn't work. (You might say that I've hacked the Closing() event to prevent closing the window. Don't worry I've taken appropriate care to handle that. I've provided other measures to close the app. There is a boolean variable which decides whether the Closing action is to be cancelled or not.)

5) Passing custom/standard message to the WPF Application's main window.

This also works only if the main window (GUI) of the WPF app is open, else it doesn't receive the message.

So, all in all, no method is working. I need a reliable method to close the WPF app gracefully from the console app. Please suggest something.

The current way I'm doing it is as follows:

In the Console App:

const uint WM_CUSTOMCLOSE = 0xFE;
IntPtr hWnd = AppProcess.MainWindowHandle;
SendMessage(hWnd, WM_CUSTOMCLOSE, 0, 0);

In the WPF app:

protected override void OnSourceInitialized(EventArgs e)
{
base.OnSourceInitialized(e);
HwndSource source = PresentationSource.FromVisual(this) as HwndSource;
source.AddHook(WndProc);
}

private IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
{
    if(msg == 0xFE)
    {
        ExitFlag = true;  //Exitflag is checked later to decide whether closing is to be cancelled.
        this.Close();
    }
    return IntPtr.Zero;
}

回答1:

Use IPC as JeffRSon suggested. MSMQ is a very easy and effective way when two processes are on the same machine.

Define a queue of your WPF application and when it starts, no matter showing UI or not, let it listen the queue. Console application can send a message to the queue with closing application message. You have to define the data contract. You can refer to:

http://www.codeproject.com/Articles/3944/Programming-MSMQ-in-NET-Part-1



回答2:

Ok, I found a way to close the WPF app. The reason it wasn't receiving the message was that for some reason, AppProcess.MainWindowHandle was not giving the handle of the main window of the WPF app, when the WPF app ran from the system tray.

So, instead I'm using the user32.dll:FindWindow() method found in the Win32 APIs to find the main window of the WPF app. After that when I pass my custom message to it, the WPF app shuts down gracefully.