;21st October 2007 - 23:55
;Moddy - Second ever MASM app. First with WinAPI.
.486
.model flat, stdcall
option casemap :none
;standard includes
include \masm32\include\windows.inc
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
;Function Prototypes
WinMain proto :DWORD, :DWORD, :DWORD, :DWORD ;WinMain = Required Windows Main Function
ExitMsg proto :DWORD ;My little "wannabe error-handling" function.
.data
;Windows requirements...
ClassName db "WinClass", 0
AppName db "Sandbox Application", 0
;Quit Messages...
QuitMsg db "Successfully Quiting!", 0
FailMsg db "Application Failed", 0
;Uninitialised data
.data?
;hInstance stores the handle to the module to be associated with the applicated :/
hInstance HINSTANCE ?
stat UINT ?
.code
start:
;Run GetModelHandle, Then move the return from it into hInstance. [The return of course, being in eax]
invoke GetModuleHandle, NULL
mov hInstance, eax
;Run WinMain, The Main Windows Process,
invoke WinMain, hInstance, NULL, NULL, 0
invoke ExitProcess, eax
;Obligatory WinMain function
WinMain proc hInst:HINSTANCE, hPrevInst:HINSTANCE, CmdLine:LPSTR, CmdShow:DWORD
;3 Local Variables
local wc:WNDCLASSEX
local msg:MSG
local hwnd:HWND
;Fill up the WNDCLASSEX class with the required information
mov wc.cbSize, SIZEOF WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, offset WndProc
mov wc.cbClsExtra, NULL
mov wc.cbWndExtra, NULL
;Use push and pop to move hInstance into wc.hInstance. REMEMBER: mov wont do memory to memory, just reg <-> mem, and reg <-> reg!
push hInstance
pop wc.hInstance
mov wc.hbrBackground, COLOR_WINDOW+1
mov wc.lpszMenuName, NULL
mov wc.lpszClassName, offset ClassName
;Invoke LoadIcon - Used to choose the icon for the application
invoke LoadIcon, NULL, IDI_APPLICATION
mov wc.hIcon, eax
mov wc.hIconSm, eax
;LoadCursor - Used to choose the cursor for the application
invoke LoadCursor, NULL, IDC_ARROW
mov wc.hCursor, eax
;CreateWindowEx - Registers a windows class for use when we call CreateWindowEx
invoke RegisterClassEx, addr wc
;Create our Window!
invoke CreateWindowEx, 0, addr ClassName, addr AppName, WS_OVERLAPPEDWINDOW or WS_VISIBLE, CW_USEDEFAULT,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInst, NULL
;Move the return from CreateWindowEx [which is currently in eax] into hwnd
mov hwnd, eax
;Create a loop which won't stop running unless someone clicks something...
.while TRUE
;Which will send a message to the app, Which GetMessage will catch...
invoke GetMessage, addr msg, NULL, 0, 0
.break .if (!eax)
;And TranslateMessage will convert into characters...
invoke TranslateMessage, addr msg
;For DispatchMessage to deal with. [i.e Send it to WndProc]
invoke DispatchMessage, addr msg
.endw
mov eax, msg.wParam
ret
WinMain endp
;This is where the messages are passed to be handed.
WndProc proc hWnd:HWND, uMsg:UINT, wParam:WPARAM, lParam:LPARAM
;If the message is WM_DESTROY then push 0, and call ExitMsg [Push 0 so ExitMsg can pop it off after its called]
.if uMsg == WM_DESTROY
xor eax, eax
mov stat, eax
invoke ExitMsg, hWnd
;DefWindowProc = The defualt message handler. So should the message NOT be WM_DESTROY - Pass it on to DefWindowProc.
.else
invoke DefWindowProc, hWnd, uMsg, wParam, lParam
ret
;Make eax 0 [xor by itself] then return.
.endif
xor eax, eax
ret
WndProc endp
;This is my *attempt* at an error handling function :P
ExitMsg proc hWnd:HWND
;Check our stat variable...
.if (stat == 0)
;So we can output our messagebox with the good message, and then exit.
invoke MessageBox, hWnd, addr QuitMsg, addr QuitMsg, MB_OK
invoke ExitProcess, 0
ret
.endif
;But if we get here, then we can't have been supplied zero. So all is NOT good.. We call MessageBox with the bad message then exit with the value that was supplied to us
invoke MessageBox, hWnd, addr FailMsg, NULL, MB_OK ;By setting the 3rd arg as NULL, It will display the default. [Default = "Error"]
invoke ExitProcess, stat
ret
ExitMsg endp
end start