来自默认 WndProc 内部的嵌套调用

发布于 2024-12-10 05:16:59 字数 4889 浏览 0 评论 0原文

我从 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 调用,以输出窗口收到的每条消息的数量,并得到:

[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

其中“未收到”行是 msgs Spy++ 说窗口收到但它们从未显示在 WndProc 中!此外,如果我在 WndProc 的开头放置一个断点,并在 WM_WINDOWPOSCHANGED 中的 DefWindowProc 调用上放置另一个断点,然后跨过 DefWindowProc 调用,则 WndProc 开头的断点不会触发...这意味着不 msg 作为 WM_WINDOWPOSCHANGED 中 DefWindowProc 调用的结果由 WndProc 接收。除非有人能看到我遗漏的东西,否则 Spy++ 不会准确地显示您的窗口收到的消息,而是显示它们的一些损坏版本,如我上面所示!

I have the following output from 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

The indents in lines 241 to 254 were added by me to make it more obvious that those messages are nested. That is, they were sent by the WM_WINDOWPOSCHANGED message in line 240.

Here is the associated WndProc (this is all from the default project created by Visual Studio 2005, except where marked to show code that I have added):

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;
}

If I run this, the VS output window has the following in it:

0
0
1
1
1
1
2
2
2
2
etc

If I uncomment the

//--lcount;

line I get:

0
0
0
0
0
0
0
0
etc

I don't understand why? I would expect to get:

0
0
1
1
0
0
1
1
etc

where the 1's represent calls to WM_ERASEBKGND and WM_NCPAINT from inside WM_WINDOWPOSCHANGED (as shown in the Spy++ output). There's obviously some fundamental misunderstanding on my part, and I can't figure it out! Any ideas/suggestions to try gratefully accepted...

If you agree with what I have stated as my expected behavior for this code I would also appreciate a comment to say so. That way I know I'm not looking at it completely wrong. :)

Edit: I think Spy++ is lying! I added an OutputDebugString call at the top of WndProc to output the number of every msg received by the window and got:

[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

where the 'not received' lines are msgs Spy++ says the window gets but they never show up in WndProc! Moreover, if I put a breakpoint at the very beggining of WndProc, and another on the DefWindowProc call in WM_WINDOWPOSCHANGED, then step over the DefWindowProc call the breakpoint at the beggining of WndProc does not fire...meaning that no msg is received by the WndProc as a result of the DefWindowProc call in WM_WINDOWPOSCHANGED. Unless someone can see something I'm missing, Spy++ does not accurately show the messages your window receives, but rather some mangled version of them, as I show above!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

呆萌少年 2024-12-17 05:16:59

您遇到这种情况的原因是因为 DefWindowProc() 将对 WM_WINDOWPOSCHANGED 执行的所有操作都是将 WM_SIZE 和 WM_MOVE 事件添加到消息队列 请参阅此处的 msdn 所以这个代码:

++lcount;
lReturnValue = DefWindowProc(hWnd, message, wParam, lParam);
--lcount;

仅增加lcount,将WM_SIZE和WM_MOVE消息添加到队列中,然后减少lcount。在 lcount 上的这两个操作之间不会调用 WM_NCPAINT。

希望有帮助吗?

the reason that your experiencing this is because all the DefWindowProc() will do with WM_WINDOWPOSCHANGED is add WM_SIZE and WM_MOVE events to the message queue See msdn here so this code:

++lcount;
lReturnValue = DefWindowProc(hWnd, message, wParam, lParam);
--lcount;

just increments lcount, adds a the WM_SIZE and WM_MOVE messages to the queue then decrements lcount. WM_NCPAINT wont get called between those two operations on lcount.

Hope that helps?

山田美奈子 2024-12-17 05:16:59

我刚刚复制了您的实验,这就是我得到的结果:

<00494> 000307A6 P WM_MOUSEMOVE fwKeys:MK_LBUTTON xPos:-4 yPos:173
<00495> 000307A6 S WM_SIZING fwSide:WMSZ_LEFT lprc:0012F71C
<00496> 000307A6 R WM_SIZING fProcessed:False
<00497> 000307A6 S WM_WINDOWPOSCHANGING lpwp:0012F710
    <00498> 000307A6 S WM_GETMINMAXINFO lpmmi:0012F36C
    <00499> 000307A6 R WM_GETMINMAXINFO lpmmi:0012F36C
<00500> 000307A6 R WM_WINDOWPOSCHANGING
<00501> 000307A6 S WM_NCCALCSIZE fCalcValidRects:True lpncsp:0012F6E4
<00502> 000307A6 R WM_NCCALCSIZE fuValidRect:0000 lpncsp:0012F6E4
<00503> 000307A6 S WM_NCPAINT hrgn:00000001
    <00504> 000307A6 S WM_GETTEXT cchTextMax:510 lpszText:0012EB68
    <00505> 000307A6 R WM_GETTEXT cchCopied:3 lpszText:0012EB68 ("F")
<00506> 000307A6 R WM_NCPAINT
<00507> 000307A6 S WM_ERASEBKGND hdc:A9010D6B
<00508> 000307A6 R WM_ERASEBKGND fErased:True
<00509> 000307A6 S WM_WINDOWPOSCHANGED lpwp:0012F710
    <00510> 000307A6 S WM_MOVE xPos:141 yPos:218
    <00511> 000307A6 R WM_MOVE
    <00512> 000307A6 S WM_SIZE fwSizeType:SIZE_RESTORED nWidth:991 nHeight:664
    <00513> 000307A6 R WM_SIZE
<00514> 000307A6 R WM_WINDOWPOSCHANGED
<00515> 000307A6 S WM_PAINT hdc:00000000
<00516> 000307A6 R WM_PAINT
<00517> 000307A6 P WM_MOUSEMOVE fwKeys:MK_LBUTTON xPos:-5 yPos:173
<00518> 000307A6 S WM_SIZING fwSide:WMSZ_LEFT lprc:0012F71C
<00519> 000307A6 R WM_SIZING fProcessed:False
<00520> 000307A6 S WM_WINDOWPOSCHANGING lpwp:0012F710
    <00521> 000307A6 S WM_GETMINMAXINFO lpmmi:0012F36C
    <00522> 000307A6 R WM_GETMINMAXINFO lpmmi:0012F36C
<00523> 000307A6 R WM_WINDOWPOSCHANGING
<00524> 000307A6 S WM_NCCALCSIZE fCalcValidRects:True lpncsp:0012F6E4
<00525> 000307A6 R WM_NCCALCSIZE fuValidRect:0000 lpncsp:0012F6E4
<00526> 000307A6 S WM_NCPAINT hrgn:00000001
    <00527> 000307A6 S WM_GETTEXT cchTextMax:510 lpszText:0012EB68
    <00528> 000307A6 R WM_GETTEXT cchCopied:3 lpszText:0012EB68 ("F")
<00529> 000307A6 R WM_NCPAINT
<00530> 000307A6 S WM_ERASEBKGND hdc:A9010D6B
<00531> 000307A6 R WM_ERASEBKGND fErased:True
<00532> 000307A6 S WM_WINDOWPOSCHANGED lpwp:0012F710
    <00533> 000307A6 S WM_MOVE xPos:139 yPos:218
    <00534> 000307A6 R WM_MOVE
    <00535> 000307A6 S WM_SIZE fwSizeType:SIZE_RESTORED nWidth:993 nHeight:664
    <00536> 000307A6 R WM_SIZE
<00537> 000307A6 R WM_WINDOWPOSCHANGED
<00538> 000307A6 S WM_PAINT hdc:00000000
<00539> 000307A6 R WM_PAINT

这与有关 WM_WINDOWSPOSCHANGED 和 WM_WINDOWSPOSCHANGING 的 MSDN 文档一致,而且这是我们所期望的。

所以,要么你的 Spy++ 版本错误,要么你的 Windows 正在做一些令人讨厌的事情。

I've just duplicated your experiment and this is what I've got:

<00494> 000307A6 P WM_MOUSEMOVE fwKeys:MK_LBUTTON xPos:-4 yPos:173
<00495> 000307A6 S WM_SIZING fwSide:WMSZ_LEFT lprc:0012F71C
<00496> 000307A6 R WM_SIZING fProcessed:False
<00497> 000307A6 S WM_WINDOWPOSCHANGING lpwp:0012F710
    <00498> 000307A6 S WM_GETMINMAXINFO lpmmi:0012F36C
    <00499> 000307A6 R WM_GETMINMAXINFO lpmmi:0012F36C
<00500> 000307A6 R WM_WINDOWPOSCHANGING
<00501> 000307A6 S WM_NCCALCSIZE fCalcValidRects:True lpncsp:0012F6E4
<00502> 000307A6 R WM_NCCALCSIZE fuValidRect:0000 lpncsp:0012F6E4
<00503> 000307A6 S WM_NCPAINT hrgn:00000001
    <00504> 000307A6 S WM_GETTEXT cchTextMax:510 lpszText:0012EB68
    <00505> 000307A6 R WM_GETTEXT cchCopied:3 lpszText:0012EB68 ("F")
<00506> 000307A6 R WM_NCPAINT
<00507> 000307A6 S WM_ERASEBKGND hdc:A9010D6B
<00508> 000307A6 R WM_ERASEBKGND fErased:True
<00509> 000307A6 S WM_WINDOWPOSCHANGED lpwp:0012F710
    <00510> 000307A6 S WM_MOVE xPos:141 yPos:218
    <00511> 000307A6 R WM_MOVE
    <00512> 000307A6 S WM_SIZE fwSizeType:SIZE_RESTORED nWidth:991 nHeight:664
    <00513> 000307A6 R WM_SIZE
<00514> 000307A6 R WM_WINDOWPOSCHANGED
<00515> 000307A6 S WM_PAINT hdc:00000000
<00516> 000307A6 R WM_PAINT
<00517> 000307A6 P WM_MOUSEMOVE fwKeys:MK_LBUTTON xPos:-5 yPos:173
<00518> 000307A6 S WM_SIZING fwSide:WMSZ_LEFT lprc:0012F71C
<00519> 000307A6 R WM_SIZING fProcessed:False
<00520> 000307A6 S WM_WINDOWPOSCHANGING lpwp:0012F710
    <00521> 000307A6 S WM_GETMINMAXINFO lpmmi:0012F36C
    <00522> 000307A6 R WM_GETMINMAXINFO lpmmi:0012F36C
<00523> 000307A6 R WM_WINDOWPOSCHANGING
<00524> 000307A6 S WM_NCCALCSIZE fCalcValidRects:True lpncsp:0012F6E4
<00525> 000307A6 R WM_NCCALCSIZE fuValidRect:0000 lpncsp:0012F6E4
<00526> 000307A6 S WM_NCPAINT hrgn:00000001
    <00527> 000307A6 S WM_GETTEXT cchTextMax:510 lpszText:0012EB68
    <00528> 000307A6 R WM_GETTEXT cchCopied:3 lpszText:0012EB68 ("F")
<00529> 000307A6 R WM_NCPAINT
<00530> 000307A6 S WM_ERASEBKGND hdc:A9010D6B
<00531> 000307A6 R WM_ERASEBKGND fErased:True
<00532> 000307A6 S WM_WINDOWPOSCHANGED lpwp:0012F710
    <00533> 000307A6 S WM_MOVE xPos:139 yPos:218
    <00534> 000307A6 R WM_MOVE
    <00535> 000307A6 S WM_SIZE fwSizeType:SIZE_RESTORED nWidth:993 nHeight:664
    <00536> 000307A6 R WM_SIZE
<00537> 000307A6 R WM_WINDOWPOSCHANGED
<00538> 000307A6 S WM_PAINT hdc:00000000
<00539> 000307A6 R WM_PAINT

This is consistent with the MSDN documentation about WM_WINDOWSPOSCHANGED and WM_WINDOWSPOSCHANGING and moreover it is what we would expect.

So, or your Spy++ version is wrong or your Windows is doing nasty things.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文