从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()都不起作用。 Kill()可以,但是如上所述,这不是我所需要的。
任何想法都可以接受,包括使用奥术Win32 API函数:)
解决方案
如果它在任务栏上,它将有一个窗口。还是我们是说它在任务栏通知区域(即SysTray)中?在这种情况下,它仍然会有一个窗口。
除了约定外,Win32应用程序实际上没有"主窗口"(主窗口是调用PostQuitMessage以响应WM_DESTROY,从而导致消息循环退出的窗口)。
在程序运行的情况下,运行Spy ++。要查找某个进程拥有的所有窗口,应从主菜单中选择Spy-> Processes。这将显示进程树。从那里,我们可以深入到线程,然后深入到Windows。这将告诉我们该进程具有哪些窗口。记下窗口类和标题。有了这些,以后就可以使用FindWindow(或者EnumWindows)查找窗口句柄。
使用窗口句柄,我们可以发送WM_CLOSE或者WM_SYSCOMMAND / SC_CLOSE(相当于单击窗口标题上的" X")消息。这应该导致程序正常关闭。
请注意,我是从Win32的角度讲的。我们可能需要使用P / Invoke或者其他技巧才能使它在.NET程序中正常工作。
这应该工作:
[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位。
问题以阐明我们为什么要尝试此操作:如果进程上唯一的用户界面是系统任务栏图标,那么为什么要取消该进程并让进程继续运行?用户将如何访问该过程?如果机器是"无人值守"的,为什么还要关心纸盘图标呢?
以下是一些答案和说明:
佩特里奇:
以前尝试过方法,问题是,我不知道窗口名,它因用户而异,版本不同,只是exe名称保持不变。我只有进程名称。正如我们在上面的代码中看到的,该进程的MainWindowHandle为0。
罗杰:
是的,我确实是指任务栏通知区域,感谢澄清。
我需要致电PostQuitMessage。我只是不知道怎么做,仅给出一个过程,而不是一个窗口。
克雷格:
我很高兴解释这种情况:该应用程序具有命令行界面,允许我们指定指示其作用以及将结果保存在何处的参数。但是一旦运行,停止它并获得结果的唯一方法是在托盘通知中右键单击它,然后选择"退出"。
现在,我的用户想要编写脚本/批处理该应用程序。他们从批处理开始完全没有问题(只需指定exe名称和一堆标志),但随后就陷入了正在运行的进程。假设没有人会更改提供API以便在运行时停止它的过程(它已经很旧了),我需要一种人为地关闭它的方法。
同样,在无人值守的计算机上,可以通过任务计划或者操作控制程序来启动用于启动进程的脚本,但是无法关闭进程。
希望这可以澄清我的处境,并再次感谢所有尝试提供帮助的人!