从C#关闭最小化/图标化过程

这是我的问题:我需要从C#程序关闭已经运行的进程。 问题是该进程现在作为一个图标运行(最小化到任务栏),除非用户至少打开一次(在无人值守的机器上永远不会发生),它将永远不会有一个主窗口。

我的另一个要求是应用程序关闭而不是被杀死 。 我需要它将它的内存缓冲区写入磁盘 – 并且杀死它会导致数据丢失。

这是我到目前为止所尝试的:

foreach (Process proc in Process.GetProcesses()) { if (proc.ProcessName.ToLower().StartsWith("myapp")) { if (proc.MainWindowHandle.ToInt32() != 0) { proc.CloseMainWindow(); proc.Close(); //proc.Kill(); <--- not good! } } } 

在窗口最小化后发现MainWindowHandle == 0之后,我添加了if子句。 删除if无济于事。 CloseMainWindow()Close()都不起作用。 杀戮()确实如此,但如上所述 – 这不是我需要的。

任何想法都会被接受,包括使用神秘的Win32 API函数:)

这应该工作:

 [DllImport("user32.dll", CharSet=CharSet.Auto)] private static extern IntPtr FindWindow(string className, string windowName); [DllImport("user32.dll", CharSet=CharSet.Auto)] private static extern IntPtr SendMessage(IntPtr hWnd, int msg, IntPtr wParam, IntPtr lParam); private const int WM_CLOSE = 0x10; private const int WM_QUIT = 0x12; public void SearchAndDestroy(string windowName) { IntPtr hWnd = FindWindow(null, windowName); if (hWnd == IntPtr.Zero) throw new Exception("Couldn't find window!"); SendMessage(hWnd, WM_CLOSE, IntPtr.Zero, IntPtr.Zero); } 

由于某些窗口不响应WM_CLOSE ,因此可能必须发送WM_QUIT 。 这些声明应该适用于32位和64位。

如果它在任务栏上,它将有一个窗口。 或者你的意思是它在任务栏通知区域(又称SysTray)? 在这种情况下,它仍然会有一个窗口。

Win32应用程序实际上没有“主窗口”,除了约定(主窗口是响应WM_DESTROY调用PostQuitMessage的窗口,导致消息循环退出)。

程序运行后,运行Spy ++。 要查找进程拥有的所有窗口,您应该从主菜单中选择Spy – > Processes。 这将显示一个进程树。 从那里,您可以深入到线程,然后到窗口。 这将告诉您进程具有哪些窗口。 记下窗口类和标题。 有了这些,您可以使用FindWindow(或EnumWindows)来查找将来的窗口句柄。

使用窗口句柄,您可以发送WM_CLOSE或WM_SYSCOMMAND / SC_CLOSE(相当于单击窗口标题上的“X”)消息。 这应该导致程序很好地关闭。

请注意,我在这里谈论Win32的观点。 您可能需要使用P / Invoke或其他技巧才能从.NET程序中使用它。

以下是一些答案和说明:

rpetrich :之前尝试过你的方法问题是,我不知道窗口名称,它因用户而 ,版本与版本不同 – 只是exe名称保持不变。 我所拥有的只是流程名称。 正如您在上面的代码中看到的那样,进程的MainWindowHandle为0。

罗杰 :是的,我确实是指任务栏通知区域 – 感谢您的澄清。 我需要调用PostQuitMessage。 我只是不知道如何,只给出一个进程,而不是一个Window。

Craig :我很乐意解释这种情况:应用程序有一个命令行界面,允许您指定参数来决定它将做什么以及它将保存结果的位置。 但是一旦它运行,停止它并获得结果的唯一方法是在托盘通知中右击它并选择“退出”。

现在我的用户想要编写应用程序的脚本/批处理。 从批处理开始它们完全没有问题(只需指定exe名称和一堆标志)但是后来遇到了正在运行的进程。 假设没有人会改变流程以提供API来在运行时停止它(它已经很老了),我需要一种人工关闭它的方法。

同样,在无人值守的计算机上,启动进程的脚本可以由任务调度或操作控制程序启动,但是没有办法关闭进程。

希望澄清我的情况,再次感谢所有想要帮助的人!

问题澄清你为什么尝试这个:如果进程中唯一的用户界面是系统托盘图标,为什么要杀死它,但让流程继续运行? 用户如何访问该流程? 如果机器“无人看管”,为什么要关注托盘图标呢?