Featured image of post Windows Hello World In Assembly??? in 2019?

Windows Hello World In Assembly??? in 2019?

Would you WANT TO? .. YES! I DO!

Can you write a Windows API Hello World In Assembly in 2019?

Short answer?

Yes. Long answer?

BUT Why would you do this to yourself?

HAHA

Because its cool..

Actually In the wee days of Windows 3.1 we wrote mostly in C.. And occasionally dipped in to ASM as needed for performance.

Computers were slower back then, so we had to really push things sometimes..

Like not just for fun.. Our computers were much slower.. :)

So lets see if we can do some real bare-metal, old-school, hair-pulling, Windows API madness.


πŸ› οΈ Tools You’ll Need

Before we get into the weeds, let’s make sure you have the right tools. You can’t just yell at the computer in assembly and expect it to listen.

  • MASM (Microsoft Macro Assembler) – Comes with Visual Studio, or you can grab it separately.
  • GoLink – A free linker that plays well with assembly.
  • GoASM – If you prefer it over MASM.
  • Windows SDK – Because we’re working with Windows API.
  • A solid cup of coffee – Trust me, you’ll need it.

✍️ The Assembly Code (MASM Style)

Here it isβ€”the moment you’ve been waiting for. Our lovely Windows GUI Hello World in assembly:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
.386
.model flat, stdcall
option casemap:none

include windows.inc
include user32.inc
include kernel32.inc
include gdi32.inc

includelib user32.lib
includelib kernel32.lib
includelib gdi32.lib

.DATA
    AppName db "HelloWin",0
    ClassName db "WinClass",0
    WindowText db "WinAPI ASM",0
    LabelText db "Name:",0
    ButtonText db "Say Hello",0
    NameBuffer db 256 dup(0)

    hInstance dd ?
    hEdit dd ?
    hWnd dd ?

.CODE

start:
    invoke GetModuleHandle, NULL
    mov hInstance, eax

    invoke LoadIcon, 0, IDI_APPLICATION
    invoke LoadCursor, 0, IDC_ARROW

    ; Register Window Class
    invoke RegisterClass, addr wc
    invoke CreateWindowEx, 0, addr ClassName, addr WindowText, \
        WS_OVERLAPPEDWINDOW, 100, 100, 300, 200, NULL, NULL, hInstance, NULL
    mov hWnd, eax

    ; Create Label
    invoke CreateWindowEx, 0, addr LabelText, addr LabelText, WS_VISIBLE or WS_CHILD, \
        20, 20, 50, 20, hWnd, NULL, hInstance, NULL

    ; Create Edit Box
    invoke CreateWindowEx, WS_EX_CLIENTEDGE, addr LabelText, NULL, \
        WS_VISIBLE or WS_CHILD or WS_BORDER or ES_AUTOHSCROLL, \
        80, 20, 150, 20, hWnd, addr hEdit, hInstance, NULL

    ; Create Button
    invoke CreateWindowEx, 0, addr ButtonText, addr ButtonText, WS_VISIBLE or WS_CHILD, \
        80, 50, 100, 30, hWnd, 1, hInstance, NULL

    ; Show the Window
    invoke ShowWindow, hWnd, SW_SHOWNORMAL
    invoke UpdateWindow, hWnd

    ; Message loop
msg_loop:
    invoke GetMessage, addr msg, NULL, 0, 0
    cmp eax, 0
    je exit_program

    invoke TranslateMessage, addr msg
    invoke DispatchMessage, addr msg
    jmp msg_loop

exit_program:
    invoke ExitProcess, 0

; Window Procedure
WndProc proc hWnd:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
    cmp uMsg, WM_COMMAND
    je process_command

    cmp uMsg, WM_DESTROY
    je close_window

    invoke DefWindowProc, hWnd, uMsg, wParam, lParam
    ret

process_command:
    cmp wParam, 1
    jne def_proc

    ; Get text from input field
    invoke GetWindowText, hEdit, addr NameBuffer, 255
    invoke MessageBox, hWnd, addr NameBuffer, addr WindowText, MB_OK
    ret

close_window:
    invoke PostQuitMessage, 0
    ret

def_proc:
    invoke DefWindowProc, hWnd, uMsg, wParam, lParam
    ret

WndProc endp

end start

πŸš€ What This Code Does

  1. Registers a window class – Because Windows likes bureaucracy.
  2. Creates the main window – Where all the magic happens.
  3. Creates a label, text field, and button – The UI elements.
  4. Handles button clicks – Reads text from the input field and pops up a MessageBox.
  5. Runs the Windows message loop – Because Windows loves messages.

πŸ” Breaking Down the Assembly Code

If you didn’t run away the first time you saw the assembly code, you probably noticed it’s doing a few key things:

  1. Setting up the application – Registering a window class and creating a main window.
  2. Creating UI elements – Label, text field, and button.
  3. Handling Windows messages – Because Windows apps are event-driven.
  4. Processing button clicks – Fetching input text and displaying a message box.

πŸ—οΈ Step 1: Setting Up the Window Class

1
2
invoke GetModuleHandle, NULL
mov hInstance, eax
  • GetModuleHandle fetches the instance handle of the application.
  • mov hInstance, eax stores it for later use.
1
invoke RegisterClass, addr wc
  • Registers a window class with Windows, telling it what kind of window we want.

πŸ–ΌοΈ Step 2: Creating the Window and UI Elements

1
2
3
invoke CreateWindowEx, 0, addr ClassName, addr WindowText, \
    WS_OVERLAPPEDWINDOW, 100, 100, 300, 200, NULL, NULL, hInstance, NULL
mov hWnd, eax
  • This creates the main window and stores the handle in hWnd.

We repeat this process for:

  • Label: "Name:"
  • Text Field: ES_AUTOHSCROLL (allows text input)
  • Button: "Say Hello"

πŸ”„ Step 3: The Windows Message Loop

1
2
3
4
5
6
7
8
msg_loop:
    invoke GetMessage, addr msg, NULL, 0, 0
    cmp eax, 0
    je exit_program

    invoke TranslateMessage, addr msg
    invoke DispatchMessage, addr msg
    jmp msg_loop
  • GetMessage retrieves messages from the Windows event queue.
  • TranslateMessage and DispatchMessage send them to the correct window procedure.

πŸ–±οΈ Step 4: Handling Button Clicks

1
2
3
4
5
cmp wParam, 1
jne def_proc
invoke GetWindowText, hEdit, addr NameBuffer, 255
invoke MessageBox, hWnd, addr NameBuffer, addr WindowText, MB_OK
ret
  • If the button is clicked (wParam == 1), we:
    • Get text from the input field
    • Display it in a message box

πŸ”’ Assembly Instructions Used- What they do

InstructionMeaning
movMoves data from one register/memory location to another
cmpCompares two values
jneJumps to a label if values are not equal
jeJumps to a label if values are equal
invokeCalls a Windows API function
jmpJumps unconditionally to a label
retReturns from a function/procedure

πŸ“ The Same Program in C (WinAPI)

Now, let’s rewrite this in C to see how much easier our lives could have been.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE hInst;
HWND hEdit;

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
                   LPSTR lpCmdLine, int nCmdShow) {
    WNDCLASS wc = { 0 };
    wc.lpfnWndProc = WndProc;
    wc.hInstance = hInstance;
    wc.lpszClassName = "WinClass";

    RegisterClass(&wc);
    HWND hWnd = CreateWindow("WinClass", "WinAPI C", WS_OVERLAPPEDWINDOW,
                             100, 100, 300, 200, NULL, NULL, hInstance, NULL);
    ShowWindow(hWnd, nCmdShow);
    UpdateWindow(hWnd);

    MSG msg;
    while (GetMessage(&msg, NULL, 0, 0)) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }
    return msg.wParam;
}

βš–οΈ C vs Assembly

FeatureAssemblyC
ReadabilityNightmare fuelMuch easier to follow
Lines of CodeA tonHalf as much
Memory ControlAbsolute controlHigher-level, but less hassle
PerformanceSlightly fasterStill fast enough
Ease of DebuggingPainfulDebugging tools help a lot
PortabilityNot portableC is far more portable

πŸ† Verdict

  • Use Assembly if you want total control over performance, memory, and execution.
  • Use C if you want readable, maintainable, and scalable code.

πŸ”— References