【问题标题】:Closing a minimized/iconized process from C#从 C# 关闭最小化/图标化进程
【发布时间】:2008-09-21 05:40:50
【问题描述】:

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

【问题讨论】:

    标签: c# winapi process kill


    【解决方案1】:

    这应该可行:

    [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 位。

    【讨论】:

      【解决方案2】:

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

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

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

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

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

      【讨论】:

        【解决方案3】:

        以下是一些答案和说明:

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

        罗杰: 是的,我的意思是任务栏通知区域 - 感谢您的澄清。 我需要调用 PostQuitMessage。我只是不知道如何,只给定一个进程,而不是一个窗口。

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

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

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

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

        【讨论】:

        • 我知道这个问题已经有六年多了,但是你有没有找到 C# 的解决方案?我最终使用了一种名为 AutoIt 的脚本语言,它有一个不会“杀死”它的 ProcessClose 函数,但没有用 C# 将其关闭。
        • 不,@kayleeFrye_onDeck,我好几年没碰过这个了 :)
        • 好的!感谢您回答这位密码考古学家! :P 我自己现在正在研究一个解决方案,用于关闭进程的常量 exe 名称。我会告诉你,如果我罢工了!
        • kayleeFrye_onDeck
        【解决方案4】:

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

        【讨论】:

        • 这不是答案。这应该是问题下的评论。
        • 注明。谢谢你的建议。虽然也许在 2008 年,当我问没有这样的事情时。 /耸肩
        • 没有答案和问题从未混为一谈,即使在 2008 年也是如此。
        • 好的。再次感谢。
        猜你喜欢
        • 2013-04-17
        • 2013-10-10
        • 1970-01-01
        • 2021-12-31
        • 2014-03-30
        • 1970-01-01
        • 2012-07-16
        • 1970-01-01
        • 2016-03-04
        相关资源
        最近更新 更多