3

这是我的问题:我需要从 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 函数 :)

4

4 回答 4

2

这应该有效:

[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_CLOSEWM_QUIT可能必须改为发送。这些声明应该适用于 32 位和 64 位。

于 2008-09-21T06:43:46.350 回答
1

如果它在任务栏上,它将有一个窗口。还是您的意思是它位于任务栏通知区域(又名 SysTray)中?在这种情况下,它仍然会有一个窗口。

Win32 应用程序并没有真正的“主窗口”,除非按照惯例(主窗口是调用 PostQuitMessage 以响应 WM_DESTROY,从而导致消息循环退出的窗口)。

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

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

请注意,我在这里是从 Win32 的角度讨论的。您可能需要使用 P/Invoke 或其他技巧来使其在 .NET 程序中工作。

于 2008-09-21T06:33:30.867 回答
0

以下是一些答案和说明:

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

Roger:是的,我的意思是任务栏通知区域——感谢您的澄清。我需要打电话给 PostQuitMessage。我只是不知道如何,只给定一个进程,而不是一个窗口。

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

现在我的用户想要编写/批处理应用程序。他们从批处理开始绝对没有问题(只需指定 exe 名称和一堆标志),但随后被一个正在运行的进程卡住了。假设没有人会更改进程以提供 API 以在运行时停止它(它已经很老了),我需要一种人为地关闭它的方法。

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

希望能澄清我的情况,再次感谢所有试图提供帮助的人!

于 2008-09-21T15:53:48.913 回答
-1

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

于 2008-09-21T14:06:57.297 回答