【发布时间】:2011-12-08 19:59:09
【问题描述】:
我从 Spy++ 得到以下输出:
<00227> 001F1732 P WM_MOUSEMOVE fwKeys:MK_LBUTTON xPos:-43 yPos:28
<00228> 001F1732 S WM_SIZING fwSide:WMSZ_LEFT lprc:0012F410
<00229> 001F1732 R WM_SIZING fProcessed:False
<00230> 001F1732 S WM_WINDOWPOSCHANGING lpwp:0012F404
<00231> 001F1732 S WM_GETMINMAXINFO lpmmi:0012EEF4
<00232> 001F1732 R WM_GETMINMAXINFO lpmmi:0012EEF4
<00233> 001F1732 R WM_WINDOWPOSCHANGING
<00234> 001F1732 S WM_NCCALCSIZE fCalcValidRects:True lpncsp:0012F3D8
<00235> 001F1732 R WM_NCCALCSIZE fuValidRect:0000 lpncsp:0012F3D8
<00236> 001F1732 S WM_NCPAINT hrgn:00000001
<00237> 001F1732 R WM_NCPAINT
<00238> 001F1732 S WM_ERASEBKGND hdc:09012308
<00239> 001F1732 R WM_ERASEBKGND fErased:True
<00240> 001F1732 S WM_WINDOWPOSCHANGED lpwp:0012F404
<00241> 001F1732 S WM_MOVE xPos:950 yPos:404
<00242> 001F1732 R WM_MOVE
<00243> 001F1732 S WM_SIZE fwSizeType:SIZE_RESTORED nWidth:282 nHeight:79
<00244> 001F1732 R WM_SIZE
<00245> 001F1732 S WM_WINDOWPOSCHANGING lpwp:0012F064
<00246> 001F1732 R WM_WINDOWPOSCHANGING
<00247> 001F1732 S WM_NCCALCSIZE fCalcValidRects:True lpncsp:0012F038
<00248> 001F1732 R WM_NCCALCSIZE fuValidRect:0000 lpncsp:0012F038
<00249> 001F1732 S WM_NCPAINT hrgn:00000001
<00250> 001F1732 R WM_NCPAINT
<00251> 001F1732 S WM_ERASEBKGND hdc:16011DB5
<00252> 001F1732 R WM_ERASEBKGND fErased:True
<00253> 001F1732 S WM_WINDOWPOSCHANGED lpwp:0012F064
<00254> 001F1732 R WM_WINDOWPOSCHANGED
<00255> 001F1732 R WM_WINDOWPOSCHANGED
<00256> 001F1732 S WM_PAINT hdc:00000000
<00257> 001F1732 R WM_PAINT
<00258> 001F1732 P WM_MOUSEMOVE fwKeys:MK_LBUTTON xPos:-9 yPos:28
第 241 到 254 行的缩进是我添加的,以便更明显地看出这些消息是嵌套的。也就是说,它们是由第 240 行的 WM_WINDOWPOSCHANGED 消息发送的。
这是关联的 WndProc(这全部来自 Visual Studio 2005 创建的默认项目,除了标记为显示我添加的代码的地方):
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
LRESULT lReturnValue = 0; //---added by me
static int lcount = 0; //---added by me
switch (message)
{
//---added by me from here vvvv
case WM_WINDOWPOSCHANGED:
++lcount;
lReturnValue = DefWindowProc(hWnd, message, wParam, lParam);
//--lcount;
return lReturnValue;
case WM_ERASEBKGND:
case WM_NCPAINT:
{
wchar_t a[20];
_itow(lcount, &a[0], 10);
OutputDebugString(a);
OutputDebugString(L"\n");
}
return DefWindowProc(hWnd, message, wParam, lParam);
//---added by me to here ^^^^
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
如果我运行它,VS 输出窗口中会显示以下内容:
0
0
1
1
1
1
2
2
2
2
etc
如果我取消注释
//--lcount;
我得到的行:
0
0
0
0
0
0
0
0
etc
我不明白为什么?我希望得到:
0
0
1
1
0
0
1
1
etc
其中 1 表示从 WM_WINDOWPOSCHANGED 内部调用 WM_ERASEBKGND 和 WM_NCPAINT(如 Spy++ 输出所示)。显然我有一些根本性的误解,我想不通!任何尝试的想法/建议都将被感激地接受......
如果您同意我所说的我对此代码的预期行为,我也会感谢您发表评论。这样我就知道我没有完全看错。 :)
编辑:我认为 Spy++ 在撒谎!我在 WndProc 的顶部添加了一个 OutputDebugString 调用,以输出窗口接收到的 每个 msg 的数量并得到:
[WM_MOUSEMOVE] // not received
WM_SIZING
WM_WINDOWPOSCHANGING
WM_GETMINMAXINFO
WM_NCCALCSIZE
WM_NCPAINT
WM_ERASEBKGND
WM_WINDOWPOSCHANGED
WM_MOVE
WM_SIZE
[WM_WINDOWPOSCHANGING] // not received
WM_NCCALCSIZE
WM_NCPAINT
WM_ERASEBKGND
[WM_WINDOWPOSCHANGED] // not received
WM_PAINT
[WM_MOUSEMOVE] // not received
“未收到”行是消息 Spy++ 说窗口得到了但它们从未出现在 WndProc 中!此外,如果我在 WndProc 的开头放置一个断点,并在 WM_WINDOWPOSCHANGED 中的 DefWindowProc 调用上放置另一个断点,然后跨过 DefWindowProc 调用,WndProc 开头的断点不会触发......这意味着 no em> msg 作为 WM_WINDOWPOSCHANGED 中的 DefWindowProc 调用的结果由 WndProc 接收。除非有人能看到我遗漏的东西,否则 Spy++ 不会准确地显示您的窗口收到的消息,而是显示它们的一些错误版本,如上所示!
【问题讨论】:
-
将 ++lcount 移到 switch 语句之前。
-
好的,我试过了。但是随后 lcount 会随着窗口接收到的每条消息而增加,因此它会变得越来越大(有时会在收到 WM_WINDOWPOSCHANGED 消息时减少)。你的想法是什么?
-
我同意你对预期行为的看法,我和你一样对结果感到惊讶。只要我手头有一台 Windows 机器,我就会尝试......顺便说一句,你做了什么来发出 WM_WINDOWPOSCHANGED 消息?手动移动窗口?
-
是的,我只是将左边缘向外拖动。
-
当然你必须在每个 return 语句之前递减它。