Win32 Tutorial Notes

All of the following tutorial notes are nearly exact copies of those at GameTutorials.com (http://www.gametutorials.com/Tutorials/tutorials.htm)


Tutorial #1 - Creating a Window (First Win32 Program), C++ source file Window.cpp

  • A basic Win32 program that creates a window and has a main loop that handles window messages: create, resize, paint (redraw), and destroy (close) though the code for these handlers is empty here.
  • Reference: http://www.gametutorials.com/Tutorials/Win32/Win32_Pg1.htm
    
    //**********************************************************************//
    //                                                                      //
    //      - "Talk to me like I'm a 3 year old!" Programming Lessons -     //
    //                                                                      //
    //      $Author:        Ben Humphrey digiben@gametutorials.com          //
    //                                                                      //
    //      $Program:       Window                                          //
    //                                                                      //
    //      $Description:   Create a simple window                          //
    //                                                                      //
    //      $Date:                  7/20/00                                 //
    //                                                                      //
    //**********************************************************************//
    
    #include <windows.h>            // We need to include windows.h
    #include <stdio.h>              // Include stdio.h for the basics
    
    // This line below is a function prototype.  If you remember
    // A function prototype is a declaration of the function, and tells
    // The compiler what to expect.  It knows that it needs to allocate memory
    // For a function containing the variables, HWND, UINT, WPARAM, LPARAM;
    // You'll notice that the function prototype doesn't have variables names...like
    // WndProc(HWND Hwnd, UINT UInt, WPARAM wParam, LPARAM lParam)
    // You don't HAVE to put variable names in your function prototype, it's your choice,
    // But in your actual function, you must.  Like I said, the compile just wants to know
    // What the function consists of, it doesn't care about the variable names.
    // The LRESULT in front of the function means:
    // A 32-bit value will be returned from a window procedure or callback function.
    // In English this means that we want a return value from the function to be a 32-bit value,
    // You would use LRESULT on a CALLBACK function, Which leads me to what a CALLBACK is:
    // If we look in HELP (F1 - MSDN) , it's a Calling convention for callback functions.
    // Well, that sounds redundant... But essentially it's used in windows functions, and allows
    // The function to be like a pointer, so we can assign the function to a variable that holds a callback.
    // This doesn't make much sense now, but once you see how it's used, it will make sense later.
    	
    LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM);		// This function handles all the messages for windows.
    
    // Remember "main()" ?  This is window's main.  It's called WinMain().
    // If we lookup WINAPI in the help, it says:
    // "Calling convention for the Win32 API."  Right..... So we just accept that for now :)
    // Just know that we must put WINAPI in front of our WinMain(), also we will have WinMain return a integer.
    // WinMain() doesn't need a function prototype, so we can just go right ahead and start coding it.
    // From here on out, almost every single variable type is going to be new.  It's going to take
    // Some getting used too.  Let me try and explain them though.  When I learned these, I didn't
    // Really know what they were, just knew that I needed them for it to compile and work :)
    // HINSTANCE hInstance - Holds information on an instance of application.  This is because 2 of the same
    // program can be running together...
    // HINSTANCE hPrevInstance - This holds a previous instance or the application, which is always NULL
    // (no information) for win32 apps. (useless)
    // PSTR szCmdLine - Holds the information from the command line.  Like you can type " -l *.*" or something
    // like that from DOS.
    // It's if you want to pass DOS command lines to your application.  PSTR is just a string.
    // int iCmdShow - This holds information on the window's state, like Maximized, Minimized, Hide, etc...	
    								
    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                        PSTR szCmdLine, int iCmdShow)                 // Anyway, so here is our "main()" for windows.  Must Have this for a windows app.
    {														
        HWND        hwnd;      // HWND - a HWND is a handle to a window.  This is used to keep track of a certain window.  Programs can have multiple windows.
                               //  We only have one though.
        MSG         msg;       // MSG  - A MeSsaGe variable to hold what messages are being sent to the window (If the window was clicked, closed, moved, etc...).
        WNDCLASSEX  wndclass;  // WNDCLASSEX - This variable will hold all the information about the window (The name, icon, cursor, color, menu bar...)
    
        wndclass.cbSize        = sizeof (wndclass);                 // Here we set the size of the wndclass. You will see this a lot in windows, it's kinda odd.
                                                                    // We use the "sizeof()" function to tell windows the size of our class.
        wndclass.style         = CS_HREDRAW | CS_VREDRAW;           // The style we want is Verticle-Redraw and Horizontal-Redraw
        wndclass.lpfnWndProc   = WndProc;                           // Here is where we assign our CALLBACK function.  Remember up above our function "WndProc"?
                                                                    // This just tells windows which function it needs to call to check for window messages.
        wndclass.cbClsExtra    = 0;                                 // We don't want to allocate any extra bytes for a class (useless for us)
        wndclass.cbWndExtra    = 0;                                 // Another useless thing for us.  I believe these last 2 are initialized to 0 anyway.
        wndclass.hInstance     = hInstance;                         // We assign our hInstance to our window.  Once again, You can have several instances of a
                                                                    // program, so this keeps track of the current one.
        wndclass.hIcon         = LoadIcon (NULL, IDI_WINLOGO);      // We call a function called LoadIcon that returns information about what icon we want.
                                                                    // I chose the Windows Logo.  The NULL is in place of a hInstance.  We don't need one in this case.
        wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW);      // We call a function called LoadCursor that returns information about what cursor we want,
                                                                    // I chose an arrow.  The NULL is in place of a hInstance.  We don't need one in this case.
                                                                    // Here we set the background color.  GetStockObject() returns a void so we must "cast) (turn it into)
                                                                    // it as a HBRUSH to be compatible with the variable "hbrBackground".  I chose GRAY
        wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
        wndclass.lpszMenuName  = NULL;                              // We don't have a menu, so let's set this to NULL.
        wndclass.lpszClassName = "Window Class 1";                  // Here we set a name for our class, to distinguish it against others.  We need to use this name
                                                                    // for later when we create the window.					
        wndclass.hIconSm       = LoadIcon (NULL, IDI_WINLOGO);      // We want the icon to be the windows logo.  This is the icon in the top left corner of the window.
    
        RegisterClassEx (&wndclass);              // We need to register our windows class with the windows OS.  We also need to pass the memory address of wndclass,
                                                  // so we use the "&".
    															
        // Now we actually create the window.
        // CreateWindow() returns a handle to the window, which we store in our HWND "hwnd".
        hwnd = CreateWindow ("Window Class 1",    // window class name - This tells CreateWindow() to use our class up above.
                             "My First Window",   // window's Title    - This will be the name on the title bar of the window.
                             WS_OVERLAPPEDWINDOW, // window style      - This flag tells windows to create a typical window, (options like resize, minimize, close, etc).
                             CW_USEDEFAULT,       // initial x position- The top left corner X value of the window in screen coordinates.  This flag let's windows choose for us.
                             CW_USEDEFAULT,       // initial y position- The top left corner Y value of the window in screen coordinates.  This flag let's windows choose for us.
                             CW_USEDEFAULT,       // initial x size	 - The bottom right corner X value of the window in screen coordinates.  This flag let's windows choose for us.
                             CW_USEDEFAULT,       // initial y size	 - The bottom right corner Y value of the window in screen coordinates.  This flag let's windows choose for us.
                             NULL,                // This is the parent window handle.  Since we don't have a parent window, we set this to NULL
                             NULL,                // This is the window menu handle, but since we don't have a menu, we set this to NULL.
                             hInstance,           // This is the program's instance handle.  We just pass it our hInstance from our WinMain().
                                                  //  By the way, Windows OS passes the info to WinMain().  It's all taken care of for us.
                             NULL);               // If we wanted to pass in a variable or structure to the "WndProc", we would do it here.
                                                  //  (I just prefer using global variables though).  I just pass in NULL.
    
        ShowWindow (hwnd, iCmdShow);              // This shows our window.  We give it our handle to our window, which now has all our windows info, and our WinMain() variable
                                                  // iCmdShow.
        UpdateWindow (hwnd);                      // This pretty much paints our window to the screen.
    
        // Here is our main loop.  This will continue to go until GetMessageReturns WM_QUIT, which will close the program.  This would happen if we closed the window.
        while (GetMessage (&msg, NULL, 0, 0))     // We need to pass in the address of "msg" because GetMessage fills in the structure "msg".  We pass in NULL for the HWND
                                                  // because that makes GetMessage check ALL windows that use our WndProc.
        {                                         // The rest we pass in 0, they are not important.
            TranslateMessage (&msg);              // "The TranslateMessage() function translates virtual-key messages into character messages." This basically means it
                                                  // translates it so windows understands it.
            DispatchMessage (&msg);               // "The DispatchMessage() function dispatches a message to a window procedure."  - This means it handles the message,
                                                  // like if the message was to close the window, it closes the window.
        }
    
        UnregisterClass("Window Class 1",hInstance);    // We need to unregister our window class with the Windows OS.  By doing this, we free up the memory allocated
                                                        // to register our window class.
        
        return msg.wParam ;                        // We return the wParam of the structure "msg".  This is why we chose WinMain() to return an int.  A wParam/lParam is a
                                                   // 32-bit message parameter.  It holds data about the message.  You will see it's uses later. 
    }
    
    // Here is the WndProc. This stands for "Window Procedure". This function handles the messages from windows. 
    // "Most everything above never changes,"
    // "The WindProc is what you usually mess around with."
    // When you code in Windows, the WndProc is the one that you really change, and is never the same.
    // So it's the most important to understand.
    // We have the LRESULT CALLBACK.  Once again, this means it returns a 32-bt integer value, and is a CALLBACK.
    //  A call back function is like a function pointer.
    // In fact, it is a function pointer.  You give the address of the function to the window class, and windows
    // fills in all the parameters for us.
    
    // HWND is our window handle, iMsg is the message being sent to windows, The WPARAM and LPARAM hold information about the message.
    
    LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
    {
        switch (iMsg)    // This checks what the message is.  Below is some of the message that windows might return.
                         //  There of course are HUNDREDS.
        {                // The only message that you NEED to deal with, is the WM_DESTROY.  The rest you don't have
                         // to check for.  I am just showing some examples on how to check for a message.
            case WM_CREATE:        // This message is sent when the window is created.
                           // We would want to put our initialization code here...
                break;             // We break from the switch statement.
    
            case WM_SIZE:          // This Message happens when we resize the window.
                           // We would put code to resize text or a picture here...
                break;             // Break from the switch statement
    
            case WM_PAINT:         // This message is sent to the WndProc when the window needs to be repainted.
                                   // This might be if we moved the window, resized it, or maximized it, or another
                                   // window was over it.
                           // Put our code here to paint what should be in the window.	
                break;             // Break from the switch statement
    
            case WM_DESTROY:       // This message is sent when the user closes the window.
                          // Here you would handle Deinitialization, freeing memory, etc..
                PostQuitMessage(0);      // You must call this function or else you will need to do control-alt-delete
                                         // and manually close the program from the programs queue.  0 = WM_QUIT.
                                         // This function actually puts a message on the message queue.
                                         // SendMessage() sends a direct message, which is acted upon immediately.
                                         // just for your information.
                break;             // Break from the switch statement
        }													
    
        return DefWindowProc (hwnd, iMsg, wParam, lParam);     // The DefWindowProc function calls the default
                                 // window procedure to provide default processing for any window messages that
                                 // an application does not process. 
                                 // This function ensures that every message is processed.  DefWindowProc is called
                                 // with the same parameters received by the WndProc. 
    }  // End of the WndProc
    
    
    // And that is all it takes to create and display a window.  Simply enough huh?
    // Sure there are a lot of things that you will need to get comfortable with, new variables, etc..
    // And most likely, you will just copy and paste what I have and mold it into what you want.
    // That's OK, but you eventually have to learn it.  There were little things that I forgot or didn't know
    // When writing this tutorial, like what LRESULT actually was, etc.. Just look it up in help (type F1
    // if you have MSDN).
    // It will be great when you can just look at all of this stuff and totally understand it.  Then you won't
    // ever need to cut paste.. (Ok, I still cut and paste, You think I want to type all this again! :)  ).
    // Here are the 5 steps to Win32 programming:
    
    // 1) Initialize a class
    // 2) Register the class
    // 3) Create the window
    // 4) Get the messages from the WndProc.
    // 5) Translate and Dispatch the Messages (Act on the messages)
    
    // That's pretty much it.  Yes, I had to learn those in school :)  
    // I am still surprised I remembered them.
    // Anyway, there are MANY messages that you can look for, I just chose a few that you will most likely always use.
    // Some other examples are WM_MOUSEMOVE, WM_LBUTTONCLICK, WM_KEYDOWN etc...  On some of these messages,
    // You will check the LPARAM and the WPARAM.  That is what holds information on the mouse coordinates, or what key
    // is pressed.
    // I didn't explain much about those in this tutorial, but I didn't want to scare you away just yet.
    // I will wait for the next tutorial for you to start pulling your hair out :)  I know it all seem foreign to you
    // right now, believe me, you will be talking like a nerd in no time :)  "And then I set up my callback as my wndproc,
    // and registered my class.."
    // He he, there's something about talking about something and no one understanding you.. it feels great! he he.
    // Good luck!  Email me if you need any clarification digiben@gametutorials.com / www.GameTutorials.com
    //
    // © 2000-2003 GameTutorials

Tutorial #2 - DeviceContext, C++ source file win_main.cpp

  • A Win32 program that creates a window and gets a device context that can be used to draw into, i.e., it points to the memory for the display device's frame buffer.
  • Reference: http://www.gametutorials.com/Tutorials/Win32/Win32_Pg1.htm
    
    // Done by TheTutor -- 3/04/02
    /* 
    This tutorial is all about what a device context. In a Win32 program, these are usually
    declared as HDC (handle to a device context). So for starters, what in the heck 
    is a device context? Well MSDN defines it as, "Structure that defines a set of graphic
    objects and their attributes, and the graphic modes that affect output. In addition, the
    device context (DC) refers to a physical output device, its name, device driver, and other
    attributes."
    
    That's a pretty good definition. An HDC (if you see HDC just think of device context) is
    essentially a "pointer" to a struct that contains all the necessary information of the
    device context.
    
    There are four types of device contexts -- They are:
    Display -- These support drawing operations on a video display terminal
    Printer -- These support writing/drawing operations on a printer
    Memory -- These support drawing operations on a bitmap
    Information -- These support retrieval of device data
    
    In general, the main two we are going to concern ourselves with is display and memory
    device contexts. In this tutorial we are only going to talk about the display HDC.
    So now that you have a rudimentary understanding of what an HDC is, lets talk about what
    this very simple program does. All we are going to do is create a window, gets it's HDC
    and using the HDC, fill the window to black. Pretty simple right?!?
    */
    
    #include <windows.h>
    #define WIN_WIDTH 320
    #define WIN_HEIGHT 240
    #define class_name "GameTutorials_HDC"
    
    // Standard callback function
    LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
    
    int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprev, PSTR cmdline, int ishow)
    {
        HWND hwnd; // This will hold the handle to our window
        MSG msg;   // This will hold any messages (such as a mouse click) that
                   // our window might receive
        WNDCLASSEX wndclassex = {0}; // This is our "window class" -- The "EX" stands
                                     // for "extended style" which gives us more options
                                     // when creating our window (although we're going to
                                     // completely ignore 'em)
    
        // Fill the fields we care about
        wndclassex.cbSize = sizeof(WNDCLASSEX);     // Always must be set
        wndclassex.style = CS_HREDRAW | CS_VREDRAW; // Window classes style
        wndclassex.lpfnWndProc = WinProc;           // Pointer to where the WinProc() is defined
        wndclassex.hInstance = hinstance;           // The handle to the instance of our window
        wndclassex.lpszClassName = class_name;      // The name of our window class
        wndclassex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // This sets the
                                                    // background color of the window to white
            
        RegisterClassEx(&wndclassex); // Register the window class so calls to CreateWindow()
                                      // and CreateWindowEx() will know what window class to
                                      // use when creating the window
        hwnd = CreateWindowEx(NULL,   // Extra window attributes, NULL means none
                              class_name,              // Name we gave our WNDCLASSEX
                              "www.GameTutorials.com -- HDC's",   // Text for the title bar
                              WS_OVERLAPPEDWINDOW,     // Style of window (see MSDN for full description)
                              CW_USEDEFAULT,           // Upper left xPos of window (Windows picks default)"
                              CW_USEDEFAULT,           // Upper left yPos of window (Windows picks default)
                              WIN_WIDTH,               // Width of window in pixels
                              WIN_HEIGHT,              // Height of window in pixels
                              NULL,                    // Handle to "parent window" (we have none, this is the parent)
                              NULL,                    // Handle to a menu (we have none)
                              hinstance,               // Handle to instance of this window (passed in by WinMain())
                              "NULL);                  // "Extra info" to pass to the WinProc (we have none)
    
        // Error check
        if(!hwnd)
            return EXIT_FAILURE;    // Something really bad happened!
    
        // Okay here is where we are getting the windows HDC -- Now what this gets us
        // is a handle to the DISPLAY device context. So once we have this we can draw
        // to our window. For any type of graphical stuff the computer needs to know 
        // where to draw. The HDC of the window tells the computer exactly that :)
        HDC hdc = GetDC(hwnd);
    
        // Now afterwards we are going to check to make sure the call worked
        // if "hdc" equals NULL, then the call has failed and we need to bail out
        // of the program
        if(!hdc)
            return EXIT_FAILURE;    // Couldn't get window's hdc -- This be bad :(
    
        ShowWindow(hwnd, ishow);    // Show the window (make it visible)
        UpdateWindow(hwnd);         // Updates the window (sends a WM_PAINT message... We'll talk
        // more about that in later tutorials... Just know it makes the
        // window GRAPHICALLY up to date)
    
        // Okay now we will make the window "black" -- There's actually a decent amount 
        // going on to do that, so we'll break it down piece by piece.
        // First we need to get a RECT that describes the CLIENT (that is the inside of the
        // window NOT counting the edges and title bar) area of the window.
        RECT rect;
        GetClientRect(hwnd,&rect); // Luckily, this handy-dandy function will do just that
    
        // Pass in the handle of the window you want the RECT for
        // and a pointer to a RECT and it will fill it with the
        // window's CLIENT dimensions
        // Now that we got the RECT we call fill that area to black -- Here's how this function 
        // breaks down:
        // hdc -- The DEVICE CONTEXT we want to draw to (our window)
        // &rect -- Address of the area in the hdc we want to draw to (the client area of the window)
        // (HBRUSH)GetStockObject(BLACK_BRUSH) -- Okay this functions technically returns an HBRUSH
        // (hence the cast) -- For now, just know this is how
        // you can specify a color -- If you feel so inclined,
        // try changing BLACK_BRUSH to DKGRAY_BRUSH -- The
        // result will be as you expect.
        FillRect(hdc,&rect,(HBRUSH)GetStockObject(BLACK_BRUSH));
    
        // main loop: loops forever until a WM_QUIT message
        while(1)
        {
            // Get Windows message(s) (for instance a key press) if there is any
            if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
            {
                if(msg.message == WM_QUIT)
                    break;
    
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
            else
            {
                // Do all the hardcore computational stuff here :)
                // In later tutorials this is where we'll place OpenGL rendering calls.
            }
        }
    
        // It is VERY IMPORTANT that you ALWAYS release the memory associated with
        // an HDC -- Supposed Win2K and up will do this for you, but even so 
        // that would ONLY happen at the end of the program, if you were doing this
        // in a for loop (kept call GetDC()) you'd chew up memory pretty fast --
        // To release the memory from a call to GetDC() just do this:
        ReleaseDC(hwnd,hdc); // Releases the memory of the HDC
    
        // It is also important that you remove the memory associated with a "window class"
        // when you are done with it. When we call RegisterClassEx() some memory gets set aside
        // for the "class description" (our WNDCLASSEX) of this window we are going to create.
        // If we don't free this memory, it will stay around (this would be bad). So we call
        // this handy dandy function to free up the memory we allocated when calling
        // RegisterClassEx() -- Most of the time you'll want to call this at the very end of
        // your Win32 program.
        // 
        // **NOTE** You ONLY need to call UnregisterClass() if you register the window class with
        // a call to RegisterClassEx(), the older register function, ReisterClass(), (notice NO Ex)
        // does not require this call
        UnregisterClass(class_name,hinstance);
    
        return msg.wParam; // And we're out
    }
    
    // The WinProc
    LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
    {
        // Depending on the message -- we'll do different stuff
        switch(message)
        {
            // As you can see we've kept the WinProc() VERY SIMPLE :)
            // Just so you know, depending on how the window is shut down, either one
            // of the messages WM_DESTROY or WM_CLOSE could be sent, thus I always
            // check for both and do the shut down code accordingly.
            // Also if you RESIZE the window, or MINIMIZE the window (or probably other things)
            // the black color we filled it to will go away -- This is because these actions
            // (resize and minimize and others) automatically cause the window to be redrawn
            // and we only fill the color once.
    
            case WM_DESTROY:
            case WM_CLOSE:
                PostQuitMessage(0);
                return 0;
        } // end of switch(message)
    
    return DefWindowProc(hwnd, message, wparam, lparam);
    }
    
    /* It's absolutely imperative that you grasp what a HDC is. You will see these again and again
       and again and again in Win32 programming. If you're still a little unsure, think of an
       HDC like this:
       An HDC is a "gateway" to the pixels that make up your window -- With a DISPLAY DEVICE CONTEXT
       (that is what GetDC() returns you) you can draw to the window. Win32 provides many
       ways for drawing to the window, FillRect() is just one of many. In future tutorials
       you will see the HDC being used repeatedly for drawing to the window. So all an HDC is, is
       a means to draw to a window.
       If you're still unsure, be sure to post you quandaries to www.GameTutorials.com
    */
    
    /*----------------------------*\
    | TheTutor                     |
    | thetutor@gametutorials.com   |
    | © 2000-2003 GameTutorials    |
    \*----------------------------*/

Tutorial #3 - ColorText, C++ source file Text.cpp

  • A Win32 program that creates a window and draws colored text into the window.
    You'll need this to display game status values (score, performance measures, etc.) in some of your game programs.
  • Reference: http://www.gametutorials.com/Tutorials/Win32/Win32_Pg1.htm
    
    // ***********************************************************************//
    //                                                                        //
    // - "Talk to me like I'm a 3 year old!" Programming Lessons -            //
    //                                                                        //
    // $Author: Ben Humphrey digiben@gametutorials.com                        //
    //                                                                        //
    // $Program: Text                                                         //
    //                                                                        //
    // $Description: Draw's "Hello World!" centered on the screen             //
    //                                                                        //
    // $Date: 7/20/00                                                         //
    //                                                                        //
    //************************************************************************//
    
    #include <windows.h> // We need to include windows.h
    #include <stdio.h> // Include stdio.h for the basics
    
    RECT windowRect = {100, 100, 400, 400};           // (NEW)
    
    // Let's create a rectangle that defines our desired window position.
    // The RECT structure works like this: {left, top, right, bottom}
    // Remember, when we initialize a variable we can fill in it's structure like this.
    // If we didn't set the structures values here, we would have do later do it like this:
    // windowRect.left = 100; windowRect.top = 100; windowRect.right = 400; windowRect.bottom = 400;
    
    // This line below is a function prototype. If you remember
    // A function prototype is a declaration of the function, and tells
    // The compiler what to expect. It knows that it needs to allocate memory
    // For a function containing the variables, HWND, UINT, WPARAM, LPARAM;
    // You'll notice that the function prototype doesn't have variables names...like
    // WndProc(HWND Hwnd, UINT UInt, WPARAM wParam, LPARAM lParam)
    // You don't HAVE to put variable names in your function prototype, it's your choice,
    // But in your actual function, you must. Like I said, the compile just wants to know
    // What the function consists of, it doesn't care about the variable names.
    // The LRESULT in front of the function means:
    // A 32-bit value will be returned from a window procedure or callback function.
    // In English this means that we want a return value from the function to be a 32-bit value,
    // You would use LRESULT on a CALLBACK function, Which leads me to what a CALLBACK is:
    // If we look in HELP (F1 - MSDN) , it's a Calling convention for callback functions.
    // We, that sounds redundant... But essentially it's used in windows functions, and allows
    // The function to be like a pointer, so we can assign the function to a variable that holds a callback.
    // This doesn't make much sense now, but once you see how it's used, it will make sense later.
    LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); // This functions handles all the messages for windows.
    
    // Remember "main()" ? This is window's main. It's called WinMain().
    // If we lookup WINAPI in the help, it says:
    // "Calling convention for the Win32 API." Right..... So we just accept that for now :)
    // Just know that we must put WINAPI in front of our WinMain(), also we will have WinMain return a integer.
    // WinMain() doesn't need a function prototype, so we can just go right ahead and start coding it.
    // From here on out, almost every single variable type is going to be new. It's going to take
    // Some getting used too. Let me try and explain them though. When I learned these, I didn't
    // Really know what they were, just knew that I needed them for it to compile and work :)
    // HINSTANCE hInstance - Holds information on an instance of application. This is because 2 of the same program can be running together...
    // HINSTANCE hPrevInstance - This holds a previous instance or the application, which is always NULL (no information) for win32 apps. (useless)
    // PSTR szCmdLine - Holds the information from the command line. Like you can type "<program name> -l *.*" or something like that from DOS.
    // It's if you want to pass DOS command lines to your application. PSTR is just a string.
    // int iCmdShow - This holds information on the window's state, like Maximized, Minimized, Hide, etc... 
    
    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                        PSTR szCmdLine, int iCmdShow)                 // Anyway, so here is our "main()" for windows. Must Have this for a windows app.
    { 
        HWND hwnd;           // HWND - a HWND is a handle to a window. This is used to keep track of a certain window. Programs can have multiple windows.
                             // We only have one though.
        MSG msg;             // MSG - A MeSsaGe variable to hold what messages are being sent to the window (If the window was clicked, closed, moved, etc...).
        WNDCLASSEX wndclass; // WNDCLASSEX - This variable will hold all the information about the window (The name, icon, cursor, color, menu bar...)
        wndclass.cbSize = sizeof (wndclass);      // Here we set the size of the wndclass. You will see this a lot in windows, it's kinda odd. We use the "sizeof()"
                                                  // function to tell windows the size of our class.
        wndclass.style = CS_HREDRAW | CS_VREDRAW; // The style we want is Verticle-Redraw and Horizontal-Redraw
        wndclass.lpfnWndProc = WndProc;           // Here is where we assign our CALLBACK function. Remember up above our function "WndProc"? This just tells windows
                                                  // which function it needs to call to check for window messages.
        wndclass.cbClsExtra = 0;                  // We don't want to allocate any extra bytes for a class (useless for us)
        wndclass.cbWndExtra = 0;                  // Another useless thing for us. I believe these last 2 are initialized to 0 anyway.
        wndclass.hInstance = hInstance;           // We assign our hInstance to our window. Once again, You can have several instances of a program,
                                                  // so this keeps track of the current one.
        wndclass.hIcon = LoadIcon (NULL, IDI_WINLOGO);    // We call a function called LoadIcon that returns information about what icon we want. I chose the Wndows Logo.
                                                          // The NULL is in place of a hInstance. We don't need one in this case.
        wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);  // We call a function called LoadCursor that returns information about what cursor we want, I chose an arrow.
                                                          // The NULL is in place of a hInstance. We don't need one in this case.
    
        // Here we set the background color. GetStockObject() returns a void so we must "cast" (turn it into) it as a HBRUSH to be compatible with the variable "hbrBackground".
        // I chose GRAY
        wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH);
        wndclass.lpszMenuName = NULL;                     // We don't have a menu, so let's set this to NULL.
        wndclass.lpszClassName = "Window Class 1";        // Here we set a name for our class, to distinguish it against others. We need to use this name for later
                                                          // when we create the window. 
        wndclass.hIconSm = LoadIcon (NULL, IDI_WINLOGO);  // We want the icon to be the Windows logo. This is the icon in the top left color of the window.
        RegisterClassEx (&wndclass);                      // We need to register our windows class with the windows OS. We also need to pass the memory address of wndclass,
                                                          // so we use the "&".
    
        // Now we actually create the window.
        // CreateWindow() returns a handle to the window, which we store in our HWND "hwnd".
        hwnd = CreateWindow ("Window Class 1",       // window class name - This tells CreateWindow() to use our class up above.
                             "Color Text",           // window's Title - This will be the name on the title bar of the window.
                             WS_OVERLAPPEDWINDOW,    // window style - This flag tells windows to create a typical window, (options like resize, minimize, close, etc).
                             windowRect.left,        // (NEW) // initial x position- The top left corner X value of the window in screen coordinates.
                                                     // We will use our rectangle to position the window.
                             windowRect.top,         // (NEW) // initial y position- The top left corner Y value of the window in screen coordinates.
                             windowRect.right,       // (NEW) // initial x size - The bottom right corner X value of the window in screen coordinates.
                             windowRect.bottom,      // (NEW) // initial y size - The bottom right corner Y value of the window in screen coordinates.
                             NULL,                   // This is the parent window handle. Since we don't have a parent window, we set this to NULL
                             NULL,                   // This is the window menu handle, but since we don't have a menu, we set this to NULL.
                             hInstance,              // This is the programs instance handle. We just pass it our hInstance from our WinMain().
                                                     // By the way, Windows OS passes the info to WinMain().  It's all taken care of for us.
                             NULL);                  // If we wanted to pass in a variable or structure to the "WndProc", we would do it here.
                                                     // (I just prefer using global variables though).  I just pass in NULL.
    
        ShowWindow (hwnd, iCmdShow);    // This shows our window. We give it our handle to our window, which now has all our windows info, and our WinMain() variable iCmdShow.
        UpdateWindow (hwnd);            // This pretty much paints our window to the screen.
    
        // Here is our main loop. This will continue to go until GetMessageReturns WM_QUIT, which will close the program. This would happen if we closed the window.
        while (GetMessage (&msg, NULL, 0, 0))         // We need to pass in the address of "msg" because GetMessage fills in the structure "msg". We pass in NULL for the HWND
                                                      // because that makes GetMessage check ALL windows that use our WndProc.
        {   // The rest we pass in 0, they are not important.
            TranslateMessage (&msg);    // "The TranslateMessage() function translates virtual-key messages into character messages." This basically means it translates
                                        // it so windows understands it.
            DispatchMessage (&msg);     // "The DispatchMessage() function dispatches a message to a window procedure." - This means it handles the message,
                                        // like if the message was to close the window, it closes the window.
        }
    
        UnregisterClass("Window Class 1",hInstance);    // We need to unregister our windows class with the windows OS.
                                                        // This way we free the memory that registering the class has taken. 
    
        return msg.wParam;     // We return the wParam of the structure "msg". This is why we chose WinMain() to return an int.
                               // A wParam/lParam is a 32-bit message parameter. It holds data about the message. You will see it's uses later. 
    }
    // Here is the WndProc. This stands for "Window Procedure". This function handles the messages from windows. All the code up above, stays mostly the same
    // When you code in windows, but the WndProc is the one that you really change, and is never the same. So it's the most important to understand.
    // "Most everything above never changes,"               // We have the LRESULT CALLBACK. Once again, this means it returns a 32-bt integer value, and is a CALLBACK.
    // "The WindProc is what you usually mess around with." // A call back function is like a function pointer.
    // In fact, it is a function pointer. You give the address of the function to the window class, and windows fills in all the parameters for us.
    // HWND is our window handle, iMsg is the message being sent to windows, The WPARAM and LPARAM hold information about the message.
    
    LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
    {   // STATIC variables are variables that aren't erased after the function quits. WndProc() gets called a million times, and if they weren't static,
        // they would be initialized each time.
        static TEXTMETRIC textInfo;    // A TEXTMETRIC holds information about a font. We will use this to center our text exactly.
        static int length=0;           // This will hold the length of our string.
        PAINTSTRUCT paintStruct;       // A PAINTSTRUCT structure is something we need to paint under WM_PAINT. Windows fills in all the data for us.
        HDC hdc=NULL;                  // An HDC is a handle to a device context. This can be thought of as a handle to the frame buffer. The frame buffer is in a video card
                                       // and holds all the image data on the screen, which is constantly being updated.
        int x, y;                      // These will be used to position our text.
        char szHello[]="Hello World!"; // We just create a string to print to the string, pretty original huh? :) Oh well, it can be associate with "Beginning" something right?
    
        switch (iMsg)                  // This checks what the message is. Below is some of the message that windows might return. There of course is HUNDREDS.
        {   // The only message that you NEED to deal with, is the WM_DESTROY. The rest you don't have to check for. I am just showing some examples on how to check for a message.
            case WM_CREATE:            // This message is sent when the window is created.
                      // We would put initialization code here, because this only happens once.
                hdc = GetWindowDC(hwnd);          // Here we pass the hwnd (handle to the window) in GetWindowDC(). This returns a handle to our device context. 
                      // Basically, if we want to do ANYTHING with graphics, we need an HDC.
                GetTextMetrics(hdc, &textInfo);   // Here we pass in our new hdc and our textInfo into GetTextMetrics(). This fills in textInfo with all the font info
                                                  // (height, width, leading, etc...).
                length = strlen(szHello);         // We want to know how many characters the string is for later.
                ReleaseDC(hwnd, hdc);             // Since we allocated an HDC with GetWindowDC(), we need to release it, or else we will have a memory leak.
                break;                            // We break from the switch statement.
    
            case WM_SIZE:              // This Message happens when we resize the window.
                GetWindowRect(hwnd, &windowRect); // Here we call a function that fills in a RECT structure with the position of the window.
                         // This message will come up if we move the window, or resize it. Then we can have an up-to-date info on the window's position.
                break;   // Break from the switch statement
    
            case WM_PAINT:     // This message is sent to the WndProc when the window needs to be repainted. This might be if we moved the window, resized it, or maximized it,
                               // or another window was over it.
                hdc = BeginPaint(hwnd, &paintStruct);   // This is how we get an HDC to paint with. BeginPaint() passes back an hdc and fills in the paintStruct structure.
                                                        // You will notice most of the functions require an HWND.
                                                        // The HWND is passed from WinMain() to the WinProc() CALLBACK function.
    
                SetTextColor(hdc, RGB(255, 0, 0));      // Here we can set our text color. We pass in our HDC and use a macro called RGB().
                // Once again, a macro is NOT a function, but is just text substitution, created with a "#define". <windows.h> has this macro in it.
                // For a quick lesson on RGB (Red-Green-Blue) , look at the bottom of this file.
    
                // Alright, here's where the math comes in :) It's just simple algebra so don't panic.
                // We want "Hello World!" to be centered in the screen. So first we want to find the width of the window.
                // To find the width of the window, we subtract the left side from the right side. Now we have the width,"
                // We want to find half of the width (the CENTER), so we divide by 2.
                // Now we have the position of half the window. in the beginning, the right side = 500, and the left side = 100.
                x = (windowRect.right - windowRect.left) / 2;      // So 500 - 100 = 400. Divide that by 2 and we have 200. x = 200
                // Then, if we want the text EXACTLY in the center, not just starting in the center, we have to have it's font width (the width of each character in pixels)
                // and how many letters in the string.
                // Well, we found out that the font's character width is 7 (I debugged it), and the length is 12. 12 Letters in "Hello World!", including the space.
                // So, to find the width of pixels of "Hello World!" we times the amount of characters times it's font character width. Then divide that by 2 to make it centered.
                x = x - ((length * textInfo.tmAveCharWidth) / 2);  // So 200 - ((12 * 7) / 2) = 158. So our X position for the string starts at 158.
    
                // Now we do the exact same thing for the Y, but with different numbers.
                y = (windowRect.bottom - windowRect.top) / 2;      // So once again, (500 - 100) / 2 = 200;
                y = y - (textInfo.tmHeight / 2);                   // Since the amount of characters doesn't matter for the Y value, we just subtract half the height of the font.
    
                // Next we want to print out the text. We will use TextOut(). It's parameters are (HDC, XPosition, YPosition, The string, and the string's length);
                TextOut(hdc, x, y, szHello, length);               // We pass in our hdc, the x and y position, the string, and the string's length.
                                                                   // Tada! Centered text! Even if you resize the window. Every time you move or resize the window, it calls WM_PAINT.
                EndPaint(hwnd, &paintStruct);                      // Now we must free our memory that was allocated for the paintStruct.
                break;   // Break from the switch statement
    
            case WM_DESTROY:        // This message is sent when the user closes the window.
                PostQuitMessage(0); // You must call this function or else you will need to do control-alt-delete and manually close the program from the programs queue. 0 = WM_QUIT.
                // This function actually puts a message on the message queue. SendMessage() sends a direct message, which is acted upon immediately. just for your information.
                break; // Break from the switch statement
            }
    
        return DefWindowProc (hwnd, iMsg, wParam, lParam); // The DefWindowProc function calls the default window procedure to provide default processing for any window messages
                                                           // that an application does not process. 
        // This function ensures that every message is processed. DefWindowProc is called with the same parameters received by the WndProc. 
    } // End of the WndProc
    
    // You are probably thinking, "Man, all this for a stupid window and a line of text?" yes, yes..
    // A lot of people don't LIKE windows programming because it can be very large, but then a window is a very complicated thing.
    // What you will end up doing, once you get familiar with all this stuff, is putting most of this
    // Into function, so you don't HAVE to copy/paste or type it all out. Like, you would create your
    // OWN CreateWindow() function that you would pass in a width and height, maybe a Title, and some other little thing.
    // This function would then do ALL of that stuff for you, all in one line. It is really nice once you get it set up.
    // You can have this program that we just finished, in a few lines, like this:
    // #include <windows.h>
    //
    // CreateMyWindow(100, 100, 400, 400, "My Window!");
    //
    // while(Messages())
    //     DisplayText("Hello World!", TEXT_CENTER);
    // There you have it. If you set up some functions, you could do all of this in 3 lines of code.
    // See where I am going with this? You might ask, "Well what if you want to check other windows messages?"
    // Well, you just make a function for those too! It's all worth it in the end. You just create a library so you never
    // Have to look at a WinProc or WinMain() again! Of course, most people LIKE dealing with the WndProc().
    // (Either that or they don't want to write all those functions :) ).
    // By the way, when I was at school, we had to create a game library. Our programs turned out to be teeny
    // Because we used our libraries. We had functions for everything, Drawing lines, triangles, circles, windows, bitmaps, you name it!
    // We did a side scroller pacman in windows with sound, menu's and everything, and it was pretty small.
    // I can't image what that would look like without libraries.
    
    // *Quick Lesson on RGB*:
    // RGB stands for Red Green and Blue. These are the primary colors of life :)
    // With these colors, you can make any color. In the RGB scale, 255 is the max.
    // As you see in our program, we used RGB(255, 0, 0); which made our text RED.
    // Here is how the macro works: RGB( Red Intensity, Green Intensity, Blue Intensity);
    // If RED is 255 (the max intensity) and GREEN and BLUE are zero, then RED is the final color.
    // Here is GREEN: RGB(0, 255, 0); Here is BLUE: RGB(0, 0, 255). Here is RED: RGB(255, 0, 0);
    // Can you guess what RGB(0, 0, 0) is? What is the absence of color? Well, what is the absence of light?
    // Dark, right... so then the color would be BLACK: RGB(0, 0, 0); Then what is RGB(255, 255, 255)?
    // What color is the highest intensity of light? It's WHITE: RGB(255, 255, 255);. Now if you remember
    // Messing around with paints when you were in elementary school, if you MIX colors they produce other colors.
    // That is the same with the macro RGB(). Here are some mixed colors:
    // PINK: RGB(255, 0, 255) YELLOW: RGB(255, 255, 0) CYAN (sky blue): RGB(0, 255, 255)
    // Now if we want a lower intensity of a color, just decrement the value, say RGB(0, 125, 0) which is a darker green.
    // Anyway, I think you get the point. Just test color combinations to get the desired color, or go buy some paints :)
    
    // *Quick Lesson on Static Variables*
    // We put a static in front of 2 of our variables, because they were initialized in WM_CREATE.
    // WM_CREATE is only called once. If a variable is NOT a global variable (Defined outside of a function),
    // Then after the function is over, the variable is destroyed, and then re-initialized when the function is called again.
    // Since WndProc is called countless times, We needed to make the 2 variables static or else they would be initialized every time.
    // Then we wouldn't have our info when we need it in WM_PAINT. If you still don't understand, write me an email and
    // I will write a simple program to show you.
    
    // digiben@gametutorials.com / www.GameTutorials.com
    //
    // © 2000-2003 GameTutorials 

Tutorial #4 - KeyboardInput, C++ source file win_main.cpp

  • A Win32 program that creates a window and handles keypress inputs in the window.
    You'll need this to handle keypress inputs from the game player (you).
  • Reference: http://www.gametutorials.com/Tutorials/Win32/Win32_Pg1.htm
    
    //
    // Done by TheTutor -- 5/12/02
    
    /* 
       This tutorial is all about receiving keyboard input in your Win32 application.
       Windows provides multiple ways to receive keyboard input, but this tutorial
       focuses on a method to get the keyboard input inside of the WinProc() by checking the
       WM_CHAR message.
       What we're going to do is pretty simple. If you press the 'R' key we'll print "RED" to
       the window in the color red. If you press the 'G' key, we'll print "GREEN" to the window
       in the color green. And I bet you get the pattern for the 'B' key :)
       So without further ado, lets get coding.
    */
    
    #include <windows.h>
    #define WIN_WIDTH 640
    #define WIN_HEIGHT 480
    // Where begin drawing the text to
    #define TEXT_X 300 
    #define TEXT_Y 220
    #define class_name "GT_KeyboardInput"
    
    // Save us a little typing %)
    typedef unsigned char uchar;
    
    // This function will print to the screen the text passed in, using
    // the RGB color passed in
    void PrintColoredText(HWND hwnd, char *text, uchar R, uchar G, uchar B);
    
    // Standard callback function
    LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
    
    int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprev, PSTR cmdline, int ishow)
    {
        HWND hwnd;    // This will hold the handle to our window
        MSG msg;      // This will hold any messages (such as a key press) that
                      // our window might receive
        WNDCLASSEX wndclassex = {0};    // This is our "window class" -- The "EX" stands
                                        // for "extended style" which gives us more options
                                        // when creating our window (although we're going to
                                        // completely ignore 'em)
    
        // Fill the fields we care about
        wndclassex.cbSize = sizeof(WNDCLASSEX);         // Always must be set
        wndclassex.style = CS_HREDRAW | CS_VREDRAW;     // Window classes style
        wndclassex.lpfnWndProc = WinProc;               // Pointer to where the WinProc() is defined
        wndclassex.hInstance = hinstance;               // The handle to the instance of our window
        wndclassex.lpszClassName = class_name;          // The name of our window class
        wndclassex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);     // This sets the background color
                                                                            // of the window to white
    
        RegisterClassEx(&wndclassex);     // Register the window class so calls to CreateWindow()
                                          // and CreateWindowEx() will know what window class to
                                          // use when creating the window
    
        hwnd = CreateWindowEx(NULL,                   // Extra window attributes, NULL means none
                              class_name,             // Name we gave our WNDCLASSEX 
                              "www.GameTutorials.com -- Keyboard Input",    // Text for the title bar
                              WS_OVERLAPPEDWINDOW,    // Style of window (see MSDN for full description)
                              CW_USEDEFAULT,          // Upper left xPos of window (Windows picks default)
                              CW_USEDEFAULT,          // Upper left yPos of window (Windows picks default)
                              WIN_WIDTH,              // Width of window in pixels
                              WIN_HEIGHT,             // Height of window in pixels
                              NULL,                   // Handle to "parent window" (we have none, this is the parent)
                              NULL,                   // Handle to a menu (we have none)
                              hinstance,              // Handle to instance of this window (passed in by WinMain())
                              NULL);                  // "Extra info" to pass to the WinProc (we have none)
        // Error check
        if(!hwnd)
            return EXIT_FAILURE;    // Something really bad happened!
    
        ShowWindow(hwnd, ishow);    // Show the window (make it visible)
        UpdateWindow(hwnd);         // Updates the window (initially draw the window)
    
        while(1)
        {
            // Get message(s) (for instance a key press) if there is any
            if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
            {
                if(msg.message == WM_QUIT)
                break;
    
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
            else
            {
                // Do all the hardcore computational and rendering stuff here :)
            }
        }
    
        UnregisterClass(class_name,hinstance);    // Free up the memory allocated by our WNDCLASSEX
    
        return msg.wParam; // And we're out
    }
    
    // The WinProc
    LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
    {
        PAINTSTRUCT ps;
        // Depending on the message -- we'll do different stuff
        switch(message)
        {
            // (NEW)
            // This is the message where all the magic happens. A WM_CHAR message
            // gets sent every time WM_KEYDOWN message is translated by the
            // TranslateMessage() function. So what does that mean? Okay see in our WinMain()
            // how we have the function call TranslateMessage(&msg). You HAVE to have
            // this call in WinMain() (with a similar type set up we are using here)
            // for you to receive the WM_CHAR message in your WinProc().
            case WM_CHAR:
            {
                // Okay the first thing is what in the heck is a TCHAR?
                // For all intents and purposes, a TCHAR == char (the normal C/C++ char)
                // On a UNICODE machine it actually equals something else, but either
                // way you can think of it as just a good ole' char
                // Now for the WM_CHAR message, the WPARAM equals the "character code"
                // that was pressed. You can think of the WPARAM equaling the ASCII 
                // representation of the key that was pressed.
                TCHAR tchar = (TCHAR)wparam; // Get the key that was pressed.
    
                // Now lets check for the 'R', 'G' or 'B' key
                // Notice how we check for BOTH upper and lowercase so not "
                // to miss one case or the other
                if(tchar == 'r' || tchar == 'R')
                    PrintColoredText(hwnd,"RED",255,0,0);
                else if(tchar == 'g' || tchar == 'G')
                    PrintColoredText(hwnd,"GREEN",0,255,0);
                else if(tchar == 'b' || tchar == 'B')"
                    PrintColoredText(hwnd,"BLUE",0,0,255);
                return 0;
            }
    
            case WM_PAINT:
                BeginPaint(hwnd,&ps);
                EndPaint(hwnd,&ps);
                return 0;
    
            case WM_DESTROY:
            case WM_CLOSE:
                PostQuitMessage(0);
                return 0;
        } // end of switch(message);
    
    return DefWindowProc(hwnd, message, wparam, lparam);
    }
    
    // Fill the window color to the RGB color passed in
    void PrintColoredText(HWND hwnd, char *text, uchar red, uchar green, uchar blue)
    {
        // Error Check
        if(!text)
            return; // If "text" isn't valid, we'll just return
    
        HDC hdc = GetDC(hwnd); // Get the windows device context
        // Error Check
        if(!hdc)
            return; // Can't fill the window without an HDC, we'll just return
    
        RECT rect;
        GetClientRect(hwnd,&rect); // Get the window's client area RECT
    
        // Clear the client area of the window to all white
        FillRect(hdc,&rect,(HBRUSH)GetStockObject(WHITE_BRUSH));
    
        // This Win32 API does just what you expect, it sets the text color for the
        // specified device context to the RGB color value passed
        SetTextColor(hdc,RGB(red,green,blue));
    
        // This function prints text to the window -- Lets break it down by parameter:
        // hdc == The device context to draw to (here hdc == "our window")
        // TEXT_X == The Window X coordinate to begin drawing the text to
        // TEXT_Y == The Window Y coordinate to begin drawing the text to
        // text == a char* (Windows defines this variable as a LPCSTR, but really that's just
        // the same as a char*) that contains the string to be displayed"
        // strlen(text) == The number of characters in the string
        TextOut(hdc,TEXT_X,TEXT_Y,text,strlen(text));
        ReleaseDC(hwnd,hdc); // Be sure to always free up your HDC
    
        /*****
    
           NOTE:
    
             In SetTextColor() we use the macro RGB()
             RGB() is a Win32 macro that makes a COLORREF. A COLORREF is a 32-bit value
             that specifies an RGB color. A COLORREF looks like this in hex:
    
             0x00bbggrr 
    
             With bb == the blue component, gg == the green component, and rr == red component
             which are each an unsigned value between 0 - 255
    
        *****/
    }
    
    /*
        More on WM_CHAR ---
    
        You probably noticed that we did not do ANYTHING with the LPARAM part of the
        WM_CHAR message. Well it's not that it doesn't include any information. On the 
        contrary, it's chucked full with useful information. So here's the table of
        information you could get out of the LPARAM if it tickled your fancy.
    
        This following is the BIT values breakdown of the 32-bit LPARAM -- Be sure to check
        MSDN for any changes
    
         0 - 15 Specifies the repeat count for the current message. The value is the number of
                times the keystroke is auto-repeated as a result of the user holding down the key
    
        16 - 23 Specifies the scan code. The value depends on the original equipment
                manufacturer (OEM)
    
           24   Specifies whether the key is an extended key, such as the right-hand alt and 
                ctrl keys that appear on an enhanced 101-key or 102-key keyboard. The value is 1 
                if it is an extended key otherwise it's 0
    
        25 - 28 Reserved
    
           29   The context code. The value is 1 if the alt key is held down while 
                the key is pressed otherwise it's 0
    
           30   The previous key state. The value is 1 if the key is down
                before the message is sent, or it is 0 if the key is up
    
           31   The transition state. The value is 1 if the key is being released, 
                or it's 0 if the key is being pressed 
    
    */
    
    /*----------------------------*\
    |           TheTutor           |
    |  thetutor@gametutorials.com  |
    |  © 2000-2003 GameTutorials   |
    \*----------------------------*/

Tutorial #5 - KeyboardInput Part2, C++ source file win_main.cpp

  • Another Win32 program that creates a window and handles keypress inputs in the window.
  • Reference: http://www.gametutorials.com/Tutorials/Win32/Win32_Pg1.htm
    
    // Done by TheTutor -- 6/27/02
    /* 
        This tutorial is all about receiving keyboard input in your Win32 application.
        Windows provides multiple ways to receive keyboard input, but this tutorial
        focuses on a method to get the keyboard input outside of the WinProc().
        For the app, we'll keep it pretty simple. We're going to write a function that determines 
        if a key (specifically an alphabetic key) is pressed. We'll check for both uppercase and 
        lowercase key presses. If you press any of the keys found in "GameTutorials" you'll see
        "GameTutorials" printed to the screen in a random color.
    
        So without further ado, lets get coding.
    */
    
    #include "input.h"
    typedef unsigned char uchar; // Less typing is good %)
    #define WIN_WIDTH 640
    #define WIN_HEIGHT 480
    
    // Where to start drawing the text to
    #define TEXT_X 280 
    #define TEXT_Y 220
    #define class_name "GT_KeyboardInput2"
    
    // This function will print to the screen the text passed in, using
    // the RGB color passed in
    void PrintColoredText(HWND hwnd, char *text, uchar R, uchar G, uchar B);
    
    // Standard callback function
    LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
    
    int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprev, PSTR cmdline, int ishow)
    {
        HWND hwnd;    // This will hold the handle to our window
        MSG msg;      // This will hold any messages (such as a key press) that
                      // our window might receive
    
        WNDCLASSEX wndclassex = {0};    // This is our "window class" -- The "EX" stands
                                        // for "extended style" which gives us more options
                                        // when creating our window (although we're going to
                                        // completely ignore 'em)
        // Fill the fields we care about
        wndclassex.cbSize = sizeof(WNDCLASSEX);      // Always must be set
        wndclassex.style = CS_HREDRAW | CS_VREDRAW;  // Window classes style
        wndclassex.lpfnWndProc = WinProc;            // Pointer to where the WinProc() is defined
        wndclassex.hInstance = hinstance;            // The handle to the instance of our window
        wndclassex.lpszClassName = class_name;       // The name of our window class
        wndclassex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);    // Background color of white 
        RegisterClassEx(&wndclassex);                // Register the window class so calls to CreateWindow()
                                                     // and CreateWindowEx() will know what window class to
                                                     // use when creating the window
    
        hwnd = CreateWindowEx(NULL,                  // Extra window attributes, NULL means none
                              class_name,            // Name we gave our WNDCLASSEX 
                              "www.GameTutorials.com -- Keyboard Input Part2",    // Title bar text
                              WS_OVERLAPPEDWINDOW,   // Style of window (see MSDN for full description)
                              CW_USEDEFAULT,         // Upper left xPos of window (Windows picks default)
                              CW_USEDEFAULT,         // Upper left yPos of window (Windows picks default)
                              WIN_WIDTH,             // Width of window in pixels"
                              WIN_HEIGHT,            // Height of window in pixels
                              NULL,                  // Handle to "parent window" (we have none, this is the parent)
                              NULL,                  // Handle to a menu (we have none)
                              hinstance,             // Handle to instance of this window (passed in by WinMain())
                              NULL);                 // "Extra info" to pass to the WinProc (we have none)
        // Error check
        if(!hwnd)
            return EXIT_FAILURE;    // Something really bad happened!
    
        ShowWindow(hwnd, ishow);    // Show the window (make it visible)
        UpdateWindow(hwnd);         // Updates the window (initially draw the window)
    
        while(1)
        {
            // Get message(s) (for instance a key press) if there is any
            if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
            {
                if(msg.message == WM_QUIT)
                    break;
    
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
            else
            {
                // If any of the letters (case sensitive) in "GameTutorials" are pressed
                // Print to the screen "GameTutorials" in a random color
                if (KeyPressed('G') || KeyPressed('a') ||
                    KeyPressed('m') || KeyPressed('e') ||"
                    KeyPressed('T') || KeyPressed('u') ||
                    KeyPressed('t') || KeyPressed('o') ||
                    KeyPressed('r') || KeyPressed('i') ||
                    KeyPressed('l') || KeyPressed('s'))
                {
                    uchar red = rand()%256;            // random number function
                    uchar green = rand())%256;
                    uchar blue = rand()%256;
                    PrintColoredText(hwnd,"GameTutorials",red,green,blue);
                }
    
                Sleep(100);    // Chill out for awhile man
            }
        }
    
        UnregisterClass(class_name,hinstance);    // Free up the memory allocated by our WNDCLASSEX
        return msg.wParam;     // And we're out
    }
    
    // The WinProc
    LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
    {
        PAINTSTRUCT ps;
    
        // We're not doing much here %)
        switch(message)
        {
            case WM_PAINT:
                BeginPaint(hwnd,&ps);
                EndPaint(hwnd,&ps);
                return 0;
    
            case WM_DESTROY:
            case WM_CLOSE:
                PostQuitMessage(0);
                return 0;
        } // end of switch(message)
    
        return DefWindowProc(hwnd, message, wparam, lparam);
    }
    
    // Fill the window color to the RGB color passed in
    void PrintColoredText(HWND hwnd, char *text, uchar red, uchar green, uchar blue)
    {
        // Error Check
        if(!text)
            return; // If "text" isn't valid, we'll just return
    
        HDC hdc = GetDC(hwnd); // Get the windows device context
        // Error Check
        if(!hdc)
            return;    // Can't fill the window without an HDC, we'll just return
                       // This Win32 API does just what you expect, it sets the text color for the
                       // specified device context to the RGB color value passed
    
        SetTextColor(hdc,RGB(red,green,blue));
        // This function prints text to the window -- Lets break it down by parameter:
        // hdc == The device context to draw to (here hdc == "our window")
        // TEXT_X == The Window X coordinate to begin drawing the text to
        // TEXT_Y == The Window Y coordinate to begin drawing the text to
        // text == a char* (Windows defines this variable as a LPCSTR, but really that's just
        // the same as a char*) that contains the string to be displayed
        // strlen(text) == The number of characters in the string
        TextOut(hdc,TEXT_X,TEXT_Y,text,strlen(text));
        ReleaseDC(hwnd,hdc); // Be sure to always free up your HDC
    
        /*****
    
           NOTE:
    
             In SetTextColor() we use the macro RGB()
             RGB() is a Win32 macro that makes a COLORREF. A COLORREF is a 32-bit value
             that specifies an RGB color. A COLORREF looks like this in hex:
    
             0x00bbggrr 
    
             With bb == the blue component, gg == the green component, and rr == red component
             which are each an unsigned value between 0 - 255
    
        *****/
    }
    
    // The Shady Business of Dealing Keys
    
    /*
    
        Luckily for us Windows makes it pretty painless to get keyboard info outside of
        the WinProc(). However it is important to note two other functions that can also
        get keyboard info:
    
        short GetKeyState(int virtualKey);    // This function is basically exactly what we wrote
                                              // You pass in a virtual key code and it returns a 
                                              // short. If the HIGH BIT on the return value is set
                                              // to one, the key is pressed. If the LOW BIT is set
                                              // to one the key is "toggled". Otherwise the key is
                                              // not pressed.
    
        Now if you are writing some input functions for a GAME and speed is critical you want
        to use this:
    
        short GetAsyncKeyState(int virtualKey);    // This function bypasses the normal "okay, a 
                                                   // key was pressed, queue it up for handling" process
                                                   // and gets you the info of a key's state 
                                                   // asynchrounously (ie NOW). Similar to the 
                                                   // other functions, if the HIGH BIT is set to 
                                                   // one the key is pressed. This time though, if 
                                                   // the LOW BIT is set to one, this means the key
                                                   // was pressed after the previous call to 
                                                   // GetAsyncKeyState()
    
        So if you're writing input code for a cool game and you could give a 
        monkey's behind about if the user entered a lowercase or uppercase letter, you 
        could simply write the KeyPressed() function like this:
    
        bool KeyPressed(char key) // Checks to see if a LETTER was pressed
        {
            key = toupper(key);
            return (GetAsyncKeyState(key) & 0x8000) == 0x8000;
        }
    
    CHALLENGE:
    
        Write a "key pressed" function that returns true or false whether any alphabetic,
        numeric, or punctuation key on the keyboard is pressed -- The function should
        handle case sensitive keys as well.
    */
    
    // Questions, comments, rantings, ravings ???
    //
    // -- You know where to post: www.GameTutorials.com
    
    /*----------------------------*\
    |  TheTutor                    |
    |  thetutor@gametutorials.com  |
    |  © 2000-2003 GameTutorials   |
    \*----------------------------*/

Tutorial #6 - MouseInput, C++ source file win_main.cpp

  • A Win32 program that creates a window and handles mouse inputs and displays the mouse (x,y) position in the window.
    You'll need this to handle mouse inputs from the game player (you).
  • Reference: http://www.gametutorials.com/Tutorials/Win32/Win32_Pg1.htm
    
    // Done by TheTutor -- 5/27/02
    
    /* 
        This tutorial is all about receiving mouse input in your Win32 application. Specifically
        we'll go over how to get the current position of the mouse. We'll get this information
        in the WinProc() by checking the WM_MOUSEMOVE message.
        The application is pretty simple. Basically every time the mouse moves, we'll display
        it's current (x,y) position of the mouse in the center of the screen. That's it!
        Nothing more and nothing less. So without further ado, lets get coding. 
    */
    
    #include <windows.h>
    #include <stdio.h>
    #define WIN_WIDTH 320
    #define WIN_HEIGHT 240
    #define class_name "GT_MouseInput"
    
    // This function will print the mouse coordinates passed in, centered in the window
    void PrintMouseCoords(HWND hwnd, int xPos, int yPos);
    
    // Standard callback function
    LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
    
    int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprev, PSTR cmdline, int ishow)
    {
        HWND hwnd;    // This will hold the handle to our window
        MSG msg;      // This will hold any messages (such as mouse movement) that
                      // our window might receive
        WNDCLASSEX wndclassex = {0};    // This is our "window class" -- The "EX" stands
                                        // for "extended style" which gives us more options
                                        // when creating our window (although we're going to
                                        // completely ignore 'em)
    
        // Fill the fields we care about
        wndclassex.cbSize = sizeof(WNDCLASSEX);      // Always must be set
        wndclassex.style = CS_HREDRAW | CS_VREDRAW;  // Window classes style
        wndclassex.lpfnWndProc = WinProc;            // Pointer to where the WinProc() is defined
        wndclassex.hInstance = hinstance;            // The handle to the instance of our window
        wndclassex.lpszClassName = class_name;       // The name of our window class
        wndclassex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);    // Make the background white
    
        RegisterClassEx(&wndclassex);     // Register the window class so calls to CreateWindow()
                                          // and CreateWindowEx() will know what window class to
                                          // use when creating the window
    
        hwnd = CreateWindowEx(NULL,       // Extra window attributes, NULL means none
                              class_name, // Name we gave our WNDCLASSEX 
                              "www.GameTutorials.com -- Mouse Input",    // Text for the title bar
                              WS_OVERLAPPEDWINDOW,    // Style of window (see MSDN for full description)
                              CW_USEDEFAULT,          // Upper left xPos of window (Windows picks default)
                              CW_USEDEFAULT,          // Upper left yPos of window (Windows picks default)
                              WIN_WIDTH,              // Width of window in pixels
                              WIN_HEIGHT,             // Height of window in pixels
                              NULL,                   // Handle to "parent window" (we have none, this is the parent)
                              NULL,                   // Handle to a menu (we have none)
                              hinstance,              // Handle to instance of this window (passed in by WinMain())
                              NULL);                  // "Extra info" to pass to the WinProc (we have none)
    
        // Error check
        if(!hwnd)
            return EXIT_FAILURE;    // Something really bad happened!
    
        ShowWindow(hwnd, ishow);    // Show the window (make it visible)
        UpdateWindow(hwnd);         // Updates the window (initially draw the window)
    
        while(1)
        {
            // Get message(s) (for instance a mouse movement) if there is any
            if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
            {
                if(msg.message == WM_QUIT)
                    break;
    
            TranslateMessage(&msg);
            DispatchMessage(&msg);
              }
              else
              {
                   // Do all the hardcore computational stuff here :)
              }
         }
    
         UnregisterClass(class_name,hinstance);    // Free up the memory allocated by our WNDCLASSEX
         return msg.wParam;                        // And we're out
    }
    
    // The WinProc
    LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
    {
         PAINTSTRUCT ps;
    
         // Depending on the message -- we'll do different stuff
         switch(message){
              // This is the message that is posted to a window when
              // the mouse moves. For a window NOT to receive this message
              // when the mouse is moved a DIFFERENT window would have to 
              // currently own the "mouse movement" (a different window would 
              // have to be in focus) and then this message would be posted to 
              // that window
              case WM_MOUSEMOVE: 
              {
                   // Here's a quick break down of the information we can get from this
                   // message
                   int flags = wparam;    // "flags" contains flags that say whether certain
                                          // virtual keys (such as the CTRL key) are being pushed or not
                                          // More info on this is supplied at the bottom of this file
                   int xPos = LOWORD(lparam);    // This gives us the horizontal (the X position) of
                                                 // the cursor
                   int yPos = HIWORD(lparam);    // This gives us the vertical (the Y position) of
                                                 // the cursor
                   PrintMouseCoords(hwnd,xPos,yPos); // Print 'em to the screen
                   return 0;
    
                   // **NOTE**
                   //
                   // You can also create a POINTS struct that is a Win32 struct that contains
                   // an 'x' and 'y' which are both defined to be SHORT's (16-bit integers)
                   // by calling this macro:
                   //
                   // POINTS point = MAKEPOINTS(lparam); // "point" will equal the (x,y) position
                   //                                    // of the mouse
               }
    
              case WM_PAINT:
                   BeginPaint(hwnd,&ps);
                   EndPaint(hwnd,&ps);
                   return 0;
    
              case WM_DESTROY:
              case WM_CLOSE:
                   PostQuitMessage(0);
                   return 0;
         } // end of switch(message)
    
         return DefWindowProc(hwnd, message, wparam, lparam);
    }
    
    // Prints the X-position and Y-position, with appropriate labels, centered
    // in the window
    void PrintMouseCoords(HWND hwnd, int xPos, int yPos)
    {
         HDC hdc = GetDC(hwnd);    // Get the windows device context
         // Error Check
         if(!hdc)
              return;    // Can't fill the window without an HDC, we'll just return
    
         RECT rect;
         GetClientRect(hwnd,&rect); // Get the window's client area RECT
    
         // Clear the window (the client area of the window) to all white
         FillRect(hdc,&rect,(HBRUSH)GetStockObject(WHITE_BRUSH));
    
         / **NOTE**
         //
         // What EXACTLY is the client area of a window? Well when you think 
         // of a window, you should think of two RECT's that describe that window. The first
         // is the WINDOW RECT. This, as the name implies, encompasses the ENTIRE window.
         // The second is the CLIENT RECT. This is the area of the window where "stuff" is
         / actually drawn. The client area EXCLUDES the title bar and thin borders around the
         // window. It's upper left corner always starts at (0,0) and is relative to the window.
         / For this app, the client rect is the rectangular area that's pure white and has
         // the mouse coordinates being displayed in it.
    
         char buffX[128] = {0};    // char buffer for the X position
         char buffY[128] = {0};     // char buffer for the Y position
         // Fill both buffers with the apporopiate text
         sprintf(buffX,"X Pos = %d",xPos);
         sprintf(buffY,"Y Pos = %d",yPos);
    
         // Now here's where you math teacher turns out to be right! To display the 
         // text horizontally centered in the window, we're going to have to use a little algebra.
         // So lets think about this. We basically want half of the text to the left of 
         // the center of the window and half of the text to the right of the center of 
         // the window so overall it will look perfectly centered. Well that gives us this 
         // equation:
         /
         // xStart = centerX - (lengthOfText / 2)
         // yStart = Whatever we choose, all we care is that the text is centered horizontally
         // 
         // But that won't quite do it. We forgot one thing, the width of each letter of 
         // text. So when we add that into the equation we get this:
         //
         // xStart = centerX - ((lengthOfText / 2) * widthOfACharacter)
         // yStart = Whatever we choose, all we care is that the text is centered horizontally
         //
         // Okay we have our equation, so now lets fill in the variables
         // First, we'll get the center of the window
         // Notice how we use the CLIENT rect to get the center (x,y) of the window
         int centerX = rect.right / 2;
         int centerY = rect.bottom / 2;
    
         // Next we'll get the "width of the text". To do this we'll fill a TEXTMETRIC struct.
         / A TEXTMETRIC is a Win32 struct that holds a whole crap load of information about 
         / a physical font.
         TEXTMETRIC textmetric;
         GetTextMetrics(hdc,&textmetric);   // This fills "textmetric" with a bunch of information
                                            // about the current font. Now since we didn't set
                                            // the font to anything in particular, this will be 
                                            // filled with the "default font's" info.
    
         // We'll draw the "Mouse's x position first" so using our equation lets calculate
         // it's starting x-pos for drawing to the window. You'll notice we use
         // the "tmAveCharWidth" variable of the TEXTMETRIC struct. This gives us the average
         // width of a character drawn, which is just what we need.
         int start = centerX - ((strlen(buffX) / 2) * textmetric.tmAveCharWidth);
    
         // Okay now it's time to actually write out the text to the screen
         // We'll draw this slightly above the vertical center of the screen,
         // hence the (centerY - 25)
         TextOut(hdc, start, centerY - 25, buffX, strlen(buffX));
    
         // Now it's time to draw out the "Mouse's y position" so lets recalculate our starting
         // position
         start = centerX - ((strlen(buffY) / 2) * textmetric.tmAveCharWidth);
         // Draw it to the screen -- We'll draw this slightly below the vertical center of 
         // the window
         TextOut(hdc, start, centerY + 25, buffY, strlen(buffY));
         ReleaseDC(hwnd,hdc); // Be sure to always free up your HDC
    }
    
    // More Mouse Movement --------------
    
    /* As promised, here's more on the "flags" that are filled every time the 
       WinProc() receives a WM_MOUSEMOVE message. It's important to
       note that "flags" (the WPARAM value) could contain any combination of 
       the following:
    
       MK_CONTROL Set if the ctrl key is down. 
       MK_LBUTTON Set if the left mouse button is down. 
       MK_MBUTTON Set if the middle mouse button is down. 
       MK_RBUTTON Set if the right mouse button is down. 
       MK_SHIFT Set if the shift key is down.
    
       So to determine if, say for instance, the crtl key is down, we would simply utilize our
       old friends the binary operators and do something like this:
    
       if(flags & MK_CONTROL)
           // Do stuff because ctrl key is down
    
       Well that's all she wrote for this chapter on mouse movement. As always, any questions 
       can be directed to the forums at www.GameTutorials.com
    */
    
    /*----------------------------*\
    |           TheTutor           |
    |  thetutor@gametutorials.com  |
    |  © 2000-2003 GameTutorials   |
    \*----------------------------*/

Tutorial #7 - MouseInput Part2, C++ source file win_main.cpp

  • Another Win32 program that creates a window and handles mouse inputs in the window.
  • Reference: http://www.gametutorials.com/Tutorials/Win32/Win32_Pg1.htm
    // Done by TheTutor -- 6/13/02
    
    /* 
       Here we'll take a second look at obtaining mouse input in your Win32 app. Specifically
       we'll go over how to check the left mouse button, right mouse button, and mouse wheel
       for input.
    
       Here's the short list of what our program will do:
    
       1) While the left mouse button is held down, the text "Left MB" will appear
          in the center of the screen
       2) While the right mouse button is held down, the text "Right MB" will appear 
          in the center of the screen
       3) Scrolling the mouse wheel will change the color of the text for both the left
          and right mouse button messages.
    
       Simple right? Right!?! You bet it will be. So lets get on with the show
    */
    
    // Okay first things first. We have to cover up a MS boo-boo. If you read MSDN it says 
    // that you can program for the mouse wheel as long as you have 98 and up. Well it turns
    // out that this simply isn't true. Depending on your OS/compiler you may have to 
    // define the "mouse wheel" yourself.
    
    #ifndef WM_MOUSEWHEEL
    #define WM_MOUSEWHEEL 522 // Value plucked from Winuser.h
    #endif
    
    #include <windows.h>
    #define WIN_WIDTH 320
    #define WIN_HEIGHT 240
    
    // The Y-pos for the display the left mouse button text and the right mouse
    // button text
    #define LMB_YPOS 80
    #define RMB_YPOS 120
    #define class_name "GT_MouseInput2"
    
    // This function prints text to the screen, horizontally centered in the window
    // with the passed in color, stating vertically at "yPos"
    void TextOutCentered(HWND hwnd, char *text, int yPos, COLORREF color);
    
    // Standard callback function
    LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam);
    
    int WINAPI WinMain(HINSTANCE hinstance, HINSTANCE hprev, PSTR cmdline, int ishow)
    {
        HWND hwnd;                      // This will hold the handle to our window
        MSG msg;                        // This will hold any messages (such as mouse movement) that
                                        // our window might receive
    
        WNDCLASSEX wndclassex = {0};    // This is our "window class" -- The "EX" stands
                                        // for "extended style" which gives us more options
                                        // when creating our window (although we're going to
                                        // completely ignore 'em)
    
        // Fill the fields we care about
        wndclassex.cbSize = sizeof(WNDCLASSEX);        // Always must be set
        wndclassex.style = CS_HREDRAW | CS_VREDRAW;    // Window classes style
        wndclassex.lpfnWndProc = WinProc;              // Pointer to where the WinProc() is defined
        wndclassex.hInstance = hinstance;              // The handle to the instance of our window
        wndclassex.lpszClassName = class_name;         // The name of our window class
        wndclassex.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);    // Make the background white
    
        RegisterClassEx(&wndclassex);    // Register the window class so calls to CreateWindow()
                                         // and CreateWindowEx() will know what window class to
                                         // use when creating the window
        hwnd = CreateWindowEx(NULL,      // Create the window
                              class_name,             // Name we gave our WNDCLASSEX 
                              "www.GameTutorials.com -- Mouse Input Part2", // Text in title bar
                              WS_OVERLAPPEDWINDOW,    // Style of window
                              CW_USEDEFAULT,          // Upper left xPos of window (Windows picks default)
                              CW_USEDEFAULT,          // Upper left yPos of window (Windows picks default)
                              WIN_WIDTH,              // Width of window in pixels
                              WIN_HEIGHT,             // Height of window in pixels
                              NULL,                   // Handle to "parent window" (we have none, this is the parent)
                              NULL,                   // Handle to a menu (we have none)
                              hinstance,              // Handle to instance of this window (passed in by WinMain())
                              NULL);                  // "Extra info" to pass to the WinProc (we have none)
        // Error check
        if(!hwnd)
            return EXIT_FAILURE;    // Something really bad happened!
    
        ShowWindow(hwnd, ishow);    // Show the window (make it visible)
        UpdateWindow(hwnd);         // Updates the window (initially draw the window)
    
        while(1)
        {
            // Get message(s) (for instance a mouse movement) if there is any
            if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
            {
                if(msg.message == WM_QUIT)
                    break;
    
                TranslateMessage(&msg);
                DispatchMessage(&msg);
            }
            else
            {
                // Do all the hardcore computational stuff here :)
            }
        }
    
        nregisterClass(class_name,hinstance);    // Free up the memory associated with the WNDCLASSEX
        return msg.wParam; // And we're out
    }
    
    // The WinProc
    LRESULT CALLBACK WinProc(HWND hwnd, UINT message, WPARAM wparam, LPARAM lparam)
    {
        PAINTSTRUCT ps;
    
        static unsigned char red, green, blue; // Our text colors
    
        // Depending on the message -- we'll do different stuff
        switch(message)
        {
            case WM_CREATE:
                // Set our text color initially to solid black
                red = green = blue = 0;
                return 0;
    
            // This is the message that is sent when the LEFT mouse button is pressed
            // while the cursor is in the CLIENT AREA (the area of the window that excludes
            // the title bar and window borders) of the window. So when we receive this
            // message we'll draw the "Left MB" text to the screen
            case WM_LBUTTONDOWN:
                TextOutCentered(hwnd,"Left MB",LMB_YPOS,RGB(red,green,blue));
                return 0;
    
            // This is the message that is sent when the LEFT mouse button is released
            // while the cursor is in the CLIENT AREA of the window. So when we receive 
            // this message we're going to be really sneaky and display the same text
            // only using the color (255,255,255), which since that's what we set our 
            // windows background color to, will make it look like the text was erased
            case WM_LBUTTONUP:
                TextOutCentered(hwnd,"Left MB",LMB_YPOS,RGB(255,255,255));
                return 0;
    
            // This is the message that is sent when the RIGHT mouse button is pressed
            // while the cursor is in the CLIENT AREA (the area of the window that excludes
            // the title bar and window borders) of the window. So when we receive this
            // message we'll draw the "Right MB" text to the screen
            case WM_RBUTTONDOWN:
                TextOutCentered(hwnd,"Right MB",RMB_YPOS,RGB(red,green,blue));
                return 0;
    
            // This is the message that is sent when the RIGHT mouse button is released
            // while the cursor is in the CLIENT AREA of the window. So when we receive 
            // this message we're going to be really sneaky and display the same text
            // only using the color (255,255,255), which since that's what we set our 
            // windows background color to, will make it look like the text was erased
            case WM_RBUTTONUP:
                TextOutCentered(hwnd,"Right MB",RMB_YPOS,RGB(255,255,255));
                return 0;
    
            // This is the message that is sent when the mouse wheel is rotated. This 
            // message will be sent to the window with the current focus. Lets get
            // the information that we care about from this message
            case WM_MOUSEWHEEL:
            {
                int flags = LOWORD(wparam);    // The LOWORD of the WPARAM holds info on whether
                                               // various virtual keys are down (like the CRTL key)
                                               // or not -- More info about the "flags" is provided
                                               // at the bottom of this file.
                                               // The HIWORD of the WPARAM holds info on the
                                               // distance that the wheel is rotated, expressed in
                                               // multiples or divisions of WHEEL_DELTA, which is
                                               // 120. A positive value indicates that the wheel was
                                               // rotated forward, away from the user; a negative
                                               // value indicates that the wheel was rotated backward,
                                               // toward the user -- Check out the bottom of this file for
                                               // more info on using WHEEL_DELTA.
                short delta = (short)HIWORD(wparam);
    
                // All we're going to worry about is if the mouse wheel
                // was rolled forwards or backwards
                // If it's rolled forward, we'll increment the color by 5
                // If it's rolled backward, we'll decrement the color by 5
                int amount = (delta >= 0) ? 5 : -5;
    
                // If the CRTL key was being held
                if(flags & MK_CONTROL)
                    red += amount;           // Change the red color component by "amount"
                else if(flags & MK_SHIFT)    // Else if the SHIFT key was being held
                    green += amount;         // Change the green color component by "amount"
                else // Else just modify the blue component by amount
                    blue += amount;
    
                // If the left mouse button is down
                if(flags & MK_LBUTTON)
                    TextOutCentered(hwnd,"Left MB",LMB_YPOS,RGB(red,green,blue));
    
                // If the right mouse button is down
                if(flags & MK_RBUTTON)
                    TextOutCentered(hwnd,"Right MB",RMB_YPOS,RGB(red,green,blue));
    
                return 0;
    
                // **NOTE**
                //
                // Additionally the following information can be obtained from this message:
                //
                // int xPos = LOWORD(lparam); // horizontal position of cursor
                //
                // int yPos = HIWORD(lparam); // vertical position of cursor
            }
    
            case WM_PAINT:
                BeginPaint(hwnd,&ps);
                EndPaint(hwnd,&ps);
                return 0;
    
            case WM_DESTROY:
            case WM_CLOSE:
                PostQuitMessage(0);
                return 0;
        } // end of switch(message)
    
        return DefWindowProc(hwnd, message, wparam, lparam);
    }
    
    // This function does most of dirty work. It will print "text" to the 
    // screen horizontally centered staring at "yPos". The text will also
    // be the same color as the COLORREF passed in.
    void TextOutCentered(HWND hwnd, char *text, int yPos, COLORREF color)
    {
        HDC hdc = GetDC(hwnd);    // Get the windows device context
    
        // Error Check
        if(!hdc)
        return;
    
        RECT rect;
        GetClientRect(hwnd,&rect);          // Get the window's client area RECT
        TEXTMETRIC textmetric;              // struct for holding information about fonts
        GetTextMetrics(hdc,&textmetric);    // Fill the TEXTMETRIC with information about
                                            // our window's font
        // Set the text color to the color passed in
        SetTextColor(hdc,color);
    
        // Calculate the staring X-pos to begin displaying the text
        // (rect.right / 2) equals the "center X" of the window
        int xPos = (rect.right / 2) - ((strlen(text) / 2) * textmetric.tmAveCharWidth);
    
        // Draw the text to the screen
        TextOut(hdc, xPos, yPos, text, strlen(text));
        ReleaseDC(hwnd,hdc); // Be sure to always free up your HDC
    }
    
    // Wheel Of Unfortunate...
    
    /*
       Unfortunately, you have to "potentially" do something special to get 
       the mouse wheel to work (yes you can blame this on MS :)
       So lets look at the code we use for WM_MOUSEWHEEL and what it's doing:
    
       #ifndef WM_MOUSEWHEEL        // This says "Okay if what MS says is supposed to be
                                    // defined isn't, lets do something about it"
       #define WM_MOUSEWHEEL 522    // We define the value to what it's suppose to equal
                                    // We get this from from Winuser.h
       #endif
    
       If you wanted to use the WHEEL_DELTA value, you would have to write code similar to what's 
       above. WHEEL_DELTA indicates the distance that the wheel is rotated, expressed
       in multiples or divisions of WHEEL_DELTA, which is 120. So if you wanted to use WHEEL_DELTA
       set it to 120. 
    
       If you are interested to why this just doesn't work, open up winuser.h (just search for 
       it on your computer) and then inside the file search for WM_MOUSEWHEEL. You'll see the
       code preventing this from working. I would HIGHLY recommend NOT changing winuser.h.
       Just do the fix as it's done in this tutorial and all is well :)
    
       By the way I could not get this to compile (without the fix) on Win98 or Win2000 
       using VC++6.0
       When dealing with messages in the WinProc() of any type, it's important to know
       exactly what they do. So for an exercise try (for example) pressing and holding the
       left mouse button, moving the cursor completely off the window, and releasing.
       See if you can get the app to show/erase the text NO MATTER where your mouse is.
    
       *HINT* look up WM_NCLBUTTONDOWN (and others similar) in MSDN
       Any other questions or concerns, you know where to post -- www.GameTutorials.com
    */
    
    /*----------------------------*\
    |  TheTutor                    |
    |  thetutor@gametutorials.com  |
    |  © 2000-2003 GameTutorials   |
    \*----------------------------*/

Tutorial #8 - FullScreen, C++ source file FullScreen.cpp

  • A Win32 program that creates a window in full screen mode (graphics run slightly faster than in window mode).
    You'll need this to provide an option in most of your game programs.
  • Reference: http://www.gametutorials.com/Tutorials/Win32/Win32_Pg2.htm
    
    // ***********************************************************************//
    //                                                                        //
    // - "Talk to me like I'm a 3 year old!" Programming Lessons -            //
    //                                                                        //
    // $Author: Ben Humphrey digiben@gametutorials.com                        //
    //                                                                        //
    // $Program: Text                                                         //
    //                                                                        //
    // $Description: This gives the user the option to go full screen         //
    //                                                                        //
    // $Date: 6/18/01                                                         //
    //                                                                        //
    //************************************************************************//
    
    #include <windows.h>         // We need to include windows.h
    #include <stdio.h>           // Include stdio.h for the basics
    #define SCREEN_WIDTH 800     // We want a 800 pixel width resolution
    #define SCREEN_HEIGHT 600    // We want a 600 pixel height resolution
    BOOL bFullScreen = FALSE;    // Create a boolean and set it to false. If we choose full screen, set it to TRUE
            
    ///////////////////////////////// CHANGE TO FULL SCREEN \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
    /////
    ///// This changes the screen to FULL SCREEN
    /////
    ///////////////////////////////// CHANGE TO FULL SCREEN \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\*
    
    void ChangeToFullScreen(int width, int height)
    {
        DEVMODE dmSettings;                          // Device Mode variable - Needed to change modes
        memset(&dmSettings,0,sizeof(dmSettings));    // Makes Sure Memory's Cleared
    
        // Get current settings -- This function fills our the settings
        // This makes sure NT and Win98 machines change correctly
        if(!EnumDisplaySettings(NULL,ENUM_CURRENT_SETTINGS,&dmSettings))
        {
            // Display error message if we couldn't get display settings
            MessageBox(NULL, "Could Not Enum Display Settings", "Error", MB_OK);
            return;
        }
    
        dmSettings.dmPelsWidth = width;                        // Set the desired Screen Width
        dmSettings.dmPelsHeight = height;                      // Set the desired Screen Height
        dmSettings.dmFields = DM_PELSWIDTH | DM_PELSHEIGHT;    // Set the flags saying we're changing the Screen Width and Height
    
        // This function actually changes the screen to full screen
        // CDS_FULLSCREEN Gets Rid Of Start Bar.
        // We always want to get a result from this function to check if we failed
        int result = ChangeDisplaySettings(&dmSettings,CDS_FULLSCREEN); 
        // Check if we didn't recieved a good return message From the function
        if(result != DISP_CHANGE_SUCCESSFUL)
        {
            // Display the error message and quit the program
            MessageBox(NULL, "Display Mode Not Compatible", "Error", MB_OK);
            PostQuitMessage(0);
        }
    }
    
    LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM); // Create a function prototype for the wndProc.
    
    // Here is our "main()" equivalent in windows, WinMain(). 
    int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR szCmdLine, int iCmdShow)
    { 
        HWND hwnd;              // Create a variable that holds a handle to our window.
        MSG msg;                // Create a variable to hold the message information
        WNDCLASSEX wndclass;    // This variable will hold all the information about the window (The name, icon, cursor, color, menu bar...)
        DWORD dwStyle;
    
        wndclass.cbSize = sizeof (wndclass);                // Here we set the size of the wndclass. 
        wndclass.style = CS_HREDRAW | CS_VREDRAW;           // The style we want is Verticle-Redraw and Horizontal-Redraw
        wndclass.lpfnWndProc = WndProc;                     // Here is where we assing our CALLBACK function. (The function to handle the messages)
        wndclass.cbClsExtra = 0;                            // We want zero extra bytes
        wndclass.cbWndExtra = 0;                            // Init this useless thing to 0
        wndclass.hInstance = hInstance;                     // We assign our hInstance to our window. 
        wndclass.hIcon = LoadIcon (NULL, IDI_WINLOGO);      // Load a logo for our window"
        wndclass.hCursor = LoadCursor (NULL, IDC_ARROW);    // Load a arrow cursor for our window.
    
        // Set the background color for the window
        wndclass.hbrBackground = (HBRUSH) GetStockObject (BLACK_BRUSH);
        wndclass.lpszMenuName = NULL;                       // We pass NULL because we don't want a menu.
        wndclass.lpszClassName = "Full Screen App";         // Create a name that we identify this window class with.
        wndclass.hIconSm = LoadIcon (NULL, IDI_WINLOGO);    // Create an icon for the top left of the window.
        RegisterClassEx (&wndclass);                        // We need to register the wndclass.
    
        if(MessageBox(NULL, "Click Yes to go to full screen (Recommended)", "Options", MB_YESNO | MB_ICONQUESTION) == IDNO)
        {
            dwStyle = WS_OVERLAPPEDWINDOW;    // If we don't want full screen, open a simple window
        } 
        else // If we chose YES
        { 
            bFullScreen = TRUE;    // Set our boolean to TRUE, we wanted fullscreen
    
            // This is the style that we need our window to have in order to be windowless fullscreen
            dwStyle = WS_POPUP | WS_CLIPSIBLINGS | WS_CLIPCHILDREN;
            ChangeToFullScreen(SCREEN_WIDTH, SCREEN_HEIGHT);     // This changes our screen to full screen with our desired resolution
        }
    
        // Here we create the window returning our handle to the window.
        hwnd = CreateWindow ("Full Screen App",    // window class name 
                             "Full Screen App",    // window's Title 
                             dwStyle,              // window style 
                             0,                    // initial x position
                             0,                    // initial y position
                             SCREEN_WIDTH,         // initial x size - Our resolution width
                             SCREEN_HEIGHT,        // initial y size - Our resolution height 
                             NULL,                 // Pass NULL for the parent window
                             NULL,                 // Pass NULL for a menu
                             hInstance,            // Pass in our hInstance
                             NULL);                // Pass NULL to the wndProc, we don't want to pass it any variables address's.
    
        ShowWindow (hwnd, iCmdShow);    // Show the window
        UpdateWindow (hwnd);            // Update our window and paint it to the screen
    
        // Start our main loop
        while (GetMessage (&msg, NULL, 0, 0))    // Create our message loop, Get the message, then translate it and handle it.
        { 
            TranslateMessage (&msg);    // Translate the message recieved from the user
            DispatchMessage (&msg);     // Handle the message recieved from the user
        }
    
        UnregisterClass("Full Screen App",hInstance);    // We need to unregister the wndclass.
    
        return msg.wParam;    // Quit the program
    }
    
    // Start our window procedure (wndProc). This handles the messages
    LRESULT CALLBACK WndProc (HWND hwnd, UINT iMsg, WPARAM wParam, LPARAM lParam)
    { 
        PAINTSTRUCT paintStruct;    // Create a paint struct
        HDC hdc;                    // Create our HDC (Handle to a Device Context = The graphics card)
    
        switch (iMsg)    // This checks what the message is. Below is some of the message that windows might return. There of course is HUNDREDS.
        {
            case WM_CREATE:    // This message is sent when the window is created.
                break;         // We break from the switch statement.
    
            case WM_PAINT:     // This message is sent to the WndProc when the window needs to be repainted.
                               // This might be if we moved the window, resized it, or maximized it, or another window was over it.
                hdc = BeginPaint(hwnd, &paintStruct);    // Get our painting HDC.
                EndPaint(hwnd, &paintStruct);            // Now we must free our memory that was allocated for the paintStruct.
                DeleteDC(hdc);                           // Free the device context
                break;         // Break from the switch statement
    
            case WM_KEYDOWN:   // If we pressed a key
                switch (wParam)    // Check what the wParam holds. The wParam holds which key we pressed.
                {
                    case VK_ESCAPE:    // If we pressed the ESCAPE key.
                        if(bFullScreen)    // If we went to full screen mode, reset the display mode
                        {    // Calling the same function with NULL and 0 reset the screen settings and resolution
                             ChangeDisplaySettings(NULL, 0);
                        }
                        PostQuitMessage(0); // Quit the program
                        break;
                 }
                 break;
    
            case WM_DESTROY:    // This message is sent when the user closes the window.
                PostQuitMessage(0);    // Post a WM_QUIT to our message loop to quit the application
                break;                 // Break from the switch statement
        }
        return DefWindowProc (hwnd, iMsg, wParam, lParam); // Return generic information to our message loop
    } // End of the WndProc
    
    /////////////////////////////////////////////////////////////////////////////////
    //
    // ** SPECIAL NOTE **
    //
    // If you run Win95 you should use this instead:
    //
    // void ChangeToFullScreen(int width, int height)
    // {
    //     DEVMODE devmode = {0};
    // 
    //     devmode.dmSize = sizeof(DEVMODE);
    //     devmode.dmPelsWidth = width;
    //     devmode.dmPelsHeight = height;
    //     devmode.dmBitsPerPel = 16; // Bits per pixel
    //     devmode.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
    // 
    //     if(ChangeDisplaySettings(&devmode, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
    //     {
    //         // Display the error message and quit the program
    //         MessageBox(NULL, "Display Mode Not Compatible", "Error", MB_OK);
    //         PostQuitMessage(0);
    //     }
    // 
    // }
    //
    //
    // * QUICK NOTES * 
    //
    // This shows you how to go to full screen in a window app. Before we create our
    // window you will notice that we have to change the style, depending on if we
    // chose full screen or not. If we didn't change the style it would be full screen,
    // but it would look like a window. We usually want to get rid of the window look,
    // and that is why we change the style of it.
    //
    // We use a message box to get the choice from the user. This is a very good idea.
    // The function MessageBox() returns the button ID that was clicked. In our case,
    // we checked on IDNO. If we clicked the NO button, then don't go to full screen.
    // If we didn't click NO, it will return IDYES, and then sets our flag/boolean to TRUE.
    // This is important because when we close the program we need to restore the settings.
    // To do this, we call the ChangeDisplaySettings() again, but pass in NULL and 0 for
    // the parameters. It restores the old settings before we changed it, which is nice
    // that we don't need to keep track of the old settings. The ChangeToFullScreen()
    // function should be modular enough to plug into any project. It's simple to use
    // and easy to cleanup.
    //
    // In the ChangeToFullScreen() function, what we do is Enumerate the current display
    // settings. This means, that we fill in our DEVMODE structure with our current screen
    // settings. If you debug you will find it will hold your current screen resolution,
    // along with other information after the function is called. But, before we pass that
    // information into ChangeDisplaySettings(), we want to change the resolution to our
    // desired resolution that was passed in. In my fire tutorial I go to 320 240 resolution.
    //
    // Just remember to call ChangeDisplaySettings() again before you close the program or
    // else you will be stuck in the changed mode until you manually change it in your
    // display settings from control panels.
    //
    // If you haven't seen the WM_KEYDOWN message yet, you can kinda see what it does.
    // The wParam holds the key that was pressed down, so we can query it like we did above.
    // Each key has a virtual key code, hence the VK_. Look in MSDN for the rest of them.
    // In this program, we check if the user hit the escape key. If so, restore the settings
    // and quit the program.
    //
    // © 2000-2003 GameTutorials

Up