[idd] helper: stop using MsgWaitForMultipleObjects

`MsgWaitForMultipleObjects` doesn't handle inner message loops,
which may happen during `TrackPopupMenu`, causing exits to fail.
This commit is contained in:
Quantum
2025-09-14 16:26:05 -04:00
committed by Geoffrey McRae
parent d006dbb547
commit 9009217366
3 changed files with 38 additions and 35 deletions

View File

@@ -22,7 +22,8 @@ bool CNotifyWindow::registerClass()
return s_atom; return s_atom;
} }
CNotifyWindow::CNotifyWindow() : m_iconData({ 0 }), m_menu(CreatePopupMenu()) CNotifyWindow::CNotifyWindow() : m_iconData({ 0 }), m_menu(CreatePopupMenu()),
closeRequested(false)
{ {
CreateWindowEx(0, MAKEINTATOM(s_atom), NULL, CreateWindowEx(0, MAKEINTATOM(s_atom), NULL,
0, 0, 0, 0, 0, NULL, NULL, hInstance, this); 0, 0, 0, 0, 0, NULL, NULL, hInstance, this);
@@ -63,6 +64,13 @@ LRESULT CNotifyWindow::onCreate()
return 0; return 0;
} }
LRESULT CNotifyWindow::onClose()
{
if (closeRequested)
destroy();
return 0;
}
LRESULT CNotifyWindow::onNotifyIcon(UINT uEvent, WORD wIconId, int x, int y) LRESULT CNotifyWindow::onNotifyIcon(UINT uEvent, WORD wIconId, int x, int y)
{ {
switch (uEvent) switch (uEvent)
@@ -95,3 +103,9 @@ void CNotifyWindow::registerIcon()
if (!Shell_NotifyIcon(NIM_SETVERSION, &m_iconData)) if (!Shell_NotifyIcon(NIM_SETVERSION, &m_iconData))
DEBUG_ERROR_HR(GetLastError(), "Shell_NotifyIcon(NIM_SETVERSION)"); DEBUG_ERROR_HR(GetLastError(), "Shell_NotifyIcon(NIM_SETVERSION)");
} }
void CNotifyWindow::close()
{
closeRequested = true;
PostMessage(m_hwnd, WM_CLOSE, 0, 0);
}

View File

@@ -10,15 +10,19 @@ class CNotifyWindow : public CWindow
NOTIFYICONDATA m_iconData; NOTIFYICONDATA m_iconData;
HMENU m_menu; HMENU m_menu;
bool closeRequested;
LRESULT onNotifyIcon(UINT uEvent, WORD wIconId, int x, int y); LRESULT onNotifyIcon(UINT uEvent, WORD wIconId, int x, int y);
void registerIcon(); void registerIcon();
virtual LRESULT handleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) override; virtual LRESULT handleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam) override;
virtual LRESULT onCreate() override; virtual LRESULT onCreate() override;
virtual LRESULT onClose() override;
public: public:
CNotifyWindow(); CNotifyWindow();
~CNotifyWindow() override; ~CNotifyWindow() override;
static bool registerClass(); static bool registerClass();
void close();
}; };

View File

@@ -31,6 +31,13 @@ static HandleT<HANDLENullTraits> l_process;
static void Launch(); static void Launch();
void CALLBACK DestroyNotifyWindow(PVOID lpParam, BOOLEAN bTimedOut)
{
DEBUG_INFO("Parent process exited, exiting...");
CNotifyWindow *window = (CNotifyWindow *)lpParam;
window->close();
}
int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd) int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nShowCmd)
{ {
wchar_t buffer[MAX_PATH]; wchar_t buffer[MAX_PATH];
@@ -79,46 +86,24 @@ int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _
return EXIT_FAILURE; return EXIT_FAILURE;
} }
if (!g_pipe.Init())
return EXIT_FAILURE;
CNotifyWindow window; CNotifyWindow window;
if (!g_pipe.Init()) HANDLE hWait;
{ if (!RegisterWaitForSingleObject(&hWait, hParent.Get(), DestroyNotifyWindow, &window, INFINITE, WT_EXECUTEONLYONCE))
window.destroy(); DEBUG_ERROR_HR(GetLastError(), "Failed to RegisterWaitForSingleObject");
hParent.Close();
}
while (true)
{
DWORD dwHandles = hParent.IsValid() ? 1 : 0;
LPHANDLE lpHandles = hParent.GetAddressOf();
DWORD dwResult = MsgWaitForMultipleObjects(dwHandles, lpHandles, FALSE, INFINITE, QS_ALLINPUT);
if (dwResult == WAIT_FAILED)
{
DEBUG_ERROR_HR(GetLastError(), "MsgWaitForMultipleObjects Failed");
g_pipe.DeInit();
return EXIT_FAILURE;
}
else if (dwResult == WAIT_OBJECT_0 + dwHandles)
{
MSG msg; MSG msg;
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) while (GetMessage(&msg, NULL, 0, 0) > 0)
{ {
if (msg.message == WM_QUIT)
goto exit;
TranslateMessage(&msg); TranslateMessage(&msg);
DispatchMessage(&msg); DispatchMessage(&msg);
} }
}
else
{
DEBUG_INFO("Parent process exited, exiting...");
hParent.Close();
window.destroy();
}
}
exit: (void) UnregisterWait(hWait);
DEBUG_INFO("Helper window destroyed."); DEBUG_INFO("Helper window destroyed.");
g_pipe.DeInit(); g_pipe.DeInit();
return EXIT_SUCCESS; return EXIT_SUCCESS;