?? tut3.html
字號:
WS_OVERLAPPEDWINDOW,\</font></font></b>
<br><b><font color="#CCCCCC"><font size=-1>
CW_USEDEFAULT,\</font></font></b>
<br><b><font color="#CCCCCC"><font size=-1>
CW_USEDEFAULT,\</font></font></b>
<br><b><font color="#CCCCCC"><font size=-1>
CW_USEDEFAULT,\</font></font></b>
<br><b><font color="#CCCCCC"><font size=-1>
CW_USEDEFAULT,\</font></font></b>
<br><b><font color="#CCCCCC"><font size=-1>
NULL,\</font></font></b>
<br><b><font color="#CCCCCC"><font size=-1>
NULL,\</font></font></b>
<br><b><font color="#CCCCCC"><font size=-1>
hInst,\</font></font></b>
<br><b><font color="#CCCCCC"><font size=-1>
NULL</font></font></b>
<br><b><font color="#CCCCCC"><font size=-1> mov
hwnd,eax</font></font></b>
<br><b><font size=-1><font color="#CCCCCC"> invoke ShowWindow,
hwnd,CmdShow </font><font color="#009900">
; display our window on desktop</font></font></b>
<br><b><font size=-1><font color="#CCCCCC"> invoke UpdateWindow,
hwnd </font><font color="#009900">
; refresh the client area</font></font></b>
<p><b><font size=-1><font color="#CCCCCC"> .WHILE TRUE </font><font color="#009900">
; Enter message loop</font></font></b>
<br><b><font color="#CCCCCC"><font size=-1>
invoke GetMessage, ADDR msg,NULL,0,0</font></font></b>
<br><b><font color="#CCCCCC"><font size=-1>
.BREAK .IF (!eax)</font></font></b>
<br><b><font color="#CCCCCC"><font size=-1>
invoke TranslateMessage, ADDR msg</font></font></b>
<br><b><font color="#CCCCCC"><font size=-1>
invoke DispatchMessage, ADDR msg</font></font></b>
<br><b><font color="#CCCCCC"><font size=-1> .ENDW</font></font></b>
<br><b><font size=-1><font color="#CCCCCC"> mov
eax,msg.wParam </font><font color="#009900">
; return exit code in eax</font></font></b>
<br><b><font color="#CCCCCC"><font size=-1> ret</font></font></b>
<br><b><font color="#CCCCCC"><font size=-1>WinMain endp</font></font></b>
<p><b><font color="#CCCCCC"><font size=-1>WndProc proc hWnd:HWND, uMsg:UINT,
wParam:WPARAM, lParam:LPARAM</font></font></b>
<br><b><font size=-1><font color="#CCCCCC"> .IF uMsg==WM_DESTROY
</font><font color="#009900">; if the user closes our window</font></font></b>
<br><b><font size=-1><font color="#CCCCCC">
invoke PostQuitMessage,NULL </font><font color="#009900">
; quit our application</font></font></b>
<br><b><font color="#CCCCCC"><font size=-1> .ELSE</font></font></b>
<br><b><font size=-1><font color="#CCCCCC">
invoke DefWindowProc,hWnd,uMsg,wParam,lParam </font><font color="#009900">
; Default message processing</font></font></b>
<br><b><font color="#CCCCCC"><font size=-1>
ret</font></font></b>
<br><b><font color="#CCCCCC"><font size=-1> .ENDIF</font></font></b>
<br><b><font color="#CCCCCC"><font size=-1> xor eax,eax</font></font></b>
<br><b><font color="#CCCCCC"><font size=-1> ret</font></font></b>
<br><b><font color="#CCCCCC"><font size=-1>WndProc endp</font></font></b>
<p><b><font color="#CCCCCC"><font size=-1>end start</font></font></b>
<h3>
Analysis:</h3>
<font color="#C0C0C0"><font size=-1>You may be taken aback that a simple
Windows program requires so much coding. But most of those codes are just
*template* codes that you can copy from one source code file to another.
Or if you prefer, you could assemble some of these codes into a library
to be used as prologue and epilogue codes. You can write only the codes
in WinMain function. In fact, this is what C compilers do. They let
you write WinMain codes without worrying about other housekeeping chores.
The only catch is that you must have a function named WinMain else C compilers
will not be able to combine your codes with the prologue and epilogue.
You do not have such restriction with assembly language. You can use any
function name instead of WinMain or no function at all.</font></font>
<br><font color="#C0C0C0"><font size=-1>Prepare yourself. This's going
to be a long, long tutorial. Let's analyze this program to death!</font></font>
<ul><b><font color="#999900"><font size=-1>.386</font></font></b>
<br><b><font color="#999900"><font size=-1>.model flat,stdcall</font></font></b>
<br><b><font color="#999900"><font size=-1>option casemap:none</font></font></b>
<p><b><font color="#999900"><font size=-1>WinMain proto :DWORD,:DWORD,:DWORD,:DWORD</font></font></b>
<p><b><font color="#999900"><font size=-1>include \masm32\include\windows.inc</font></font></b>
<br><b><font color="#999900"><font size=-1>include \masm32\include\user32.inc</font></font></b>
<br><b><font color="#999900"><font size=-1>include \masm32\include\kernel32.inc</font></font></b>
<br><b><font color="#999900"><font size=-1>includelib \masm32\lib\user32.lib</font></font></b>
<br><b><font color="#999900"><font size=-1>includelib \masm32\lib\kernel32.lib</font></font></b></ul>
<font color="#CCCCCC"><font size=-1>The first three lines are "necessities".
.386 tells MASM we intend to use 80386 instruction set in this program.
.model flat,stdcall tells MASM that our program uses flat memory addressing
model. Also we will use stdcall parameter passing convention as the default
one in our program.</font></font>
<br><font color="#CCCCCC"><font size=-1>Next is the function prototype
for WinMain. Since we will call WinMain later, we must define its function
prototype first so that we will be able to invoke it.</font></font>
<br><font color="#CCCCCC"><font size=-1>We must include windows.inc at
the beginning of the source code. It contains important structures and
constants that are used by our program. The include file , windows.inc,
is just a text file. You can open it with any text editor. Please note
that windows.inc does not contain all structures, and constants (yet).
hutch and I are working on it. You can add in new items if they are not
in the file.</font></font>
<br><font color="#CCCCCC"><font size=-1>Our program calls API functions
that reside in user32.dll (CreateWindowEx, RegisterWindowClassEx, for example)
and kernel32.dll (ExitProcess), so we must link our program to those two
import libraries. The next question : how can I know which import library
should be linked to my program? The answer: You must know where the API
functions called by your program reside. For example, if you call an API
function in gdi32.dll, you must link with gdi32.lib.</font></font>
<br><font color="#CCCCCC"><font size=-1>This is the approach of MASM. TASM
's way of import library linking is much more simpler: just link to one
and only one file: import32.lib.</font></font>
<ul><b><font color="#999900"><font size=-1>.DATA</font></font></b>
<br><b><font color="#999900"><font size=-1> ClassName
db "SimpleWinClass",0</font></font></b>
<br><b><font color="#999900"><font size=-1> AppName
db "Our First Window",0</font></font></b>
<p><b><font color="#999900"><font size=-1>.DATA?</font></font></b>
<br><b><font color="#999900"><font size=-1>hInstance HINSTANCE ?</font></font></b>
<br><b><font color="#999900"><font size=-1>CommandLine LPSTR ?</font></font></b></ul>
<font color="#CCCCCC"><font size=-1>Next are the "DATA" sections.</font></font>
<br><font color="#CCCCCC"><font size=-1>In .DATA, we declare two zero-terminated
strings(ASCIIZ strings): ClassName which is the name of our window class
and AppName which is the name of our window. Note that the two variables
are initialized.</font></font>
<br><font color="#CCCCCC"><font size=-1>In .DATA?, two variables are declared:
hInstance (instance handle of our program) and CommandLine (command line
of our program). The unfamiliar data types, HINSTANCE and LPSTR, are really
new names for DWORD. You can look them up in windows.inc. Note that all
variables in .DATA? section are not initialized, that is, they don't have
to hold any specific value on startup, but we want to reserve the space
for future use.</font></font>
<ul><b><font color="#999900"><font size=-1>.CODE</font></font></b>
<br><b><font color="#999900"><font size=-1> start:</font></font></b>
<br><b><font color="#999900"><font size=-1> invoke
GetModuleHandle, NULL</font></font></b>
<br><b><font color="#999900"><font size=-1> mov
hInstance,eax</font></font></b>
<br><b><font color="#999900"><font size=-1> invoke
GetCommandLine</font></font></b>
<br><b><font color="#999900"><font size=-1> mov
CommandLine,eax</font></font></b>
<br><b><font color="#999900"><font size=-1> invoke
WinMain, hInstance,NULL,CommandLine, SW_SHOWDEFAULT</font></font></b>
<br><b><font color="#999900"><font size=-1> invoke
ExitProcess,eax</font></font></b>
<br><b><font color="#999900"><font size=-1> .....</font></font></b>
<br><b><font color="#999900"><font size=-1>end start</font></font></b></ul>
<font color="#CCCCCC"><font size=-1>.CODE contains all your instructions.
Your codes must reside between <starting label>: and end <starting
label>. The name of the label is unimportant. You can name it anything
you like so long as it is unique and doesn't violate the naming convention
of MASM.</font></font>
<br><font color="#CCCCCC"><font size=-1>Our first instruction is the call
to GetModuleHandle to retrieve the instance handle of our program. Under
Win32, instance handle and module handle are one and the same. You can
think of instance handle as the ID of your program. It is used as parameter
to several API functions our program must call, so it's generally a good
idea to retrieve it at the beginning of our program.</font></font>
<br><b><font color="#009900"><font size=-1>Note: Actually under win32,
instance handle is the linear address of your program in memory.</font></font></b>
<br><font color="#CCCCCC"><font size=-1>Upon returning from a Win32 function,
the function's return value, if any, can be found in eax. All other values
are returned through variables passed in the function parameter list you
defined for the call.</font></font>
<br><font color="#CCCCCC"><font size=-1>A Win32 function that you call
will nearly always preserve the segment registers and the ebx, edi, esi
and ebp registers. Conversely, ecx and edx are considered scratch registers
and are always undefined upon return from a Win32 function.</font></font>
<br><b><font color="#009900"><font size=-1>Note: Don't expect the values
of eax, ecx, edx to be preserved across API function calls.</font></font></b>
<br><font color="#CCCCCC"><font size=-1>The bottom line is that: when calling
an API function, expects return value in eax. If any of your function will
be called by Windows, you must also play by the rule: preserve and restore
the values of the segment registers, ebx, edi, esi and ebp upon function
return else your program will crash very shortly, this includes your window
procedure and windows callback functions.</font></font>
<br><font color="#CCCCCC"><font size=-1>The GetCommandLine call is unnecessary
if your program doesn't process a command line. In this example, I show
you how to call it in case you need it in your program.</font></font>
<br><font color="#CCCCCC"><font size=-1>Next is the WinMain call. Here
it receives four parameters: the instance handle of our program, the instance
handle of the previous instance of our program, the command line and window
state at first appearance. Under Win32, there's NO previous instance. Each
program is alone in its address space, so the value of hPrevInst is always
0. This is a leftover from the day of Win16 when all instances of a program
run in the same address space and an instance wants to know if it's the
first instance. Under win16, if hPrevInst is NULL, then this instance is
the first one.</font></font>
?? 快捷鍵說明
復制代碼
Ctrl + C
搜索代碼
Ctrl + F
全屏模式
F11
切換主題
Ctrl + Shift + D
顯示快捷鍵
?
增大字號
Ctrl + =
減小字號
Ctrl + -