News:

Masm32 SDK description, downloads and other helpful links
Message to All Guests
NB: Posting URL's See here: Posted URL Change

Main Menu

Get yourself a good ASM "skeleton"

Started by NoCforMe, December 11, 2023, 08:05:35 AM

Previous topic - Next topic

NoCforMe

We seem to have quite a few newbies here, which is a good thing. I'm posting this for them, and for any other members who might not have a good skeleton program.

A skeleton is a ready-made template you can open and use to create a new assembly-language program from, without having to reinvent the wheel each time. I'm guessing that most, if not all, of the longtime programmers here have such a file they use regularly.

Here's mine. It's a basic starting point for a Windows GUI (graphical user interface) program. It creates a window with a status bar, centers the window on the screen, and that's about it. It's up to you to add stuff to it, to make it stand up and do tricks. (The status bar is very handy for displaying debugging messages.)

This is my preferred coding style; it may not be yours. If this isn't to your liking, then go and create a template that you can live with. It'll save you a lot of time and trouble.

My style:
  • Global variables start with a CapitalLetter
  • Local variables start with a lowercaseLetter
  • Symbolic constants (EQUates) start with a $dollarSign
  • Lots of comments! Think about revisiting your code in 6 months or a year

;============================================
; -- Skeleton --
; -- [project title here] --
;
;============================================

.nolist
include \masm32\include\masm32rt.inc
.list

;============================================
; Defines, prototypes, etc.
;============================================

$mainWinWidth EQU 600
$mainWinHeight EQU 500

;===== Window styles: =====
; Change 1st 2 styles to "WS_OVERLAPPEDWINDOW" if you want a resizeable window:
$mainWinStyles EQU WS_CAPTION or WS_SYSMENU or WS_CLIPCHILDREN or WS_VISIBLE

;===== Window background colors: =====
$bkRED EQU 254
$bkGRN EQU 243
$bkBLUE EQU 199

$BkColor EQU $bkRED OR ($bkGRN SHL 8) OR ($bkBLUE SHL 16)

$SBID EQU 1111
$SBX EQU 0
$SBY EQU $mainWinHeight - $SBHeight
$SBWidth EQU $mainWinWidth
$SBHeight EQU 40
$numStatusParts EQU 4

$SB_styles EQU WS_CHILD OR WS_VISIBLE


;============================================
; HERE BE DATA
;============================================
.data

WC WNDCLASSEX < SIZEOF WNDCLASSEX, \
CS_HREDRAW or CS_VREDRAW or CS_BYTEALIGNWINDOW, \
NULL, \ ;lpfnWndProc
NULL, \ ;cbClsExtra
NULL, \ ;cbWndExtra
NULL, \ ;hInstance
NULL, \ ;hIcon
NULL, \ ;hCursor
NULL, \ ;hbrBackground
NULL, \ ;lpszMenuName
NULL, \ ;lpszClassName
NULL > ;hIconSm


StatusParts DD 50, 150, 250, -1

NullString DB 0

MainClassName DB "[class name here]", 0

MainTitleText DB "[window title here]", 0


;============================================
; UNINITIALIZED DATA
;============================================
.data?

MainWinHandle HWND ?
InstanceHandle HINSTANCE ?
StatusHandle HWND ?
SBheight DD ?

;============================================
; CODE LIVES HERE
;============================================
.code


start: INVOKE GetModuleHandle, NULL
MOV InstanceHandle, EAX

CALL WinMain
INVOKE ExitProcess, EAX


;====================================================================
; Mainline proc
;====================================================================

WinMain PROC
LOCAL msg:MSG, brush:HBRUSH, wX:DWORD, wY:DWORD, gpRect:RECT


; Create  brush to set background color:
INVOKE CreateSolidBrush, $BkColor
MOV brush, EAX

; Register class for parent window:
MOV EAX, InstanceHandle
MOV WC.hInstance, EAX
MOV WC.lpfnWndProc, OFFSET MainWindowProc
MOV EAX, brush
MOV WC.hbrBackground, EAX
MOV WC.lpszClassName, OFFSET MainClassName
; INVOKE LoadIcon, InstanceHandle, 500    ; icon ID
; MOV WC.hIcon, EAX
MOV WC.hIcon, NULL
INVOKE LoadCursor, NULL, IDC_ARROW
MOV WC.hCursor, EAX
INVOKE RegisterClassEx, OFFSET WC

INVOKE GetSystemMetrics, SM_CXSCREEN
MOV EDX, $mainWinWidth
CALL CenterDim
MOV wX, EAX
INVOKE GetSystemMetrics, SM_CYSCREEN
MOV EDX, $mainWinHeight
CALL CenterDim
MOV wY, EAX

; Create our main window:
INVOKE CreateWindowEx, WS_EX_OVERLAPPEDWINDOW, OFFSET MainClassName,
OFFSET MainTitleText, $mainWinStyles, wX, wY, $mainWinWidth,
$mainWinHeight, NULL, NULL, InstanceHandle, NULL
MOV MainWinHandle, EAX

; Create the status bar:
INVOKE CreateStatusWindow, $SB_styles, OFFSET NullString, MainWinHandle, $SBID
MOV StatusHandle, EAX
MOV EDX, EAX
; Get the height of the status bar:
INVOKE GetWindowRect, EDX, ADDR gpRect
MOV EAX, gpRect.bottom
SUB EAX, gpRect.top
MOV SBheight, EAX

; Divide status bar into parts:
INVOKE SendMessage, StatusHandle, SB_SETPARTS, $numStatusParts, OFFSET StatusParts

;============= Message loop ===================
msgloop:
INVOKE GetMessage, ADDR msg, NULL, 0, 0
TEST EAX, EAX ;EAX = 0 = exit
JZ exit99
INVOKE TranslateMessage, ADDR msg
INVOKE DispatchMessage, ADDR msg
JMP msgloop

exit99: MOV EAX, msg.wParam
RET

WinMain ENDP


;====================================================================
; Main Window Proc
;====================================================================

MainWindowProc PROC hWin:DWORD, uMsg:DWORD, wParam:DWORD, lParam:DWORD
LOCAL gpRect:RECT

MOV EAX, uMsg
; CMP EAX, WM_COMMAND
; JE do_command
CMP EAX, WM_CREATE
JE do_create
CMP EAX, WM_CLOSE
JE do_close
CMP EAX, WM_SIZE
JE dosize

dodefault:
; use DefWindowProc for all other messages:
INVOKE DefWindowProc, hWin, uMsg, wParam, lParam
RET

do_command:
; MOV AX, WORD PTR wParam
; CMP AX, ---- ;Check command code here.
; JE ---

do_create:

; Window creation code here

XOR EAX, EAX
RET

dosize:
INVOKE GetClientRect, hWin, ADDR gpRect
MOV EDX, gpRect.bottom
SUB EDX, gpRect.top
SUB EDX, SBheight
INVOKE MoveWindow, StatusHandle, 0,  EDX, gpRect.right, SBheight, TRUE

XOR EAX, EAX
RET

do_close:
INVOKE PostQuitMessage, NULL
MOV EAX, TRUE
RET


MainWindowProc ENDP


;====================================================================
; CenterDim
;
; Returns half screen dimension (X or Y) minus half window dimension
;
; On entry,
; EAX = screen dimension
; EDX = window dimension
;
; Returns:
; sdim/2 - wdim/2
;====================================================================

CenterDim PROC

SHR EAX, 1 ;divide screen dimension by 2
SHR EDX, 1 ;divide window dimension by 2
SUB EAX, EDX
RET ;Return w/# in EAX

CenterDim ENDP


END start
Assembly language programming should be fun. That's why I do it.

jj2007

Attached another version, with a menu, an edit control and a statusbar but shorter and different in style. Inter alia, it uses the Switch ... Case syntax in the WndProc:

WndProc proc uses esi edi ebx hWnd, uMsg, wParam:WPARAM, lParam:LPARAM
  SWITCH uMsg
  CASE WM_CREATE ; this message serves to initialise your application
mov hStatusbar, rv(CreateStatusWindow, WS_CHILD OR WS_VISIBLE, chr$("I'm the status bar"), hWnd, 110)
  CASE WM_COMMAND ; react to menu clicks
... (see attachment)
  CASE WM_DESTROY ; bye bye
invoke PostQuitMessage, NULL
  ENDSW
  invoke DefWindowProc, hWnd, uMsg, wParam, lParam ; default processing
  ret
WndProc endp

The WM_SIZE handler demonstrates the difference between the invoke and push-push-call styles of coding.

NoCforMe

BTW, I also have skeletons for console apps (command-line invoked, no GUI window) and dialog-as-program apps, where the main window is a dialog. You might want to whip up a few different flavors yourself.
Assembly language programming should be fun. That's why I do it.

jack

thanks NoCforMe and jj, this a great idea  :thumbsup:

daydreamer

Great noCforme
Prefer global handles in my code,
For example Hdc so i can use GDI in several proc
Used also ddraw and d3d templates many years ago
my none asm creations
https://masm32.com/board/index.php?topic=6937.msg74303#msg74303
I am an Invoker
"An Invoker is a mage who specializes in the manipulation of raw and elemental energies."
Like SIMD coding

jj2007

Here is an alternative WM_SIZE handler for the template attached in reply #1:

  CASE WM_SIZE ; adjust edit control to main window
invoke SendMessage, hStatusbar, WM_SIZE, wParam, lParam ; autosize
; **** adjust size of edit control ****
movzx eax, word ptr lParam ; width of client area
movzx edx, word ptr lParam+2 ; height
sub eax, 6 ; width minus 3 pixels to the left and right
sub edx, 26 ; leave space under edit control for the statusbar
invoke MoveWindow, hEdit, 3, 3, eax, edx, 0

In this version, the WM_SIZE message is passed on to the statusbar child window, forcing it to resize.

daydreamer

best with ddraw skeleton it only produces 2.5kb exe,so 1.5kb room for a 4k demo
my none asm creations
https://masm32.com/board/index.php?topic=6937.msg74303#msg74303
I am an Invoker
"An Invoker is a mage who specializes in the manipulation of raw and elemental energies."
Like SIMD coding

KSS

NoCforMe, no need "MOV    WC.hIcon, NULL" because "NULL, \      ;hIcon":
.data

WC    WNDCLASSEX <    SIZEOF WNDCLASSEX, \
            CS_HREDRAW or CS_VREDRAW or CS_BYTEALIGNWINDOW, \
            NULL, \        ;lpfnWndProc
            NULL, \        ;cbClsExtra
            NULL, \        ;cbWndExtra
            NULL, \        ;hInstance
            NULL, \        ;hIcon
            NULL, \        ;hCursor
            NULL, \        ;hbrBackground
            NULL, \        ;lpszMenuName
            NULL, \        ;lpszClassName
            NULL >        ;hIconSm
:bgrin:

jj2007

@KSS: save some bytes

wcx WNDCLASSEX <WNDCLASSEX, CS_HREDRAW or CS_VREDRAW, WndProc, 0, 0, 1, 2, 3, COLOR_BTNFACE+1, 0, txClass, 4>
txClass db "Masm32GUI", 0 ; class name, will be registered below
...
  wc equ [ebx.WNDCLASSEX] ; we use an equate for better readability
  mov ebx, offset wcx
  mov wc.hInstance, rv(GetModuleHandle, 0) ; rv ("return value") is a Masm32 macro
  mov wc.hIcon, rv(LoadIcon, eax, IDI_APPLICATION)
  mov wc.hIconSm, eax ; the rv macro returns results in eax
  mov wc.hCursor, rv(LoadCursor, NULL, IDC_ARROW) ; get a cursor
  invoke RegisterClassEx, addr wc ; the window class needs to be registered

NoCforMe

Quote from: KSS on December 21, 2023, 08:30:23 PMNoCforMe, no need "MOV    WC.hIcon, NULL" because "NULL, \        ;hIcon":
.data

WC    WNDCLASSEX <    SIZEOF WNDCLASSEX, \
            CS_HREDRAW or CS_VREDRAW or CS_BYTEALIGNWINDOW, \
            NULL, \        ;lpfnWndProc
            NULL, \        ;cbClsExtra
            NULL, \        ;cbWndExtra
            NULL, \        ;hInstance
            NULL, \        ;hIcon
            NULL, \        ;hCursor
            NULL, \        ;hbrBackground
            NULL, \        ;lpszMenuName
            NULL, \        ;lpszClassName
            NULL >        ;hIconSm
:bgrin:


Yes, you're correct of course; good catch.

Some of my templates are works in progress, with previous changes not completed. Maybe someday they'll be done. (Not likely ...)

Every little bit helps.
Assembly language programming should be fun. That's why I do it.