← 回總覽

如果对话框想要拦截自己的消息循环该怎么办?

📅 2026-03-28 07:14 Raymond Chen 软件编程 3 分鐘 3260 字 評分: 86
Win32 API Windows 编程 C++ 对话框 消息循环
📌 一句话摘要 本文演示了对话框如何通过子类化(subclassing)其所有者来拦截 WM_ENTERIDLE 消息,从而实现自定义的消息循环和事件处理。 📝 详细摘要 本文探讨了一个特定的 Windows 编程挑战:当对话框不拥有消息循环时,如何自定义其消息循环。作者 Raymond Chen 解释了一种技术,即在对话框的所有者(owner)上使用 SetWindowSubclass 来拦截 WM_ENTERIDLE 消息。通过过滤这些消息以确保它们源自特定的对话框,对话框可以安全地处理事件(例如可等待计时器),而不会干扰可能处于活动状态的其他对话框。文章提供了实用的代码示例,并讨论了

Sign in to use highlight and note-taking features for a better reading experience. Sign in now

So far, we’ve been looking at how a dialog box owner can customize the dialog message loop. But what about the dialog itself? Can the dialog customize its own dialog message loop?

Sure. It just has to steal the messages from its owner.

The dialog box can subclass its owner and grab the WM_ENTER­IDLE message. Now, maybe it should be careful only to grab WM_ENTER­IDLE messages that were triggered by that dialog and not accidentally grab messages that were triggered by other dialogs.

HANDLE hTimer;

LRESULT CALLBACK EnterIdleSubclassProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam, UINT_PTR id, [[maybe_unused]] DWORD_PTR data) { if (message == WM_ENTERIDLE &:& wParam == MSGF_DIALOGBOX && (HWND)lParam == (HWND)id) { return SendMessage(hdlg, message, wParam, lParam); } else { return DefSubclassProc(hwnd, message, wParam, lParam); } }

INT_PTR CALLBACK DialogProc(HWND hdlg, UINT message, WPARAM wParam, LPARAM lParam) { LARGE_INTEGER twoSeconds;

switch (message) { ⟦ ... ⟧

case WM_INITDIALOG: hTimer = CreateWaitableTimerW(nullptr, FALSE, nullptr); twoSeconds.QuadPart = -2 * wil::filetime_duration::one_second; SetWaitableTimer(h, &twoSeconds, 2000, nullptr, nullptr, FALSE); SetWindowSubclass(GetParent(hdlg), EnterIdleSubclassProc, (UINT_PTR)hdlg, 0); ⟦ other dialog box setup ⟧ return TRUE;

case WM_ENTERIDLE: OnEnterIdle(hdlg, (UINT)wParam, (HWND)lParam); return 0;

⟦ ... ⟧ }

return FALSE; }

When the dialog box initializes, we create the periodic waitable timer (for demonstration purposes) and also subclass our owner window with the Enter­Idle­Subclass­Proc. We use the dialog window handle as the ID for two reasons. First, it lets us pass a parameter to the subclass procedure so it knows which dialog box it is working on behalf of. (We could also have passed it as the data parameter.) More importantly, it allows multiple dialogs to use the Enter­Idle­Subclass­Proc to subclass their owner, and the multiple subclasses won’t conflict with each other.

The subclass procedure checks whether it is a WM_ENTER­IDLE, marked as coming from a dialog box message loop, and where the dialog box handle is the one we have. If so, then we forward the WM_ENTER­IDLE back into the dialog for processing. That processing consists of using the On­Enter­Idle function we created at the start of the series, which processes waitable timer events while waiting for a message to arrive.

Okay, but should we be careful to grab WM_ENTER­IDLE messages only if they correspond to our dialog box? Because if the owner displays some other modal dialog box while our dialog is up (not really a great idea, but hey, weirder things have happened), then we still want to process our waitable timer events. But on the other hand, maybe that other dialog wants to customize the message loop in a different way. Probably best to steal messages only if they originated from our dialog box.

查看原文 → 發佈: 2026-03-28 07:14:41 收錄: 2026-03-28 10:00:40

🤖 問 AI

針對這篇文章提問,AI 會根據文章內容回答。按 Ctrl+Enter 送出。