首页
社区
课程
招聘
[求助]钻一下牛角。没有消息循环依然能处理消息
发表于: 2008-11-17 15:16 6436

[求助]钻一下牛角。没有消息循环依然能处理消息

2008-11-17 15:16
6436

先上段代码

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .386
                .model flat,stdcall
                option casemap:none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include                windows.inc
include                gdi32.inc
includelib        gdi32.lib
include                user32.inc
includelib        user32.lib
include                kernel32.inc
includelib        kernel32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .data?

hInstance        dd                ?
hWinMain        dd                ?

                .const
szCaption db 'A   MessageBox   !',0   
szWINText db 'Hello,   World   !',0   
szClassName        db        'MyClass',0
szCaptionMain        db        'My first Window !',0
szText                db        'Win32 Assembly, Simple and powerful !',0
szButton        db        'button',0
szButtonText        db        '&OK',0
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 窗口过程
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcWinMain        proc        uses ebx edi esi,hWnd,uMsg,wParam,lParam
                local        @stPs:PAINTSTRUCT
                local        @stRect:RECT
                local        @hDc

                mov        eax,uMsg
;********************************************************************
                .if        eax ==        WM_PAINT
                        invoke        BeginPaint,hWnd,addr @stPs
                        mov        @hDc,eax

                        invoke        GetClientRect,hWnd,addr @stRect
                        invoke        DrawText,@hDc,addr szText,-1,\
                                addr @stRect,\
                                DT_SINGLELINE or DT_CENTER or DT_VCENTER

                        invoke        EndPaint,hWnd,addr @stPs
;********************************************************************
; 建立一个按钮
;********************************************************************
                .elseif        eax ==        WM_CREATE
                        invoke        CreateWindowEx,NULL,\
                                offset szButton,offset szButtonText,\
                                WS_CHILD or WS_VISIBLE,\
                                10,10,65,22,\
                                hWnd,1,hInstance,NULL
;********************************************************************
                .elseif        eax ==        WM_CLOSE
                        invoke        DestroyWindow,hWinMain
                        invoke        PostQuitMessage,NULL
;********************************************************************
                .else
                        invoke        DefWindowProc,hWnd,uMsg,wParam,lParam
                        ret
                .endif
;********************************************************************
                xor        eax,eax
                ret

_ProcWinMain        endp

;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_WinMain        proc
                local        @stWndClass:WNDCLASSEX
                local        @stMsg:MSG

                invoke        GetModuleHandle,NULL
                mov        hInstance,eax
                invoke        RtlZeroMemory,addr @stWndClass,sizeof @stWndClass
;********************************************************************
; 注册窗口类
;********************************************************************
                invoke        LoadCursor,0,IDC_ARROW
                mov        @stWndClass.hCursor,eax
                push        hInstance
                pop        @stWndClass.hInstance
                mov        @stWndClass.cbSize,sizeof WNDCLASSEX
                mov        @stWndClass.style,CS_HREDRAW or CS_VREDRAW
                mov        @stWndClass.lpfnWndProc,offset _ProcWinMain
                mov        @stWndClass.hbrBackground,COLOR_WINDOW + 1
                mov        @stWndClass.lpszClassName,offset szClassName
                invoke        RegisterClassEx,addr @stWndClass
;********************************************************************
; 建立并显示窗口
;********************************************************************
                invoke        CreateWindowEx,WS_EX_CLIENTEDGE,offset szClassName,offset

szCaptionMain,\
                        WS_OVERLAPPEDWINDOW,\
                        100,100,600,400,\
                        NULL,NULL,hInstance,NULL
                mov        hWinMain,eax
                invoke        ShowWindow,hWinMain,SW_SHOWNORMAL
                invoke        UpdateWindow,hWinMain
                  invoke  MessageBox,NULL,offset szText,\
                        offset   szCaption,MB_OK
;********************************************************************
; 消息循环
;********************************************************************
;                .while        TRUE
;                        invoke        GetMessage,addr @stMsg,NULL,0,0
;                        .break        .if eax        == 0
;                        invoke        TranslateMessage,addr @stMsg
;                        invoke        DispatchMessage,addr @stMsg
;                .endw
;                ret

_WinMain        endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
                call        _WinMain
                invoke        ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                end        start

这里仔细的朋友可以看到消息循环的代码被我注释掉了。
不过编译出来的程序依然能够正常的处理任何消息。
(这时候不要按消息框的确定按钮。)
我的疑问是,当我们按下关闭主窗口的按钮的时候,
程序就开始弹出无数个窗口,这个是因为刚好
call        _WinMain 指令紧接着排列在 messagebox函数调用的后面
然后程序开始新一轮的 注册窗口 创建窗口 更新窗口 然后问题来了,当运行到
invoke  MessageBox,NULL,offset szText,offset   szCaption,MB_OK
的时候 程序就不再创建消息框了。。这个是为什么?我OD过好多次 也找不到原因。
哪位如果略知一二,欢迎指教。


[注意]传递专业知识、拓宽行业人脉——看雪讲师团队等你加入!

收藏
免费 7
支持
分享
最新回复 (6)
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
2
系统会给你一个默认的 msg loop
2008-11-17 16:15
0
雪    币: 6075
活跃值: (2236)
能力值: (RANK:1060 )
在线值:
发帖
回帖
粉丝
3
靠,运行了以后音箱跟放屁一样。这个原因是本该Modal的MessageBox消息循环处理了主窗口的消息,细节你自己研究吧。以下为调用栈:

procexp:

0.exe+0x1000
user32.dll!GetDC+0x14f
user32.dll!DefWindowProcW+0x184
user32.dll!DefWindowProcW+0x1d0
ntdll.dll!KiUserCallbackDispatcher+0x13
user32.dll!PeekMessageW+0x167
user32.dll!CallMsgFilterW+0x103 // 消息循环
user32.dll!DrawStateW+0x1f2
user32.dll!SoftModalMessageBox+0x677
user32.dll!MessageBoxIndirectA+0x23a
user32.dll!MessageBoxTimeoutW+0x7a
user32.dll!MessageBoxTimeoutA+0x9c
user32.dll!MessageBoxExA+0x1b
user32.dll!MessageBoxA+0x45
0.exe+0x117f
0.exe+0x1186

windbg:

00 0012f884 77d18734 image00400000+0x1000
01 0012f8b0 77d18816 user32!InternalCallWinProc+0x28
02 0012f918 77d1b4c0 user32!UserCallWinProcCheckWow+0x150
03 0012f96c 77d1b50c user32!DispatchClientMessage+0xa3
04 0012f994 7c92eae3 user32!__fnDWORD+0x24
05 0012f9b8 77d193e9 ntdll!KiUserCallbackDispatcher+0x13
06 0012f9e4 77d19402 user32!NtUserPeekMessage+0xc
07 0012fa10 77d2daaf user32!PeekMessageW+0xbc
08 0012fa58 77d2593f user32!DialogBox2+0xe4
09 0012fa80 77d3a91e user32!InternalDialogBox+0xd0
0a 0012fd40 77d3a284 user32!SoftModalMessageBox+0x938
0b 0012fe90 77d661d3 user32!MessageBoxWorker+0x2ba
0c 0012fee8 77d66278 user32!MessageBoxTimeoutW+0x7a
0d 0012ff1c 77d50617 user32!MessageBoxTimeoutA+0x9c
0e 0012ff3c 77d505cf user32!MessageBoxExA+0x1b
0f 0012ff58 0040117f user32!MessageBoxA+0x45
10 0012ffbc 00401186 image00400000+0x117f
11 0012fff0 00000000 image00400000+0x1186
2008-11-17 16:18
0
雪    币: 2110
活跃值: (21)
能力值: (RANK:260 )
在线值:
发帖
回帖
粉丝
4
消息循环的概念,一般是指GetMessage();DispatchMessage()的循环。

实际上,大部的系统消息是直接发送到窗口过程的,而不放入消息队列的。

你可以做这样一上试验,窗口过程什么都不做,只是每调用一次,就将一个全局计数变量增1,然后将消息直接交给DefWndProc().

主函数里CreateWindow()后,ShowWindow(),UpdateWindow(),然后检测一下这个计数值,你会发现窗口过程已经被调用的次数远远超出你的想象。

或者更进一步,窗口函数将收到的消息记录下来,可以看看在CreateWindow的过程中都会收到哪些消息。

再进一步,你在主函数里调用比如MoveWindow()或InvalidateRect()之类的函数,你会发现不用你DispatchMessage(),消息是直接被发送到窗口过程的。

这也是为什么Windows的窗口必须有一个回调函数 ,而且采取先GetMessage()再DispatchMessage()这样“笨重”方法,如果你看过X Window的书,可以知道X Window的编程模型是(用Windows的API来类比,实际X的概念不叫Message,而叫Event)只有Get,没有Dispatch的,因为它没有采用回调机制,而是由程序自行对收到的事件进行判断。
2008-11-17 20:15
0
雪    币: 200
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
我也看看........
2008-11-18 00:03
0
雪    币: 210
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
6
昨天晚上研究了很长时间,跟人也讨论一会,也没什么进展,现在怀疑是跟消息列队内的消息有关
,因为 假设我们按了消息框的确定按钮,程序流程也同样先从Messagebox内部的消息循环返回,然后开始新一轮的 注册窗口 创建窗口 更新窗口 ,到达Messagebox后能够正常显示消息框。
但按了主窗口的关闭按钮后,再调用的Messagebox函数,其内部处理流程就会发生变化,跑几次消息循环就自己出来了。对Messagebox内部的机制还不是很清楚。再研究一下
2008-11-18 09:16
0
雪    币: 245
活跃值: (25)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
7
我来补个最终答案,_WinMain最后加一句就行了:

        invoke PeekMessage,addr @stMsg, NULL, 0, 0, PM_REMOVE

_WinMain  endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:
    call  _WinMain
    invoke  ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
    end  start
2010-2-5 12:54
0
游客
登录 | 注册 方可回帖
返回
//