(Translation) Win32ASM tutorial -12-end

zhaozj2021-02-16  50

This is the last one of this series of tutorials. Below I may post the example of writing a game with compilation. Still the basis, facing beginners. Here, the original author would like to thank: james of support, the right to provide free Chinese translation of this article.

- Translator TAOWEN2002

13.0 Windows in Windows

In this chapter, we will create a program with a window.

12.1 window

You may have guessed the reason why Windows called Windows. In Windows, there are two programs: GUI programs and console programs. The program of console mode looks like a DOS program that runs in a -DOS-DOS. Most of the programs you use are the GUI (Graphical User Interface) program, which has a graphical interface for interacting with the user. This is done by the creation window. Almost everything you see in Windows is a window. First, create a parent window, then a self-window (control) like editing box, static control (text tag - translator's note), buttons, etc.

13.2 Window Class

Every window has a name. You define your own classes for your parent window. For controls, you can use Windows standard class names (for example, "Edit", "Static", "Button")

13.3 Structure

The window class in your program is registered with the "RegisterClassex" function. (RegisterClassex is the expansion version of RegisterClass, the latter is not used) The statement of this function is:

Atom RegisterClassex (

Const Wndlcassex * lpwcx // has the address of the structure of class data

);

LPWCX: Points to the WNDCLASSEX structure. Before passing it to the function, you must fill in the structure with the appropriate class properties.

The unique parameter is a pointer to the structure. Let's take a look at some basic knowledge:

A structure is a collection of variables (data). It defines the Struct:

SomeStructure STRUCTDWORD1 DD? DWORD2 DD? SOME_WORD DW? ABYTE DB? ANOTHERBYTE DB? SomeStructure Ends

(The structure name is not necessarily capitalized)

You can use the question mark to define your variable in the unaptified Data section. Now you can create a structure according to the definition:

Initialized

InitializedStructure SomeStructure <100, 200, 10, 'A', 90H>

Uninitialized

UninitializedStructure SomeStructure <>

In the first example, a new structure is created (saving its OFFSET with the initialized structure), and each element of the structure is filled in with the initialization value. The second example only tells MASM to allocate memory as the structuren, and each data element is initialized. After creating a structure, you can use it in your code:

Mov Eax, INITIALIZEDSTRUCTURE.SOME_WORD; EAX is now 10 Inc uninitializedstructure.dword1; structure DWORD1 step

This is how the structure is in memory:

Memory address

content

Offset of initializedstructure

100 (DWORD, 4 BYTES)

Offset of initializedstructure 4

200 (DWORD, 4 BYTES) Offset of InitializedStructure 8

10 (Word, 2 Bytes)

Offset of InitializedStructure 10

65 or 'a' (1 byte)

Offset of InitializedStructure 11

90h (1 byte)

12.3 WNDCLASSEX

Now I have already learned enough structural knowledge, let us handle RegisterClassex. In the Win32 Programmer Reference, you can find the definition of the WNDCLASSEX structure.

typedef struct _WNDCLASSEX {// wc UINT cbSize; UINT style; WNDPROC lpfnWndProc; int cbClsExtra; int cbWndExtra; HANDLE hInstance; HICON hIcon; HCURSOR hCursor; HBRUSH hbrBackground; LPCTSTR lpszMenuName; LPCTSTR lpszClassName; HICON hIconSm;} WNDCLASSEX;

Explanation

CBSIZE

The size of the WndClassex structure. Used for Windows certification. You can get its size with SizeOf: Mov Wc.cbsize, SizeOf WndClassex

Style

Specify a style for class (if the window must have a scroll bar, plus the redraint flag. Wait)

lpfnwndproc

Pointing to the pointer to the Windows process (there are more content behind this chapter)

Cbclsextra

How much additional memory is made after the Windows class structure. Don't be important for us

CbWndextra

How much additional memory is assigned after the Windows instance. Not important to us

Hinstance

The strength handle of your program. You can get this handle with the getmoudlehandle function

Hicon

Window icon resource handle

Hcursor

Window cursor resource handle

HBRBACKGROUND

The brush handle for filling the background, or one of the standard brush type, such as Color_Window, Color_BTNFACE, Color_Background.

Lpsz Genename

Pointing a zero tail string of a specified menu class name

LPSZCLASSNAME

Pointing a zero tail string of a specified window class name

Hiconsm

A small icon handle associated with a window class

Create a folder named FirstWindow in your Win32 folder and create a new file called Window.asm in this folder, enter the content:

.486.model flat, stdcalloption casemap: noneincludelib /masm32/lib/kernel32.libincludelib /masm32/lib/user32.libincludelib /masm32/lib/gdi32.libinclude /masm32/include/windows.incinclude /masm32/include/kernel32.incinclude /masm32/include/user32.incinclude /masm32/include/gdi32.inc

Then create a .bat file called make.bat. Paste these text into:

@echo offml / c / coff window.asmlink / subsystem: windows window.objpause> NUL

From now on, in order to save space, only the small segment code is displayed. You can display all code here throughout . The complete code is displayed in a new window.

Translator Note: For the convenience, I put these back. 13.4 Registration class

Now we register in the process called WinMain. The initialization of the window during this process is completed.

Join these to your assembly file:

Winmain Proto Stdcall: DWORD,: DWORD,: DWORD.DATA?

Hinstance DD?

.code

Invoke GetModuleHandle, Nullmov Hinstance, EaxIvoke Winmain, Hinstance, Null, Null, SW_SHOWNORMAL

End Start

These codes get the module handle through getModuleHandle and put the module handle into the Hinstance variable. This handle is frequently used in the Windows API. Then it calls the WinMain process. This is not an API function, but a process we will define. The prototype is: Winmain Proto StdCall: DWORD,: DWORD,: DWORD,: DWORD, and thus a function with 4 parameters:

Now put these code in End Start:

Winmain Proc Hinst: DWORD, HPREVINST: DWORD, CMDLINE: DWORD, CMDSHOW: DWORD

Retwinmain ENDP

You don't need to use this WinMain process at all, but this is a very common way to intermire your program. Visual C automatically initializes the parameters of this function, but we must do it yourself. Don't manage HPREVINST and CMDLINE now. Concentrated attention on Hinst and cmdshow. HinST is an instance handle (= module handle), and cmdshow is the sign of how the window is displayed. (You can find more about the showWindows section in the API reference section)

Invoke Winmain, Hinstance, Null, Null, SW_SHOWNORMAL in front code call this function with the correct instance handle and display flag. Now we can write our initialization code in WinMain.

Winmain Proc Hinst: DWORD, HPREVINST: DWORD, CMDLINE: DWORD: WNDCLASSEXLOCAL HWND: DWORD

Retwinmain ENDP

This has two partial variables we will use during the process.

.DATA

ClassName DB "firstwindowclass", 0.code

WinMain proc hInst: DWORD, hPrevInst: DWORD, CmdLine: DWORD, CmdShow: DWORDLOCAL wc: WNDCLASSEXLOCAL hwnd: DWORD; now set all the structure members of the WNDCLASSEX structure wc: mov wc.cbSize, SIZEOF WNDCLASSEXmov wc.style, CS_HREDRAW or CS_VREDRAWmov wc.lpfnWndProc, OFFSET WndProcmov wc.cbClsExtra, NULLmov wc.cbWndExtra, NULLpush hInstpop wc.hInstancemov wc.hbrBackground, COLOR_WINDOWmov wc.lpszMenuName, NULLmov wc.lpszClassName, OFFSET ClassNameinvoke LoadIcon, NULL, IDI_APPLICATIONmov wc.hIcon, eaxmov wc.hIconSm, EaxInvoke Loadcursor, Null, IDC_ARROWMOV WC.HCURSOR, EAXINVOKE RegisterClassex, Addr Wcretwinmain Endp

Let's take a look at what happened:

Mov wc.cbsize, sizeof wndclassexmov wc.style, cs_hredraw or cs_vredrawmov wc.lpfnwndproc, offset wndprocmov wc.cbclsextra, nullmov wc.cbwndextra, null

The size of the structure is initialized (this is registerclassex requirements). Set the style of "CS_HREDRAW or CS_VREDRAW" and then set the offset of the window process. What you will know later is a window process, now you only need to remember that you need the address of the WNDPROC process. This address can be obtained through "OFFSET WndProc". Cb.clsextra and Cb.Wndextra We did not use their NULL.

Push hinstpop wc.hinstance

Wc.hinstance is set to WinMain's Hinst parameters. Why don't we use: Mov wc.hinstance, hinst? Because the MOV instruction is not allowed to move from an address to another. With PUSH / POP, the value is pressed into the stack and then pop it into the target.

Mov wc.hbrbackground, color_windowmov wc.lpszmenuname, nullmov wc.lpszclassname, Offset ClassName

The background color of the class is set to Color_Window, and the menu is not defined and the LPSZClassName is set to a class name string pointing to zero end: "firstWindowClass" it should be a unique name defined in your program.

Invoke Loadicon, Null, IDi_Applicationmov Wc.hicon, Eaxmov Wc. Hiconsm, EAX

The window needs an icon. But because we want a handle to point to the icon, we use LoadCon to load the icon and get the handle. Loadicon has two parameters: hinstance and lpiconname. Hinstance is a module handle that contains an executable file of an icon. LPiconName is a pointer to a string of the icon resource and the icon ID. If you use null to Hinstance, you can choose this one from some standard charts (this is because we have no icon resources here) HiconSM is a small icon, you can use the same handle. Invoke LoadCursor, Null, IDC_Arrowmov Wc.hcursor, EAX

The same is true for the cursor. NULL is Hinstance, and uses a standard cursor type: IDC_ARROW, standard Windows arrow type cursor.

Invoke RegisterClassex, Addr WC

Now, finally use registerclassex to register class, by a pointer to the WndClassex structure.

13.5 Creating a window

Now, you have already registered a class, you can use it to create a window:

HWND CREATEWINDOWEX

DWORD dwExStyle, // extended window styleLPCTSTR lpClassName, // pointer to registered class nameLPCTSTR lpWindowName, // pointer to window nameDWORD dwStyle, // window styleint x, // horizontal position of windowint y, // vertical position of windowint nWidth, / / window widthint nHeight, // window heightHWND hWndParent, // handle to parent or owner windowHMENU hMenu, // handle to menu, or child-window identifierHINSTANCE hInstance, // handle to application instanceLPVOID lpParam // pointer to window-creation data) ;

DWEXStyle and DWStyle are parameters for two decisive window styles.

LPClassName is a pointer to class names you registered.

LPWindowname is the name of your window (if any, this will become the title of your window)

X, Y, nwidth, nheight determines the location and size of your window

HMENU is the handle of the menu window (discussed later, now empty)

Hinstance is the handle of the program instance

LPPARARM is the extension value you can use in your program

.DATA

Appname "firstwindow", 0

.code

INVOKE CreateWindowEx, NULL, ADDR ClassName, ADDR AppName, / WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, / CW_USEDEFAULT, 400,300, NULL, NULL, / hInst, NULLmov hwnd, eaxinvoke ShowWindow, hwnd, SW_SHOWNORMALinvoke UpdateWindow, hwnd

(Note / seem to be in the same line when the assembler reads a line)

Our code will create a new window with our just registered class name. The title is "firstwindow" (program name, appname), the style is WS_OVERLAPPEDWINDOW, which is a window style that creates a title, system menu, a scalable border, and maximizing / minimizing button. CW_USERDEFAULT The location of X and Y will make Windows use the default location for the new window. The (initial) size of the window is 400 × 300 pixels. The return value of the function is the window handle, hwnd. It is stored in a local variable hwnd. Then the window is displayed with ShowWindow. UpdateWindow make sure the window is drawn.

13.6 message loop

The window can communicate through the message and your program and other window. Whenever, a message is sent to the specified window. Its window procedure is called. Each window has a message loop or message pump (PUMP). This is an endless check whether there is a loop for messages with your window. And if there is, pass the message to the DispatchMessage function. This function calls your window process. The message loop and window process are two completely different things! ! !

Winmain Proc Hinst: Hinstance, Hprevinst: Hinstance, Cmdline: lpstr, cmdshow: dwordlocal wc: wndclassexlocal hwnd: dwordlocal msg: msg; <<< New

........

. While Trueinvoke GetMessage, Addr MSG, NULL, 0, 0.Break .if (! EAX) Invoke TranslateMessage, Addr Msginvoke DispatchMessage, Addr Msg.Endw

This is what the message loop looks like. .While true,. Nendw will continue before the EAX is 0. If it receives a WM_QUIT message, getMessage returns 0, which will close the window thus to exit when getMessage returns 0. If this is not this (0), the message is passed to TranslateMessage (this function translates the button to messages) and the message is unpackaged by Windows with the DispatchMessage function. The message itself is in the component of a message loop in the MSG structure (Local MSG: MSG is joined the process, adding a local message structure called MSG) You can use this message in all your programs.

13.7 window process

The message will be sent to the window process. One window process looks like this:

WNDPROC Proto Stdcall: DWORD,: DWORD,: DWORD,: DWORD

.code

WndProc proc hWnd: DWORD, uMsg: DWORD, wParam: DWORD, lParam: DWORDmov eax, uMsg.IF eax == XXXX.ELSEIF eax == XXXX.ELSE invoke DefWindowProc, hWnd, uMsg, wParam, lParam.ENDIFretWndProc endp

Window process always has 4 parameters

HWnd contains window handles

UMSG message

The first parameter of the WPARAM message (defined by message)

LPARAM message second parameter (defined by message)

The message that the window does not processes should be passed to the DefWindowProc, which will handle it. An example of a window process:

WndProc proc hWnd: DWORD, uMsg: DWORD, wParam: DWORD, lParam: DWORDmov eax, uMsg.IF eax == WM_CREATE invoke MessageBox, NULL, ADDR AppName, ADDR AppName, NULL.ELSEIF eax == WM_DESTROY invoke PostQuitMessage, NULL.ELSE Invoke DefWindowProc, HWND, UMSG, WPARAM, LPARAM.ENDIFRETWNDPROC ENDP This code shows the program name when the window is initialized. Also note that I have added the processing of the WM_DESTROY message. This message is sent when the window will be turned off. The program should be reacted with PostquitMessage.

Take a look at the final code:

.486

.Model flat, stdcall

Option CaseMAP: NONE

INCLUDELIB /MASM32/LIB/kernel32.lib

INCLUDELIB /MASM32/LIB/USER32.LIB

INCLUDELIB /MASM32/LIB/GDI32.LIB

INCLUDE /MASM32/INCLUDE/Windows.inc

INCLUDE /MASM32/INCLUDE / WANEL32.INC

INCLUDE /MASM32/INCLUDE/USER32.INC

INCLUDE /MASM32/INCLUDE/gdi32.inc

Winmain Proto Stdcall: DWORD,: DWORD,: DWORD,: DWORD

WNDPROC Proto Stdcall: DWORD,: DWORD,: DWORD,: DWORD

.DATA?

Hinstance DD?

.DATA

ClassName DB "firstwindowclass", 0

Appname DB "firstwindow", 0

.code

Start:

Invoke getModuleHandle, NULL

Mov Hinstance, EAX

Invoke Winmain, Hinstance, Null, NULL, SW_SHOWNORMAL

Invoke EXITPROCESS, NULL

Winmain Proc Hinst: Hinstance, Hprevinst: Hinstance, Cmdline: lpstr, cmdshow: DWORD

Local WC: WNDCLASSEX

Local hwnd: DWORD

Local MSG: MSG

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

Push hinst

POP wc.hinstance

Mov wc.hbrbackground, Color_Window

Mov wc.lpszMenuname, NULL

MOV wc.lpszclassname, Offset ClassName

Invoke Loadicon, NULL, IDI_APPLICATION

Mov wc.hicon, EAX

Mov wc.hiconsm, EAX

Invoke loadcursor, null, IDC_ARROW

Mov wc.hcursor, EAX

Invoke RegisterClassex, Addr Wcinvoke CreateWindowex, Null, Addr ClassName, AddR Appname, /

WS_OVERLAPPEDWINDOW-WS_SIZEBOX-WS_MAXIMIMIMIZEBOX, CW_USEDEFAULT, /

CW_USEDEFAULT, 400, 300, NULL, NULL, /

Hinst, null

MOV HWND, EAX

Invoke ShowWindow, Hwnd, SW_SHOWNORMAL

Invoke UpdateWindow, HWnd

.While true

Invoke GetMessage, Addr MSG, NULL, 0, 0

.Break .if (! EAX)

Invoke TranslateMessage, Addr MSG

Invoke DispatchMessage, Addr MSG

.Endw

Mov Eax, Msg.wParam

RET

Winmain ENDP

WNDPROC PROC HWND: DWORD, UMSG: DWORD, WPARAM: DWORD, LPARAM: DWORD

MOV EAX, UMSG

.IF EAX == WM_CREATE

Invoke Messagebox, Null, Addr Appname, Addr Appname, Null

.ELSEIF EAX == WM_DESTROY

Invoke PostquitMessage, NULL

.Lse

Invoke DefWindowProc, Hwnd, UMSG, WPARAM, LPARAM

.Endif

RET

WNDPROC ENDP

End Start

转载请注明原文地址:https://www.9cbs.com/read-26623.html

New Post(0)