TinmanQC icon

Asm

TinmanQC | PRO | 04/15/21 09:00:49 PM UTC | 0 ⭐ | 14924 👁️ | Never ⏰ | []
ASM (NASM) |

0 B

|

None

|

0 👍

/

0 👎

;-------------------------------------------------------------------------------------------------------------------
; Hello, Windows!  in x86 ASM - (c) 2021 Dave's Garage - Use at your own risk, no warranty!
;-------------------------------------------------------------------------------------------------------------------
 
; Compiler directives and includes
 
.386                        ; Full 80386 instruction set and mode
.model flat, stdcall                ; All 32-bit and later apps are flat. Used to include "tiny, etc"
option casemap:none             ; Preserve the case of system identifiers but not our own, more or less
 
 
; Include files - headers and libs that we need for calling the system dlls like user32, gdi32, kernel32, etc
include \masm32\include\windows.inc     ; Main windows header file (akin to Windows.h in C)
include \masm32\include\user32.inc      ; Windows, controls, etc
include \masm32\include\kernel32.inc        ; Handles, modules, paths, etc
include \masm32\include\gdi32.inc       ; Drawing into a device context (ie: painting)
 
; Libs - information needed to link ou binary to the system DLL callss
 
includelib \masm32\lib\kernel32.lib     ; Kernel32.dll
includelib \masm32\lib\user32.lib       ; User32.dll
includelib \masm32\lib\gdi32.lib        ; GDI32.dll
 
; Forward declarations - Our main entry point will call forward to WinMain, so we need to define it here
 
WinMain proto :DWORD, :DWORD, :DWORD, :DWORD    ; Forward decl for MainEntry 
 
; Constants and Datra
 
WindowWidth equ 640             ; How big we'd like our main window
WindowHeight    equ 480
 
.DATA
 
ClassName       db "MyWinClass", 0      ; The name of our Window class
AppName     db "Dave's Tiny App", 0     ; The name of our main window
 
.DATA?                      ; Uninitialized data - Basically just reserves address space
 
hInstance   HINSTANCE ?         ; Instance handle (like the process id) of our application
CommandLine LPSTR     ?                     ; Pointer to the command line text we were launched with
 
;-------------------------------------------------------------------------------------------------------------------
.CODE                       ; Here is where the program itself lives
;-------------------------------------------------------------------------------------------------------------------
 
MainEntry proc
 
    LOCAL   sui:STARTUPINFOA        ; Reserve stack space so we can load and inspect the STARTUPINFO
 
    push    NULL                ; Get the instance handle of our app (NULL means ourselves)
    call    GetModuleHandle         ; GetModuleHandle will return instance handle in EAX
    mov hInstance, eax          ; Cache it in our global variable
 
    call    GetCommandLineA         ; Get the command line text ptr in EAX to pass on to main
    mov CommandLine, eax
 
    ; Call our WinMain and then exit the process with whatever comes back from it
 
    ; Please check this, I have only typed it, not tested it :-)
 
    lea eax, sui            ; Get the STARTUPINFO for this process
    push    eax
    call    GetStartupInfoA         ; Find out if wShowWindow should be used
    test    sui.dwFlags, STARTF_USESHOWWINDOW   
    jz  @1
    push    sui.wShowWindow         ; If the show window flag bit was nonzero, we use wShowWindow
    jmp @2
@1:
    push    SW_SHOWDEFAULT          ; Use the default 
@2: 
    push    CommandLine
    push    NULL
    push    hInstance
    call    WinMain
 
    push    eax
    call    ExitProcess
 
MainEntry endp
 
; 
; WinMain - The traditional signature for the main entry point of a Windows programa
;
 
WinMain proc hInst:HINSTANCE, hPrevInst:HINSTANCE, CmdLine:LPSTR, CmdShow:DWORD
 
    LOCAL   wc:WNDCLASSEX           ; Create these vars on the stack, hence LOCAL
    LOCAL   msg:MSG
    LOCAL   hwnd:HWND
 
    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
    mov wc.lpfnWndProc, OFFSET WndProc      ; Our callback function to handle window messages
    mov wc.cbClsExtra, 0            ; No extra class data
    mov wc.cbWndExtra, 0            ; No exttra window data
    mov eax, hInstance
    mov wc.hInstance, eax           ; Our instance handle
    mov wc.hbrBackground, COLOR_3DSHADOW+1  ; Default brush colors are color plus one
    mov wc.lpszMenuName, NULL           ; No app menu
    mov wc.lpszClassName, OFFSET ClassName  ; The window's class name
 
    push    IDI_APPLICATION             ; Use the default application icon
    push    NULL    
    call    LoadIcon
    mov wc.hIcon, eax
    mov wc.hIconSm, eax
 
    push    IDC_ARROW               ; Get the default "arrow" mouse cursor
    push    NULL
    call    LoadCursor
    mov wc.hCursor, eax
 
    lea eax, wc
    push    eax
    call    RegisterClassEx             ; Register the window class 
 
    push    NULL                    ; Bonus data, but we have none, so null
    push    hInstance               ; Our app instance handle
    push    NULL                    ; Menu handle
    push    NULL                    ; Parent window (if we were a child window)
    push    WindowHeight                ; Our requested height
    push    WindowWidth             ; Our requested width
    push    CW_USEDEFAULT               ; Y
    push    CW_USEDEFAULT               ; X
    push    WS_OVERLAPPEDWINDOW + WS_VISIBLE    ; Window stytle (normal and visible)
    push    OFFSET AppName              ; The window title (our application name)
    push    OFFSET ClassName            ; The window class name of what we're creating
    push    0                   ; Extended style bits, if any
    call    CreateWindowExA
    cmp eax, NULL
    je  WinMainRet              ; Fail and bail on NULL handle returned
    mov hwnd, eax               ; Window handle is the result, returned in eax
 
    push    eax                 ; Force a paint of our window
    call    UpdateWindow
 
MessageLoop:
 
    push    0
    push    0
    push    NULL
    lea eax, msg
    push    eax
    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 eax, msg                ; Translate 'msg'
    push    eax
    call    TranslateMessage
 
    lea eax, msg                ; Dispatch 'msg'
    push    eax
    call    DispatchMessage
 
    jmp MessageLoop
 
DoneMessages:
    
    mov eax, msg.wParam             ; Return wParam of last message processed
 
WinMainRet:
    
    ret
 
WinMain endp
 
;
; WndProc - Our Main Window Procedure, handles painting and exiting
;
 
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
 
    LOCAL   ps:PAINTSTRUCT              ; Local stack variables
    LOCAL   rect:RECT
    LOCAL   hdc:HDC
 
    cmp uMsg, WM_DESTROY
    jne NotWMDestroy
 
    push    0                   ; WM_DESTROY received, post our quit msg
    call    PostQuitMessage             ; Quit our application
    xor eax, eax                ; Return 0 to indicate we handled it
    ret
 
NotWMDestroy:
 
    cmp uMsg, WM_PAINT
    jne NotWMPaint
 
    lea eax, ps                 ; WM_PAINT received
    push    eax
    push    hWnd
    call    BeginPaint              ; Go get a device context to paint into
    mov hdc, eax
 
    push    TRANSPARENT
    push    hdc
    call    SetBkMode               ; Make text have a transparent background
 
    lea eax, rect               ; Figure out how big the client area is so that we
    push    eax                 ;   can center our content over it
    push    hWnd
    call    GetClientRect
 
    push    DT_SINGLELINE + DT_CENTER + DT_VCENTER
    lea eax, rect
    push    eax
    push    -1
    push    OFFSET AppName
    push    hdc
    call    DrawText                ; Draw text centered vertically and horizontally
 
    lea eax, ps
    push    eax
    push    hWnd
    call    EndPaint                ; Wrap up painting
 
    xor eax, eax                ; Return 0 as no further processing needed
    ret
 
NotWMPaint:
    
    push    lParam
    push    wParam
    push    uMsg
    push    hWnd
    call    DefWindowProc               ; Forward message on to default processing and
    ret                     ;   return whatever it does
 
WndProc endp
 
END MainEntry                       ; Specify entry point, else _WinMainCRTStartup is assumed
 
 

Comments

  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎

    
        
  •  icon
    01/01/70 12:00:00 AM UTC
    Plain Text |

    0 B

    |

    👍

    /

    👎