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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
|
; #########################################################################
;
; GENERIC.ASM is a roadmap around a standard 32 bit
; windows application skeleton written in MASM32.
;
; #########################################################################
; Assembler specific instructions for 32 bit ASM code
.386 ; minimum processor needed for 32 bit
.model flat, stdcall ; FLAT memory model & STDCALL calling
option casemap :none ; set code to case sensitive
; #########################################################################
; ---------------------------------------------
; main include file with equates and structures
; ---------------------------------------------
include windows.inc
; -------------------------------------------------------------
; In MASM32, each include file created by the L2INC.EXE utility
; has a matching library file. If you need functions from a
; specific library, you use BOTH the include file and library
; file for that library.
; -------------------------------------------------------------
include user32.inc
include kernel32.inc
; #########################################################################
; ------------------------------------------------------------------------
; MACROS are a method of expanding text at assembly time. This allows the
; programmer a tidy and convenient way of using COMMON blocks of code with
; the capacity to use DIFFERENT parameters in each block.
; ------------------------------------------------------------------------
; 1. szText
; A macro to insert TEXT into the code section for convenient and
; more intuitive coding of functions that use byte data as text.
szText MACRO Name, Text:VARARG
LOCAL lbl
jmp lbl
Name db Text,0
lbl:
ENDM
; 2. m2m
; There is no mnemonic to copy from one memory location to another,
; this macro saves repeated coding of this process and is easier to
; read in complex code.
m2m MACRO M1, M2
push M2
pop M1
ENDM
; 3. return
; Every procedure MUST have a "ret" to return the instruction
; pointer EIP back to the next instruction after the call that
; branched to it. This macro puts a return value in eax and
; makes the "ret" instruction on one line. It is mainly used
; for clear coding in complex conditionals in large branching
; code such as the WndProc procedure.
return MACRO arg
mov eax, arg
ret
ENDM
; #########################################################################
; ----------------------------------------------------------------------
; Prototypes are used in conjunction with the MASM "invoke" syntax for
; checking the number and size of parameters passed to a procedure. This
; improves the reliability of code that is written where errors in
; parameters are caught and displayed at assembly time.
; ----------------------------------------------------------------------
WinMain PROTO :DWORD,:DWORD,:DWORD,:DWORD
WndProc PROTO :DWORD,:DWORD,:DWORD,:DWORD
TopXY PROTO :DWORD,:DWORD
; #########################################################################
; ------------------------------------------------------------------------
; This is the INITIALISED data section meaning that data declared here has
; an initial value. You can also use an UNINIALISED section if you need
; data of that type [ .data? ]. Note that they are different and occur in
; different sections.
; ------------------------------------------------------------------------
.data
szDisplayName db "Generic",0
CommandLine dd 0
hWnd dd 0
hInstance dd 0
; #########################################################################
; ------------------------------------------------------------------------
; This is the start of the code section where executable code begins. This
; section ending with the ExitProcess() API function call is the only
; GLOBAL section of code and it provides access to the WinMain function
; with the necessary parameters, the instance handle and the command line
; address.
; ------------------------------------------------------------------------
.code
; -----------------------------------------------------------------------
; The label "start:" is the address of the start of the code section and
; it has a matching "end start" at the end of the file. All procedures in
; this module must be written between these two.
; -----------------------------------------------------------------------
start:
invoke GetModuleHandle, NULL ; provides the instance handle
mov hInstance, eax
invoke GetCommandLine ; provides the command line address
mov CommandLine, eax
invoke WinMain,hInstance,NULL,CommandLine,SW_SHOWDEFAULT
invoke ExitProcess,eax ; cleanup & return to operating system
; #########################################################################
WinMain proc hInst :DWORD,
hPrevInst :DWORD,
CmdLine :DWORD,
CmdShow :DWORD
;====================
; Put LOCALs on stack
;====================
LOCAL wc :WNDCLASSEX
LOCAL msg :MSG
LOCAL Wwd :DWORD
LOCAL Wht :DWORD
LOCAL Wtx :DWORD
LOCAL Wty :DWORD
szText szClassName,"Generic_Class"
;==================================================
; Fill WNDCLASSEX structure with required variables
;==================================================
mov wc.cbSize, sizeof WNDCLASSEX
mov wc.style, CS_HREDRAW or CS_VREDRAW \
or CS_BYTEALIGNWINDOW
mov wc.lpfnWndProc, offset WndProc ; address of WndProc
mov wc.cbClsExtra, NULL
mov wc.cbWndExtra, NULL
m2m wc.hInstance, hInst ; instance handle
mov wc.hbrBackground, COLOR_BTNFACE+1 ; system color
mov wc.lpszMenuName, NULL
mov wc.lpszClassName, offset szClassName ; window class name
invoke LoadIcon,hInst,500 ; icon ID ; resource icon
mov wc.hIcon, eax
invoke LoadCursor,NULL,IDC_ARROW ; system cursor
mov wc.hCursor, eax
mov wc.hIconSm, 0
invoke RegisterClassEx, ADDR wc ; register the window class
;================================
; Centre window at following size
;================================
mov Wwd, 500
mov Wht, 350
invoke GetSystemMetrics,SM_CXSCREEN ; get screen width in pixels
invoke TopXY,Wwd,eax
mov Wtx, eax
invoke GetSystemMetrics,SM_CYSCREEN ; get screen height in pixels
invoke TopXY,Wht,eax
mov Wty, eax
; ==================================
; Create the main application window
; ==================================
invoke CreateWindowEx,WS_EX_OVERLAPPEDWINDOW,
ADDR szClassName,
ADDR szDisplayName,
WS_OVERLAPPEDWINDOW,
Wtx,Wty,Wwd,Wht,
NULL,NULL,
hInst,NULL
mov hWnd,eax ; copy return value into handle DWORD
invoke LoadMenu,hInst,600 ; load resource menu
invoke SetMenu,hWnd,eax ; set it to main window
invoke ShowWindow,hWnd,SW_SHOWNORMAL ; display the window
invoke UpdateWindow,hWnd ; update the display
;===================================
; Loop until PostQuitMessage is sent
;===================================
StartLoop:
invoke GetMessage,ADDR msg,NULL,0,0 ; get each message
cmp eax, 0 ; exit if GetMessage()
je ExitLoop ; returns zero
invoke TranslateMessage, ADDR msg ; translate it
invoke DispatchMessage, ADDR msg ; send it to message proc
jmp StartLoop
ExitLoop:
return msg.wParam
WinMain endp
; #########################################################################
WndProc proc hWin :DWORD,
uMsg :DWORD,
wParam :DWORD,
lParam :DWORD
; -------------------------------------------------------------------------
; Message are sent by the operating system to an application through the
; WndProc proc. Each message can have additional values associated with it
; in the two parameters, wParam & lParam. The range of additional data that
; can be passed to an application is determined by the message.
; -------------------------------------------------------------------------
.if uMsg == WM_COMMAND
;----------------------------------------------------------------------
; The WM_COMMAND message is sent by menus, buttons and toolbar buttons.
; Processing the wParam parameter of it is the method of obtaining the
; control's ID number so that the code for each operation can be
; processed. NOTE that the ID number is in the LOWORD of the wParam
; passed with the WM_COMMAND message. There may be some instances where
; an application needs to seperate the high and low words of wParam.
; ---------------------------------------------------------------------
;======== menu commands ========
.if wParam == 1000
invoke SendMessage,hWin,WM_SYSCOMMAND,SC_CLOSE,NULL
.elseif wParam == 1900
szText TheMsg,"Assembler, Pure & Simple"
invoke MessageBox,hWin,ADDR TheMsg,ADDR szDisplayName,MB_OK
.endif
;====== end menu commands ======
.elseif uMsg == WM_CREATE
; --------------------------------------------------------------------
; This message is sent to WndProc during the CreateWindowEx function
; call and is processed before it returns. This is used as a position
; to start other items such as controls. IMPORTANT, the handle for the
; CreateWindowEx call in the WinMain does not yet exist so the HANDLE
; passed to the WndProc [ hWin ] must be used here for any controls
; or child windows.
; --------------------------------------------------------------------
.elseif uMsg == WM_CLOSE
; -------------------------------------------------------------------
; This is the place where various requirements are performed before
; the application exits to the operating system such as deleting
; resources and testing if files have been saved. You have the option
; of returning ZERO if you don't wish the application to close which
; exits the WndProc procedure without passing this message to the
; default window processing done by the operating system.
; -------------------------------------------------------------------
szText TheText,"Please Confirm Exit"
invoke MessageBox,hWin,ADDR TheText,ADDR szDisplayName,MB_YESNO
.if eax == IDNO
return 0
.endif
.elseif uMsg == WM_DESTROY
; ----------------------------------------------------------------
; This message MUST be processed to cleanly exit the application.
; Calling the PostQuitMessage() function makes the GetMessage()
; function in the WinMain() main loop return ZERO which exits the
; application correctly. If this message is not processed properly
; the window disappears but the code is left in memory.
; ----------------------------------------------------------------
invoke PostQuitMessage,NULL
return 0
.endif
invoke DefWindowProc,hWin,uMsg,wParam,lParam
; --------------------------------------------------------------------
; Default window processing is done by the operating system for any
; message that is not processed by the application in the WndProc
; procedure. If the application requires other than default processing
; it executes the code when the message is trapped and returns ZERO
; to exit the WndProc procedure before the default window processing
; occurs with the call to DefWindowProc().
; --------------------------------------------------------------------
ret
WndProc endp
; ########################################################################
TopXY proc wDim:DWORD, sDim:DWORD
; ----------------------------------------------------
; This procedure calculates the top X & Y co-ordinates
; for the CreateWindowEx call in the WinMain procedure
; ----------------------------------------------------
shr sDim, 1 ; divide screen dimension by 2
shr wDim, 1 ; divide window dimension by 2
mov eax, wDim ; copy window dimension into eax
sub sDim, eax ; sub half win dimension from half screen dimension
return sDim
TopXY endp
; ########################################################################
end start
|