为啥消息框不阻塞线程? [复制]
Posted
技术标签:
【中文标题】为啥消息框不阻塞线程? [复制]【英文标题】:Why doesn't message box block the thread? [duplicate]为什么消息框不阻塞线程? [复制] 【发布时间】:2017-10-23 13:22:11 【问题描述】:考虑下面的代码 sn-p,在 WM_TIMER 消息上显示一个消息框。
#define IDT_TIMER1 1001
INT_PTR CALLBACK DialogProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
switch(message)
//...
case WM_INITDIALOG:
//...
SetTimer(hWnd, IDT_TIMER1, 1000, (TIMERPROC)NULL);
break;
case WM_TIMER:
int ret = MessageBox(hWnd, L"Cancel operation?", NULL, MB_YESNO);
if(ret == IDYES)
EndDialog(hWnd, 0);
else
// no-op: keep going
break;
//...
default:
return FALSE;
return FALSE;
我希望此代码在初始计时器滴答时显示一个消息框,并阻止线程直到用户单击按钮。 实际上会发生新消息框在每个计时器滴答声中显示,即使用户没有点击任何按钮。
当我检查线程的调用堆栈时,我看到对DialogProc()
的多次调用,所有调用都停留在调用MessageBox()
的线上(即都在等待用户输入)。
鉴于调用堆栈的状态,DialogProc()
怎么可能一直在 same 线程中被调用,而 MessageBox()
在尚未返回最后一次打电话给DialogProc()
?
附:请注意,我不是在问如何完成所需的行为。我只是在寻找洞察力,以了解导致实际行为的“幕后”发生了什么。
【问题讨论】:
【参考方案1】:MessageBox
启动一个新的Message Loop,除其他外,它可以通过正常的 Windows 回调机制访问并调用您的DialogProc
。
如果它不这样做,那么像 WM_PAINT
这样的事件将不会得到处理,并且您的应用看起来就像它已经死了(除了消息框)。由于计时器仍在运行,WM_TIMER
事件会在适当的时间排队。
【讨论】:
【参考方案2】:MessageBox
进入渲染窗口、处理按钮所需的嵌套消息循环。
在MessageBox
调用中指定为第一个参数的窗口已被EnableWindow
禁用,但这不会禁用所有消息,因此您仍会收到 WM_PAINT、WM_TIMER 和其他消息。通常它会禁用用户输入:鼠标、键盘,以及使用鼠标调整窗口大小。
这个伪代码展示了 MessageBox 模拟的潜在实现方式:
int MessageBox( HWND owner_hwnd, ... )
...
HWND box_hwnd = CreateWindowEx( ..., owner_hwnd, ... );
...
EnableWindow( owner_hwnd, FALSE );
...
while ( !done )
MSG msg;
GetMessage( &msg, ... );
if ( IsDialogMessage( box_hwnd, &msg ) )
continue;
TranslateMessage( &msg );
DispatchMessage( &msg );
...
EnableWindow( owner_hwnd, TRUE );
...
DestroyWindow( box_hwnd );
...
return button;
【讨论】:
以上是关于为啥消息框不阻塞线程? [复制]的主要内容,如果未能解决你的问题,请参考以下文章