我有一个交互式Win32应用程序,在某些时候我需要启动另一个应用程序并等待其他应用程序完成。在其他应用程序运行期间,交互式应用程序不应该响应调整大小和移动窗口(当然这意味着交互式应用程序仍应继续重绘)。
我目前的做法是:
EnableWindow(handle, FALSE)
)WM_APP
消息将再次启用主窗口(EnableWindow(handle, TRUE)
); 线程T:
CreateProcess
WaitForSingleObject
WM_APP
向主窗口发布特殊PostMessage
消息。这很好用,但我不确定这是不是正确的方法。
是否有更好的方法或者我应该继续这样做?
答案 0 :(得分:2)
您的方法很好,只需确保使用PostMessage()
向主窗口发送特殊的WM_APP消息
如果主线程正好等待线程T,则避免死锁。
正如评论者指出的,创建线程的替代方法是使用带有MsgWaitForMultipleObjectsEx
的消息循环。
我看到的优势:
如果这是针对您的方案的更好方法,您必须自己判断。
可用于等待进程(或任何其他可等待句柄)处理消息的功能如下所示。它的实现非常复杂(有关背景信息,请参阅我的答案末尾的链接),但使用非常简单(参见后续示例)。
// Function to process messages until the state of any of the given objects is signaled,
// the timeout is reached or a WM_QUIT message is received.
// Parameter hDialog can be nullptr, if there is no dialog.
//
// Returns ERROR_SUCCESS if any of the given handles is signaled.
// Returns ERROR_TIMEOUT in case of timeout.
// Returns ERROR_CANCELLED if the WM_QUIT message has been received.
// Returns the value of GetLastError() if MsgWaitForMultipleObjectsEx() fails.
DWORD WaitForObjectsWithMsgLoop(
HWND hDialog, const std::vector<HANDLE>& handles, DWORD timeOutMillis = INFINITE )
{
if( handles.empty() )
return ERROR_INVALID_PARAMETER;
DWORD handleCount = static_cast<DWORD>( handles.size() );
DWORD startTime = GetTickCount();
DWORD duration = 0;
do
{
DWORD status = MsgWaitForMultipleObjectsEx(
handleCount, handles.data(),
timeOutMillis - duration,
QS_ALLINPUT,
MWMO_INPUTAVAILABLE );
if( status == WAIT_FAILED )
{
// MsgWaitForMultipleObjectsEx() has failed.
return GetLastError();
}
else if( status >= WAIT_OBJECT_0 && status < WAIT_OBJECT_0 + handleCount )
{
// Any of the handles is signaled.
return ERROR_SUCCESS;
}
else if( status == WAIT_OBJECT_0 + handleCount )
{
// New input is available, process it.
MSG msg;
while( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
if( msg.message == WM_QUIT )
{
// End the message loop because of quit message.
PostQuitMessage( static_cast<int>( msg.wParam ) );
return ERROR_CANCELLED;
}
// Enable message filter hooks (that's what the system does in it's message loops).
// You may use a custom code >= MSGF_USER.
// https://blogs.msdn.microsoft.com/oldnewthing/20050428-00/?p=35753
if( ! CallMsgFilter( &msg, MSGF_USER ) )
{
// Optionally process dialog messages.
if( ! hDialog || ! IsDialogMessage( hDialog, &msg ) )
{
// Standard message processing.
TranslateMessage( &msg );
DispatchMessage( &msg );
}
}
}
}
duration = GetTickCount() - startTime;
}
while( duration < timeOutMillis );
// Timeout reached.
return ERROR_TIMEOUT;
}
该功能可用于对话框程序,如下所示。为简洁省略了错误处理。
INT_PTR CALLBACK YourDialogProc( HWND hDlg, UINT message, WPARAM wParam, LPARAM lParam )
{
static bool s_childProcessRunning = false;
switch( message )
{
case YourMessageToLaunchProcess:
{
// prevent reentrancy in case the process is already running
if( s_childProcessRunning )
{
MessageBoxW( hDlg, L"Process already running", L"Error", MB_ICONERROR );
return TRUE;
}
// Prepare CreateProcess() arguments
STARTUPINFO si{ sizeof(si) };
PROCESS_INFORMATION pi{};
wchar_t command[] = L"notepad.exe"; // string must be writable!
// Launch the process
if( CreateProcessW( NULL, command, NULL, NULL, FALSE, 0, NULL, NULL, &si, &pi ) )
{
// Set flag to prevent reentrancy.
s_childProcessRunning = true;
// Wait until the child process exits while processing messages
// to keep the window responsive.
DWORD waitRes = WaitForObjectsWithMsgLoop( hDlg, { pi.hProcess } );
// TODO: Check waitRes for error
s_childProcessRunning = false;
// Cleanup
CloseHandle( pi.hThread );
CloseHandle( pi.hProcess );
}
return TRUE;
}
// more message handlers...
}
return FALSE;
}
强制旧的新事物链接: