/****************************************************************** Module : newskel.cpp Purpose : CTEC1638/2003W Minimal Windows NT skeleton. Comments : Use this program as a basis for your programs in this course. Author : Mike Boldin, Niagara College Canada, Date : 2003.01.07 Modification History : 2003.01.07 Adapted from MINSDK2.C by Rob McGregor 2004.01.27 Comments added by Michael Janzen *******************************************************************/ /* 1 2 3 4 5 6 7 8 123456789012345678901234567890123456789012345678901234567890123456789012345678*/ // This includes all the header files needed (usually). // Note that the windows.h actually included header files so // you end up including more than one header file. #include // Put any local includes here. That is: header files in the same directory // as your source code. (Example: "resource.h") // Note that you need to use "" to say local /* Local includes */ // Put structs, classes (if used), #defines, etc here if need them /* User-defined data types */ // C (and C++) requires that functions be defined before you call them. // One way to do this is to define them at the top of you file, like here. /* Function prototypes */ LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM ); BOOL InitApplication( HINSTANCE ); BOOL InitInstance( HINSTANCE, INT ); /* Global constants */ // This is a constant pointer to a constant string. // You cannot change the string, nor can you change the pointer to point // to another string. // The idea is that you can put constant string near the top so that they // are easy to find and change later, if required. const char * const APP_NAME = // The app name "CTEC1638"; // Same as above. This is the title that will appear on the window and // on the task bar const char * const APP_TITLE = // caption text "A Minimal Windows NT Skeleton"; /* Global variables */ // The idea here is to define a structure that will work as a global // variable. Currently the only thing in here is a handle to the program // instance. You can think of a handle as a kind of pointer without having // to use the *. // (It's actually a little different, but you can think of it as a pointer) typedef struct tagGlobal { // This will eventually be set to point to this program's instance. // This "pointer" will be needed to tell certain window's API function // where to find resources (icons, cursors, accelerators, etc ..) HINSTANCE hInst; // handle to instance for resources } GLOBAL, * LPGLOBAL; // This is a function which returns the global structure. // Because it is defined as static, there is only one global structure of this type // in the program. The (HINSTANCE) 0 means that the value of hInst is initiated as // 0. It will be changed later to store the handle to the program's instance. LPGLOBAL GetGlobalData( ) { static GLOBAL data = { (HINSTANCE) 0 // hInst }; return ( & data ); } /****************************************************************** Function : WinMain(HINSTANCE, HINSTANCE, LPSTR, INT) Purpose : Program entry point. Calls initialization function, processes message loop. *******************************************************************/ // Your windows program starts here. It is like the main(...) method // in a consol program. // // hThisInst is the handle to your program's instance (described a bit above) // // hPrevInst is a pointer to a previous instance, but is mostly included // for historical purposes (windows 3.1). It is (basically) always set to NULL. // // lpszArgs can be used to pass command line arguments to your program. For example, // if you click a data file with an associated program you may want to look at // lpszArgs to see which file to load // // nWinMode will eventually be used in CreateWindow(...) to set the program // initially as maximized, minimized, or overlapped (usually the default). INT WINAPI WinMain( HINSTANCE hThisInst, HINSTANCE hPrevInst, LPSTR lpszArgs, INT nWinMode ) { // // If no previous instance register the new window class // if ( ! hPrevInst ) // Are other instances of the app running? { // Initialize 1st instance // This kind of works as creating the template for your window. // Sets the window class on how you want you windows to look, act, etc .. if ( ! InitApplication( hThisInst ) ) { // If InitApplication fails you program gets to here and // then exits ( return(FALSE) ). MessageBox( HWND_DESKTOP, "InitApplication", APP_NAME, MB_OK ); return ( FALSE ); // Exits if unable to initialize } } // Perform initializations that apply to a specific instance // This basically creates the window, and puts the program's instance // in global data (has to be done somewhere) if ( ! InitInstance( hThisInst, nWinMode )) { // If InitInstance fails then exit the program return ( FALSE ); } // // Enter the application message loop. Get and dispatch // messages until a WM_QUIT message is received // MSG message; // window message // Get a message from the message queue. Store it in message. // Right now just using (HWND) 0 as the window handle. This // will need to be changed if your program uses accelerators // The last two zeros mean to get all the messages, rather than // a range of messages while ( GetMessage( & message, (HWND) 0, 0, 0 ) ) { // Some "keys" use more than one key press, so change them // into something more managable. For example you don't want // to consider ALT-T, or SHIFT-Q, or CONTROL-C as two key presses. // // Translate virtual key codes TranslateMessage( & message ); // Dispatch message to window // // Instruct windows to call the function you specified earlier when // initiating the application (the function is WndProc). // // This may seem a little weird, but windows is a multitasking // environment. Windows may have to do something else right away // and will call your function when it has some free time. DispatchMessage( & message ); } // When GetMessag returns false (i.e. PostQuitMessage(0) was issued then // you get to this return and exit the program. return ( message.wParam ); // Returns value from PostQuitMessage } /****************************************************************** Function : InitApplication(HINSTANCE) Purpose : Initializes window data and registers window class. *******************************************************************/ BOOL InitApplication( HINSTANCE hInstance ) { // Rather than pass the RegisterClassEx a whole bunch of // arguments, put the arguments into a structure (wcl) // and pass the structure to windows. WNDCLASSEX wcl; // window class // wcl is actually a structure, and cannot set it's own size // Therefore this sets the size of the structure (windows uses // the size internally). wcl.cbSize = sizeof(WNDCLASSEX); // // Fill in window class structure with parameters // that describe the main window // // Pass windows the handle to this application wcl.hInstance = hInstance; // handle to this instance // Pass the name of this application to windows // Note that APP_NAME is actually a string defined above wcl.lpszClassName = APP_NAME; // window class name // This line is important. This is how you instruct windows // to call your function called "WndProc" when you dispatch a message. wcl.lpfnWndProc = (WNDPROC) WndProc; // window function // Set the windows style. This isn't all that useful a comment, but // you can set certain things here. // CS_HREDRAW says to redraw the entire window when the width of the // window changes. CS_VREDRAW does the same thing with the height. // Look at the windows help for other options here. // Notice that the two options are or-ed together. wcl.style = CS_HREDRAW | CS_VREDRAW; // Load the default icons and cursor. If you set create icon // or cursor as a resource, then put the name here (use quotes). // Remember to also put the handle to the application rather than // the 0 so windows knows where to look for the resource wcl.hIcon = LoadIcon( 0, IDI_APPLICATION ); // large icon wcl.hIconSm = LoadIcon( 0, IDI_WINLOGO ); // small icon wcl.hCursor = LoadCursor( 0, IDC_ARROW ); // cursor style // If you created a menu as a resource, then put the name here. // (use quotes both here and when naming your resource) wcl.lpszMenuName = 0; // no menu // Not sure exactly what these do, but you can check the windows // help if you want to find out. wcl.cbClsExtra = 0; // no extra wcl.cbWndExtra = 0; // information needed // Make the window background to the default wcl.hbrBackground = (HBRUSH) ( COLOR_WINDOW + 1 ); // Register the window class and return success or failure // // Now that all the parameters have been set, pass the structure to // windows to make a sort of template of your window. return ( RegisterClassEx( & wcl ) ); } /****************************************************************** Function : InitInstance(HINSTANCE, int) Purpose : Saves instance handle and creates main window *******************************************************************/ // Here hInstance is the handle to the application and nCmdShow is // how the window is initially displayed (maximize, minimize, etc) // This function actually creates the window that you want to use. BOOL InitInstance( HINSTANCE hInstance, int nCmdShow ) { // Get the global data structure out of the method defined above // and put it in G. LPGLOBAL G = GetGlobalData( ); // Store instance handle in global variable G->hInst = hInstance; // // Create a main window for this application instance. // // Tell windows the name of you application, the title you // want on the title bar (both are really strings, which // are defined above), // The style is set to overlap, which is what is thought of as // a normal window, // the CW_USEDEFAULT means windows can decide the initial position // and size. If you set a size or position (integers) you have to // supply both an x and a y value. // The parent is set to be the desktop. // The menu handle is not used. You probably already set the menu // using your windows class (wcl) if you made a menu. Therefore, just // leave the menu as is most of the time. // hInstance is the applications handle (pointer to memory where you program // is). // Check windows help for creation parameters. // // CreateWindow returns the handle to the newly created window // (again, think of it kind of as a pointer to the memory where the // window is located). The handle is captured in hWndMain in case // it is needed later. // Note that you will need to copy the handle to global memory if you // need to use it outside this function. HWND hWndMain = // Main window handle CreateWindow( APP_NAME, // window class name APP_TITLE, // window caption WS_OVERLAPPEDWINDOW, // window style CW_USEDEFAULT, // initial x position CW_USEDEFAULT, // initial y position CW_USEDEFAULT, // initial x size CW_USEDEFAULT, // initial y size HWND_DESKTOP, // parent window handle (HMENU) 0, // window menu handle hInstance, // program instance handle 0 // creation parameters ); // // Return FALSE if window handle is NULL // (window not could not be created) // // Just make sure that the CreateWindow worked. Otherwise send // a false back, which will eventually cause the program to exit. if ( ! hWndMain ) { MessageBox( HWND_DESKTOP, "CreateWindow", "InitInstance", MB_OK ); return ( FALSE ); } // // Make the window visible and update its client area // // When the window is created it is initially not visible. // This function make it visible. Remember that nCmdShow was initially // an argument to WinMain which was passed as an argument to this function. ShowWindow( hWndMain, nCmdShow ); // Show the window // Technically you may not need this, but it is a good idea // to force the window to be painted the first time it is // displays (i.e. when ShowWindow is called). UpdateWindow( hWndMain ); // Sends WM_PAINT message return ( TRUE ); // Success! } /****************************************************************** Function : WndProc(HWND, UINT, WPARAM, LPARAM) Purpose : Processes messages. This function is called by Windows NT and is passed messages from the message queue. *******************************************************************/ // Okay, after you dispatch a message to the operating system, and the operating // system finds some time, the operating system calls this function. // (Because you told it this was the function to call when you registered your // windows class). // The CALLBACK means that the OS can call this function. // // Windows passes four arguments to this function. hWnd is the handle that points // to your window at which the message is directed (in this program there is only one // window, so its easy to figure out which windows). // nMessage is the actual message. You should probably start with this variable. // For example, if nMessage is WM_CHAR (an integer, which windows has defined as WM_CHAR) // then a character was pressed. // If nMessage is equal to WM_COMMAND, then probably a menu item was selected. // The meaning of wParam and lParam change depending on the value of nMessage. // For example, if nMessage is WM_COMMAND (a menu item) then wParam contains the // menu ID that was selected (actually only the last half of wParam contains this information). // With WM_COMMAND, lParam is not used. // Note: To get to the last half of wParam, use LOWORD(wParam). LRESULT CALLBACK WndProc( HWND hWnd, // window handle UINT nMessage, // type of message WPARAM wParam, // additional information LPARAM lParam ) // additional information { // Figure out which message has been sent switch ( nMessage ) { // If the message has been sent to end the program then post the quit message // which will cause the GetMessage in the message loop to return false, the // message loop will finish, and the program will end. case WM_DESTROY: /* terminate the program */ PostQuitMessage( 0 ); break; // Rather than make a case statement for every message that windows can send, // let windows have a default for any messages you have not handled. // For example: if a WM_LBUTTONDOWN message is received (a left mouse button // was pushed down) then the default behaviour is not to do anything. default: /* Let Windows NT process any messages not specified in the preceding switch statement. */ return DefWindowProc( hWnd, nMessage, wParam, lParam ); } return LRESULT( 0 ); }