最小的 64 位 MASM GUI 应用程序无法正常工作

问题描述 投票:0回答:1

我尝试在汇编中制作一个最小的 64 位 Windows GUI 程序(!)。我使用了 MASM 编译器 (ml64.exe) 和 MASM64 包含文件 (https://masm32.com/board/index.php?topic=10052.0)。我这样做是出于好奇并了解 windows / x86 cpu 实际工作原理。

接下来是整个列表。我用以下方法编译了这个程序: ml64.exe helloworld64.exe /link /subsystem:windows /entry:WinMain

option casemap:none
option prologue:none
option epilogue:none

include win64.inc ; MASM64 include file
include kernel32.inc    ; Handles, modules, paths, etc
include user32.inc      ; Windows, controls, etc

includelib kernel32.Lib
includelib user32.lib

.data
    ClassName byte "MyWinClass", 0, 0, 0
    AppName byte "Testprogramma by Tijs", 0, 0, 0

.data?
    hInstance HINSTANCE ?
    uExitCode dword ?

.code

WinMain proc
    local wc:WNDCLASSEX     ; Create these vars on the stack, hence LOCAL
    local msg:MSG
    local hwnd:HWND
    local sui:STARTUPINFO
    local nCmdShow:dword
    
    ; prologue:
    push rbp
    mov rbp, rsp
    sub rsp, 170h

    ; GetStartupInfoA:
    lea rcx, sui
    call GetStartupInfoA            ; Find out if wShowWindow should be used
    test sui.dwFlags, STARTF_USESHOWWINDOW   
    jz @1
    movzx eax, sui.wShowWindow        ; If the show window flag bit was nonzero, we use wShowWindow
    mov nCmdShow, eax
    jmp @2

@1:
    mov nCmdShow, SW_SHOWDEFAULT        ; Use the default 

@2:
    ; GetModuleHandle:
    mov rcx, NULL           ; Get the instance handle of our app (NULL means ourselves)
    call GetModuleHandle        ; GetModuleHandle will return instance handle in EAX
    mov hInstance, rax

    ; Fill WNDCLASSEX:
    mov wc.cbSize, sizeof WNDCLASSEX    ; Fill in the values in the members of our windowclass
    mov wc.style, CS_HREDRAW or CS_VREDRAW ; Redraw if resized in either dimension
    lea rax, WndProc
    mov wc.lpfnWndProc, rax     ; Our callback function to handle window messages
    mov wc.cbClsExtra, 0        ; No extra class data
    mov wc.cbWndExtra, 0        ; No extra window data
    mov rax, hInstance
    mov wc.hInstance, rax       ; Our instance handle
    mov wc.hbrBackground, COLOR_3DSHADOW+1 ; Default brush colors are color plus one
    mov wc.lpszMenuName, NULL       ; No app menu
    lea rax, ClassName
    mov wc.lpszClassName, rax       ; The window's class name

    ; loadicon
    mov rcx, 0              ; hInstance
    mov rdx, IDI_APPLICATION        ; Use the default application icon (lpIconName)
    call LoadIcon
    mov wc.hIcon, rax
    mov wc.hIconSm, rax

    ; LoadCursor
    mov rcx, 0
    mov rdx, IDC_ARROW          ; Get the default "arrow" mouse cursor
    call LoadCursor
    mov wc.hCursor, rax

    ; RegisterClassExA
    lea rcx, wc
    call RegisterClassExA           ; Register the window class 
    cmp ax, 0               ; Registering failed
    je WinMainRet

    ; CreateWindowExA
    mov rcx, 0              ; Extended style bits, if any
    lea rdx, ClassName          ; The window class name of what we're creating
    lea r8, AppName             ; The window title (our application name)
    mov r9d, WS_OVERLAPPEDWINDOW + WS_VISIBLE ; Window stytle (normal and visible)
    mov eax, CW_USEDEFAULT
    mov dword ptr [rsp + 20], eax       ; X
    mov dword ptr [rsp + 28], eax       ; Y
    mov dword ptr [rsp + 30], 800       ; Our requested width
    mov dword ptr [rsp + 38], 600       ; Our requested height
    mov qword ptr [rsp + 40], NULL      ; Parent window (if we were a child window)
    mov qword ptr [rsp + 48], NULL      ; Menu handle
    mov rax, hInstance
    mov [rsp + 50], rax         ; Our app instance handle
    mov qword ptr [rsp + 58], 0
    call CreateWindowExA
    cmp rax, NULL
    je WinMainRet               ; Fail and bail on NULL handle returned
    mov hwnd, rax           ; Window handle is the result, returned in eax

    ; ShowWindow(hWnd, nCmdShow)
    mov rcx, rax
    mov edx, nCmdShow
    call ShowWindow

    ; UpdateWindow(hWnd)
    mov rcx, hwnd                       ; Force a paint of our window
    call UpdateWindow

MessageLoop:
    lea rcx, msg
    mov rdx, NULL
    mov r8d, 0
    mov r9d, 0
    call GetMessage                     ; Get a message from the application's message queue
    cmp eax, 0                          ; When GetMessage returns 0, it's time to exit
    je DoneMessages

    lea rcx, msg                        ; Translate 'msg'
    call TranslateMessage

    lea rcx, msg                        ; Dispatch 'msg'
    call DispatchMessage

    jmp MessageLoop

DoneMessages:
    mov rax, msg.wParam                 ; Return wParam of last message processed

WinMainRet:
    mov uExitCode, eax

    ; MessageBoxA
    ;mov rcx, NULL
    ;lea rdx, ClassName
    ;lea r8, ClassName
    ;mov r9d, MB_OK
    ;call MessageBoxA

    mov ecx, uExitCode
    call ExitProcess
    
    ; epilogue:
    mov rsp, rbp
    pop rbp
    ret

WinMain endp

WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM

    push rbp
    mov rbp, rsp
    sub rsp, 20h

    cmp edx, WM_DESTROY
    jne NotWMDestroy

    ; WM_DESTROY:
    mov ecx, 0                  ; WM_DESTROY received, post our quit msg
    call PostQuitMessage                ; Quit our application
    xor rax, rax                    ; Return 0 to indicate we handled it
    mov rsp, rbp
    pop rbp
    ret

NotWMDestroy:
    cmp edx, WM_PAINT
    jne Default
    
    ; WM_PAINT:
    xor rax, rax
    mov rsp, rbp
    pop rbp
    ret

Default:
    ; DEFAULT:
    call DefWindowProc              ; Forward message on to default processing and
    mov rsp, rbp
    pop rbp
    ret                     ;   return whatever it does

WndProc endp

end

程序可以运行,但窗口未正确初始化。该窗口的尺寸尽可能最小,只有最小化、调整大小和关闭按钮可见。窗口大小应为 800x600 像素。 我想制作一个文件大小最小的程序。但我不知道如何调试这个程序。 编辑:小丑指出

mov dword ptr [rsp + 20], eax
中的数字及其后面的行是十进制的,但它们应该是十六进制的 (
mov dword ptr [rsp + 20h], eax
)

windows user-interface assembly x86-64
1个回答
0
投票

终于通过安装Masm64 SDK让它工作了。

源代码

来源来自masm32.com上的hutch

windows.asm

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    include C:\masm64\include64\masm64rt.inc
    
    .data?
      hInstance dq ?
      hWnd      dq ?
      hIcon     dq ?
      hCursor   dq ?
      sWid      dq ?
      sHgt      dq ?
      hBrush    dq ?

    .data
      classname db "template_class",0
      caption db "Testprogramma by Tijs",0

    .code

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

entry_point proc

    GdiPlusBegin                    ; initialise GDIPlus

    mov hInstance, rv(GetModuleHandle,0)
    mov hIcon,     rv(LoadIcon,hInstance,10)
    mov hCursor,   rv(LoadCursor,0,IDC_ARROW)
    mov sWid,      rv(GetSystemMetrics,SM_CXSCREEN)
    mov sHgt,      rv(GetSystemMetrics,SM_CYSCREEN)
    mov hBrush,    rv(CreateSolidBrush,00C4C4C4h)

    call main

    GdiPlusEnd                      ; GdiPlus cleanup

    invoke ExitProcess,0

    ret

entry_point endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

main proc

    LOCAL wc      :WNDCLASSEX
    LOCAL lft     :QWORD
    LOCAL top     :QWORD
    LOCAL wid     :QWORD
    LOCAL hgt     :QWORD

    mov wc.cbSize,         SIZEOF WNDCLASSEX
    mov wc.style,          CS_BYTEALIGNCLIENT or CS_BYTEALIGNWINDOW
    mov wc.lpfnWndProc,    ptr$(WndProc)
    mov wc.cbClsExtra,     0
    mov wc.cbWndExtra,     0
    mrm wc.hInstance,      hInstance
    mrm wc.hIcon,          hIcon
    mrm wc.hCursor,        hCursor
    mrm wc.hbrBackground,  hBrush
    mov wc.lpszMenuName,   0
    mov wc.lpszClassName,  ptr$(classname)
    mrm wc.hIconSm,        hIcon

    invoke RegisterClassEx,ADDR wc

    mov wid, 800                            ; Set window width to 800
    mov hgt, 600                            ; Set window height to 600

    mov rax, sWid                           ; calculate offset from left side
    sub rax, wid
    shr rax, 1
    mov lft, rax

    mov rax, sHgt                           ; calculate offset from top edge
    sub rax, hgt
    shr rax, 1
    mov top, rax

  ; ---------------------------------
  ; centre window at calculated sizes
  ; ---------------------------------
    invoke CreateWindowEx,WS_EX_LEFT or WS_EX_ACCEPTFILES, \
                          ADDR classname,ADDR caption, \
                          WS_OVERLAPPEDWINDOW or WS_VISIBLE,\
                          lft,top,wid,hgt,0,0,hInstance,0
    mov hWnd, rax

    call msgloop

    ret

main endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

msgloop proc

    LOCAL msg    :MSG
    LOCAL pmsg   :QWORD

    mov pmsg, ptr$(msg)                     ; get the msg structure address
    jmp gmsg                                ; jump directly to GetMessage()

  mloop:
    invoke TranslateMessage,pmsg
    invoke DispatchMessage,pmsg
  gmsg:
    test rax, rv(GetMessage,pmsg,0,0,0)     ; loop until GetMessage returns zero
    jnz mloop

    ret

msgloop endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

WndProc proc hWin:QWORD,uMsg:QWORD,wParam:QWORD,lParam:QWORD

    LOCAL dfbuff[260]:BYTE

    .switch uMsg
      .case WM_COMMAND
        .switch wParam
          .case 200
            invoke SendMessage,hWin,WM_SYSCOMMAND,SC_CLOSE,NULL
          .case 300
            invoke MsgboxI,hWin, \
                   "Generic 64 bit Template written with ML64.EXE", \
                   "About Generic Template",MB_OK,10
        .endsw

      .case WM_CREATE
        .return 0

      .case WM_DROPFILES
        invoke DragQueryFile,wParam,0,ADDR dfbuff,260
        invoke MsgboxI,hWin,ADDR dfbuff,"Drop File Name",MB_OK,10

      .case WM_CLOSE
        invoke SendMessage,hWin,WM_DESTROY,0,0

      .case WM_DESTROY
        invoke PostQuitMessage,NULL

    .endsw

    invoke DefWindowProc,hWin,uMsg,wParam,lParam

    ret

WndProc endp

; ¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤¤

    end

构建

这假设您已安装 Microsoft Visual Studio 2019。

makeit.bat

@echo on

if not defined DevEnvDir (
  call "C:\Program Files (x86)\Microsoft Visual Studio\2019\Professional\VC\Auxiliary\Build\vcvars64.bat"
)

set appname=window

ml64.exe /c /nologo %appname%.asm

link.exe /SUBSYSTEM:WINDOWS /ENTRY:entry_point /LARGEADDRESSAWARE %appname%.obj

输出窗口(800x600)

© www.soinside.com 2019 - 2024. All rights reserved.