如何从 C# 控制台应用程序关闭在系统托盘中运行的 WPF 应用程序?

问题描述:

我正在开发一个包含两部分的应用程序:

I'm developing an application which has 2 parts:

1) 从系统托盘运行的 WPF 应用程序.它确实有一个 GUI 窗口,可以通过右键单击系统托盘图标 & 来打开它.在上下文菜单上选择一个选项,但并不经常需要它&该应用程序将在大部分时间从系统托盘运行.此外,我更改了 MainWindow 的 Closing() 事件,以便在用户尝试关闭应用程序时将其最小化.

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) 一个控制台应用程序,它在不显示控制台的情况下运行它的目的是轮询另一个应用程序的启动/关闭.一旦启动/关闭其他应用程序,控制台应用程序也会启动/关闭 WPF 应用程序.(请不要告诉我使用 Windows 服务来执行此操作.我之前已经探索过该路线.由于多种原因,它对我不起作用,我不会在这里招募).

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).

问题:我无法从控制台应用程序关闭 WPF 应用程序.我正在做的事情如下.首先,我获取 WPF 应用程序的进程:

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) 杀死进程:AppProcess.Kill();

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

这是唯一有效的方法,但非常不雅观.它还使 SysTray 图标未处理,因此是不可接受的.

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();

2) AppProcess.Close();

根本不起作用&我不知道为什么.

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

3) AppProcess.Dispose();

3) AppProcess.Dispose();

根本不起作用&我不知道为什么.

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

4) AppProcess.CloseMainWindow();

4) AppProcess.CloseMainWindow();

这仅在用户保持 WPF 应用程序的 GUI 处于打开状态时才有效,正如我之前提到的,这种情况很少发生.所以,通常这也不起作用.(你可能会说我已经破解了 Closing() 事件来阻止关闭窗口.别担心,我已经采取了适当的措施来处理这个问题.我已经提供了其他措施来关闭应用程序.有一个布尔变量决定是否取消关闭操作.)

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) 将自定义/标准消息传递到 WPF 应用程序的主窗口.

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

这也仅在 WPF 应用程序的主窗口 (GUI) 打开时才有效,否则它不会收到消息.

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

所以,总而言之,没有任何方法有效.我需要一种可靠的方法来从控制台应用程序优雅地关闭 WPF 应用程序.请提出建议.

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.

我目前的做法如下:

在控制台应用中:

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

在 WPF 应用中:

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;
}

好的,我找到了关闭 WPF 应用程序的方法.它没有收到消息的原因是由于某种原因,当 WPF 应用程序从系统托盘运行时,AppProcess.MainWindowHandle 没有提供 WPF 应用程序的主窗口的句柄.

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.

因此,我使用 Win32 API 中的 user32.dll:FindWindow() 方法来查找 WPF 应用程序的主窗口.之后,当我将自定义消息传递给它时,WPF 应用程序会正常关闭.

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.