Wednesday, September 29, 2010

Create a simple window


In this lesson we will write a Windows program, it will display a standard desktop window.

Theory:

Windows program, in writing graphical user interface needs to call a large number of standard Windows Gui function. This is indeed beneficial to both users and programmers, for users, face a window with a set of standards, the operation of these windows are the same, so use a different application without having to re-learn operation. To the programmer, these are after Gui source code of Microsoft's rigorous testing can be used at any time bring. As for the specific course, to write programs for programmers still difficult. In order to create a window-based applications, must strictly abide by the norms. Achieve this is not difficult, as long as the use of modular or object-oriented programming can be.

I have listed below a window in the desktop display a few steps:

Get your application handle (required);
Get command line parameters (if you want to get from the command line parameters, optional);
Register window class (required, unless you use the Windows predefined window class, such as the MessageBox or dialog box;
Create window (required);
Display window on the desktop (required unless you do not want to immediately display it);
Refresh the window client area;
Access to unlimited access to the window message loop;
If there is a message arrives, the window for the window callback function processing;
If the user closes the window, to exit the deal.
Compared to single-user programming under DOS is, Windows the procedure under the framework structure is quite complex. However, Windows and DOS in the system architecture is completely different. Windows is a multitasking operating system, so the system while there are synergies between multiple applications running. This requires Windows programmer must strictly comply with programming specifications, and to develop good programming style.

Content:

Here is our simple window program's source code. Enter the complex details, I will outline key points focused on the vital territories of points:

You should use the program to all the constants and the structure of the declaration into a header file, and the beginning of the source code contains the header files. To do so will save you a lot of time, so that once again Qiaojian Pan. Currently, the most perfect is the hutch to write header files, you can go to the hutch or my website. You can also define your own constants and structure, but the best put them in a separate header file
With includelib instructions, including your program to the library file, for example: if your program to call the "MessageBox", you should add the following line in the source file: includelib user32.lib This statement tells MASM that your program will use some to introduce library. If you reference more than a library, simply adding includelib statement, do not worry about how to deal with so many linker library, as long as the link with the link switch / LIBPATH can specify the path where the library.
Use in other parts of the definition of function prototypes in header files, constants, and structure, it is necessary to maintain and strictly defined in the same header file, including the case. Function definition in the query, this will save you a lot of time;
Compile, link with the makefile file, remove duplicate keystroke.
.386
. Model flat, stdcall
option casemap: none
include masm32includewindows.inc
include masm32includeuser32.inc
includelib masm32libuser32.lib; calls to functions in user32.lib and kernel32.lib
include masm32includekernel32.inc
includelib masm32libkernel32.lib

WinMain proto: DWORD,: DWORD,: DWORD,: DWORD

. DATA; initialized data
ClassName db "SimpleWinClass", 0; the name of our window class
AppName db "Our First Window", 0; the name of our window

. DATA?; Uninitialized data
hInstance HINSTANCE?; Instance handle of our program
CommandLine LPSTR?
. CODE; Here begins our code
start:
invoke GetModuleHandle, NULL; get the instance handle of our program.
; Under Win32, hmodule == hinstance mov hInstance, eax
mov hInstance, eax
invoke GetCommandLine; get the command line. You don''t have to call this function IF
; Your program doesn''t process the command line.
mov CommandLine, eax
invoke WinMain, hInstance, NULL, CommandLine, SW_SHOWDEFAULT; call the main function
invoke ExitProcess, eax; quit our program. The exit code is returned in eax from WinMain.

WinMain proc hInst: HINSTANCE, hPrevInst: HINSTANCE, CmdLine: LPSTR, CmdShow: DWORD
LOCAL wc: WNDCLASSEX; create local variables on stack
LOCAL msg: MSG
LOCAL hwnd: HWND

mov wc.cbSize, SIZEOF WNDCLASSEX; fill values in members of wc
mov wc.style, CS_HREDRAW or CS_VREDRAW
mov wc.lpfnWndProc, OFFSET WndProc
mov wc.cbClsExtra, NULL
mov wc.cbWndExtra, NULL
push hInstance
pop wc.hInstance
mov wc.hbrBackground, COLOR_WINDOW +1
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 wc; register our window class
invoke CreateWindowEx, NULL,
ADDR ClassName,
ADDR AppName,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
CW_USEDEFAULT,
NULL,
NULL,
hInst,
NULL
mov hwnd, eax
invoke ShowWindow, hwnd, CmdShow; display our window on desktop
invoke UpdateWindow, hwnd; refresh the client area

. WHILE TRUE; Enter message loop
invoke GetMessage, ADDR msg, NULL, 0,0
. BREAK. IF (! Eax)
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
. ENDW
mov eax, msg.wParam; return exit code in eax
ret
WinMain endp

WndProc proc hWnd: HWND, uMsg: UINT, wParam: WPARAM, lParam: LPARAM
. IF uMsg == WM_DESTROY; if the user closes our window
invoke PostQuitMessage, NULL; quit our application
. ELSE
invoke DefWindowProc, hWnd, uMsg, wParam, lParam; Default message processing
ret
. ENDIF
xor eax, eax
ret
WndProc endp

end start

Analysis:

A simple Windows program to see so many lines, you are not a bit like withdraw? But you need to know is above most of the code is just the template, the template means entails the code on almost all standard Windows programs it is the same. Writing Windows programs, you can copy the code to copy to, of course, write code to duplicate one of these libraries are also very good. In fact, the real focus to write the code in WinMain. This is the same number of C compilers, do not be concerned with other chores and concentrate on the WinMain function. The only difference is the C compiler source code requires that you have to have a function called WinMain. Otherwise, C will not know which functions and the code around the link. Relative C, assembly language provides greater flexibility, it does not require a force called WinMain function.

Now we start analyzing, you can get mentally prepared, this is not a very easy living.

.386
. Model flat, stdcall
option casemap: none

WinMain proto: DWORD,: DWORD,: DWORD,: DWORD

include masm32includewindows.inc
include masm32includeuser32.inc
include masm32includekernel32.inc
includelib masm32libuser32.lib
includelib masm32libkernel32.lib

You can be the first three lines as a "must".

.386 Told us to use 80386 instruction set MASN.
. Model flat, stdcall tell MASM we use memory addressing modes, where you can join the stdcall tell MASM we use the agreed parameters.

Next is the WinMain function prototype affirm, because we later use to the function, it must be declared. We must include window.inc file, because it contains a lot of use to the constant and the structure is defined, the file is a text file, you can use any text editor to open it, window.inc not contain all the constants and structure definition, but hutch, and I have been constantly adding new content. If you temporarily can not find in window.inc, you may also join.

Our program calls stationed in user32.dll (example: CreateWindowEx, RegisterWindowClassEx) and kernel32.dll (ExitProcess) in the function, it must link two libraries. Then if I ask: what library you need to chain into your program? The answer is: first find the function you want to call any library, and then included. For example: If you want to call the function in gdi32.dll, you must include gdi32.inc header file. And compared with MASM, TASM will have to be much simpler, you can simply introduce a library that is: import32.lib.

. DATA

ClassName db "SimpleWinClass", 0
AppName db "Our First Window", 0

. DATA?

hInstance HINSTANCE?
CommandLine LPSTR?

Followed DATA "section." In. DATA, we defined two to NULL terminated string (ASCIIZ): ClassName which is the Windows class name, AppName is the name of our window. These two variables are initialized. Not initialize volume on the two sides. DATA? "Section" in which representatives of the application handle hInstance, CommandLine save the parameters passed from the command line. HINSTACE and LPSTR name the two data types, which are defined in the header file, an alias can be seen as a DWORD, the reason for such a re-set just to easy to remember. You can view windows.inc files in. DATA? The variables are not initialized, which means that the program has just started what their values are irrelevant, just hold a piece of memory, the future can re-use it.

. CODE
start:
invoke GetModuleHandle, NULL
mov hInstance, eax
invoke GetCommandLine
mov CommandLine, eax
invoke WinMain, hInstance, NULL, CommandLine, SW_SHOWDEFAULT
invoke ExitProcess, eax
.....
end start

. DATA "section" contains all your application code that must have been. Code and between the end. The label's name as long as the Windows standard and to ensure compliance with the only the specific name does not matter what Dao Shi. We process the first statement is called GetModuleHandle to find the handle to our application. In Win32, the application handle and module handle is the same. You can handle as an instance of your application ID. We call some function is regarded as a parameter to be passed, it will be at the beginning and saved it can save a lot of things.

Special Note: WIN32 handle to the next instance of your application is actually a linear address in memory.

WIN32 functions in the function return value if it is to pass through the eax register. The value of other parameters can be passed in. return address. A WIN32 function is called when the segment register and always keep it ebx, edi, esi and ebp registers, while the value of ecx, and edx is always uncertain and can not return is to apply. Special Note: From the Windows API function return, eax, ecx, edx call in the value and not necessarily the same as before. When the function returns, the return value is placed in eax. If your application available to the Windows function calls, we must also respect the point, that is, at the entrance to save the segment register in the function and ebx, esp, esi, edi and the function returns the value of the resume. If not this way, then your application will soon collapse. From your program, call the function available to Windows in general there are two: Windows window procedure and the Callback function.

If your application does not handle the command line then do not call GetCommandLine, here is just to tell you how to do it if you want to call should be.

Here is the call to WinMain a. The function of a total of four parameters: the application instance handle, the application of the previous instance handle, command-line parameters string pointer and a window to display. Win32 does not handle the concept of the previous examples, so the second parameter is always 0. The reason is to keep it and Win16 compatibility considerations, in Win16, if hPrevInst is NULL, then the function is first run. Special Note: You do not have to declare a function called WinMain, in fact, in this respect you can completely decide that you do not even have an equivalent function and WinMain. As long as you are copying it GetCommandLine WinMain code after the function they achieve exactly the same. In the WinMain returns, the return code into eax in. Then by the end of the application ExitProcess function to the return code passed to Windows.

WinMain proc Inst: HINSTANCE, hPrevInst: HINSTANCE, CmdLine: LPSTR, CmdShow: DWORD

The above definition is WinMain. Note that with the proc command after the parameter: type form of parameters, which are passed to WinMain by the caller, and we quote directly using the parameter name can be. As for the stacking and the balance of return stack when the stack at compile time by the MASM before adding the relevant order and the order of assembly instructions to carry out. LOCAL wc: WNDCLASSEX LOCAL msg: MSG LOCAL hwnd: HWND LOCAL pseudo-instruction for the local variables on the stack allocated memory space, all the LOCAL directive must be followed after the PROC. LOCAL followed by a statement of the variables in the form of the variable name: variable type. For example, LOCAL wc: WNDCLASSEX that tells MASM to the local side called wc amount allocated in the stack length is the length of WNDCLASSEX structure memory space, then we use the local variable is no need to consider the stack, taking into account under DOS compilation, to say that this is a gift. But this requires that local variables declared at the end of the release of the stack in the function room (that can not be referenced in function in vitro), another drawback is that you can not initialize because your local variables, have to again later in another their assignment.

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 hInstance
pop wc.hInstance
mov wc.hbrBackground, COLOR_WINDOW +1
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 w

The above lines from the concept that really are very simple. As long as a few lines of instructions can be achieved. The main concept is the window class (window class), a window the window class is a specification, this specification defines a window of several major elements, such as: icons, cursors, background colors, and is responsible for handling the window function . When you generate a window must have such a window class. If you want to generate more than one window of the same type, the best way is to store up to the window class, this method can save a lot of memory space. Maybe today you will not feel too much, but look at the most only 1M PC memory, to do so is necessary. If you want to define your own window class must be created: In a WINDCLASS or WINDOWCLASSEXE structure of the constituent elements indicate your window, and then call the RegisterClass or RegisterClassEx, Then according to the window class created window. Windows on the different characteristics of different window class must be defined. WINDOWS There are several predefined window class, such as: buttons, edit boxes, etc.. To generate the kind of style of window is not required to redefine the window class, and as long as the package pre-defined class class name as a parameter can call CreateWindowEx.

The most important members of the WNDCLASSEX than lpfnWndProc the. Prefix lpfn that the member is a pointer to a function of the long pointer. In the Win32 memory model is FLAT because of type, there is no difference between near or far. Each window class must have a window procedure, when the Windows window belonging to a specific message to the window, the window of the window class to deal with all the news, such as a keyboard or mouse message message. As the process window intelligently handled almost all of the windows message loop, so you just joined the message in which the process can be. Now I will explain each member WNDCLASSEX

WNDCLASSEX STRUCT DWORD
cbSize DWORD?
style DWORD?
lpfnWndProc DWORD?
cbClsExtra DWORD?
cbWndExtra DWORD?
hInstance DWORD?
hIcon DWORD?
hCursor DWORD?
hbrBackground DWORD?
lpszMenuName DWORD?
lpszClassName DWORD?
hIconSm DWORD?
WNDCLASSEX ENDS

cbSize: WNDCLASSEX size. We can use the sizeof (WNDCLASSEX) to obtain accurate values.
style: class derived from this window, the window has style. You can use "or" operator to put some style or together.
lpfnWndProc: window handle function pointers.
cbClsExtra: specified immediately after the window class structure for the additional bytes.
cbWndExtra: examples in the window after the specified followed by additional bytes. If an application using the resources CLASS pseudo instructions to register a dialog class, then the member must be set to DLGWINDOWEXTRA.
hInstance: The instance handle of the module.
hIcon: Handle of the icon.
hCursor: cursor handle.
hbrBackground: background brush handle.
lpszMenuName: a pointer pointing to the menu.
lpszClassName: a pointer pointing to class name.
hIconSm: and the small icon associated window class. If the value is NULL. Put the hCursor the icon into the appropriate size of small icons.
invoke CreateWindowEx, NULL, ADDR ClassName, ADDR AppName, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL,
NULL, hInst, NULL

Register window class, we will call CreateWindowEx to create the actual window. Please note that the function has 12 parameters.

CreateWindowExA proto dwExStyle: DWORD, lpClassName: DWORD, lpWindowName: DWORD,
dwStyle: DWORD, X: DWORD, Y: DWORD, nWidth: DWORD, nHeight: DWORD, hWndParent: DWORD, hMenu: DWORD,
hInstance: DWORD, lpParam: DWORD

We take a closer look at these parameters:

dwExStyle: Add window style. Compared to the old CreateWindow This is a new parameter. In 9X/NT you can use the new window style. Style you can specify the window style in general, but some special window style, such as top-level window must be specified in this parameter. If you do not specify any particular style, it serves to this parameter set to NULL.
lpClassName: (required). ASCIIZ form of window class name of the address. Can be your custom class, it can be the predefined class name. As described above, each application must have a window class.
lpWindowName: ASCIIZ form of the name of the address window. The name appears in the title bar. If this parameter blank, the title bar nothing.
dwStyle: window style. Here you can specify the appearance of the window. You can specify this parameter is zero, but not as the window system menu, there is no maximize and minimize buttons, there is no close button, so you have to press Alt + F4 to close it. The most common window class style is WS_OVERLAPPEDWINDOW. A kind of window style is a bitwise mask, so that you can use "or" the window you want style or up. As WS_OVERLAPPEDWINDOW is the most inconvenient by several common style or up.
X, Y: the upper left corner of the window specified in pixels of the screen coordinates. Default can be specified as CW_USEDEFAULT, so Windows will automatically specify the most suitable location window.
nWidth, nHeight: in pixels of the window size. Default can be specified as CW_USEDEFAULT, so Windows will automatically specify the most suitable size of the window.
hWndParent: parent window handle (if any). This parameter tells Windows that this is a child window and his parent window is. This MDI (multiple document structure) is different here is not limited to child window and parent window client area. He just used to tell Windows paternity between the various windows in order to destroy the parent window is destroyed together with its child windows. In our example program, because only one window, so set this parameter to NULL.
hMenu: WINDOWS menu handle. If only the system menu is designated the parameter NULL. Looking back WNDCLASSEX structure lpszMenuName parameters, it also specifies a menu, this is a default menu, any class derived from the window If you want to use other menu windows need re-specified in the parameter. In fact, this parameter has a dual meaning: on the one hand, if this is a custom window menu handle on behalf of the parameter, on the other hand, if this is a pre-defined window, the argument on behalf of the window ID. Windows is based on lpClassName parameter to distinguish between a custom window or predefined window.
hInstance: create the instance of the application window handles.
lpParam: (optional) point to the window want to pass data structure pointer type parameters. If the window in the production of MDI in the delivery CLIENTCREATESTRUCT structure parameters. In general, the total value of zero, which means that there is no parameter to the window. By GetWindowLong function retrieves the value.


mov hwnd, eax
invoke ShowWindow, hwnd, CmdShow
invoke UpdateWindow, hwnd

After the success of calling CreateWindowEx, the window handle in eax of. We must save this value for later use. We have just created a window does not automatically display, it must call ShowWindow to follow our hope that the way to display the window. The next call UpdateWindow to update the client area.

. WHILE TRUE
invoke GetMessage, ADDR msg, NULL, 0,0
. BREAK. IF (! Eax)
invoke TranslateMessage, ADDR msg
invoke DispatchMessage, ADDR msg
. ENDW

This time we have a window on the screen. But it can not receive messages from the outside world. Therefore, we must provide relevant information to it. We cycle through a message to complete the work. Each module has only one news cycle, we continue to call the GetMessage to get a message from Windows. GetMessage passes a MSG structure to Windows, then Windows in the function of filling the relevant information, has been to Windows to find and fill GetMessage will return to the good news. During this time, control of the system may be transferred to other applications. This constitutes a multi-task structure under Win16. If GetMessage received WM_QU99v message will return FALSE, so that the end loop and exit the application. TranslateMessage is a utility function is a function, it received the original key messages from the keyboard, and then interpreted WM_CHAR, in the WM_CHAR into the message queue, because after the explanation of the message containing the ASCII key code, scan code than the original good understanding much more. If your application does not deal with key messages, you can not call the function. DispatchMessage will send a message to the window procedure responsible for the function.

mov eax, msg.wParam
ret
WinMain endp

If the news cycle is over, exit code stored in the wParam in MSG, you can put it in eax register to pass the current Windows does not use Windows to the end of the code, but we'd better comply with the Windows standard has anti-accident.

WndProc proc hWnd: HWND, uMsg: UINT, wParam: WPARAM, lParam: LPARAM

It is our window handler. You can easily give the function name. The first parameter hWnd is the handle of the window to receive messages. uMsg is to receive messages. Note uMsg is not a MSG structure, in fact, only a DWORD type on the number. Windows define hundreds of messages, most of your application will not handle the. When news of the window occurs, Windows will send a related message to the window. The window procedure handler is smart to deal with these messages. wParam and lParam only additional parameters, to facilitate the transfer and the message more relevant data.

. IF uMsg == WM_DESTROY
invoke PostQuitMessage, NULL
. ELSE
invoke DefWindowProc, hWnd, uMsg, wParam, lParam
ret
. ENDIF
xor eax, eax
ret
WndProc endp

Key part of the above can be said. This is why we need to write Windows programs a major part of the rewrite. Here you check the Windows transfer program over the news, if news is we are interested to be addressed, dealt with, pass 0 in eax register, or must call DefWindowProc, to the window procedure receives the parameters passed to the lack of Province window handler. All messages you have to deal with the WM_DESTROY, when your application at the end of Windows to deliver the news came in an application when you explain to the message on the screen when it has disappeared, which is only to inform your application window has been destroyed, you must prepare their own return to Windows. In this message, you can do some cleanup, but can not prevent exit the application. If you want to do that, you can handle WM_CLOSE message. After processing the clean-up work, you must call PostQuitMessage, the function will WM_QU99v message back to your application, but the message will make GetMessage return, and put 0 in eax register, and then the end of the message loop and return WINDOWS . You can call your program DestroyWindow function, which sends a WM_DESTROY message to your own applications, thus forcing it to withdraw.






Recommended links:



News about PIMS And Calendars



Directory Log Analysers



Stan Shih: I would like to Share my experience



ASF converter



VOB to MP4



Print Outsourcing: the neglected Corners of



Review Clocks AND Alarms



Hot Hot behind



SAP sales drop turmoil SPREAD to China, CEO to resign



Analysis of 2008 Strategic adjustments Taobao causes and consequences of B2C



EASY Astrology Or Biorhythms Or Mystic



Hide IP address detection and Experience



Digital photo print 2



Europe and the United States will not be outsourced as "mirage"?



MKV to IPod



No comments:

Post a Comment