CreateWindow创建对话框!
先介绍下系统创建对话框原理,搞清楚后就可以自己模仿来创建了!
一般情况下大家都习惯了用资源创建对话框 对话框有两种:模态和非模态 创建这两种对话框的函数是不相同的 模态用DialogBoxParam 非模态用CreateDialogParam 两种对话框的区别在于 消息循环的区别。
模态对话框调用用DialogBoxParam后,在函数内部会取得对话框资源 然后根据资源里指定的窗口风格来创建窗口 接着就调用消息循环来取得消息 所以该函数不会立马返回 除非调用EndDialog将其结束后函数才返回 所以如果是主窗口的消息里调用这个创建模态对话框则该窗口是不会再处理其他消息 因为窗口函数未返回也就是DispatchMessage函数未返回下一个GetMessage是没机会执行 怎样保证对话框是一直激活状态 在最上面而让用户没机会切换到其他窗口的呢 因为模态对话框会一直检测当前窗口是不是该对话框不是则设置为当前激活窗口 否则还是可以切换到其他窗口 只是这个对话框的父窗口不能再相应消息了!
记得在DialogBoxParam里有个自己指定的回调函数么?对话框是这样管理消息的,对话框类"#32770"的WNDCLASSEX结构里指定的回调函数是user32.dll模块内部的函数,用它来处理对话框消息,在处理之前会首先调用用户定义的对话框过程!
想要结束模态对话框(点右上角的X,关闭)就必须在对话框过程的WM_CLOSE消息中调用EndDialog!WM_CLOSE在winuser.h中定义为:#define WM_CLOSE 0x0010 ,所以根据这个我们知道默认对话框窗口函数是处理这个WM_CLOSE消息时是不会摧毁对话框窗口!而EndDialog又干啥了能摧毁对话框呢?我自己逆向了下这个函数 发现先GetActiveWindow 找到如果当前激活窗口是对话框 再调用SetWindowPos将窗口长宽设置为0 最后调用PostMessage(hWnd,WM_NULL,0,0)来摧毁对话框,WM_NULL是这样定义的:#define WM_NULL 0x0000,这样我们就知道原理了 就是点关闭按钮后发送了一个WM_NULL消息,这个消息是对话框类的窗口函数来处理以摧毁对话框和结束对话框的消息循环 当模态对话框的消息循环退出后DialogBoxParam函数就返回了!
对非模态对话框CreateDialogParam只是负责创建了窗口,根据资源里是否制定WS_VISIBLE来决定创建后窗口是否显示,如果不指定必须在函数返回后自己ShowWindow(hWnd,SW_VISIBLE)来显示窗口,这个函数就是添加了一个WS_VISIBLE风格,然后自己调用消息循环来处理窗口消息!
若要关闭非模态对话框只要在自己的窗口函数里调用DestroyWindow(hWnd)就可以了 该函数会再次发送WM_DESTROY消息 来摧毁非模态对话框!
对于调用自己的窗口函数 会根据需要处理的消息来判断 如果需要处理则自己处理 然后返回TRUE表示已经处理了 否则返回0 内建对话框过程会处理这个消息 唯一注意的就是内建对话框过程不会处理WM_INITDIALOG消息!
这里需要理解的就是窗口和创建这个窗口的线程之间的关系 如果DestroyWindow摧毁窗口后不再手动发送一个PostQuitMessage消息来使得循环退出的 GetMessage如果取得的是WM_QUIT 在winuser定义:#define WM_QUIT 0x0012 会返回0,其他消息返回非0,如果消息循环判断接受到这个WM_QUIT则退出循环 这样线程才会结束 否则可能窗口摧毁了这个窗口线程还在循环中!
因为非模态对话框是自己写消息循环的 所以可以自己定义什么消息下就退出循环!比如WM_QUIT~
对话框的窗口回调函数为 (我机器上的地址) 77D3E577 : USER32.DefDlgProc
77D3E577 USER32.DefDlgProcA 8BFF mov edi, edi
77D3E579 /. 55 push ebp
77D3E57A |. 8BEC mov ebp, esp
77D3E57C |. 8B4D 08 mov ecx, dword ptr [ebp+8]
77D3E57F |. E8 5C9FFDFF call 77D184E0
77D3E584 |. 85C0 test eax, eax
77D3E586 |. 74 11 je short 77D3E599
77D3E588 |. 6A 01 push 1
77D3E58A |. FF75 14 push dword ptr [ebp+14]
77D3E58D |. FF75 10 push dword ptr [ebp+10]
77D3E590 |. FF75 0C push dword ptr [ebp+C]
77D3E593 |. 50 push eax
77D3E594 |. E8 1855FEFF call 77D23AB1
77D3E599 |> 5D pop ebp
77D3E59A \. C2 1000 retn 10
当有消息来时先调用USER32.DefDlgProcA,然后在其中用下面一句调用用户定义的函数
77D18731 . FF55 08 call dword ptr [ebp+8] ; test.00401070
如果没有则返回由默认窗口过程继续处理!
WM_SETFONT WM_INITDIALOG 都要经过这个用户自定义函数处理下!
该函数用EDI存储消息代码,然后比较进行选择执行相关代码!
ENDDIALOG发送WM_NULL消息,然后发送WM_DESTROY(摧毁窗口)WM_NCDESTROY,
77D27603 . 6A 01 push 1 ; /RemoveMsg = PM_REMOVE
77D27605 . 53 push ebx ; |MsgFilterMax
77D27606 . 53 push ebx ; |MsgFilterMin
77D27607 . 53 push ebx ; |hWnd
77D27608 . 8D45 E0 lea eax, dword ptr [ebp-20] ; |
77D2760B . 50 push eax ; |pMsg
77D2760C . E8 8A1CFFFF call PeekMessageW ; \PeekMessageW
77D27611 . 85C0 test eax, eax
77D27613 . 0F84 A0000000 je 77D276B9
77D27619 . 837D E4 12 cmp dword ptr [ebp-1C], 12
77D2761D . 895D FC mov dword ptr [ebp-4], ebx
77D27620 . 0F84 C2A50000 je 77D31BE8
77D27626 . F646 14 20 test byte ptr [esi+14], 20
77D2762A . 0F85 99290100 jnz 77D39FC9
77D27630 > 8D45 E0 lea eax, dword ptr [ebp-20]
77D27633 . 50 push eax ; /pMsg
77D27634 . FF75 08 push dword ptr [ebp+8] ; |hWnd
77D27637 . E8 E8FDFFFF call IsDialogMessageW ; \IsDialogMessageW
77D2763C . 85C0 test eax, eax
77D2763E . 0F84 CB000000 je 77D2770F
77D27644 > 395D 10 cmp dword ptr [ebp+10], ebx
77D27647 . 0F84 AFA50000 je 77D31BFC
77D2764D > 8B4D 08 mov ecx, dword ptr [ebp+8]
77D27650 . B2 01 mov dl, 1
77D27652 . E8 CA510000 call 77D2C821
77D27657 . 85C0 test eax, eax
77D27659 .^ 75 98 jnz short 77D275F3
77D2765B > 53 push ebx ; /ObjectId
77D2765C . 53 push ebx ; |ObjectTypeId
77D2765D . FF75 08 push dword ptr [ebp+8] ; |hWnd
77D27660 . 6A 11 push 11 ; |Event = EVENT_SYSTEM_DIALOGEND
77D27662 . E8 64230000 call NotifyWinEvent ; \NotifyWinEvent
77D27667 . 8B4D 08 mov ecx, dword ptr [ebp+8]
77D2766A . B2 01 mov dl, 1
77D2766C . E8 B0510000 call 77D2C821
77D27671 . 85C0 test eax, eax
77D27673 . 5F pop edi
77D27674 . 74 3D je short 77D276B3
77D27676 . 8BB6 A8000000 mov esi, dword ptr [esi+A8]
77D2767C . 3BF3 cmp esi, ebx
77D2767E . 0F84 71A50000 je 77D31BF5
77D27684 . 8B76 18 mov esi, dword ptr [esi+18]
77D27687 > FF75 08 push dword ptr [ebp+8] ; /hWnd
77D2768A . E8 0D3B0000 call DestroyWindow ; \DestroyWindow
77D2768F . 395D 0C cmp dword ptr [ebp+C], ebx
77D27692 . 74 1D je short 77D276B1
77D27694 . 6A 0C push 0C
77D27696 . E8 0B220000 call 77D298A6
77D2769B . 85C0 test eax, eax
77D2769D . 74 12 je short 77D276B1
77D2769F . 6A 06 push 6
77D276A1 . FF75 0C push dword ptr [ebp+C]
77D276A4 . E8 3210FFFF call 77D186DB
77D276A9 . 85C0 test eax, eax
77D276AB . 0F84 37140200 je 77D48AE8
77D276B1 > 8BC6 mov eax, esi
77D276B3 > 5E pop esi
77D276B4 . 5B pop ebx
77D276B5 . C9 leave
77D276B6 . C2 1000 retn 10
77D276B9 > 395D 10 cmp dword ptr [ebp+10], ebx
77D276BC . 0F84 F7A40000 je 77D31BB9
77D276C2 . 395D 0C cmp dword ptr [ebp+C], ebx
77D276C5 . 74 22 je short 77D276E9
77D276C7 . FF75 0C push dword ptr [ebp+C] ; /hWnd
77D276CA . E8 441C0000 call IsWindow ; \IsWindow
77D276CF . 85C0 test eax, eax
77D276D1 . 0F84 09140200 je 77D48AE0
77D276D7 > 395D 0C cmp dword ptr [ebp+C], ebx
77D276DA . 74 0D je short 77D276E9
77D276DC . 3BFB cmp edi, ebx
77D276DE . 74 09 je short 77D276E9
77D276E0 . 395D FC cmp dword ptr [ebp-4], ebx
77D276E3 . 0F84 B9700100 je 77D3E7A2
77D276E9 > 8B4D 08 mov ecx, dword ptr [ebp+8]
77D276EC . B2 01 mov dl, 1
77D276EE . E8 2E510000 call 77D2C821
77D276F3 . 85C0 test eax, eax
77D276F5 .^ 0F84 60FFFFFF je 77D2765B
77D276FB . F646 2B C0 test byte ptr [esi+2B], 0C0
77D276FF .^ 0F85 56FFFFFF jnz 77D2765B
77D27705 . E8 021DFFFF call WaitMessage ; [WaitMessage
77D2770A .^ E9 3EFFFFFF jmp 77D2764D
77D2770F > 8D45 E0 lea eax, dword ptr [ebp-20]
77D27712 . 50 push eax ; /pMsg
77D27713 . E8 DE14FFFF call TranslateMessage ; \TranslateMessage
77D27718 . 8D45 E0 lea eax, dword ptr [ebp-20]
77D2771B . 50 push eax ; /pMsg
77D2771C . E8 E012FFFF call DispatchMessageW ; \DispatchMessageW
77D27721 .^ E9 1EFFFFFF jmp 77D27644
所以自己用CreateWindow创建对话框 类用"#32770" 必须要窗口子类化 把窗口过程设置成自己的 然后处理下就OK!