Pages

vineri, 10 aprilie 2026

FASM : mouse crosshair with lines on the window GDI.

For a year now, it keeps hacking me on Windows. And when I am in a bad mood, I turn to complex things. Today, I wanted to see if I could make a functional assembly code with Microsoft's Copilot artificial intelligence and my assembly knowledge with FASM. Here is what resulted.
The program is a Win32 GUI application written in FASM that draws a crosshair (vertical + horizontal line) following the mouse cursor inside a window classic GDI.
1. Window Setup
The app starts by registering a Win32 window class (WNDCLASSEX) and creating a standard overlapped window. Nothing unusual here — just the classic Win32 boilerplate.
2. Message Loop
The program enters the main loop:
  • GetMessage
  • TranslateMessage
  • DispatchMessage
This keeps the window responsive and forwards events to the window procedure.
3. Tracking the Mouse
Whenever the mouse moves inside the window, Windows sends a WM_MOUSEMOVE message. The program extracts the X and Y coordinates from lParam:
  • LOWORD(lParam) → X
  • HIWORD(lParam) → Y
These values are stored and the window is invalidated so it can be repainted.
4. Drawing the Crosshair (GDI)
All drawing happens inside WM_PAINT using classic GDI:
  • MoveToEx
  • LineTo
  • Ellipse
  • TextOut
  • FillRect
The steps are:
  • Clear the client area
  • Get the window’s current size (GetClientRect)
  • Draw a vertical line at the mouse’s X position
  • Draw a horizontal line at the mouse’s Y position
  • Draw a small circle at the intersection
  • Print the coordinates in the corner
Because the client size is read dynamically, the crosshair always stretches across the entire window — no matter how it’s resized.
See the source code
; mouse_crosshair.asm
format PE GUI 4.0
entry start
include "win32a.inc"

WM_MOUSEMOVE = 0x0200

section '.data' data readable writeable

    szClass db "MouseGraph",0
    szTitle db "Mouse Crosshair Demo",0

    mouseX dd 0
    mouseY dd 0

    fmt    db "X=%d  Y=%d",0
    buffer db 64 dup(0)

    rc  RECT
    ps  PAINTSTRUCT
    wc  WNDCLASSEX
    msg MSG

section '.code' code readable executable

start:
    invoke GetModuleHandle,0
    mov [wc.hInstance],eax

    mov [wc.cbSize],sizeof.WNDCLASSEX
    mov [wc.style],CS_HREDRAW or CS_VREDRAW
    mov [wc.lpfnWndProc],WndProc
    mov [wc.cbClsExtra],0
    mov [wc.cbWndExtra],0
    mov [wc.hIcon],0
    mov [wc.hIconSm],0
    mov [wc.lpszMenuName],0
    mov [wc.lpszClassName],szClass
    mov [wc.hbrBackground],COLOR_WINDOW+1

    invoke LoadCursor,0,IDC_ARROW
    mov [wc.hCursor],eax

    invoke RegisterClassEx,wc

    invoke CreateWindowEx,0,szClass,szTitle,\
           WS_VISIBLE+WS_OVERLAPPEDWINDOW,\
           200,200,800,600,0,0,[wc.hInstance],0

msg_loop:
    invoke GetMessage,msg,0,0,0
    test eax,eax
    jz exit
    invoke TranslateMessage,msg
    invoke DispatchMessage,msg
    jmp msg_loop

exit:
    invoke ExitProcess,0

; ---------------------------------------------------------
proc WndProc hWnd,uMsg,wParam,lParam

    cmp [uMsg],WM_MOUSEMOVE
    je .mouse

    cmp [uMsg],WM_PAINT
    je .paint

    cmp [uMsg],WM_DESTROY
    je .destroy

.def:
    invoke DefWindowProc,[hWnd],[uMsg],[wParam],[lParam]
    ret

; ---------------- WM_MOUSEMOVE ----------------
.mouse:
    mov eax,[lParam]
    and eax,0FFFFh
    mov [mouseX],eax

    mov eax,[lParam]
    shr eax,16
    and eax,0FFFFh
    mov [mouseY],eax

    invoke InvalidateRect,[hWnd],0,TRUE
    ret

; ---------------- WM_PAINT ----------------
.paint:
    invoke BeginPaint,[hWnd],ps
    mov esi,eax ; hdc

    ; clean client
    invoke GetClientRect,[hWnd],rc
    invoke FillRect,esi,rc,COLOR_WINDOW+1

    ; pen red
    invoke CreatePen,PS_SOLID,1,0x0000FF
    mov ebx,eax
    invoke SelectObject,esi,ebx

    ; ---------------- linie verticala (cruce) ----------------
    mov eax,[mouseX]        ; X constant
    mov edx,[rc.bottom]     ; Y max (jos)
    invoke MoveToEx,esi,eax,0,0
    invoke LineTo,esi,eax,edx

    ; ---------------- line  ----------------
    mov eax,[mouseY]        ; Y constant
    mov edx,[rc.right]      ; X max (dreapta)
    invoke MoveToEx,esi,0,eax,0
    invoke LineTo,esi,edx,eax

    ; punct în intersec?ie
    mov eax,[mouseX]
    mov edx,[mouseY]
    invoke Ellipse,esi,eax-4,edx-4,eax+4,edx+4

    ; text coordonate
    invoke wsprintf,buffer,fmt,[mouseX],[mouseY]
    invoke lstrlen,buffer
    invoke TextOut,esi,10,10,buffer,eax

    invoke EndPaint,[hWnd],ps
    ret

; ---------------- WM_DESTROY ----------------
.destroy:
    invoke PostQuitMessage,0
    ret

endp

section '.idata' import data readable
library kernel32,"KERNEL32.DLL",\
        user32,"USER32.DLL",\
        gdi32,"GDI32.DLL"

include "api/kernel32.inc"
include "api/user32.inc"
include "api/gdi32.inc"