WPF应用程序不响应WM_CLOSE
WPF app does not respond to WM_CLOSE
我试图从c++应用程序关闭c# . net 4 WPF应用程序。c++应用程序使用枚举窗口的标准技术,找到与给定进程ID对应的窗口,通过PostMessage向窗口发送WM_CLOSE,然后WaitForSingleObject(pid, 5000)。然而,我的WPF应用程序从未关闭,即WaitForSingleObject超时。
我的WPF应用程序覆盖了Window::OnClosed():
- 如果我手动关闭WPF应用程序点击窗口的X,这个方法被调用。
- 类似地,如果在Windows的任务管理器中的应用程序选项卡中,我在WPF进程上做"结束任务",则该方法被调用(显然在该选项卡上使用WM_CLOSE消息,而在进程选项卡上,结束任务使用WM_QUIT消息)。 当我的c++应用程序发送WM_CLOSE时,这个方法永远不会被调用
- 当我的c++应用程序发送WM_QUIT代替(所以所有c++源代码不变,除了发送的消息),我的WPF应用程序终止。
- 我已经尝试在WPF应用程序中创建自己的WndProc()处理程序,如果我将鼠标移到WPF GUI上,方法确实会被调用,但是当我的c++应用程序发送WM_CLOSE时,这个方法永远不会被调用,这几乎就像我的WPF应用程序没有得到WM_CLOSE消息。
- 我已经创建了一个c#应用程序,从那里我可以使用Process.GetProcessById(pid)和proc.CloseMainWindow(),这应该做与WM_CLOSE相同。这个是有效的:调用OnClosed()方法。
PostMessage(hwnd, WM_CLOSE)是从c++应用程序优雅地关闭WPF应用程序的正确方式吗?
我最终找到了答案,而且很简单:问题是与"找到与给定进程ID对应的那个"相关的代码。问题是,我不做太多低级的win32的东西,所以我错过了一个重要的细节。下面是发生的事情和解决方案,以防对某人有所帮助:
c++函数closeProc()打开一个必须关闭的现有进程的句柄,并为win32函数EnumWindows找到的每个窗口调用回调函数requestMainWindowClose(),并假设requestMainWindowClose()已经将关闭消息发送给感兴趣的进程,因此它等待进程退出。如果进程没有在一定时间内退出,它将尝试通过TerminateProcess()强制终止它。如果仍然不起作用,它就会放弃。closeProc()看起来像这样:
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,这里是原始代码:
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;
}
如上所述,回调函数确定EnumWindows()给出的窗口句柄的进程ID (nextWindow),并与我们想要关闭的期望进程(closePid)进行比较。如果存在匹配,则该函数发送一个CLOSE消息并返回。
到目前为止一切都很好。问题是它返回false,因此EnumWindows()只将消息发送到进程的一个窗口,并且看起来WPF应用程序有多个窗口:即使您的代码只创建一个窗口,隐藏窗口也会在后台由WPF创建。它们都是通过EnumWindows找到的;但是第一个窗口很少是应用程序的主窗口。所以requestMainWindowClose()从来没有发送CLOSE到我的WPF应用程序的主窗口,从来没有机会。实际上修复就是这么简单,即不返回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消息。
与系统菜单上的Close命令直接对应的是:
PostMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0);
你可以试试这个
- ofstream::close() 是否在 Linux 上调用同步?
- 如果我在字符数组上使用 close() 会发生什么?
- "WM" C++是什么意思?
- ZeroMQ 在 context.close() 中被阻止.如何在C++中安全地关闭套接字和上下文?
- 什么是窗口最大化/最小化/恢复的WM Windows消息
- inData.open and inData.close in C++
- 为什么 QQuickWindow->close() 不从 rootObjects 中删除对象?
- 请求X11在C或C++中合成WM的图像
- 如何在OS X上阻止QProgressDialog的'native close button'?
- 对ifstream对象调用close时出现分段错误
- 关闭文件流时出错,其存在取决于与 C++ 中的 .close() 语句相同的布尔值
- QSqlDriver::close使应用程序崩溃
- 确保QSerialPort.close在程序执行完成之前完成
- Qt窗口不会使用其他类的"this->close()"关闭
- 为什么boost shared_ptr包含带有close()的标头
- close和_close,read和_read,write和_write——有什么区别
- 在我的Linux中调用了哪个版本的close(),来自posix lib或内核
- close() 和 closesocket() 可互换
- QFile::flush() vs QFile::close()
- To ::close() or to ::fclose()?