【问题标题】:Send WM_CLOSE message to a process with no window向没有窗口的进程发送 WM_CLOSE 消息
【发布时间】:2014-04-21 12:41:44
【问题描述】:

开始一个进程 -

 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 signals。现在,我只需要某种方式将 WM_CLOSE 消息发送到这些应用程序。

Edit2:如果有窗口,WM_CLOSE 会触发CTRL_CLOSE_EVENT。但是当任何进程以 CreateNoWindow = true 启动时,这永远不会触发。

【问题讨论】:

  • 好吧,您不能将消息发布到不存在的窗口句柄。
  • @SriramSakthivel:对不起,错字。现已编辑。
  • @500-InternalServerError:任何解决方法?
  • @AseemGautam 你可以杀死它。
  • 您可以将 WM_CLOSE 发送到没有窗口的进程,但它永远不会做任何事情,因为它没有消息泵、没有 windowproc 和 defwinproc。如果您想要其他方法来关闭事物,请继续阅读。如果没有,我们就完成了。

标签: c# windows winapi


【解决方案1】:

有什么方法可以发送 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 处理程序并释放控制台。

【讨论】:

  • 如果这不是解决方案,那是什么?
  • @Gabe 有什么问题?
  • 大卫,不要太严格。您可以从正确的问题中理解 OP 正在努力“如何关闭窗口......”。您解释了为什么它不起作用,如果您能说出 op 手头有哪些选项会更好。 1) 杀戮是一个残酷的选择。
  • @SriramSakthivel 也许吧。但我倾向于相信回答所提出的问题。我真的不想推测实际问题是什么。提问者没有说明根本问题。我对猜测它是什么感觉不太自信。
  • 听起来你想问的问题是,如何向另一个进程发送CTRL_CLOSE_EVENT 信号?
猜你喜欢
  • 2023-03-26
  • 2013-12-18
  • 2010-12-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-10-29
相关资源
最近更新 更多