The World's Simplest Windows ProgramNow that you have a general overview of the Windows OS and some of its properties and underlying design issues, let's begin our journey into real Windows programming with our first Windows program. It's customary to write a "Hello World" program in any new language or OS that you're learning, so let's try that. Listing 2.1 is the standard DOS-based "Hello World." Listing 2.1 A DOS-Based "Hello World" Program// DEMO2_1.CPP - standard version #include <stdio.h> // main entry point for all standard DOS/console programs void main(void) { printf("\nTHERE CAN BE ONLY ONE!!!\n"); } // end main Now let's see how it's done with Windows. TIP By the way, if you want to compile DEMO2_1.CPP, you can actually create what's called a CONSOLE APPLICATION with the VC++ or Borland compilers. These are like DOS applications, but 32-bit. They run only in text mode, but they're great for testing out ideas and algorithms. To do this make sure to set the target .EXE as CONSOLE APPLICATION in the compiler NOT Win32 .EXE! To compile the program, follow these steps: It All Begins with WinMain()As I mentioned before, all Windows programs begin execution at the function named WinMain(). This is equivalent to main() in a straight DOS program. What you do in WinMain() is up to you. If you want, you can create a window, start processing events, and draw things on the screen. On the other hand, you can just make a call to one of the hundreds (or are there thousands?) of Win32 API functions. This is what we're going to do. I just want to print something on the screen in a little message box. There just so happens to be a Win32 API function that does this—MessageBox(). Listing 2.2 is a complete, compilable Windows program that creates and displays a message box that you can move around and close. Listing 2.2 Your First Windows Program// DEMO2_2.CPP - a simple message box #define WIN32_LEAN_AND_MEAN #include <windows.h> // the main windows headers #include <windowsx.h> // a lot of cool macros // main entry point for all windows programs int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow) { // call message box api with NULL for parent window handle MessageBox(NULL, "THERE CAN BE ONLY ONE!!!", "MY FIRST WINDOWS PROGRAM", MB_OK | MB_ICONEXCLAMATION); // exit program return(0); } // end WinMain To compile the program, follow these steps:
And you thought that a basic Windows program had hundreds of lines of code! Anyway, when you compile and run the program, you should see something like what's depicted in Figure 2.5. Figure 2.5. Running DEMO2_2.EXEDissecting the ProgramNow that you have a complete Windows program, let's take it apart line by line and see what's going on. The very first line of code is #define WIN32_LEAN_AND_MEAN This deserves a bit of explanation. There are two ways to create Windows programs—with the Microsoft Foundation Classes (MFC), or with the Software Development Kit (SDK). MFC is much more complex, totally based on C++ and classes, and 10 times more powerful and complicated than you will ever need for games. On the other hand, the SDK is manageable, can be learned in a week or two (at least the rudiments of it), and uses straight C. Hence, the SDK is what I'm going to use in this book. So, WIN32_LEAN_AND_MEAN instructs the compiler (header file logic, actually) not to include extraneous MFC overhead. Now that we have that out of the way, let's move on. Next, the following header files are included: #include <windows.h> #include <windowsx.h> The first include of "windows.h" really includes all the Windows header files. There are a lot of them, so this is something like an inclusion macro to save you from manually including dozens of explicit header files. The second include, "windowsx.h", is a header that contains a number of important macros and constants that make Windows programming easier. And now, for the important part—the main entry point of all Windows applications, WinMain(): int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprevinstance, LPSTR lpcmdline, int ncmdshow); First off, you should notice that weird WINAPI declarator. This is equivalent to the PASCAL function declarator, which forces the parameters to be passed from left to right, rather than the normal right-to-left order with the default CDECL. However, the PASCAL calling convention declarator is now obsolete, and WINAPI has taken its place. You must use WINAPI for the WinMain() function; otherwise, the startup code will end up passing the parameters incorrectly to the function! Examining ParametersNext, let's look at each of the parameters in detail:
As you can see from Table 2.2, there are a lot of settings for ncmdshow (many of which make no sense at this point). In reality, the majority of these settings will never be sent in ncmdshow. You will use them with another function, ShowWindow(), which actually displays a window once it's created. However, we will get to this a little later in the chapter. The point I want to make is that Windows has a lot of options, flags, and so on that you will never use, but they're still there. It's like VCR programming options—more is always better, as long as you don't need to use them if you don't want to. Windows is designed this way. It has to make everybody happy, so that means including a lot of options. In fact, we will use SW_SHOW, SW_SHOWNORMAL, and SW_HIDE 99 percent of the time, but you need to know the other for that one percent! Choosing a Message BoxFinally, let's talk about the actual function call to MessageBox() within WinMain(). MessageBox() is a Win32 API function that does something useful for us, so we don't have to do it. It is used to display messages with various icons, along with a button or two. You see, simply displaying messages is so common in Windows applications that a function was written just to save application programmers the half hour or so it would take to write one every time. MessageBox() doesn't do much, but it does enough to get a window up on the screen, ask a question, and wait for the user's input. Here is the prototype for MessageBox(): int MessageBox( HWND hwnd, // handle of owner window LPCTSTR lptext, // address of text in message box LPCTSTR lpcaption,// address of title of message box UINT utype); // style of message box The parameters are defined as follows:
Take a look at Table 2.3 to see a (somewhat abridged) list of the various MessageBox() options. You can logically OR the values together in Table 2.3 to create the desired message box. Usually, you will OR only one flag from each group. And of course, like all good Win32 API functions, MessageBox() returns a value to let you know what happened. In our case, who cares? But in general, you might want to know the return value if the message box was a yes/no question and so forth. Table 2.4 lists the possible return values.
Finally, a table that can list all the values without defoliating an entire forest! Anyway, this completes the line-by-line analysis of our first Windows program—click! TIP Now I want you to get comfortable making changes to the program and compiling it in different ways. Try mucking with various compiler options, like optimization. Then try running the program through the debugger and see if you can figure that out. When you're done, come back. If you want to hear a sound, a cheap trick is to use the MessageBeep() function. You can look it up in the Win32 SDK. It's similar to the MessageBox() function as far as simplicity of use. Here it is: BOOL MessageBeep(UINT utype); // the sound to play The different sounds can be from among the constants shown in Table 2.5. See how cool the Win32 API is? There are literally hundreds of functions to play with. Granted, they aren't the fastest things in the world, but for general housekeeping, I/O, and GUI stuff, they're grrrreat! (I felt like Tony the Tiger for a second <BG>.) Let's take a moment to summarize what we know at this point about Windows programming. The first thing is that Windows is multitasking/multithreaded, so multiple applications can run simultaneously. However, we don't have to do anything to make this happen. What does concern us is that Windows is event-driven. This means that we have to process events (which we have no idea how to do at this point) and respond to them. Okay, sounds good. And finally, all Windows programs start with the function WinMain(), which has a few more parameters than the normal DOS main() but is within the realm of logic and reason. With all that in mind, it's time to write a real Windows application. (But before we start, you might want to grab something to drink. Normally I would say Mountain Dew, but these days I'm a Red Bull man. Tastes like crap, but it keeps the synapses going and the can looks cool.) |