Chapter 2 Windows Programming Model "Lilu Dallas Multipass!" - Lilu, The 5th Element (Movie "Fifth Element") Windows Programming is like going to see dentist: Although it is clear that it is good to be, no one likes Always find a dentist. right? In this chapter, I will use "Zen" method - or in other words, it is to introduce you to the basic Windows programming in depth. Although I can't guarantee that you will make more like to go to dentist after reading this chapter, but I will guarantee that you will prefer Windows programming than ever. Below is the content of this chapter:? Windows history? Windows basic style? Windows class (Class)? Create a window? Event Handler? Event Drive Programming and Event Cycling? Open multiple windows of Windows I have to liberate your thoughts and feel scared (especially the stubborn molecules of DOS). Let us quickly browse the formation and development of Windows, and its relationship with the game development world, ok? The development of earlier versions of WindowsWindows begins with Windows version 1.0. This is the first attempt of Microsoft's commercial window operating system, of course it is a failed product. Windows 1.0 is fully established on the DOS basis (this is an error), can't perform multiple tasks, the run is very slow, it looks also. Its appearance may be the most important reason for its failure. In addition to ironic, the problem is also that Windows 1.0 can provide higher hardware, image, and sound performance compared to the 80286 computer (or poor 8086) that the era. However, Microsoft moved steadily and quickly launched Windows 2.0. I remember to get the Software Publishing Corporation when I get the Windows 2.0 Beta beta. In the conference room, it is crowded with supervisors at all levels of the company, including the company president (like it, he is a cocktail). We run the Windows 2.0 Beta demo version, load multiple applications, which seems to be said. However, IBM has launched PM. PM looks much better, and it is based on the operating system OS / 2, which is more advanced than Windows 2.0. WINDOWS 2.0 is still DOS-based window manager. That day, the director's conclusion is: "Yes, but it is not an operating system that can continue to be developed. Let us continue to develop DOS programs, give me another cocktail?" Windows 3.x in 1990, the planets of each galaxy finally alliance Because Windows 3.0 came out, and the performance was cool! Although it still can't catch up with Mac OS standards, who is still concerned? (The real programmer is annoying Mac). Software developers can finally create charming applications on the PC, and commercial applications have gradually detached from DOS. This has become the turning point of the PC, and finally eliminates the MAC exactly outside the commercial application, and then extruded it out of the desktop publishing industry (at that time, Apple launched a new hardware every 5 minutes). Although Windows 3.0 works well, there are still many problems, software vulnerabilities, but from the technical say that it is a huge breakthrough after Windows 2.0, there is a problem that is inevitable.
In order to solve these problems, Microsoft launched Windows 3.1, starting the public relations department and the market department to call Windows 4.0, however, Microsoft decided to refer to Windows 3.1, because it is not enough to call the upgrade version. It has not yet made the market department's advertising promotion. WINDOWS 3.1 is very reliable. It has multimedia extensions to provide audio and video support, and it is still an excellent, comprehensive operating system, and users can work in a unified manner. In addition, there are some other versions, such as Windows 3.11 that can support the network (for Windows for Workgroups). The only problem is that Windows 3.1 is still a DOS application, running on the DOS extension. On the other hand, people engaged in game programming are still singing "sticking to DOS post until the purgatory!", And I even burned a Windows 3.1 box! However, in 1995, the real start cooled - Windows 95 finally launched. It is a truly 32-bit, multitasking, multi-threaded operating system. It is true that some 16-bit code is retained, but in a large extent, Windows 95 is the ultimate development and release platform of the PC. (Of course, Windows NT 3.0 is also launched, but NT is still not available for most users, so it will not be described here.) After Windows 95 is launched, I really start like Windows programming. I have been hate using Windows 1.0, 2.0, 3.0 and 3.1 to program, although this hate is less and less. When Windows 95 appears, it completely changes my thoughts, just like other people who are conquered - it looks very cool! That is what I need. The most important thing in the game programming is how the game packaging is designed, and the game screen issued to the magazine. Send a free thing to the reviewer is also a good idea.
So almost one night, Windows 95 has changed the entire computer industry. Indeed, there are still some companies still using Windows 3.1 (Can you believe it?), But Windows 95 makes Intel-based PCs a choice of all applications other than games. Yes, although the game programmer knows the DOS exiting the game programming industry is just a time problem, but DOS is still their core. In 1996, Microsoft issued the Game SDK (Game Software Development Kit), which is basically the first version of DirectX. This technology can only work in Windows 95, but it is too slow, even competing but DOM games (such as Doom and Duke Nukem, etc.). So the game developer continues to develop games for DOS32, but they know, if timeday, DirectX must have enough speed, so that the game is smoothly running on the PC. At version 3.0, DirectX's speed is as fast as DOS32 on the same computer. When it comes to version 5.0, DirectX has been quite perfect and implements the initial commitment of the technology. In this regard, we will refer to DirectX when we will involve DirectX in Chapter 5, "DirectX Foundation, and COM". Now we have to realize that the combination of Win32 and DirectX is the only choice for developing games on the PC. Now look back in history. Windows 981998, Windows 98 is launched. This is mostly a step in the technology revolution, and unlike Windows 95 is a full revolutionary product, there is no doubt that it also has an important position. Windows 98 is like a sports car modified by old cars - the appearance is fashionable, speed is fast, so there is no one. It is a 32-bit, which can support anything you think and have an unlimited expansion. It is well integrated DirectX, 3D graphics, network, and internet. Windows 98 and Windows 95 are also very stable. It is true that Windows 98 will still crash, but please believe me, there are many more than Windows 95. Moreover, Windows 98 supports plug and play and supports very well - is time! Windows Me was released in the second half of 1999 to the first half of 2000, WINDOWS ME (or millennium, Millennium) was released. It is difficult to explain ME, basically still 98 kernels, but more closely integrate multimedia and web support. ME is positioned in the consumer market, not a technical or commercial market. For functionality, it is no different from Windows 98. Moreover, some applications are troublesome upon run due to the higher integration of ME. Some old hardware is completely not supported, and ME is only a good choice to configure a newer computer. For example, you can run 98 well with a computer in 1995, but use it to run ME. Say it back, for configuring a newer computer, used to game, this is still a more reliable, stable operating system. When Windows XP is written in this book, Microsoft has just released a new operating system Windows XP. I really like to use it. Windows XP can be said to be the most old operating system I have ever seen. It has a look of 98 or ME while there is a stability and reliability of Windows 2000 or NT. XP is a big step in the operating system for consumers. However, it also brings a bad place. XP is a complete 32-bit Windows compatible operating system. It is necessary to comply with the norm in convincing the hardware software developer. This is good, when paying the price, XP does not support a lot of software that violates the rules of the game.
From the other hand, this is also a good thing. In the long run, all software companies will recompile their programs to clean them with bad and hardware-related code. These bad code is that 98 and 98 are so unstable, the culprit. Thus, XP is like a Nirvana - we have the coolest and most fashionable operating system, if you want to use, you must go to the rules. In any case, in order not to become a compatibility discussion disaster template, XP provides users with two tools that help them run their desired software. First, the XP operating system is constantly updating yourself through Microsoft updates, and many companies keep in solving various annoying software issues. Second, XP has a "compatibility" mode, by running in this mode, you can run the software that is not compatible with XP; in short, you only need to block the error detection, the software can run. In addition to these issues, I suggest that readers don't hesitate to upgrade to Windows XP as soon as possible. Windows NT / 2000 Now let's discuss Windows NT. During the writing of this book, Windows NT is launching version 5.0, and has been officially named Windows 2000. With my personal estimate, it will eventually replace Windows 9x into the operating system selection of everyone. 2000 is much striper than Windows 9X; and most game programmers have developed games that will run on Windows 9x / Me / XP on NT. The coolst Windows 2000 is that it fully supports plug and play and WIN32 / DirectX, so applications written for Windows 9x using DirectX can run on Windows 2000. This is a good news, because from history, it is the largest market share of developers who write PC games. So what is the lowest standard? If you have written a Win32 application using DirectX (or other tools), it can run on Windows 95, 98, ME, XP, and 2000 or later. This is a good thing. Therefore, anything you have learned in this book can be easily applied to a variety of operating systems. Yes, even the Windows CE 3.0 / Pocket PC 2002 system is also supported by DirectX and Win32. Windows Basics: Win9x / NT and DOS, Windows is a multi-task operating system, allowing many applications and / or applets to run simultaneously, maximizing the performance of hardware. This indicates that Windows is a shared environment - an application cannot be exclusively throughout the system. Although Windows 95, 98, ME, XP and 2000 / NT are all similar, but there are still many technical differences. But we can conduct a general discussion on our concern. The Windows machine referred to herein is generally a Win9X / NT or Windows environment. let's start! MultiTasking and multithreading, as I said, Windows allows different applications to be executed simultaneously in a polling (Round-Robin), each application takes up a short period of time. Then I turn to the next application. As shown in Figure 2-1, the CPU is shared by several different applications in a loop. It is responsible for judging the next running application, and assigns running time to each application is the scheduler (Scheduler). Figure 2-1: Multiple processing schedulers on a single processor can be very simple - each application assigns fixed runtime, or it can be very complicated - set the application to different priorities and preemptive or Low priority events. For Win9x / NT, the scheduler adopts a priority-based preemptive.
This means that some applications take up more time than other applications, but if an application requires a CPU processing, while another task runs, the current task can be blocked or taken first. But don't worry too much, unless you are writing OS (operating system) or real-time code - the details of the scheduling are important. In most cases, Windows will execute and schedule your app without having to participate. In-depth contacts, we can see that it is not only multitasking, but also multithreaded. This means that the program consists of many more simple plurality of threads of executions. These threads are considered a process of having a heavier weight - just like a program, thereby being scheduled. In fact, at the same time, 30 to 50 threads on your computer are running simultaneously and perform different tasks. So in fact you might run a program, but this program consists of one or more execution threads. Windows actual multi-threaded scandition diagram As shown in Figure 2-2, it can be seen from the figure that each program is actually consisting of a primary thread and several working threads. Figure 2-2: A More Realistic Multithreaded View Of Windows. Getting Threads Let us take a look at how much threads are running now. On the Windows machine, press the CTRL Alt Delete key to pop up the Active Program Task Manager that is running the running task (process). This is different from what we want, but it is also very close. We want a tool or program that displays the actual thread number of actual threads. Many shared software and commercial software tools can do this, but Windows embeds these tools embedded. Under the installation of Windows (generally Windows /), you can find an executable that names Sysmon.exe (Windows 95/98) or Prefmon.exe (Windows NT). Figure 2-3 depicts the Sysmon.exe program running on my Windows 98 machine. In addition to the running thread, there are a large amount of information, such as memory usage and processor loading, etc. In actually, when you develop, I like to make Sysmon.exe run, thereby understanding what is going on and how the system is loaded. Figure 2-3: Sysm running You may want to know if you can control the creation of threads, the answer is capable! ! ! In fact, this is one of the most exciting things that Windows game programming - just like we hope, in addition to the game main process, we can also perform other tasks, we can also create threads like other tasks. Note that in the Windows 98 / NT environment, there is actually a new type of execution object called fiber. It is simpler than the thread (understand the thread is composed of the fiber) This and the DOS game program is written Very different. DOS is a single-threaded operating system, that is, once your program starts running, it can only run the program (except for interrupt handler from time to time). Therefore, if you want to use any multitasking or multithreading, you must simulate yourself (see "Sams Teach YourSelf Game Programming in 21 Days" About a complete DOS-based multitasking kernel introduction). This is also what the game programmer is doing in so many years. Indeed, simulating multitasking and multithreading is far from being compared with a complete support system that supports multitasking and multi-threaded, but for a single game, it can work well.
I want to mention a detail before we come into contact with the true Windows programming and those working code. You may think that Windows is really a magical operating system because it allows multiple tasks and programs to be executed immediately. Keep in mind that it is not true. If there is only one processor, you can only perform one execution stream, thread, program, or any object you call. Windows is too fast to switch, so that it looks like several programs run at the same time. On the other hand, if there are several processors, you can run multiple programs at the same time. For example, I have a dual CPU's Pentium II computer with two 400MHz Pentium II processors running Windows NT 5.0. With this configuration, you can perform two instructions simultaneously. I hope that in the near future, the new microprocessor structure of the personal computer can allow multiple threads or fibers to perform simultaneous implementation, such a target as part of the processor design. For example, Pentium has two execution unit - u tubes and V tubes. Therefore it can perform two instructions simultaneously. However, both instructions are from the same thread. Similarly, Pentium II, II, IV can perform multiple simple instructions simultaneously, but they also need from the same thread. The event model Windows is a multi-task / multi-threaded operating system, and is also an event-driven operating system. Unlike the DOS program, the Windows program is waiting for the user to use, and thus triggers an event, and Windows responds to the event and operates. Please see the schematic shown in Figure 2-4, which describes a large number of application windows, and each program sends events and messages to Windows. Windows processes some of them, most of the messages and events are passed to the application. Figure 2-4: Windows Event Handling. The advantage is that you don't have to care about other running applications, Windows will handle them. What you have to care is your own application and the information in the window. This is impossible in Windows 3.0 / 3.1. Those versions of Windows are not a real multitasking operating system, and each application will generate the next program. That is, the application running in these versions of Windows feels quite rough and slow. If there are other application interference systems, this program that is "warm" will stop working. But this situation will not appear in Windows 9X / NT. The operating system will terminate your application at the appropriate time - of course, running speed, you will not notice. Up to now, readers have learned all the concepts of operating systems. Fortunately, there is Windows currently the best preparation of the game's operating system. You don't have to worry about program scheduling - what you want is the game code and how to maximize the performance of your computer. In this chapter, we have to contact some actual programming work, which is easy to learn how easy Windows programming is available. But (now there is, but) before conducting actual programming, we should understand some of the agreements that Microsoft programmers like to use. This will not be made by those weird functions and variable names. Programming by Microsoft: Hungarian symbol representation If you are working on a company like Microsoft, there are thousands of programmers in different projects, and to some extent, a standard way to write code should be proposed to some extent. Otherwise, the result will be confusing. So a person named Charles Simonyi is responsible for creating a set of specification to write Microsoft code. This specification has always been used as a basic guidance manual for writing code. All Microsoft's API, interface, technical document, etc. are all adopted.
This specification is often referred to as Hungarian symbolic representation, which may be because he often overtime, it is hungry, and hunger and hungry, hungry, hungry, may also be because of him It is a Hungarian. Although I don't know the origin of the name, the key is that you still have to understand this specification so that you can read Microsoft code. Hungarian symbol representations include many agreements related to the following names:? Variable? Function? Type and constant? Class. Parameter Table 2-1 gives the prefix code used by Hungary symbol representation. These codes are used in most cases for prefix variable names, and other agreements are determined according to the name. Other explanations can refer to this table. Table 2-1: Prefix Code Prefix Data Type (Basic Type) for Hungarian Symbol Specification (Basite Type) C Char By Byte Byte (No Symbol Character) N Short Short Integer and Integer (Represents A number) I I int integer x, y Short Short integer (usually used for X coordinates and y coordinate) CX, CY Short short integer (usually used to represent the length of x and y; c Representation count) B Bool (integer) W uint (no symbol integer) and Word Word) L long (long integer) DW DWORD (no symbol length integer) FN function pointer S String SZ, STR Terminal LP 32-bit pointer H number with a byte 0 (null value) (commonly used to represent Windows Object) Named variable of the MSG message variable Hungarian symbol representation, the variable can be represented by the prefix code in Table 2-1. In addition, when a variable is composed of one or several subnames, each sub-name begins with a capital letter. Here are a few examples: char * szfilename; // a null terminated string
INT * LPIDATA; / / A 32-bit Pointer to an IntBool Bsemaphore; // a Boolean Value
Word dwmaxcount; // a 32-bit unsigned Word According to the naming rules of local variables I know, there is a naming rule for global variables: int g_ixpos; // a global x-position
INT g_itimer; // a global time
Char * g_szstring; // A Global Null Terminated String In general, global variables are only started with G in g_ or sometimes. The name function of the function is identical, but there is no prefix. In other words, only the first letter must be capitalized. Here are several examples: int Plotpixel (int ix, int ip, int oc);
Void * MEMSCAN (Char * szstring); and use underscores in the function name. For example, the following function name is an invalid Hungarian symbol representation: int GET_PIXEL (Int IX, INT IY); type and constant naming all types and constants are uppercase letters, but the name can be used in the name. For example: constling num_sectors = 100; // a C Style Constant
#define max_cells 64 // a c Style Constant
#define powerunit 100 // a c style constanttypedef unsigned char uchar; // a user defined Type This does not have any difference - very standard definition. Although most Microsoft programmers do not use underscore, I still like it because this makes the name more readable. Timed in C , keyword constant more than one thing. In the previous code line, it is used to create a constant variable. This is similar to #define, but it adds this feature of type information. Const is not just like #define is a simple pretreatment text replace, but also more like a variable. It allows the compiler to perform type check and transformation. The agreement of the name naming class may be troublesome. But I also saw that many people use this agreement and supplement independently. In any case, all C classes must be prefixed with uppercase C, and the first letters of each sub-name of the class name must be capitalized. Here are a few examples: class cvector {public: cvector () {ix = iy = = imagnitude = 0;} cvector (int x, int y, int z) {ix = x; iy = y; IZ = z; }.
Private: int ix, iy, iz; // the position of the vectorint imagnitude; // the magnitude of the Vector
}; The parameter naming of the name of the parameter is the same as the standard variable name. But not always. For example, the following example gives a function definition: uchar getpixel (int x, int y); in this case, the more accurate Hungarian function prototype is: uchar getpixel (int ix, int y); but these two ways I have Have seen it. In fact, you may even see these variable names, but just see type, as shown below: uchar getpixel (int, int); of course, this is just the prototype, the real function declaration must have binding The variable name, this is already mastered. Note to learn to read Hungarian symbol indication does not mean you must always use it! In fact, I have been programming for more than 20 years, and I am not ready to change my programming style. Therefore, the code in this book will use the coding style of the class Hungarian symbol representation in the case of using the Win32 API function, and in other locations will use my own style. It must be noted that the first letter of the variable name I use has no capitalization, and I also use the underline. The simplest Windows program in the world is now a general understanding of the Windows operating system and its characteristics and basic design issues, then let us start the real Windows programming from the first Windows program. Write a habitual practice with a new language or the operating system you have learned to write "Hello World" text, let us also try it. Program Listing 2-1 is a standard DOS-based "Hello World" program. Listing 2-1: DOS-based "Hello World" program // demo2_1.cpp - Standard Version # include
// main entry point for all standard dos / console programsvoid main (void) {Printf ("/ Nthere Can Be Only !!! / N");} // end main
Now let's take a look at how to complete the same function under Windows. The presentation will make a sentence, if you want to compile Demo2_1.cpp, you should actually create a console application (console application) with the VC or Borland compiler. This is the application of class DOS, just it is 32-bit, which is only used in text mode, but it is useful for testing ideas and algorithms. Note The target .exe should be set to the console application in the compiler, not Win32 .exe! To compile this program, perform the following steps: 1. Create a new console application .exe project and include Demo2_1.cpp2 in the T3DCHAP02 / directory on the disc. Compile and connect. 3. Run it! (You can also run Demo2_1.exe on a pre-compiled optical disc.) Always start from WinMain () as previously described above, all Windows programs start with WinMain (), this and orthodox DOS programs are main () Start the same. The content in WinMain depends on you. If you prefer, you can create a window and start processing the event and draw something on the screen. On the other hand, you can call one of a hundred (or thousands) WIN32 API functions. This is exactly what we will do. I just want to display some things in a message on the screen. This happens to be a function of Win32 API function messagebox (). Program List 2.2 is a complete, compileable Windows program created and displays a message box that moves and closes everywhere. Program List 2-2: First Windows Program // Demo2_2.cpp - A Simple Message Box # Define Win32_Lean_and_mean # include
// the main windows headers
#include
// a Lot of Cool Macros
// main entry point for all windows programsint WINAPI WinMain (HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow) {// call message box api with NULL for parent window handleMessageBox (NULL, "THERE CAN BE ONLY ONE !!!" , "My First Windows Program", MB_OK | MB_ICONEXCLAMATION); // EXIT ProgramReturn (0);} // End WinMain To compile the program, follow these steps: 1. Create a new Win32 .exe project and contain the CD-ROM Demo2_2.cpp under T3DCHAP02 / under T3DCHAP02. 2. Compile and connect programs. 3. Run! (Or run the pre-compiling version Demo2_2.exe directly on the CD-ROM.) You must always think that there is at least one hundred lines of code for a basic Windows program. When you compile and run this program, you will see the content shown in Figure 2-5. Figure 2-5: Running Demo2_2.exe Program Analysis There is now a complete Windows program that allows us to analyze the contents of the program. First first line program is #define win32_lean_and_mean, this should be explained slightly. There are two ways to create a Windows program - using the Microsoft Foundation Classes, MFC, or uses the Software Development Kit, SDK. The MFC is completely based on C and classes. It is much more complicated than the tools required for previous game programming, and the functions are strong enough and complex enough to cope with the needs of the game. SDK is a manageable package that can learn (at least preliminary learning) within one or two weeks, and it uses orthodox C language. Therefore, the tool I used in this book is SDK. Win32_lean_and_mean Indicates the compiler (actually determines the list of header files) Do not include the MFC content we don't need. Now we have left the title again, come back and continue to see the program. Then, the header files listed below are included: # include # include
The first one contains "windows.h" actually includes all Windows header files. Windows has many of the first file, which is a bit like a batch contains, saving many manually containing explicit header files.
The second includes "Windowsx.h" is a header with many important macros and constants that simplifies Windows programming.
The following is the most important part - all the main entry positions of all Windows applications WinMain ():
Int WinApi Winmain (Hinstance Hinstance,
Hinstance Hprevinstance,
LPSTR LPCMDLINE,
INT ncmdshow;
First, you should pay attention to the strange WinAPI declare. This is equivalent to the PASCAL function declaration, and it enforces the parameters to pass on the left, not the parameter like the default CDECL declare. Transfer from right to left. However, the PASCAL call agreed statement has been outdated, and WinAPI replaces the function. WinMain () must be used; otherwise, an incorrect parameter is returned to the function and terminate the start program.
Inspection parameters
Let us take a look at each parameter in detail:
Hinstance-This parameter is an instance handle that Windows generates for your application. An example is a pointer or number used to track resources. In this case, Hinstance is like a name or address, used to track your application. HPREVINSTANCE-this parameter is no longer used, but in the old version of Windows, it tracks the previous instance of the application (in other words, it is an application instance of the current instance). No wonder Microsoft wants to remove it, it is like a time travel - let us take a headache.
• lpcmdline - This is a null-terminated string, and the command line parameters in the standard C / C main (int Argc, char ** argv) function are similar. Different, it does not have a separate parameter to indicate the number of command line parameters like Argc. For example, if you create a Windows application with Test.exe, and use the following parameters:
Test.exe One Two Three
LPCMDline will contain the following data:
LPCMDLINE = "One Two Three"
Note that .exe's file name is not part of the command line.
• ncmdshow - the last parameter is a integer. It is passed to the application during startup, with how to open the master application window. In this way, the user will have a little control application how the application is started. Of course, as a programmer, if you want to ignore it, you can use it. (You pass the parameters to showwindow (), we are more advanced!) Table 2-2 lists the most common parameter values of NCMDSHOW.
Table 2-2: Windows Codes for ncmdshow
Value function
SW_SHOWNORMAL activates and displays a window. If the window minimizes or maximizes, Windows returns it to the original size and location. When the window is displayed for the first time, the application will specify the flag.
SW_SHOW activates a window and displays the current size and location
SW_HIDE hides a window and activates another window
SW_MAXIMIZE maximizes the specified window
SW_MINIMIZE minimizes the specified window and activates the next window under the z order.
SW_RESTORE activates and displays a window. If the window minimizes or maximizes, Windows returns it to the original size and location. When it is restored to the minimum window, the application must specify the flag.
SW_SHOWMAXIMized activates a window and displayed with maximizing the window.
SW_SHOWMINIMIZED Activate a window and displayed at minimization window
SW_SHOWMINNOACTIVE displays a window in a minimized window, and the activated window remains activated.
SW_SHOWNA displays a window in the current state, and the activated window remains activated.
SW_SHOWNOACTIVATE Displays the window in size and position above, and the activated window remains activated.
As shown in Table 2-2, NCMDSHOW has many settings (there is no meaning in many values). In fact, most of these settings are not delivered in NCMDSHOW. You can use another function showWindow () to use them, which is responsible for displaying a created window. This will be discussed in detail later in this chapter.
What I want to say is that Windows has a lot of you from unused options and markers, just like the video programming option -, the better, you are using. Windows is designed in this way. This will make everyone satisfied, which means it contains many options. In fact, we will only use SW_SHOW, SW_SHOWNORMAL and SW_HIDE in 99%, but you have to know other options that will be used in 1%. Select a message box
Finally, let us discuss the actual mechanism of WinMain () to call MessageBox (). Messagebox () is a Win32 API function, that is, doing something for us, so that we don't need to do it. This function is often used to display information with different icons and one or two buttons. You see, simple information shows that it is very common in the Windows application. It has such a function to save programmers, not to spend more than half an hour for more than half an hour.
Messagebox () does not have too much fancy, but it is very duty. It can display a window on the screen to propose a problem and accept the user's input. Here is a function prototype of Messagebox ():
Int messagebox (hwnd hwnd, // handle of ooner window
LPCTSTR LPTEXT, / / Address of Text In Message Box
LPCTSTSTR LPCAPTION, / / Address of Title of Message Box
Uint utype); // style of message box
The parameter is defined as follows:
HWND - This is the handle of the information box connection window. At present, we have not told window handles, so it is considered to be the parent window of the information box. In Demo2_2.cpp, we set it to null null, so the Windows desktop is used as a parent window.
? Lptext - This is a null value termination string containing the display text.
• LPCAPTION-This is a null value termination string containing the text box title.
Utype - This is probably the only exciting parameter in the cluster parameter, which decides which information box.
Table 2-3 lists several MessageBox () options (some deletions).
Table 2-3: MessageBox () option
Sign description
The following sets of control information boxes
The MB_OK message box contains a button: OK, this is the default value
The MB_OKCANCEL message frame contains two buttons: OK and Cancel
The MB_RETRYCANCEL message frame contains two buttons: Retry and Cancel
MB_YESNO information boxes contain two buttons: Yes and NO
The MB_YESNOCANCEL information box contains three buttons: Yes, NO and Cancel
The MB_ABortRetryignore information box contains three buttons: Abort, Retry and Ignore
This set of control adds a little "poor multimedia" on the icon.
MB_ICONEXCLAMATION information box displays an exclamation mark icon
The MB_ICONInformation information box displays an icon composed of lowercase letters I in a circle
MB_ICONQUESTION message box displays a question mark icon
MB_ICONSTOP information box displays a terminator icon
This flag group controls the highlight button when the default is
MB_DEFBUTTONN where N is a number indicating the default button (1 ~ 4), count from left to right
Note: There are other advanced OS grade signs, we have not discussed. If you want to know more details, you can consult the online help of the compiler Win32 SDK.
You can use the values in Table 2-3 for logic or operations to create a message box. In general, only one flag can only be used from each group to perform or operate. Of course, like all Win32 API functions, the MessageBox () function returns a value to notify the program that will occur. But who cares about this in this example? Typically, if the information box is the case of YES / NO questions, you want to know this return value. Table 2-4 lists possible return values.
Table 2-4: Back value of MessageBox ()
Value button
IDABORT ABORT
IDCANCEL CANCEL
Idignore Ignore
IDNO NO
IDOK OK
IDRETRY RETRY
IDYES YES
Finally, this table has not missed all return values. The progressive analysis of our first Windows program - click on our first Windows program is now completed.
Indicate
Now I hope that you can easily modify this program and compile in a different way. Use different compiler options such as optimization. Then try to run the program through the debugger to see if you are already appreciated. After completing, please return here.
If you want to hear the sound, a simple skill is to use the MessageBeep () function, you can check it in Win32 SDK, which is as simple as the MessageBox () function. Below is the function prototype:
Bool messagebeep (uint utype); // the Sound to Play
Different sounds can be obtained from the constants shown in Table 2-5.
Table 2-5: Sound Identifiers for MessageBeep ()
Value sound
MB_ICONASTERISK system asterisk
MB_ICONEXCLAMATION system exclamation mark
MB_ICONHAND system hand pointer
MB_ICONQUESTION system question mark
MB_OK system default value
0xffffffffffffffFfff uses the standard beep of the computer speaker, is annoying
Note: If you have already installed the MS-Plus theme song, you should be able to get interesting results.
See how cool Win32 API! There can be hundreds of functions. Although they are not the fastest functions in the world, they are already great for general daily work, input and output and graphical user interfaces.
Let us spend some time to summarize the knowledge we have known to the WINDOWS programming. First, Windows supports multi-task / multi-threads, so you can run multiple applications at the same time. We can do this without having to worry. We are most concerned about that Windows is an event-driven. This means that we must deal with events (we don't know how to do this at this point) and respond. Ok, I have listened to it. Finally all Windows programs start with functions WinMain (), the parameters in the Winmain () function are more main () than standard DOS, but these parameters are logical and reasoning areas.
Mastered the above content, I went to write a real Windows application.
Realistic Windows app
Although this book's goal is to write 3D games running in a Windows environment, you don't need to know more Windows programming. In fact, what you need is a basic Windows program, you can open a window, process information, call the main game loop, and more. I have learned these, the goal in this chapter is to show you how to create a simple Windows application, and lay the foundation for the programming programming program similar to 32-bit DOS environments.
The key to a Windows program is to open a window. One window is a work area that displays text and graphics information. To create a fully utility Windows program, just do the following:
1. Create a Windows class. 2. Create an event handle or WinProc.
3. Register the Windows class with Windows.
4. Create a window with the previously created Windows class.
5. Create a primary event loop that can get from the event handle or transmitting Windows information from the event handle.
Let us learn more about every step.
Windows class
Windows is actually an object-oriented operating system, so a lot of concepts and programs in Windows are from C . One of the concepts is the Windows class. Each window, control, list box, dialog, and widgets in Windows are actually a window. The difference is that they define their classes. A Windows class is a description of a window type that Windows can operate.
There are many predefined Windows classes such as buttons, list boxes, file selectors, and more. You can also create your Windows classes anymore. In fact, you can create at least one Windows class for each application written by yourself. Otherwise your program will be very troublesome. Therefore, when you draw a window, consider a Windows class as a template for Windows to facilitate processing information.
There are two data structures that control the Windows class information: WNDCLASS and WNDCLASSEX. Wndclass is a relatively old one, may soon be discarded, so we should use the new extension WNDCLASSEX. The two structures are very similar. If you are interested, you can check WNDCLASS in Win32. Let's take a look at WndClassex defined in the Windows header file.
TypedEf struct _wndclassex
{
Uint Cbsize; // Size of this Structure
Uint style; // style flags
Wndproc lpfnwndproc; // function Pointer to Handler
Int cbclsextra; // extra class info
Int CbWndextra; // Extra WINDOW INFO
Handle hinstance; // the instance of the application
Hicon Hicon; // the main icon
Hcursor hcursor; // the cursor for the window
Hbrush Hbrbackground; // the background brush to pieint the window
LPCTSTR LPSZMENUNAME; // the name of the menu to attach
LPCTSTR LPSZCLASSNAME; // the name of the class itself
Hicon Hiconsm; // The Handle of The Small icon
WNDCLASSEX;
So what you have to do is create a structure, then fill in all fields:
WNDCLASSEX WINCLASS; // a Blank Windows Class
The first field CBSIZE is very important (although Petzold ignored it in "Programming Windows 95"), it is the size of the WNDCLASSEX structure itself. You may want to ask, why should you know the size of this structure? This question is good because this structure is passed as a pointer, the recipient first checks the first field to determine how much the minimum size is minimum. This is a bit like prompts and help information so that other functions do not have to calculate the size of this class when running. Therefore, we only need to write like this:
Winclass.cbsize = sizeof (wndclassex);
The second field contains a style information flag describing the general attribute of the window. There are many such signs, so I didn't list them all. Just use them to create any type of window. Table 2-6 lists commonly used signs. Readers can arbitrarily logical "or" operations to derive the hoped window type.
Table 2-6: Style Flags for Window Classes
Identification description
If the CS_HREDRAW moves or changes the window width, refresh the entire window.
If the CS_VREDRAW moves or changes the window height, refresh the entire window.
CS_OWNDC assigns a single-value device description table for each window in this class (described in detail later in this chapter)
CS_DBLCLKS Sends a double-click information to the window program when the user doubles the mouse, and the cursor is located in the window belonging to this class.
CS_PARENTDC Sets a shearing area of a child window in the female window so that the child window can draw in the female window.
CS_SAVEBITS holds user images in a window to facilitate the screen when the window is covered, and the screen is not required. However, this will take up more memory, and more slower than artificial operations.
CS_NOCLOSE prohibits closing commands on the system menu
Note: The part of the bold display is the most commonly used sign.
Table 2-6 contains a lot of logo, if you feel confused, I will not blame you. Now, the style identifier is set, and the screen is refreshed if the window moves or changed the size, and a static device descript will be obtained, and the ability to handle the double-click event.
We will discuss the device description table in detail in Chapter 3, "Advanced Windows Program", but basically, it is used as the data structure of image coloring in the window. Therefore, if you want to handle an image, apply to a device description table for the particular window of interest. If a Windows class is set, it gets a device descriptor by cs_owndc, if you don't want to apply for an apparatus description table each time you process an image, you can save it for a while. What is it to help you or make you more confused? Windows is like this - you know, the more problems. All right! Let's talk about how to set the style field:
WinClass.Style = CS_VREDRAW | CS_HREDRAW | CS_OWNDC | CS_DBLCLICKS;
The next field of the WNDCLASSEX structure is LPFNWndProc is a function pointer to the event handle. Basically, it is set to the callback function of the class. The callback function is often used in Windows programming. The working principle is as follows: When there is an incident, Windows notifies you by calling a callback function you have provided, this province to your blind inquiry. Subsequently in the callback function, the required operation is again.
This process is the basic Windows event loop and the operation process of event handle. Apply for a callback function to the Windows class (of course, a specific prototype) is required. When an event occurs, Windows calls it for you as shown in Figure 2-6. About this item We will introduce more in more detail below. But now, readers only want to set it to the event function you will write:
WinClass.lpfnWndProc = WinProc; // this is Our function
Figure 2-6: The Windows Event Handler Callback in Action.
Indicate
The function pointer is a bit like the virtual function in C . If you are not familiar with them, talk about it here. Suppose there are two functions that are also used to operate two numbers: int Add (INTOP1, INTOP2) {RETURN (OP1 OP2);
INT SUB (int OP1, INTOP2) {RETURN (OP1-OP2);
To use the same call to call any of the two functions, you can use a function pointer to be implemented, as follows:
// define a function Pointer Takes Two int AND
Returns an Int
INT (INT, INT);
Then you can give a function point to the function:
Math = add;
Int result = math (1, 2); // this real cals add (1, 2)
// Result Will BE 3
Math = Sub; int result = Math (1, 2); // this real calls sub (1, 2) // Result Will be -1, good. The following two fields, Cbclsextra, and CbWndextra are designed to indicate that Windows saves additional runtime information to some units of Windows classes. However, most people use these fields and simply set their values to 0, as shown below: WinClass.cbclsextra = 0; // extra class info spacewinclass.cbWndextra = 0; // Extra window info space Next is a hinstance field . It is Hinstance that passes to the WinMain () function at startup, so simply simply copy from WinMain (): WinClass.hinstance = Hinstance; // Assign The Application Instance remaining fields and Windows class images Related to the discussion, spend a little more time to review the handle. Will you have repeatedly seen the handle in the Windows program and type: the bitmap handle, the cursor handle, the handle of anything. Keep in mind that the handle is just an identifier based on an internal Windows type. In fact, they are all integers. But Microsoft may change this, so the safe use of Microsoft type is a good idea. In short, you will see more and more "[...] handles", keep in mind that any type of prefix H is usually a handle type. Ok, go back to the original place to continue. The next field is the type of icon that represents the application. You can load an icon you own yourself, but now use the system icon for your convenience, you need to set a handle for it. To retrieve a handle for a common system icon, you can use the loadICON () function: winclass.hicon = loadicon (null, idi_application); this line code loads a standard application icon - although it is not a feature, it is simple. If you are interested in the loadICON () function, please see the prototype below, Table 2-7 gives several icon options: Hicon Loadicon (Hinstance Hinstance, // Handle of Application Instancelpctstr LPICONNAME); // icon-name String or icon Resource IdentifierHINSTANCE is an instance of the application loaded icon resource from the application (discussed in detail later). Now set it to NULL to load a standard icon. LPiconName is a null value termination string containing the load icon resource name. When Hinstance is NULL, the value of LPICONNAME is as shown in Table 2-7. Table 2-7: Icon Identifiers for Loadicon () Value Description IDI_Application Default Application Icon IDI_ASTERISK Search IDi_Exclamation Exclamation Number IDI_HAND Hand Icon IDI_QUESTION Question mark IDi_winlogo Windows logo, now we have already introduced half of the field. Do a deep breathing and take a break, let us introduce the next field hcursor. Similar to Hicon, it is also an image object handle. Different, HCursor is a cursor handle that is not until the user area enters the window. Using the loadcursor () function can get a resource or a predefined system cursor. We will discuss resources later, and the resource is the same data segment like bitmap, cursor, icon, sound, etc., which is compiled into the application and can be accessed at runtime.
The cursor settings of the Windows class are as follows: WinClass.hcursor = loadingcursor (null, idc_arrow); the following is the prototype of the loadCursor () function (Table 2-8 lists different system cursor identifiers): HCURSOR LOADCURSOR (Hinstance Hinstance) , // Handle of Application Instancelpctstr LpCursorname); // name string or cursor resource IdentifierHinstance is your .exe's application instance. The .exe application contains resource data, can solve the custom cursor by name. But now we don't plan to use this feature, so let's set Hinstance to NULL to use the default system cursor. LpCursorname identifies the resource name string or resource handle (we don't use it now), or a constant to identify the system default value as shown in Table 2-8. Table 2-8: LoadCursor () Value Value Description IDC_Arrow Standard Arrow IDC_AppStarting Standard Arrows and Small Hour IDC_CROSS Language Line IDC_IBEAM Text I Type IDC_NO Triangular Circle IDC_SIZEALL Arrow IDC_SENESW Points to Northeast - Southwest Direction Arrow IDC_SIZENS pointing to the two-way arrow IDC_SIZENWSE in the north-south direction pointing to the southeast - the two-way arrow IDC_SIZEWE in the northwest direction pointing the two-way arrow IDC_UPARROW in the northwest direction IDC_UPARROW vertical arrow IDC_WAIT Hourglass Now we have to go to the head! We will have to introduce all - the remaining fields are more meaningful. Let's take a look at Hbrbackground. Whether when you draw or refresh a window, Windows will at least fill the background of the window with the user predefined color or by Windows - brush (brush). Therefore, HBRBackground is a brush handle for windows refresh. The painting, brush, color and graphics are part of GDI (graphics device interface), and we will discuss in detail in the next chapter. Now introduce how to apply for a basic system brush to fill the window. This function is implemented by a getStockObject () function, as shown in the following program (note transformation to (HBrush)): WinClass.hbrbackGround = (HBrush) getStockObject (white_brush); getStockObject () is a general function for obtaining a Windows system A handle of brush, brush, palette or font. GetStockObject () has only one parameter to indicate which resource loaded. Table 2-9 Only the possibility of painting and brush is listed. Table 2-9: GetStockObject () object identifier value of inventory described BLACK_BRUSH WHITE_BRUSH white black brush brush brush LTGRAY_BRUSH GRAY_BRUSH gray light gray dark gray DKGRAY_BRUSH Brush Brush Brush Hollow HOLLOW_BRUSH NULL_BRUSH empty (NULL) black brush BLACK_PEN Brush White_Pen White Brush Null_Pen Null (NULL) The next field in the brush WNDCLASS structure is lpsz Genename. It is a null value termination ASCII string for menu resource names for loading and selecting a window. The working principle will be discussed in Chapter 3 "Advanced Windows Programming".
Now we need to set the value to null: winclass.lpszmenuname = null; // the name of the menu to attach As I just mentioned, each Windows class represents the different window types created by your application. To some extent, the class is similar to the template, and Windows requires some way to track and identify them. Therefore, the next field lpszclassname is used for this purpose. This field is configured to terminate the string of a null value containing the related class text marker. I personally like identifiers such as "Winclass1", "Winclass2". You can preference, but you should make a simple understanding, as shown below: WinClass.lpszclassname = "winclass1"; // the name of the class itself This is the name, you can use its name to reference this new Windows class, "winclass1" - is cool, is it? Finally, the small application icon. This is the newly added function in Windows class WNDClassex, not in the old version of WNDCLASS. First, it is a handle pointing to your window title bar and Windows desktop taskbar.
You often need to load a custom resource, but now you can use a standard Windows icon with a standard Windows icon by loading: Winclass.Hiconsm = Loadicon (NULL, IDI_APPLICATION); // The Handle of The Small Icon Let us whole recall the definition of the entire class: WNDCLASSEX winclass; // this will hold the class we create // first fill in the window class structurewinclass.cbSize = sizeof (WNDCLASSEX); winclass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW; winclass. lpfnWndProc = WindowProc; winclass.cbClsExtra = 0; winclass.cbWndExtra = 0; winclass.hInstance = hinstance; winclass.hIcon = LoadIcon (NULL, IDI_APPLICATION); winclass.hCursor = LoadCursor (NULL, IDC_ARROW); winclass.hbrBackground = GetStockObject ( BLACK_BRUSH); winclass.lpszMenuName = NULL; winclass.lpszClassName = "WINCLASS1"; winclass.hIconSm = LoadIcon (NULL, IDI_APPLICATION); of course, if you want to save some typing time, this can simply initialize the structure as follows: WNDCLASSEX winclass = {winclass.cbSize = sizeof (WNDCLASSEX), CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW, WindowProc, 0,0, hinstance, LoadIcon (NULL, IDI_APPLICATION), LoadCursor (NULL, IDC_ARROW), GetS TOCKOBJECT (Black_brush), NULL, "Winclass1", Loadicon (Null, IDi_Application)}; this really saves a lot of input! Registering the Windows class Now Windows classes have been defined and stored in WinClass, you must notify Windows for new classes. This feature is done by the registerClassex () function, using a pointer to the new class definition, as shown below: RegisterClassex (& WinClass); WARNING I have not used the "Winclass1" class name in our example, for RegisterClassex () Speaking, you must use the actual structure of the class, because Windows does not know the existence of this class before this class calls the registerclassex () function. you got it? In addition, in order to stand, there is an old version of the registerclass () function to register the class based on the old structure WNDCLASS. Once the class is registered, we can arbitrarily create its window. Please see how this work is made below, then look at the event handle and main event loop, and find what work will be done by making a Windows application running.
Creating a window To create a window (or object of a class window), use the CreateWindow () or CREATEWINDOWEX () function. The latter is an update version that supports additional type parameters, we use it. This function is a function of creating a Windows class, and we have to take a point by one. When you create a window, you must provide a positive name for this Windows class - we now use "Winclass1" named. This is an identifier that identifies the Windows class and distinguishes between other classes and embedded, such as buttons, text boxes. This is CreateWindowEx () function prototype: HWND CreateWindowEx (DWORD dwExStyle, // extended window styleLPCTSTR lpClassName, // pointer to registered class nameLPCTSTR lpWindowName, // pointer to window name DWORD dwStyle, // window style int x, // horizontal position of window int y, // vertical position of window int nWidth, // window width int nHeight, // window height HWND hWndParent, // handle to parent or owner window hMENU hMenu, // handle to menu, or child-window IdentifierHinstance Hinstance, // Handle To Application InstancelPvoid LPPARAM); // Pointer To WINDOW-CREATION DATA If the function performs success, a handle pointing to the new window will return; otherwise return null Null. Most of the above parameters are self-definitive, but let's quickly browse:? DWEXStyle-The extended style flag is a high-level characteristic, most case, can be set to NULL. If the reader is interested in the value, you can consult the Win32 SDK help, which has a detailed description of this identifier. WS_EX_TOPMOST is the only value I used, which keeps the window in the upper part. • LPClassName - This is the basic class name of the window you created - such as "Winclass1". ? Lpwindowname- This is a null value termination string containing the window title - such as "My First Window". DWStyle - This is a general window logo for explaining window appearance and behavior - it is very important! Table 2-10 lists some of the most common values. Of course, these values can be used in any combination of logical "or" to obtain various features. ? X, y - This is the pixel coordinate of the top left corner of the window. If you don't care, you can use CW_USEDEFAULT, which will be determined by Windows. ? NWIDTH, NHEIGHT - this is the width and height of the window represented by pixels. If you don't care, you can use CW_USEDEFAULT, which will be determined by Windows to determine the window size. HWndParent- If there is a parent window, this is a handle pointing to the parent window. If there is no parent window, take null, the desktop is the parent window. HMenu- This is a handle that is attached to the window menu. The next chapter will be described in detail, and it is now assigned NULL. Hinstance - This is an instance of the application.
This is used from WinMain () using Hinstance. • LPPARAM-Advanced feature set to null. Table 2-10 lists various window logo settings. Table 2-10: General Style Values for dwStyle content type created WS_POPUP WS_OVERLAPPED pop-up window overlay window with a title bar and borders, similar WS_TILED type WS_OVERLAPPEDWINDOW have overlapping WS_OVERLAPPED, WS_CAPTION, WS_SYSMENU, WS_THICKFRAME, WS_MINIMIZEBOX and WS_MAXIMIZEBOX style Window WS_Visible begins with the window WS_SYSMENU title bar with window menu, WS_CAPTION must also be specified WS_BORDER has a window WS_CAPTION with a thin line boundary (including WS_Border style) WS_ICONIC starts to minimize windows, similar WS_MINIMIZE Style WS_Maximize starts to maximize window WS_MaximizeBox has a window with a maximum button. Can't use with WS_EX_CONTEXTHELP style. WS_SYSMENU must also specify a window that minimizes WS_MINIMIZE, similar to the WS_ICONIC style WS_MINIMIZEBOX has a minimization button. Can't merge with the WS_EX_CONTEXTHELP style. WS_SYSMENU must also specify WS_POPUPWINDOW with WS_BORDER, WS_POPUP WS_SYSMENU type and pop-up windows; WS_POPUPWINDOW the WS_CAPTION and S must also be specified so that the window menu is visible WS_VSCROLL WS_SIZEBOX a window boundary may change, and the same type WS_THICKFRAME WS_HSCROLL window with a horizontal scroll bar Window with a vertical scroll bar Note: Displayed with bold is often used. Below is a simple overlapping window that creates a size of 400x400 pixels using standard controls in (0,0). HWND HWND; // WINDOW HANDLE
// Create the window, bail if problemif (! (hwnd = createwindowex (null, // extended style "winclass1", // class "Your Basic Window", // Title WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, // Initial X , Y 400, 400, // initial width, height null, // handle to piertance, // handle to menu hinstance, // instance of this application null)) // Extra create parmsreturn (0); this window is created It may be visible or undesirable. However, in this example, we add automatic type identifier WS_Visible. If this identifier is not added, the following function is called to manually display the window: // this show the windowWindowWindow (HWND, NCMDSHOW); Remember the ncmdshow parameters in Winmain ()? This is the convenience of using it. Although we use WS_Visible to overwrite the ncmdshow parameters, but should also be passed as a parameter to showwindow (). Let's update the Windows content and generate a WM_PAINT information, which is completed by calling the function updateWindow (): // this sendows a wm_paint message to window and makes // Sure the contents are refreshedupdateWindow (); Event Handle I don't Understand your situation, but pay attention to me now makes you master the core of Windows. It has a mysterious novel. Keep in mind that the event handler (Event Handler) is the callback function called from the main event loop when the event occurs. Looking back in Figure 2-6, consolidating your impression of the general data stream. The event handle is written by yourself, it can handle all the events you care about. The rest of the work will be handed over to Windows. Of course, keep in mind that the more events and messages you can handle, the more features it is. Before writing a program, let's discuss some details of the event handle, that is, what the event handle can do, how to work. First, for any Windows class created, there is a separate event handle. From now, I will call it with Windows' Procedure, referred to as WinProc. When the message sent by the user or Windows is received and placed in the primary event sequence, WinProc receives the message sent by the main event loop. This is simply a crazy winding, let me change ... When the user is running the task, your window and / or other application window generate events and messages. All messages enter a queue, and your window is sent to your window dedicated queue. The main event is then retrieved and sends them to the WinProc of your window. This almost hundreds of possible messages and variables, so we are not all analyzed.
Fortunately, you can start and run the Windows application with little messages and variables. Simply put, the main event loop feeds the messages and events to WinProc, and WinProc processes them. Therefore, not only you have to pay attention to WinProc, the main event loop is also concerned about WinProc. Now we briefly understand WinProc, now assume that WinProc receives only messages. Now let's take a look at WinProc's working mechanism, let's take a look at its prototype: LResult Callback WindowProc (Hwnd Hwnd, // Window Handle of Senderuint Msg, // The Message IDwparam WParam, // Further Defines MessagelParam LPARAM); // Further Defines Message, of course, this is just the prototype of the callback function. As long as the function address is passed to WinClass.lpfnWndProc, you can call any information on this function, as shown below: WinClass.lpfnWndProc = WINDOWPROC; Remember? In short, these parameters are quite natural:? HWnd- This is a Windows handle, which is only used when you use the same window class to create multiple windows. In this case, hwnd is the only way to indicate which window comes from. Figure 2-7 shows this situation. Figure 2-7: Multiple Windows Based on The Same Class.? MSG - This is a real WinProc processing message identifier. This identifier can be one of many major messages. • WPARAM and LPARAM- Further match or classified information sent to the MSG parameter. Finally, we are interested in return type LRESULT and declaration setup callback. These keywords are required, can't forget them! Therefore, most people have to do to use Switch () to process the messages represented by MSG and then write code for each case. On the MSG, you can know if you need to further request the value of WPARAM and / or LPARAM. Is it cool? So let's take a look at all possible messages passed by WinProc, then look at WinProc work mechanism. Table 2-11 briefly lists some basic message specifiers. Table 2-11: a Short List of Message IDS Value Description WM_Activate When the window is activated or becomes a focus, pass the WM_CREATE When the window is closed when the window is closed, the WM_DESTROY is delivered when the window is created. WM_MOVE is transmitted when the window may be destroyed. When the window is moved, WM_MOUSEMOVE pass when the mouse is transferred when the mouse is released when a key is released when a key is released, transferring WM_Timer when pressing a key, passing the WM_USER, allowing the message WM_USER to pass the message WM_PAINT When a window is returned, WM_QUIT is transferred when Windows When the application last ends, WM_SIZE passes the WM_SIZE. When a window changes the size, you should take care of the table 2-11, understand the functions of all messages. One or more of the above messages will be passed to WinProc at the application runtime. The message setup itself is in the MSG, while other information is stored in WPARAM and LPARAM. Therefore, referring to the meaning of the parameters represented by the online Win32 SDK to find the parameters of a message are a good idea. Fortunately, we are only interested in the following three messages: • WM_CREATE- When the window is created, the message is delivered so that you can start, initialize, or resource configuration. • WM_PAINT - The message is passed when a window content needs to be redrawn. This may have many reasons: the user moves the window or changing its size, pops up other applications and blocks your window.
• WM_DESTROY - The message will be passed to the window when your window will be destroyed. Usually this is due to the shutdown button that the user clicks on the window, or it is caused from the window's system menu. Regardless of the above way, all resources should be released, and the Windows fully terminated the application should be notified by sending a WM_Quit message. Alongings will also be described in detail later. Don't panic, let's take a complete WinProc to process all of these messages. LRESULT CALLBACK WindowProc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {// this is the main message handler of the systemPAINTSTRUCT ps; // used in WM_PAINTHDC hdc; // handle to a device context // what is the messageswitch (msg) {CASE WM_CREATE: {// Do INITIALIZATION STUFF Here
// Return Success Return (0);} Break;
Case WM_Paint: {// simply validate the window hdc = beginpaint (hwnd, & ps); // you Would do all Your Painting Here Endpaint (hwnd, & ps);
// Return Success Return (0);} Break;
Case WM_DESTROY: {// Kill The Application, This Sends a wm_quit message postquitmessage (0);
// Return Success Return (0);} Break;
DEFAULT: BREAK;
} // End Switch
// Process Any Messages That We Didn't Take Care Ofreturn (DEFWINDOWPROC (HWND, MSG, WPARAM, LPARAM);
} // End WinProc can be seen above, most of the function is composed of space - this is a good thing. Let us start explaining WM_CREATE. This function is just Return (0). That is to inform Windows you have already handled it, so there is no more operation. Of course, all initialization work can be performed in the WM_CREATE message, but that is determined by you. The next message WM_Paint is very important. This message is sent when the window needs to redraw. It is generally said that this indicates that you should work with you. For DirectX games, this is not something big, because you will once will redraw on the screen at a speed of 30 to 60fps (frame / sec). But for the standard Windows application, it is a big event. I will introduce WM_PAINT in more detail in the later chapter. The current function is to inform Windows, you have saved the window, so stop sending the WM_PAINT message. To complete this feature, you must activate the client area of the window. There are many ways to do, but the call function beginpaint () and endpaint () are the easiest. This pair call will activate the window and draw a background with the background drawing of the variable HBRBackground originally stored in the Windows class. Below is the relevant program code for you to verify: // begin PaintingHDC = BeginPaint (hwnd, & ps); // You Would Do All your Painting HereEndPaint (HWND, & PS); Need to remind a few things. First, please note that the first parameter of each call is the window handle HWnd. This is a very necessary parameter because the beginpaint () - endpaint () function can draw in any application window, so the window handle indicates which window to be heavy. The second parameter is the address of the PAINTSTRUCT structure that contains the rectangular area that must be heavy. Here is PAINTSTRUCT structure: typedef struct tagPAINTSTRUCT {HDC hdc; BOOL fErase; RECT rcPaint; BOOL fRestore; BOOL fIncUpdate; BYTE rgbReserved [32];} PAINTSTRUCT; in fact, these need to consider now, when we discuss the Graphics Device Interface (GDI This function will be discussed again. The most important field is RCPaint, which is a rectangular structure (RECT) that indicates the minimum heavy painting area. Figure 2-8 shows the content of this field. Note that Windows has been trying to do the least work as much as possible, so when a window content is destroyed, Windows will at least tell you that the content needs to be restored to the smallest rectangle.
If you are interested, you will find that only the four corners of the rectangle are the most important, as shown below: TypeDef struct tagRect {long left; // Left x-Edge of Rect Long Top; // Top Y-EDGE OF RECT LONG Right; // Right X-Edge of Rect Long Bottom; // Bottom Y-Edge of Rect} Rect; Figure 2-8: Repainting The Invalid Region Only. The last thing that call the beginpaint () function should pay attention to, It returns a handle of graphics context or HDC: HDC HDC; // handle to graphics contexthdc = beginpaint (hwnd, & ps); graphics environment is to describe video systems and data structures being drawn. Wonderful is that if you need to draw graphics, you can get a handle to the graphic environment. This is the content of the WM_Paint message. WM_DESTROY news is actually very interesting. WM_DESTROY is sent when the user closes the window. Of course just close the window, not the application. The application continues to run, but there is no window. Some processing is performed. In most cases, when the user closes the main window, it means that the application is to be closed. Therefore, you must notify the system by sending a message. This message is WM_QUIT. Because the message is often used, there is a function postquitMessage () to complete the send job for you. What you have to do in the WM_DESTROY handler is to clear everything, then call PostQuitMessage (0) to inform Windows termination applications. The WM_QUIT is then placed in the message queue, so that the main event loop is terminated at some time. There are still many details in the WinProc handle we have analyzed. First, you must noticed Return (0) after each processing program. It has two purposes: exiting WinProc and notifying Windows you have handled information. The second important detail is the default message handler DefaultWindowProc (). This function is a transfer function that delivers Windows default processing messages. Therefore, if the message is not processed, you can end all of your event handlers by the call as follows: // process any Messages That We Didn't Take Care ofreturn (DefWindowProc (HWnd, MSG, WPARAM, LPARAM) I know that these codes may be too contrast, it seems to be more trouble. However, once you have a basic Windows application framework, you only need to copy it and add your own code. As I said, my main goal is to help you create a game console that can be used, and almost forgot any WINDOWS work that is running. Let us go to the next part - the main event loop. The part of the main event is difficult to end! The main event loop is so simple, do not believe? Write one hand to see a given you: // Enter Main Event loopWhile (GetMessage (& MSG, NULL, 0)) {// Translate Any Accelerator Keys TranslateMessage (& MSG);
// send the message to the window proc dispatchMessage (& msg);} // End while is so simple? Yes, it is so simple! Let's take a look. As long as getMessage () returns a non-zero value, the main program while () will begin. GetMessage () is a key code for the primary event loop. The only use is to get a message in the part queue and processed. You will notice that getMessage () has four parameters. The first parameter is very important to us, and the rest of the parameters can be set to NULL or 0. The prototype is listed below for reference: BOOL GetMessage (lpmsg lpmsg, // address of structure with message hwnd hwnd, // handle of window uint wmsgfiltermin, //lfiltermax); // Last Message You may have guess When it is, the MSG parameter is the storage unit where Windows places the next message. But the MSG parameters of WinProc () are different, the MSG is a complex data structure, not just an integer. When a message is passed to WinProc, it is processed and decomposed into individual components. MSG structure defined as follows: typedef struct tagMSG {HWND hwnd; // window where message occurred UINT message; // message id itself WPARAM wParam; // sub qualifies message LPARAM lParam; // sub qualifies message DWORD time; // Time of Message Event Pt; // position of mouse} msg; seeing the point eyebrows, is it? Note All parameters passed to WinProc () are included in this structure, as well as other parameters, such as the time of the event and the position of the mouse. GetMessage () get the next message from the time series, then the next called function is TranslateMessage (). TranslateMessage () is a virtual accelerator key translator - in a slogan is an input tool. Now just call it, don't take it. The last function DispatchMessage () indicates the location where all operations occur. When the message is obtained by getMessage (), the function translateMessage () is slightly processed and converted, and WinPROC is called further processing by the function dispatchMessage (). DispatchMessage () calls WinProc and sends the appropriate parameters from the initial MSG structure. Figure 2-9 shows the entire processing process. Figure 2-9: The mechanics of event loop message processing. Yes, you have become a Windows expert! If you have understood the concepts discussed above and the importance of event loops, event handlers, etc., it has been successful. The rest is only some details. Program List 2.3 is a complete Windows program, which is created a window and waiting to be closed.
Program List 2-3: A basic windows program // demo2_3.cpp - a complete windows program // inclus /// # define win32_lean_and_mean // Just Say no to mfc
#include
// incrude all the windows headers
#include
// incrude useful macros
#include
#include
// defines
// defines for windows # define window_class_name "winclass1"
// globals
// FUNCTIONS // LRESULT CALLBACK WindowProc (HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam) {// this is the main message handler of the systemPAINTSTRUCT ps; // used in WM_PAINTHDC hdc; // handle to a device context
// What is the messagewitch (msg) {copy wm_create: {// do initialization stuff Here
// Return Success Return (0);} Break;
Case WM_Paint: {// simply validate the window hdc = beginpaint (hwnd, & ps); // you Would do all Your Painting Here Endpaint (hwnd, & ps);
// Return Success Return (0);} Break; Case WM_DESTROY: {// Kill The Application, This Sends A WM_Quit Message PostquitMessage (0);
// Return Success Return (0);} Break;
DEFAULT: BREAK;
} // End Switch
// Process Any Messages That We Didn't Take Care Ofreturn (DEFWINDOWPROC (HWND, MSG, WPARAM, LPARAM);
} // End WinProc
// WinMain Int WinApi WinMain (Hinstance Hinstance, Hinstance Hprevinstance, LPSTR LPCMDLINE, INT NCMDSHOW) {
WNDCLASSEX WINCLASS; // this will hold the class we createhwnd hwnd; // generic window handlemsg msg; // generic message
// first fill in the window class structurewinclass.cbSize = sizeof (WNDCLASSEX); winclass.style = CS_DBLCLKS | CS_OWNDC | CS_HREDRAW | CS_VREDRAW; winclass.lpfnWndProc = WindowProc; winclass.cbClsExtra = 0; winclass.cbWndExtra = 0; winclass.hInstance = hinstance; winclass.hIcon = LoadIcon (NULL, IDI_APPLICATION); winclass.hCursor = LoadCursor (NULL, IDC_ARROW); winclass.hbrBackground = GetStockObject (BLACK_BRUSH); winclass.lpszMenuName = NULL; winclass.lpszClassName = WINDOW_CLASS_NAME; winclass.hIconSm = Loadicon (NULL, IDI_APPLICATION); // Register The Window Classif (! RegisterClassex (& WinClass)) Return (0);
// Create The Windowif (! (hWnd = CreateWindowEx (null, // extended style window_class_name, // class "Your Basic Window", // Title WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, // Initial X, Y 400, 400, // Initial Width, Height Null, // Handle To Parent Null, // The INSTANCE OF This Application NULL)) // Extra CREATION PARMSRETURN (0);
// Enter Main Event LoopWhile (GetMessage (& MSG, NULL, 0)) {// Translate Any Accelerator Keys TranslateMessage (& MSG);
// send the message to the window of proc dispatchMessage (& msg);} // end while
// Return to Windows Like thisreturn (msg.wparam);
} // End WinMain
// To compile Demo2_3.cpp, just create a .exe application in a Win32 environment, and add Demo2_3.cpp to the project. If you like, you can run a pre-compiled program Demo2_3.exe directly on the CD-ROM. Figure 2-10 shows the sample in the operation. Figure 2-10: Run Demo2_3.exe before making the next part, I have something to say. First, if you read the incident cycle, you will find that it looks not a real-time program. That is, the main event loop is basically locked when the program is waiting for the message passed through GetMessage (). This is indeed true; you must avoid this in a variety of ways, as you need to perform your game processing continuously, and processes them when Windows events appear. Generating a real-time event loop has a real-time unsuccessful event loop. What you need is a method of testing if there is a message in a message sequence. If so, you handle it; otherwise, continue to handle other game logic and repeat. The running test function is PeekMessage (). The prototype almost the GetMessage () varies as follows: BOOL PeekMessage (LPMSG lpMsg, // pointer to structure for message HWND hWnd, // handle to window UINT wMsgFilterMin, // first message UINT wMsgFilterMax, // last message UINT wRemoveMsg ); // Removal Flags If there is a available message, the return value is non-zero. The difference is that the last parameter, which controls how to retrieve the message from the message sequence. For WremoveMSG, the valid flag is: • After PM_NOREMOVE- PeekMessage () processing, the message is not removed from the sequence. • After PM_Remove- PeekMessage () processing, the message has been removed from the sequence. If you take these two cases, you can make two options: If you have a message, use PeekMessage () and PM_NOREMOVE, call getMessage (); another option is: Use PM_Remove, if there is a message, use The peekMessage () function itself retrieves the message. The latter case is generally used. Below is the core logic code, we will make a slight change in the main event loop to reflect this new technology: while (TRUE) {// Test if there is a message in queue, if So Get IF (PEEKMESSAGE (& MSG, NULL) , 0, 0, pm_remove)) {// Test if this is a quit if (msg.Message == wm_quit) Break; // Translate Any Accelerator Keys TranslateMessage (& MSG); // send the message to the window Proc DispatchMessage & msg);} // end if
// main game processing goes here game_main ();} // end while I have displayed the important part of the program. The first part of the bold body is: if (msg.Message == wm_quit) Break; how to test it from the infinite cyclic body while (TRUE). Keep in mind that when you process the WM_DESTROY message in WinProc, your job is to pass the WM_Quit message by calling the postquitMessage () function. WM_QUIT slowly moves in the event sequence, you can detect it, so you can jump out of the main cycle. The last part of the program with a bold display pointed out that the position of the main game program code loop is called. But don't forget, after running an animation or game logic, call GAME_MAIN () or call any program must be returned. Otherwise, the Windows main event loop will not process the message. Examples of this new type of real-time structure are ideal for game logic handlers, see the source program demo2_4.cpp, and DEMO2_4.exe related to the CD-ROM. This structure is actually the prototype of the remaining part of this book. Open multiple windows Before completing the contents of this chapter, I want to discuss a more important topic you may be very concerned - how to open multiple windows. In fact, this is a small thing, in fact, you already know how to open multiple windows. What you need to do is to call the function CreateWindowEx () multiple times to create these windows, the fact is true. However, there are some problems that need attention. First, remember when you create a window, it must be based on a window class. In all things, this window class defines WinProc or event handles. This details are critical and should pay attention to it. You can use the same class to create any number of windows, but all the messages of these windows are sent to the same WinProc as defined by the event handle points to the LPfnWndProc field in the WinClassex structure. Figure 2-11 shows in detail the message flow in this case. Figure 2-11: The Message Flow for Multiple Windows with The Same Windows Class. This may be, or you may not think. If you want each window with your own WinProc, you must create more than one window class and use different classes to create your respective windows. Thus, for each window class, there are different WinProc send messages. Figure 2-12 reflects this process.
Figure 2-12: Multiple Windows Classes with multiple windows. Remember these, the following is an example of creating two windows with the same class: // Create the first windowif (! (HWnd = CreateWindowEx (null, // extended style Window_class_name, // Class "Window 1 Based on WinClass1", // Title WS_OVERLAPPEDWINDOW | WS_VISIBLE, 0, 0, // Initial X, Y 400, 0, // Initial Width, Height Null, // Handle To Parent Null, // Handle To Menu Hinstance, // Instance of this Application NULL)) // Extra Creation Parmsreturn (0);