首页
社区
课程
招聘
[旧帖] [原创]发一个罗云斌的menu代码的详细解释,有不足和错误之处还望各位多多指教,多谢 0.00雪花
发表于: 2010-12-10 22:18 986

[旧帖] [原创]发一个罗云斌的menu代码的详细解释,有不足和错误之处还望各位多多指教,多谢 0.00雪花

2010-12-10 22:18
986
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Sample code for < Win32ASM Programming 2nd Edition>
; by 罗云彬, http://asm.yeah.net
;程序详细注释:by 塘鱼
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Menu.asm
; 菜单资源的使用例子
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 使用 nmake 或下列命令进行编译和链接:
; ml /c /coff Menu.asm
; rc Menu.rc
; Link /subsystem:windows Menu.obj Menu.res
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .386
                .model flat, stdcall
                option casemap :none
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Include 文件定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
include                windows.inc
include                user32.inc
includelib        user32.lib
include                kernel32.inc
includelib        kernel32.lib
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; Equ 等值定义
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
ICO_MAIN        equ                1000h        ;图标
IDM_MAIN        equ                2000h        ;菜单
IDA_MAIN        equ                2000h        ;加速键
IDM_OPEN        equ                4101h
IDM_OPTION        equ                4102h
IDM_EXIT        equ                4103h
IDM_SETFONT        equ                4201h
IDM_SETCOLOR        equ                4202h
IDM_INACT        equ                4203h
IDM_GRAY        equ                4204h
IDM_BIG                equ                4205h
IDM_SMALL        equ                4206h
IDM_LIST        equ                4207h
IDM_DETAIL        equ                4208h
IDM_TOOLBAR        equ                4209h
IDM_TOOLBARTEXT        equ                4210h
IDM_INPUTBAR        equ                4211h
IDM_STATUSBAR        equ                4212h
IDM_HELP        equ                4301h
IDM_ABOUT        equ                4302h
IDM_APP                equ                4303h                        ;塘鱼定义的测试参数
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .data?
hInstance        dd                ?                        ;实例句柄
hWinMain        dd                ?                        ;主程序句柄
hMenu                dd                ?                        ;主菜单句柄
hSubMenu        dd                ?                        ;子菜单句柄,注意这里的子菜单也必须是一个顶层菜单不能是二级菜单即;popup类型的
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 数据段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .const
szClassName        db        'Menu Example',0                        ;定义程序窗口类名
szCaptionMain        db        'Menu',0                                ;定义程序名字
szMenuHelp        db        '帮助主题(&H)',0                        ;定义菜单窗口HELP
szMenuAbout        db        '关于本程序(&A)...',0
szCaption        db        '菜单选择',0                               
szFormat        db        '您选择了菜单命令:%08x',0                ;窗口格式定义
szApp                db        '塘鱼',0                                ;塘鱼定义的一个测试参数
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
; 代码段
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                .code
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_DisplayMenuItem        proc        _dwCommandID                        ;显示窗口菜单ID的函数,读者可以比较,是否和资源文件中的定义一致
                        local        @szBuffer[256]:byte                ;预定义一个256字节的区域作为缓冲区;buffer
                               
                pushad                                                ;函数开始时,保护好现场
                invoke        wsprintf,addr @szBuffer,addr szFormat,_dwCommandID                ;调用wsprintf函数格式化字符串format
                invoke        MessageBox,hWinMain,addr @szBuffer,offset szCaption,MB_OK        ;调用窗口函数,显示格式化好了的字符串,其在buffer去中
                popad                                                ;函数结束后还原现场,pop掉所有被保护的参数
                ret                                                ;程序从此地返回

_DisplayMenuItem        endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_Quit                proc                                                ;退出程序
                               
                invoke        DestroyWindow,hWinMain                        ;销毁程序窗口
                invoke        PostQuitMessage,NULL                        ;发送结束消息循环指令,从此退出循环,这个过程不可更改
                ret                                                ;程序从此地返回

_Quit                endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_ProcWinMain        proc        uses ebx edi esi hWnd,uMsg,wParam,lParam                ;过程处理程序的初始化定义
                local        @stPos:POINT                                                ;定义了一个结构体:POINT,用来获取鼠标光标的信息
                local        @hSysMenu                                                ;定义了系统菜单的句柄

                mov        eax,uMsg                                                ;将消息结构体Msg的值放到eax中,分支处理eax
                .if        eax ==        WM_CREATE                                        ;发出创建窗口命令
                        invoke        GetSubMenu,hMenu,1                                ;获得子菜单句柄,这里是查看菜单,因为:npos被指定为1
                        mov        hSubMenu,eax
;********************************************************************
;        在系统菜单中添加菜单项
;********************************************************************
                        invoke        GetSystemMenu,hWnd,FALSE                        ;获取系统菜单句柄,并用AppendMenu函数添加命令
                        mov        @hSysMenu,eax
                        invoke        AppendMenu,@hSysMenu,MF_SEPARATOR,0,NULL               
                        ;调用添加菜单函数,添加HELP和ABOUT菜单到系统菜单上
                        invoke        AppendMenu,@hSysMenu,0,IDM_HELP,offset szMenuHelp               
                        invoke        AppendMenu,@hSysMenu,0,IDM_ABOUT,offset szMenuAbout
                        ;这时候你可以做个小实验尝试一下即取消我注释掉的自己添加的菜单,编译连接。
                        ;invoke        AppendMenu,@hSysMenu,0,IDM_APP,offset        szApp
                       
;********************************************************************
; 处理菜单及加速键消息
;********************************************************************
                .elseif        eax ==        WM_COMMAND                                       
                        invoke        _DisplayMenuItem,wParam                                ;调用显示菜单函数显示菜单命令ID读者可以和资源文件中的定义比较,呵呵一定是一模一样的
                        mov        eax,wParam                                        ;wParam中间存放的是通知码和命令ID
                        movzx        eax,ax                                                ;将ax扩展成32位,这里的作用是忽视掉由加速键发送的命令,将其一并处理,这样做的好处是精简代码,把高16位扩展成了0
                        .if        eax ==        IDM_EXIT                                ;分支判断程序是否结束
                                call        _Quit                                        ;如果结束,调用退出函数_quit
                        .elseif        eax >=        IDM_TOOLBAR && eax <= IDM_STATUSBAR        ;程序检查,IDM_TOORBAR到IDM_STATUSBAR之间的命令是否被选中
                                mov        ebx,eax                                        ;如果被选中,用ebx保存被选定的命令ID
                                invoke        GetMenuState,hMenu,ebx,MF_BYCOMMAND        ;调用getmenustate函数检查菜单的状态,由于uflag中定义的是me_bycommand所以使用的是命令ID形式
                                .if        eax ==        MF_CHECKED                        ;检测命令ID是否被选中,如果选中则撤销选中
                                        mov        eax,MF_UNCHECKED
                                .else
                                        mov        eax,MF_CHECKED                        ;检测命令ID是否被选中,如果未被选中则选中
                                .endif
                                invoke        CheckMenuItem,hMenu,ebx,eax                ;调用checkmenuitem函数,将IMD_BIG和IDM_DETAIL定义为互斥空间,在此区间内永远只有一个被选中
                        .elseif        eax >=        IDM_BIG && eax <= IDM_DETAIL
                                invoke        CheckMenuRadioItem,hMenu,IDM_BIG,IDM_DETAIL,eax,MF_BYCOMMAND        ;调用checkmenuradioitem函数检测互斥空间,eax中是被选中的命令ID其余的将被撤销
                        .endif
;********************************************************************
; 处理系统菜单消息
;********************************************************************
                .elseif        eax == WM_SYSCOMMAND                                                ;调用WM_SYSCOMMAND命令处理系统命令
                        mov        eax,wParam                                                ;这一步主要是为了把wparam的高字节扩展成0
                        movzx        eax,ax                                                        ;可以方便程序一并处理加速键和菜单命令,可以简化程序
                        .if        eax == IDM_HELP || eax == IDM_ABOUT || eax == IDM_APP        ;这是我们自己添加修改的系统菜单,我们调用_displaymenutiem函数
                                invoke        _DisplayMenuItem,wParam                                ;可以让她显示出命令ID这是会和我们资源中的定义是一样的
                        .else                                                               
                                invoke        DefWindowProc,hWnd,uMsg,wParam,lParam                ;调用DefWindowProc函数是为了处理默认的系统消息,如放大移动缩小还原
                                ret                                                        ;程序从此地返回
                        .endif
;********************************************************************
; 按下右键时弹出一个POPUP菜单
;********************************************************************
                .elseif eax == WM_RBUTTONDOWN                                                ;右键菜单需要调用消息,WM_RBUTTONDOWN
                        invoke        GetCursorPos,addr @stPos                                ;首先获取鼠标信息,存入以定义的结构体:@stPos
                        invoke        TrackPopupMenu,hSubMenu,TPM_LEFTALIGN,@stPos.x,@stPos.y,NULL,hWnd,NULL                ;调用函数TrackPopupMenu从客服区单击鼠标的方式弹出右键菜单@stPos.x,@stPos.y是结构体,@stPos中存放鼠标位置的参数
;********************************************************************
                .elseif        eax ==        WM_CLOSE                                                ;收到关闭窗口的命令,调用QUTI函数销毁窗口,这一过程不可逆转
                        call        _Quit
;********************************************************************
                .else
                        invoke        DefWindowProc,hWnd,uMsg,wParam,lParam                        ;否则按照默认方式处理窗口
                        ret
                .endif
;********************************************************************
                xor        eax,eax                                                                ;清空eax的值并返回
                ret

_ProcWinMain        endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
_WinMain        proc
                local        @stWndClass:WNDCLASSEX                        ;定义WNDCLASSEX结构体用来存储窗口风格
                local        @stMsg:MSG                                ;定义消息结构体,用来给过程处理函数执行
                local        @hAccelerator                                ;定义参数用来保存加速键句柄,以备后面使用

                invoke        GetModuleHandle,NULL                        ;获取实例句柄
                mov        hInstance,eax
                invoke        LoadMenu,hInstance,IDM_MAIN                ;调用loadmenu函数,获取菜单句柄,和要加载资源的命令ID这里是:IDM_MAIN       
                mov        hMenu,eax
                invoke        LoadAccelerators,hInstance,IDA_MAIN        ;获取加速键句柄
                mov        @hAccelerator,eax
;********************************************************************
; 注册窗口类
;********************************************************************
                invoke        RtlZeroMemory,addr @stWndClass,sizeof @stWndClass        ;将结构体参数清0
                invoke        LoadIcon,hInstance,ICO_MAIN                                ;获取默认窗口图标和程序图标
                mov        @stWndClass.hIcon,eax
                mov        @stWndClass.hIconSm,eax
                invoke        LoadCursor,0,IDC_ARROW                                        ;获取默认鼠标指针
                mov        @stWndClass.hCursor,eax
                push        hInstance
                pop        @stWndClass.hInstance                                        ;传递句柄,由于两个操作数都在内存中,所以要用PUSH和POP指令
                mov        @stWndClass.cbSize,sizeof WNDCLASSEX                        ;定义结构体的大小,以方便微软对版本的区别
                mov        @stWndClass.style,CS_HREDRAW or CS_VREDRAW                ;定义窗口风格
                mov        @stWndClass.lpfnWndProc,offset _ProcWinMain                ;最重要的一个参数,用来确定调用窗口过程的地址
                mov        @stWndClass.hbrBackground,COLOR_WINDOW + 1                ;定义窗口的背景,注意的是需要在参数后+1
                mov        @stWndClass.lpszClassName,offset szClassName                ;要创建窗口类的名称
                invoke        RegisterClassEx,addr @stWndClass                        ;注册窗口函数其中Ex,是又16位扩展的风格
;********************************************************************
; 建立并显示窗口
;********************************************************************
                invoke        CreateWindowEx,WS_EX_CLIENTEDGE,\                        ;建立窗口函数
                        offset szClassName,offset szCaptionMain,\
                        WS_OVERLAPPEDWINDOW,\
                        100,100,400,300,\
                        NULL,hMenu,hInstance,NULL
                mov        hWinMain,eax
                invoke        ShowWindow,hWinMain,SW_SHOWNORMAL                        ;显示窗口和刷新客服区
                invoke        UpdateWindow,hWinMain
;********************************************************************
; 消息循环
;********************************************************************
                .while        TRUE                                               
                        invoke        GetMessage,addr @stMsg,NULL,0,0                        ;从消息队列中获取消息
                        .break        .if eax        == 0
                        invoke        TranslateAccelerator,hWinMain,@hAccelerator,addr @stMsg                ;加速键消息处理(注:加速键即快捷键)
                        .if        eax == 0                                                        ;处理完毕后检查eax的值,如果返回值为0,即处理完毕就继续消息的转换和分配,这样做的好处就是,不会把加速键交给DISPATH函数分配执行
                                invoke        TranslateMessage,addr @stMsg                       
                                invoke        DispatchMessage,addr @stMsg                                ;分配消息给过程处理函数
                        .endif
                .endw
                ret

_WinMain        endp
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
start:                                                                                        ;程序入口点
                call        _WinMain
                invoke        ExitProcess,NULL
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
                end        start

[课程]Linux pwn 探索篇!

收藏
免费 0
支持
分享
最新回复 (4)
雪    币: 768
活跃值: (515)
能力值: ( LV13,RANK:460 )
在线值:
发帖
回帖
粉丝
2
够详细~支持!
2010-12-10 23:01
0
雪    币: 0
活跃值: (10)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
3
不错学习了,分析的很精辟
2010-12-10 23:03
0
雪    币: 284
活跃值: (16)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
4
masm写菜单·
2010-12-11 07:39
0
雪    币: 52
活跃值: (35)
能力值: ( LV2,RANK:10 )
在线值:
发帖
回帖
粉丝
5
这个看不懂,汗啊!
2010-12-11 11:11
0
游客
登录 | 注册 方可回帖
返回
//