WPF应用程式没有回应WM_CLOSE [英] WPF app does not respond to WM_CLOSE

查看:225
本文介绍了WPF应用程式没有回应WM_CLOSE的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图从c ++应用程序关闭一个C#.NET 4 WPF应用程序。 C ++应用程序使用枚举窗口的标准技术,找到对应于给定进程ID的窗口,通过PostMessage发送窗口WM_CLOSE,然后通过WaitForSingleObject(pid,5000)发送窗口。但是,我的WPF应用程序永远不会关闭,即WaitForSingleObject超时。

I am trying to close a C# .NET 4 WPF application from a c++ application. The C++ app uses the standard technique of enumerating windows, finding the one that corresponds to a given process ID, sending the window a WM_CLOSE via PostMessage, then WaitForSingleObject(pid, 5000). However, my WPF app never closes, ie the WaitForSingleObject times out.

我的WPF应用程式会覆写Window :: OnClosed():

My WPF app overrides the Window::OnClosed():


  • 我通过点击窗口的X手动关闭WPF应用程序,这个方法被调用。

  • 同样,如果在Windows任务管理器的应用程序选项卡中,我对WPF进程做了结束任务,这个方法被调用(显然在该选项卡上使用WM_CLOSE消息,在进程选项卡上,结束任务使用WM_QUIT消息)。

  • 当我的C ++应用程序发送WM_CLOSE时,此方法不会被调用

  • 对于发送的消息),我的WPF应用程序终止。

  • 我已经尝试在WPF应用程序中创建自己的WndProc()处理程序,如果我将鼠标悬停在WPF GUI上,方法会被调用,但是当我的C ++应用程序发送WM_CLOSE方法从未被调用,它几乎像我的WPF应用程序没有得到WM_CLOSE消息。

  • 我创建了一个C#应用程序,我可以使用Process.GetProcessById(pid)和proc.CloseMainWindow (),它应该做同样的WM_CLOSE。这一个工作:OnClosed()方法被调用。

  • If I manually close the WPF app by clicking on the X of the window, this method gets called.
  • Similarly, if in Windows' Task Manager in the Application tab I do "End Task" on the WPF process, this method gets called (apparently on that tab the WM_CLOSE message is used, whereas on the Processes tab the End Task uses a WM_QUIT message).
  • When my C++ app sends the WM_CLOSE, this method is never called
  • When my C++ app sends WM_QUIT instead (so all C++ source code unchanged except for the message sent), my WPF app is terminated.
  • I have tried creating my own WndProc() handler in the WPF app, and method does get called if I mouse over the WPF GUI, but again when my C++ app sends the WM_CLOSE, this method is never called, it's almost like my WPF app does not get the WM_CLOSE message.
  • I have created a C# app from where I can use Process.GetProcessById(pid) and proc.CloseMainWindow(), which is supposed to do the same as WM_CLOSE. This one works: the OnClosed() method gets called.

PostMessage(hwnd,WM_CLOSE)是否正确地从C ++应用程式关闭WPF应用程式?

Is PostMessage(hwnd, WM_CLOSE) the right way to gracefully close a WPF app from a C++ app?

推荐答案

我最终找到了答案,很简单:问题是关于找到一个对应于给定的进程ID 。问题是,我不做很多低级的win32东西,所以我错过了一个重要的细节。下面是发生的情况和解决方案,以防它帮助某人:

I did find the answer eventually, and it was quite simple: the problem was the code related to "finding the one that corresponds to a given process ID". Issue is that I don't do much low level win32 stuff, so I missed an important detail. Here is what was happening and solution, in case it helps someone:

C ++函数closeProc()打开一个必须关闭的现有进程的句柄,回调函数requestMainWindowClose()被一个win32函数EnumWindows找到的每个窗口调用,并假定requestMainWindowClose()已经向关注的进程发送了关闭消息,因此它等待进程退出。如果进程在一定时间内没有退出,它将尝试通过TerminateProcess()强制终止它。如果仍然不工作,它放弃。 closeProc()如下所示:

The C++ function closeProc() opens a handle to the existing process that must be closed, and causes a callback function requestMainWindowClose() to be called for each Window found by a win32 function EnumWindows, and assumes that requestMainWindowClose() has sent the close message to the process of interest, so it waits for the process to exit. If the process doesn't exit within a certain time, it will try to terminate it forcefully via TerminateProcess(). If that still doesn't work, it gives up. The closeProc() looks like this:

void closeProc()
{
    HANDLE ps = OpenProcess( SYNCHRONIZE | PROCESS_TERMINATE, FALSE, dwProcessId );
    if (ps == NULL)
        throw std::runtime_error(...);

    EnumWindows( requestMainWindowClose, dwProcessId );

    static const int MAX_WAIT_MILLISEC = 5000; 
    const DWORD result = WaitForSingleObject(ps, MAX_WAIT_MILLISEC);
    if (result != WAIT_OBJECT_0)
    {
        if (result == WAIT_TIMEOUT)
        {
            LOGF_ERROR("Could not clcose proc (PID %s): did not exit within %s ms",
                dwProcessId << MAX_WAIT_MILLISEC);
        }
        else
        {
            LOGF_ERROR("Could not close proc (PID %s): %s", 
                dwProcessId << getLastWin32Error());
        }

        LOGF_ERROR("Trying to *terminate* proc (PID %s)", dwProcessId);
        if (TerminateProcess(ps, 0))
            exited = true;
        }
    }

    CloseHandle( ps ) ;
}

问题出现在requestMainWindowClose中,原来的代码是:

The problem was in requestMainWindowClose, here was the original code:

BOOL CALLBACK 
requestMainWindowClose( HWND nextWindow, LPARAM closePid )
{
    DWORD windowPid;
    GetWindowThreadProcessId(nextWindow, &windowPid);
    if ( windowPid==(DWORD)closePid )
    {
        ::PostMessage( nextWindow, WM_CLOSE, 0, 0 );
        return false;
    }

    return true;
}

如上所述,回调函数确定Window句柄的进程ID它(nextWindow)由EnumWindows()并与我们想要关闭的所需进程(closePid)进行比较。如果存在匹配,则函数向其发送CLOSE消息并返回。

As defined above the callback function determines the process ID of the Window handle given to it (nextWindow) by EnumWindows() and compares to the desired process we want to close (closePid). If there is a match, the function sends it a CLOSE message and returns.

到目前为止,所有都是好的。问题是它返回false,所以EnumWindows()只发送消息到进程的一个窗口,它看起来像WPF应用程序有多个窗口:即使你的代码只创建一个窗口,隐藏的窗口在幕后创建由WPF。它们都是由EnumWindows找到的;但第一个很少,如果有的话,主要的应用程序窗口。所以requestMainWindowClose()从来没有发送CLOSE到我的WPF应用程序的主窗口,从来没有机会。

All is good so far. The problem is that it returns false, so EnumWindows() only ever sends the message to one window of the process, AND it looks like WPF applications have multiple windows: even if your code only creates one window, hidden windows get created behind the scenes by WPF. They are all found by EnumWindows; but the first one is rarely if ever the main application window. So requestMainWindowClose() was never sending the CLOSE to the main window of my WPF app, never got a chance.

确实,修复是那么简单,即不返回false:

Indeed the fix was that simple, ie don't return false:

BOOL CALLBACK 
requestMainWindowClose( HWND nextWindow, LPARAM closePid )
{
    DWORD windowPid;
    GetWindowThreadProcessId( nextWindow, &windowPid );
    if ( windowPid==(DWORD)closePid )  
        ::PostMessage( nextWindow, WM_CLOSE, 0, 0 );

    return true; 
}

只有WPF的顶层应用程序窗口才会响应CLOSE消息。

Only the top app window of a WPF will respond to the CLOSE message.

这篇关于WPF应用程式没有回应WM_CLOSE的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆