这是我的问题:我需要从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 子句。删除如果没有帮助。 CloseMainWindow()关闭()都不起作用。 Kill()可以,但如上所述 - 这不是我需要的。

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

有帮助吗?

解决方案 3

以下是一些答案和说明:

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

<强>罗杰: 是的,我确实是指任务栏通知区域 - 感谢您的澄清。 我需要来调用PostQuitMessage。我只是不知道如何处理,而不是一个窗口。

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

现在我的用户想要编写应用程序的脚本/批处理。他们从一个批处理开始它是完全没有问题的(只需指定exe名称和一堆标志)但是后来遇到了正在运行的进程。假设没有人会改变流程以提供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 - &gt;主菜单中的进程。这将显示一个进程树。从那里,您可以深入到线程,然后到窗口。这将告诉您进程具有哪些窗口。记下窗口类和标题。有了这些,您可以使用FindWindow(或EnumWindows)来查找将来的窗口句柄。

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

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

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

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top