请求解释Flat Assembler 64位Windows GUI空窗口代码运行机制
64-bit FASM Windows Empty Window Code Full Breakdown
Hey there! Let's walk through this minimal Win64 GUI template line by line—this is the core structure of almost every Windows GUI app, so understanding each piece will give you a solid foundation for writing more complex Win64 GUI apps in assembly.
First, the Header & Import Section
format PE64 GUI 5.0 entry start include 'win64a.inc' section '.idata' import data readable writeable library kernel32,'KERNEL32.DLL',\ user32,'USER32.DLL' include 'api\\kernel32.inc' include 'api\\user32.inc'
format PE64 GUI 5.0: Tells FASM to output a 64-bit Portable Executable (PE) file for the Windows GUI subsystem—this means no console window will pop up alongside your GUI.entry start: Marksstartas the program's entry point (where execution begins).include 'win64a.inc': Pulls in pre-defined macros, constants, and type definitions for Win64 assembly (saves you from writing all that boilerplate yourself).- The
.idatasection: Declares the external DLLs (kernel32.dllfor core system functions,user32.dllfor GUI functions) and imports their APIs—this lets Windows know which system functions your program needs to call.
Data Section (.data)
section '.data' data readable writeable _title TCHAR 'Win64 program template',0 _class TCHAR 'FASMWIN64',0 _error TCHAR 'Startup failed.',0 wc WNDCLASSEX sizeof.WNDCLASSEX,0,WindowProc,0,0,NULL,NULL,NULL,COLOR_BTNFACE+1,NULL,_class,NULL msg MSG
_title,_class,_error: Wide-character strings (TCHARis Unicode in Win64) used for the window title, unique window class name, and error message. The trailing0marks the end of the string.wc WNDCLASSEX: Initializes aWNDCLASSEXstructure—this defines the "blueprint" for your window. Let's break down the initial values:sizeof.WNDCLASSEX: Size of the structure (required for Windows to parse it correctly).0: Window class style (we'll stick with defaults here).WindowProc: The function that will handle all messages sent to windows of this class.0,0: Extra class and window data (unused here).NULL: Placeholder for the app instance handle (we'll fill this in later).NULL,NULL: Placeholders for the window icon and cursor (we'll load system defaults later).COLOR_BTNFACE+1: Sets the window's background color to a light gray (standard button face color).NULL: No menu attached to this window class._class: Links this structure to our unique window class name.NULL: Placeholder for the small icon (we'll set this later).
msg MSG: Declares aMSGstructure to store messages that Windows sends to our program.
Code Section (.text): Execution Starts Here
section '.text' code readable executable start: sub rsp,8 ; Make stack dqword aligned invoke GetModuleHandle,0 ;GetModuleHandle,0? mov [wc.hInstance],rax ;wc.hInstance? invoke LoadIcon,0,IDI_APPLICATION ;LoadIcon,0,IDI_APPLICATION? mov [wc.hIcon],rax ;wc.hIcon? mov [wc.hIconSm],rax ;ec.hIconSm? invoke LoadCursor,0,IDC_ARROW ;LoadCursor,0,IDC_ARROW? mov [wc.hCursor],rax ;wc.hCursor? invoke RegisterClassEx,wc ;RegisterClassEx,wc? test rax,rax ;test? jz error invoke CreateWindowEx,0,_class,_title,WS_VISIBLE+WS_DLGFRAME+WS_SYSMENU,128,128,256,192,NULL,NULL,[wc.hInstance],NULL test rax,rax jz error
Let's unpack your marked questions:
sub rsp,8: 64-bit Windows requires the stack to be 16-byte aligned before calling any API. This adjusts the stack pointer to meet that requirement.invoke GetModuleHandle,0:GetModuleHandle(NULL)retrieves the handle of the current executable (your app's instance). Windows needs this to associate your window class with your program.mov [wc.hInstance],rax: Stores the app instance handle in thehInstancefield of ourWNDCLASSEXstructure—this fills in the placeholder we left earlier.invoke LoadIcon,0,IDI_APPLICATION:LoadIcon(NULL, IDI_APPLICATION)loads the default system application icon. UsingNULLtells Windows to use a system-wide resource instead of one from our app.mov [wc.hIcon],rax/mov [wc.hIconSm],rax: Assigns the loaded icon to both the main window icon (title bar) and small icon (taskbar).invoke LoadCursor,0,IDC_ARROW:LoadCursor(NULL, IDC_ARROW)loads the default system arrow cursor.mov [wc.hCursor],rax: Assigns the cursor to our window class, so the arrow shows up when hovering over the window.invoke RegisterClassEx,wc: Registers our window class with Windows. Until this is done, we can't create any windows of this type.test rax,rax: A quick way to check if the return value ofRegisterClassExis 0 (which means it failed). Thetestinstruction performs a bitwise AND ofraxwith itself—ifraxis 0, the zero flag is set.jz error: Jumps to theerrorlabel if the zero flag is set (i.e., registration failed).invoke CreateWindowEx,...: Creates an actual window instance using our registered class. The parameters are:0: No extended window styles._class: Our window class name._title: The window's title bar text.WS_VISIBLE+WS_DLGFRAME+WS_SYSMENU: Window style—makes the window visible, adds a dialog-style border, and includes the system menu (close/minimize buttons).128,128: X/Y position of the window's top-left corner.256,192: Width/height of the window.NULL,NULL: No parent window or menu.[wc.hInstance]: Our app's instance handle.NULL: No extra data to pass to the window.
- The second
test rax,raxandjz errorchecks if window creation failed (returns 0) and jumps to error handling if so.
The Message Loop (msg_loop)
msg_loop: ;What does this function? invoke GetMessage,msg,NULL,0,0 cmp eax,1 jb end_loop jne msg_loop invoke TranslateMessage,msg invoke DispatchMessage,msg jmp msg_loop
This is the heart of any Windows GUI app—it's responsible for receiving and processing messages from the system:
invoke GetMessage,msg,NULL,0,0: Fetches the next message from the system's message queue and stores it in themsgstructure. Returns:1if a normal message was received.0if theWM_QUITmessage is received (telling the app to exit).-1if an error occurred.
cmp eax,1/jb end_loop: If the return value is less than 1 (either 0 or -1), jump toend_loopto exit the program.jne msg_loop: If the return value isn't 1, loop back to fetch the next message (this handles edge cases, though in practice,GetMessagereturning 0 would have already triggered thejbjump).invoke TranslateMessage,msg: Converts virtual-key messages (like keyboard presses) into character messages (so you can handle text input later).invoke DispatchMessage,msg: Sends the message to our window procedure (WindowProc) to be processed.jmp msg_loop: Loop back to fetch the next message.
Error Handling & Exit
error: invoke MessageBox,NULL,_error,NULL,MB_ICONERROR+MB_OK end_loop: invoke ExitProcess,[msg.wParam]
error: If window class registration or window creation fails, pops up an error message box with an exclamation icon and OK button.end_loop: CallsExitProcessto terminate the program, using thewParamfrom theWM_QUITmessage (usually 0) as the exit code.
Window Procedure (WindowProc)
proc WindowProc uses rbx rsi rdi, hwnd,wmsg,wparam,lparam ;? ; Note that first four parameters are passed in registers, ; while names given in the declaration of procedure refer to the stack ; space reserved for them - you may store them there to be later accessible ; if the contents of registers gets destroyed. This may look like: ; mov [hwnd],rcx ; mov [wmsg],edx ; mov [wparam],r8 ; mov [lparam],r9 cmp edx,WM_DESTROY je .wmdestroy .defwndproc: ;What does this? invoke DefWindowProc,rcx,rdx,r8,r9 jmp .finish .wmdestroy: invoke PostQuitMessage,0 xor eax,eax .finish: ret endp
This is the function that handles all messages sent to our window:
proc WindowProc uses rbx rsi rdi, hwnd,wmsg,wparam,lparam: Defines the procedure.uses rbx rsi rditells FASM to save these registers (they're non-volatile in 64-bit Windows, meaning we have to preserve their values for the caller). The parametershwnd,wmsg,wparam,lparamare mapped to registers in Win64 calling convention:rcx = hwnd(window handle)rdx = wmsg(message ID, likeWM_DESTROY)r8 = wparam(first message-specific parameter)r9 = lparam(second message-specific parameter)
The comment explains you can store these register values to the stack variables if you need to reuse them after modifying the registers.
cmp edx,WM_DESTROY: Checks if the message isWM_DESTROY(sent when the user closes the window).je .wmdestroy: Jumps to theWM_DESTROYhandler if the message matches..defwndproc:: Handles all messages we don't explicitly process.invoke DefWindowProc,rcx,rdx,r8,r9calls the system's default window procedure, which takes care of standard behavior like resizing, repainting, and closing the window frame. We then jump to.finishto return the result..wmdestroy:: When the window is closed:invoke PostQuitMessage,0: Sends aWM_QUITmessage to the message loop, which triggers the loop to exit.xor eax,eax: Sets the return value to 0 (required forWM_DESTROYhandling).
.finish:: Returns to the caller (viaret) with the appropriate result inrax.
内容的提问来源于stack exchange,提问作者Julian Stanev
相关产品推荐
相关产品推荐

