向没有窗口的进程发送WM_CLOSE消息

5

启动一个进程 -

 ProcessStartInfo psi = new ProcessStartInfo("G:\\SampleWinApp.exe");            
 psi.UseShellExecute = false;
 psi.CreateNoWindow = true;            
 Process prcs = Process.Start(psi);

使用PostMessage发送WM_CLOSE

的指令。

const int WM_CLOSE = 0x0010;

public void SendCloseSignal(Process proc)
{
    uint uiPid = (uint) proc.Id;
    bool bResult = EnumWindows(new WNDENUMPROC(EnumWindowsProc), uiPid);
    if (!bResult && Marshal.GetLastWin32Error() == 0) {
        object objWnd = processWnd[uiPid];
        if (objWnd != null) {
            IntPtr ptrWnd = (IntPtr) objWnd;
            PostMessage(ptrWnd, WM_CLOSE, 0, 0);
            return;
        }
    }

    foreach (ProcessThread thread in proc.Threads) {
        PostThreadMessage((uint) thread.Id, WM_CLOSE, UIntPtr.Zero, IntPtr.Zero);
    }

}

private static bool EnumWindowsProc(IntPtr hwnd, uint lParam)
{
    uint uiPid = 0;
    if (GetParent(hwnd) == IntPtr.Zero)
    {
        GetWindowThreadProcessId(hwnd, ref uiPid);
        if (uiPid == lParam)
        {
            processWnd[uiPid] = hwnd;
            return false;
        }
    }
    return true;
} 

使用 CreateNoWindow = false 启动exe时,会发送WM_CLOSE消息并优雅地关闭应用程序。但是,当使用 CreateNoWindow = true 时,WM_CLOSE消息永远不会到达进程。即使PostThreadMessage也似乎无效。有没有办法发送WM_CLOSE消息?我已经搜索了一整天,但没有任何进展。

编辑:每个应用程序都安装了一个Windows服务。启动/停止服务会启动/停止应用程序。目前我们在服务停止时强制终止应用程序。由于这是一种暴力结束方式,应用程序无法正常关闭。其中一些应用程序监听 CTRL信号。现在,我只需要找到一种向这些应用程序发送WM_CLOSE消息的方法。

编辑2:如果存在窗口,则WM_CLOSE触发CTRL_CLOSE_EVENT。但是,当使用CreateNoWindow = true启动任何进程时,这从未触发。


@SriramSakthivel:抱歉,打错字了。已经修改了。 - A G
@500-服务器内部错误:有什么解决方法吗? - A G
@AseemGautam 你可以把它Kill掉(残忍地)。 - Sriram Sakthivel
1
你可以向一个没有窗口、没有消息泵、没有窗口过程和默认窗口过程的进程发送WM_CLOSE消息,但它永远不会起作用。如果你想要其他关闭方法,请继续阅读。如果不需要,我们就完成了。 - david.pfx
显示剩余4条评论
1个回答

5
有没有办法发送WM_CLOSE消息?
WM_CLOSE是发送给窗口的。如果进程中没有窗口,则没有任何东西来处理该消息。如果您希望关闭没有窗口的进程,则发送WM_CLOSE不是解决方案。
看起来你只是想杀死进程。当控制台进程具有关联的窗口时,您正在使用WM_CLOSE消息触发CTRL_CLOSE_EVENT信号。
由于CTRL_CLOSE_EVENT已经是一种相当粗暴的杀死进程的方式,因此在我看来,您完全可以简单地将其杀死。您已经拥有一个Process对象。只需使用Process.Kill()杀死它即可。
另一方面,也许您真正想问的问题是:
如何在另一个进程中发出CTRL_CLOSE_EVENT信号?
相关问题可以在这里找到:Can I send a ctrl-C (SIGINT) to an application on Windows? 在我看来,那里最好的答案不是被接受的答案,而是Nemo1024的答案。该答案链接到他的博客文章:http://stanislavs.org/stopping-command-line-applications-programatically-with-ctrl-c-events-from-net/ 据我所知,该文章应该为您提供解决问题所需的信息。它列出了四种情况。前两种涉及使用WM_CLOSE作为触发关闭信号的手段。第三种是杀死进程。第四个可能是您要寻找的。当然,这第四个选项最复杂。引用文章中的内容:
在此线程底部找到提示后,我终于开始了没有窗口的进程。当停止进程的时间到来时,父级将其控制台附加到子级,停止自己监听Ctrl-C事件并向控制台发出事件,以使附加的子级终止。然后它为自己恢复Ctrl-C处理程序并释放控制台。

1
那么如果这不是解决方案,那是什么? - Gabe
1
@Gabe,有什么问题吗? - David Heffernan
David,不要太严格了。从问题中可以看出OP正在苦苦挣扎“如何关闭一个窗口……”。你解释了为什么它不起作用,如果你能说一下OP手头有哪些选择会更好。1)Kill是一种残酷的可选项。 - Sriram Sakthivel
1
@SriramSakthivel 可能吧。但我倾向于回答被问到的问题。我不想猜测实际问题是什么。提问者没有说明潜在的问题。我不太自信去猜测它是什么。 - David Heffernan
1
听起来你想问的问题是:“我怎样向另一个进程发送 CTRL_CLOSE_EVENT 信号?” - David Heffernan
显示剩余4条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接