我正在尝试从c ++应用程序中关闭C#.NET 4 WPF应用程序。 C ++应用程序使用枚举窗口的标准技术,找到与给定进程ID对应的那个,通过PostMessage向窗口发送WM_CLOSE,然后使用WaitForSingleObject(pid,5000)。但是,我的WPF应用程序永远不会关闭,即WaitForSingleObject超时。
我的WPF应用程序会覆盖Window :: OnClosed():
PostMessage(hwnd,WM_CLOSE)是从C ++应用程序优雅地关闭WPF应用程序的正确方法吗?
答案 0 :(得分:1)
系统菜单上的“关闭”命令的直接等效项为:
PostMessage(hwnd, WM_SYSCOMMAND, SC_CLOSE, 0);
你可以试试。
答案 1 :(得分:1)
我最终确实找到了答案,而且非常简单:问题是与“找到与给定进程ID相对应的代码”相关的代码。问题是我没有做太多低级别的win32,所以我错过了一个重要的细节。以下是发生的事情和解决方案,以防有人帮助:
C ++函数closeProc()打开一个必须关闭的现有进程的句柄,并为win32函数EnumWindows找到的每个Window调用一个回调函数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()给它的Window句柄(nextWindow)的进程ID,并与我们想要关闭的所需进程(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消息。