学习笔记:一个win32asm简单的带控件对话框程序及较详细注释

本文介绍了一个使用MASM编写的Windows应用程序实例,涉及资源文件、Makefile配置、菜单创建及控件交互等内容。通过示例代码展示了如何利用MASM进行Windows环境下的编程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

;一共四个文件:
;.asm  masm代码,调用ml编译
;.rc   资源文件,调用rc编译
;makefile  makefile文件,被nmake解释,它调用ml、rc、link
;make.bat 设置环境,并调用nmake
;编译条件及方法:
;安装vc、masm、必要的话将nmake、rc等程序拷到masm的相应目录(参见bat文件)
;运行make.bat编译链接就会得到可执行程序
;
;make.bat内容
;set Masm32Dir=D:/Masm32
;set include=%Masm32Dir%/Include;%include%
;set lib=%Masm32Dir%/lib;%lib%
;set path=%Masm32Dir%/Bin;%Masm32Dir%;%PATH%
;set Masm32Dir=
;nmake
;
;makefile内容
;NAME=controls
;$(NAME).exe: $(NAME).obj $(NAME).res
;        Link /SUBSYSTEM:WINDOWS /LIBPATH:c:/masm32/lib $(NAME).obj $(NAME).res
;$(NAME).res: $(NAME).rc
;        rc $(NAME).rc
;$(NAME).obj: $(NAME).asm
;        ml /c /coff /Cp $(NAME).asm
;
;controls.rc内容
;#define IDM_HELLO 1
;#define IDM_CLEAR 2
;#define IDM_GETTEXT 3
;#define IDM_EXIT 4
;
;FirstMenu MENU
;{
; POPUP "&Test Controls"
;        {
;         MENUITEM "Say Hello",IDM_HELLO
;         MENUITEM "Clear Edit Box",IDM_CLEAR
;         MENUITEM "Get Text", IDM_GETTEXT
;         MENUITEM SEPARATOR
;         MENUITEM "E&xit",IDM_EXIT
;        }
;}
;
;controls.asm内容如下
;lion tutorial 07 09章内容的结合,StrLen似乎是从linux源代码中拷的
;注释主要是09章的,之前的注释就没加了,本来每行都有注释


.386
.model flat,stdcall
option casemap:none

WinMain proto :DWORD,:DWORD,:DWORD,:DWORD
StrLen  proto :DWORD

include /masm32/include/windows.inc
include /masm32/include/user32.inc
include /masm32/include/kernel32.inc
include /masm32/include/gdi32.inc
includelib /masm32/lib/user32.lib
includelib /masm32/lib/kernel32.lib
includelib /masm32/lib/gdi32.lib

.data
ClassName db "SimpleWinClass",0
AppName  db "Our First Window",0
MenuName db "FirstMenu",0
ButtonClassName db "button",0
ButtonText db "My First Button",0
EditClassName db "edit",0
TestString db "Wow! I'm in an edit box now",0
MouseClick db 0         ; 0=no click yet

.data?
hInstance HINSTANCE ?
CommandLine LPSTR ?
hwndButton HWND ?
hwndEdit HWND ?
buffer db 512 dup(?)
hitpoint POINT <>

.const
ButtonID equ 1
EditID equ 2
IDM_HELLO equ 1
IDM_CLEAR equ 2
IDM_GETTEXT equ 3
IDM_EXIT equ 4

.code

StrLen proc item:DWORD
    push    ebx
    mov     eax,item               ; get pointer to string
    lea     edx,[eax+3]            ; pointer+3 used in the end
  @@:    
    mov     ebx,[eax]              ; read first 4 bytes
    add     eax,4                  ; increment pointer
    lea     ecx,[ebx-01010101h]    ; subtract 1 from each byte
    not     ebx                    ; invert all bytes
    and     ecx,ebx                ; and these two
    and     ecx,80808080h   
    jz      @B                     ; no zero bytes, continue loop
    test    ecx,00008080h          ; test first two bytes
    jnz     @F
    shr     ecx,16                 ; not in the first 2 bytes
    add     eax,2
  @@:
    shl     cl,1                   ; use carry flag to avoid branch
    sbb     eax,edx                ; compute length
    pop     ebx

    ret

StrLen endp

start:
 invoke GetModuleHandle, NULL
 mov    hInstance,eax
 invoke GetCommandLine
 mov CommandLine,eax
 invoke WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT
 invoke ExitProcess,eax
WinMain proc hInst:HINSTANCE,hPrevInst:HINSTANCE,CmdLine:LPSTR,CmdShow:DWORD
 LOCAL wc:WNDCLASSEX
 LOCAL msg:MSG
 LOCAL hwnd:HWND
 mov   wc.cbSize,SIZEOF WNDCLASSEX
 mov   wc.style, CS_HREDRAW or CS_VREDRAW
 mov   wc.lpfnWndProc, OFFSET WndProc
 mov   wc.cbClsExtra,NULL
 mov   wc.cbWndExtra,NULL
 push  hInst
 pop   wc.hInstance
 mov   wc.hbrBackground,COLOR_BTNFACE+1
 mov   wc.lpszMenuName,OFFSET MenuName
 mov   wc.lpszClassName,OFFSET ClassName
 invoke LoadIcon,NULL,IDI_APPLICATION
 mov   wc.hIcon,eax
 mov   wc.hIconSm,eax
 invoke LoadCursor,NULL,IDC_ARROW
 mov   wc.hCursor,eax
 invoke RegisterClassEx, addr wc
 INVOKE CreateWindowEx,WS_EX_CLIENTEDGE,ADDR ClassName,ADDR AppName,/
           WS_OVERLAPPEDWINDOW,CW_USEDEFAULT,/
           CW_USEDEFAULT,600,400,NULL,NULL,/
           hInst,NULL
 mov   hwnd,eax
 INVOKE ShowWindow, hwnd,SW_SHOWNORMAL
 INVOKE UpdateWindow, hwnd
 .WHILE TRUE
                INVOKE GetMessage, ADDR msg,NULL,0,0
                .BREAK .IF (!eax)
                INVOKE TranslateMessage, ADDR msg
                INVOKE DispatchMessage, ADDR msg
 .ENDW
 mov     eax,msg.wParam
 ret
WinMain endp
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
 LOCAL hdc:HDC
 LOCAL ps:PAINTSTRUCT
 .IF uMsg==WM_DESTROY
  invoke PostQuitMessage,NULL
 .ELSEIF uMsg==WM_CREATE
  ;使用子窗口控件时,先调用CreateWindow 或 CreateWindowEx。
  ;在这里由于WINDOWS 已经注册了这些子控件,所以无须我们再注册。当然我们不能改变它们的类名称。
  ;其他必须指定的参数还有父窗口的句柄和将要产生的子控件的ID号。
  ;一般我们应在父窗口的WM_CREATE消息中产生字控件。
  invoke CreateWindowEx,WS_EX_CLIENTEDGE, ADDR EditClassName,NULL,/
                        WS_CHILD or WS_VISIBLE or WS_BORDER or ES_LEFT or/
                        ES_AUTOHSCROLL,/
                        50,35,200,25,hWnd,EditID,hInstance,NULL
  mov  hwndEdit,eax
  invoke SetFocus, hwndEdit ;调用SetFocus把焦点设到编辑控件上以便用户立即可以输入
  invoke CreateWindowEx,NULL, ADDR ButtonClassName,ADDR ButtonText,/
                        WS_CHILD or WS_VISIBLE or BS_DEFPUSHBUTTON,/
                        75,70,140,25,hWnd,ButtonID,hInstance,NULL
  mov  hwndButton,eax
 .ELSEIF uMsg==WM_COMMAND
  ;子控件产生后,当其状态改变时将会向父窗口发送消息。
  ;子控件向父窗口发送的消息是WM_COMMAND,并在传递的参数wPara的底位中包括控件的ID号,
  ;消息号在wParam的高位,lParam中则包括了子控件的窗口的句柄。
  ;父窗口也可以通过调用函数SendMessage向子控件发送消息,其中第一个参数是子控件的窗口句柄,
  ;第二个参数是要发送的消息号,附加的参数可以在wParam和lParam中传递,
  ;其实只要知道了某个窗口的句柄就可以用该函数向其发送相关消息。
  
  ;  Low word of wParam  High word of wParam  lParam
  ;Menu   Menu ID    0     0
  ;Control  Control ID   Notification code  Child Window Handle

  mov eax,wParam 
   ;因为菜单和控件的ID号可能相同,而且子窗口空间的消息号也有可能为0。
  .IF lParam==0 ;lParam中则包括了子控件的窗口的句柄
   .IF ax==IDM_HELLO
    ;SetWindowText是一个通用函数,即可以用它来设定一个窗口的标题,
    ;也可以用它来改变一个按钮上的文字。
    invoke SetWindowText,hwndEdit,ADDR TestString
    invoke SendMessage,hwndEdit,WM_KEYDOWN,VK_END,NULL
   .ELSEIF ax==IDM_CLEAR
    invoke SetWindowText,hwndEdit,NULL
   .ELSEIF  ax==IDM_GETTEXT
    ;要得到按钮上的文字,则调用GetWindowText
    invoke GetWindowText,hwndEdit,ADDR buffer,512
    invoke MessageBox,NULL,ADDR buffer,ADDR AppName,MB_OK
   .ELSE
    invoke DestroyWindow,hWnd
   .ENDIF
  .ELSE
   .IF ax==ButtonID ;wPara的底位中包括控件的ID号
    shr eax,16 ;消息号在wParam的高位
    .IF ax==BN_CLICKED
     ;发送一条IDM_GETTEXT消息让主窗口过程处理,
     ;这只要把传送的消息设置为WM_COMMAND,再把wParam的低字节中设置为IDM_GETTEXT即可
     invoke SendMessage,hWnd,WM_COMMAND,IDM_GETTEXT,0
    .ENDIF
   .ENDIF
  .ENDIF
 .ELSEIF uMsg==WM_LBUTTONDOWN
  ;对于所有的消息,窗口过程函数传入的参数lParam包含了鼠标的位置,其中底位为x坐标,高位为y坐标,
  ;这些坐标值都是相对于窗口客户区的左上角的值,wParam中则包含了鼠标按钮的状态。
  mov eax,lParam
  and eax,0ffffh
  mov hitpoint.x,eax
  mov eax,lParam
  shr eax,16
  mov hitpoint.y,eax
  mov MouseClick,TRUE
  invoke InvalidateRect,hWnd,NULL,TRUE
 .ELSEIF uMsg==WM_PAINT
  invoke BeginPaint,hWnd, ADDR ps
  mov    hdc,eax
  .IF MouseClick
;   invoke lstrlen,ADDR AppName
   invoke StrLen,ADDR AppName
   invoke TextOut,hdc,hitpoint.x,hitpoint.y,ADDR AppName,eax
  .ENDIF
  invoke EndPaint,hWnd, ADDR ps
 .ELSE
  invoke DefWindowProc,hWnd,uMsg,wParam,lParam
  ret
 .ENDIF
 xor    eax,eax
 ret
WndProc endp

end start

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值