Part A - Foundations

Windows Programming

Create a Windows application
Introduce the Windows data types
Design a dialog box

Windows | Simple Dialog | Data Types | Dialog | Exercises



We start with the simplest of Windows applications.  These use the Windows API and require basic familiarity with windowing concepts.  In this chapter, we introduce these concepts and present two applications that implement simple communication between the user and the application. 


Windows

A window is a rectangular area that covers all or part of a two-dimensional screen.  A window may be totally independent of any another window, may be related to another window, or may be a part of another window. 

Although a two-dimensional screen can display many windows simultaneously, the operating system only allows the user access to one window at a time.  The currently accessible window is called the active window.  We say that the active window is the window that has the user's focus



Windows operating systems communicate with their windows using messages.  A message is a self-contained packet of data with two endpoints.  The communication can be a two-way process.  The system can send its messages to any window and the active window can send its messages to the system. 

Each Windows application owns all of its windows.  The application itself provides the logic for

  • implementing each of its windows
  • processing the messages that the system sends to each window
  • creating the messages that its windows send to the system

An application passes each message that it processes back to the system.  The application has first, but not last, crack at each message.  Windows applications create and manage their windows and messages to and from them through calls to the Windows API. 

The operating system maintains a queue of messages for each application and sends all messages associated with the active window to a specialized function that the application programmer provides to process those messages.  We call this function the window procedure.  The operating system calls the window procedure for the active window whenever the parent application has dispatched a message for that window. 

The Entry Point

The entry point for a Windows application is a function named WinMain().  This function contains the entry and exit level logic for the application and replaces the main function of console-based programs.  The definition of this function takes the form

 int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hprev, LPSTR cp, int show) { 

     // add entry and exit level logic here
 }

The Windows API defines the symbolic names WINAPI, HINSTANCE and LPSTR as:

 #define  WINAPI  __stdcall
 typedef  HANDLE  HINSTANCE;
 typedef  PVOID   HANDLE;
 typedef  void*   PVOID;
 typedef  CHAR*   LPSTR;
 typedef  char    CHAR;

__stdcall is a Windows specific qualifier that informs the compiler that the function itself (WinMain()) and not the caller function should clean up the stack after completing execution. 

The first two parameters of WinMain() are simply generic pointers, while the third is the address of a C-style null-terminated string.

The first parameter (hinst) is a handle to the current instance of the application.  A handle is a pointer that indirectly points to an instance.  A handle bars direct changes to the instance itself.  An example is fp in the declaration FILE* fpfp points to a data structure that manages a file.  This definition of fp provides access to the file but does not allow any direct changes to the file.  A handle is often implemented as a pointer to an entry in a hidden table that contains a pointer to the instance itself.  In order to make changes to the instance, we use a lower-level function with a reduced degree of indirection (for example, fprintf(fp, ...)).

The second parameter (hprev) is a handle to the previous instance of the application.  This parameter is always nullptr

The third parameter (cp) receives the address of a C-style null-terminated string that holds the command line for the application.  Note that this string does not include the program name. 

The fourth parameter (show) receives an integer value that identifies the method of initially displaying the application window.

Header Files

The header files for the Windows API contain the definitions of the symbolic names.  The complete API includes such components as Cryptography, DDE, RPC, Shell, and Windows Sockets.  Typically, these are unnecessary in game programs.  To exclude them and thereby reduce the size of the header files considerably, we define WIN32_LEAN_AND_MEAN before including the header file:

 #define  WIN32_LEAN_AND_MEAN
 #include <windows.h>

The binary code for the user interface components of the Windows API is stored in user32.lib.  The linker needs this file to resolve external references to WinMain() as well as any other components. 

Window Procedure

We select our own name for the window procedure.  If the application owns several windows, we code a separate procedure with a unique name for each window. 

All window procedures share the same signature apart from their name.  The signature includes four parameters:

 BOOL CALLBACK identifier(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp

where identifier denotes the name of the procedure.  Windows defines the symbolic names BOOL, CALLBACK, HWND, UINT, WPARAM and LPARAM for the Windows 32-bit (Win32) platform as:

 typedef  int           BOOL;
 #define  CALLBACK      __stdcall
 typedef  HANDLE        HWND;
 typedef  unsigned int  UINT;
 typedef  UINT_PTR      WPARAM;
 typedef  unsigned int  UINT_PTR;
 typedef  LONG_PTR      LPARAM;
 typedef  long          LONG_PTR;

WPARAM stands for 'word' parameter.  LPARAM stands for 'long' parameter.

The first parameter (hwnd) is a handle to the window for which the incoming message was targeted.  We use this handle to identify the window in calls to its functions.  The second parameter (msg) receives an integer that identifies the message itself.  The third parameter (wp) optionally holds a value associated with the message, typically an integer.  The fourth parameter (lp) holds another value associated with the message, typically an address.  The third and fourth parameter values are message specific.


Simple Dialog Sample

For our first sample, let us create an application that processes a trivial communication with the user.  It displays a simple window with two buttons as shown below.

Pressing the "Continue" button redisplays this dialog box.  Pressing the "Quit" button closes it and terminates execution. 

Let us name the window procedure for this application dlgProc.  The call to create the dialog box looks something like

 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>     // for WinMain and Windows Types
 #include "Translation.h" // for IDD_DLG
 BOOL CALLBACK dlgProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp);

 int WINAPI WinMain(HINSTANCE hinst, HINSTANCE hprev, LPSTR cp, int show) {
     bool rc;
     rc = DialogBox((HINSTANCE)hinst, MAKEINTRESOURCE(IDD_DLG), nullptr,
      dlgProc) == TRUE;
     return rc;
 }

DialogBox() is a Windows function-like macro that creates a modal dialog box from a template resource.  Modal means that execution pauses until the user completes some action.  A template resource is data that describes some part of the user interface. 

The first argument (hinst) is a handle to the application.  The second argument (MAKEINTRESOURCE(IDD_DLG)) identifies the resource that describes the dialog box's format.  IDD_DLG is the symbolic name identifying the template resource.  MAKEINTRESOURCE is a Windows function-like macro that transforms our identifier into a system identifier.  The third argument (nullptr) is a handle to the window that owns the dialog box.  The fourth argument (dlgProc) points to the window procedure that receives the messages sent by the operating system.  The prototype for this procedure identifies dlgProc as a valid symbol in the subsequent macro call.

DialogBox() does not return control to its caller until an EndDialog() function has destroyed the dialog box (see below). 

We define the symbolic name IDD_DLG for the dialog box in Translation.h

 // Translation.h

 #define IDD_DLG 101
 #define COPYRIGHT_LINE_1 "fwk4gps is copyright (c) 2012, Chris Szalwinski."
 #define COPYRIGHT_LINE_2 "PostgreSQL Open Source License (TPL).\
 ../Licenses.txt"
 #define WND_CAPTION L"fwk4gps" 

WND_CAPTION holds the string that appears in the title bar. COPYRIGHT_LINE_? holds the string that appears below the buttons.

The window procedure for the dialog box is:

 // APIUserInput.cpp

 BOOL CALLBACK dlgProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {

     BOOL rc = FALSE;
     // Process message msg
     switch (msg) {
     case WM_INITDIALOG:
         // Initialize
         MessageBox(hwnd, L"Initialized", L"Message", MB_OK);
         MessageBox(hwnd, L"OK Pressed", L"Message", MB_OK);
         rc = TRUE;
         break;
     case WM_COMMAND:
         switch (LOWORD(wp)) {
         case IDOK:
             MessageBox(hwnd, L"Continuing", L"Message", MB_OK);
             rc = TRUE;
             break;
         case IDCANCEL:
             MessageBox(hwnd, L"Ending", L"Message", MB_OK);
             EndDialog(hwnd, FALSE);
             rc = TRUE;
             break;
         }
         break;
     }
     return rc;
 }

Each message (msg) received by dlgProc() passes through the switch construct.  The outer switch processes either of two messages: WM_INITDIALOG or WM_COMMAND.  The WM_ prefix identifies a message from the Windows system itself. 

The system sends a WM_INITDIALOG message immediately before displaying the dialog box.  This gives our application the opportunity to initialize the box.  Here, the MessageBox() function pops-up a message window with the caption "Message", the note "Initialized" and an OK button.  Execution pauses until the user presses the OK button.  Once the user has pressed OK, dlgproc() pops-up the second message box window.  Once the user has pressed OK again, dlgProc() returns control to the operating system, which in turn displays the dialog box.

The system sends a WM_COMMAND message in response to any activity within the dialog box.  The low-order word (2-bytes) of the parameter wp identifies the button pressed.  The Windows macro LOWORD(wp) retrieves this low-order word from wp

The inner switch construct processes either of two button presses identified by the symbolic names IDOK and IDCANCEL.  If the user has pressed the "Continue" button, the MessageBox() function pops-up a message window with the caption "Message", the note "Continuing" and an OK button.  If the user has pressed the "Quit" button, dlgProc() calls EndDialog(), the system subsequently closes the dialog box and returns control to the calling function that opened the dialog box.

Resource Description

A dialog boxis format is an application's resource.  A resource does not include any executable logic and does not require re-compilation of the application when we re-format the resource.  The resource compiler compile the resource only and the linker incorporates our redesign into the application. 

Resource creation involves four steps:

  1. identifying the resource symbolically (IDD_DLG)
  2. describing the resource in a script
  3. compiling the script using the resource compiler
  4. linking the compiled script with the application's binary code

A script that defines a resource is a text file with the extension .rc.  The script may contain:

  • comments that the resource compiler will ignore
  • pre-defined macros, which take no arguments and cannot be redefined
  • pre-processor directives, which instruct the resource pre-processor to perform actions on the script before compiling the script
  • resource-definition statements that name and describe resource elements

The resource pre-processor interprets syntax in the same way that the C/C++ pre-processor interprets syntax. 

The command for compiling a resource-definition script at the command line is

 rc [options] resource-definition-script-file

 Options      Description

 /?           Display a list of all command-line options.
 /fo resname  Create a compiled resource file named resname.
 /v           Display messages that report the progress of the compiler. 

A compiled resource file has the extension .res.

Resource-definition elements use the following symbolic names (and others):

 Symbolic Name   Category    Description

 DIALOG          Resource    Defines the template that the application
                             will use to create dialog box
 CAPTION         Statement   Sets the title for the dialog box
 FONT            Statement   Sets the font with which the system will
                             draw text within the dialog box
 STYLE           Statement   Sets the window style for the dialog box 
 BEGIN           Statement   Identifies the start of a block of
                             control statements
 END             Statement   Identifies the end of a block of
                             control statements
 PUSHBUTTON      Control     Creates a push button control

Symbolic names also provide referencing of resource elements between the resource definition and the application.  Microsoft calls these symbolic names IDs.  Examples include:

 Symbolic Name   Description

 IDOK, IDCANCEL  For standard push button IDs within a dialog.

The script for our 2-button dialog box is:

 // Dialog.rc

 #include <afxres.h>
 #include "Translation.h"  // for IDC_?, IDD_DLG

 IDD_DLG  DIALOG DISCARDABLE 200, 100, 200, 80
 STYLE    DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
 CAPTION  DLG_NAME
 FONT     8, "MS Sans Serif", 0, 0, 0x0
 BEGIN
     PUSHBUTTON "Continue", IDOK,      40, 15, 50, 15
     PUSHBUTTON "Quit",     IDCANCEL, 110, 15, 50, 15
     LTEXT      COPYRIGHT_LINE_1, IDC_STATIC, 8, 40, 200, 10
     LTEXT      COPYRIGHT_LINE_2, IDC_STATIC, 8, 50, 200, 10
 END 

The afxres.h header file defines the non-application, resource-specific symbolic names, along with several IDs (such as IDOK and IDCANCEL).  DISCARDABLE lets the system swap resource memory to disk once the dialog is not in use. 

The four integer sets specify the absolute position of the top-left corner of each resource element and the relative position of its bottom-right corner in dialog units (not pixels) (left, top, width, height). 

The STYLE statement defines the dialog box's style.  DS_MODALFRAME specifies that the box is modal: the user must respond before execution will continue.  WS_POPUP requests a pop-up window.  WS_CAPTION requests a window with a title bar.  WS_SYSMENU allows the controls within the dialog box to receive the keyboard focus when the user presses the TAB key.  Pressing the TAB key shifts keyboard focus to the next control with the WS_TABSTOP style.

The CAPTION statement describes the title shown in the top bar of the dialog box.

The FONT statement describes the font size and the font face for the dialog box.  The resource compiler translates the dialog units into pixels using the font defined by this statement.

BEGIN and END enclose statements that describe the controls within the dialog box: here, there is one pushbutton named "Continue" and another named "Quit".  Pressing the "Continue" button sends an IDOK notification through the system.  Pressing the "Quit" button sends an IDCANCEL notification through the system. 


Windows Data Types

Windows defines its own data types symbolically and expresses them in upper case.  The character, integer, and Boolean types are equivalent to their lower-case counterparts in the C/C++ languages.  Most of the pointer-type names begin with the prefix P (for pointer) or LP (for long pointer). 

The data types for a Win32 platform include:

 Type        Description                           Windows Definition

 BOOL        Boolean variable (TRUE or FALSE)      typedef int BOOL;

 BOOLEAN     Boolean variable (TRUE or FALSE)      typedef BYTE BOOLEAN;

 BYTE        Byte (8 bits)                         typedef unsigned char BYTE;

 CALLBACK    Calling convention for callback       #define CALLBACK __stdcall
             functions

 CHAR        8-bit Windows (ANSI) character        typedef char CHAR;

 COLORREF    Red, green, blue (RGB) value(32 bits) typedef DWORD COLORREF;

 CONST       Variable whose value is to remain     #define CONST const
             constant

 DWORD       32-bit unsigned integer               typedef unsigned long DWORD;

 DWORDLONG   64-bit unsigned integer               typedef ULONGLONG DWORDLONG;

 FLOAT       Floating-point variable               typedef float FLOAT;

 HANDLE      Handle to an object                   typedef PVOID HANDLE;

 HDC         Handle to a device context (DC)       typedef HANDLE HDC;

 HINSTANCE   Handle to an instance                 typedef HANDLE HINSTANCE;

 HRESULT     Return code used by interfaces. It
             may hold an error code plus status    typedef LONG HRESULT;
             information

 HWND        Handle to a window                    typedef HANDLE HWND;

 INT         32-bit signed integer                 typedef int INT;

 LONG        32-bit signed integer                 typedef long LONG;

 LONGLONG    64-bit signed integer                 typedef __int64 LONGLONG;

 LONG_PTR    Signed long type for pointer          typedef long LONG_PTR;
             precision

 LPARAM      Long parameter for passing message    typedef LONG_PTR LPARAM;
             data

 LPDWORD     Pointer to a DWORD                    typedef DWORD *LPDWORD;

 LPHANDLE    Pointer to a HANDLE                   typedef HANDLE *LPHANDLE;

 LPINT       Pointer to an INT                     typedef int *LPINT;

 LPLONG      Pointer to a LONG                     typedef long *LPLONG;

 LPSTR       Pointer to a null-terminated string
             of 8-bit Windows (ANSI) characters    typedef CHAR *LPSTR;

 LPTSTR      An LPWSTR if UNICODE is defined, an   #ifdef UNICODE
             LPSTR otherwise                           typedef LPWSTR LPTSTR;
                                                   #else
                                                       typedef LPSTR LPTSTR;
                                                   #endif

 LPVOID      Pointer to any type                   typedef void *LPVOID;

 LPWORD      Pointer to a WORD                     typedef WORD *LPWORD;

 LPWSTR      Pointer to a null-terminated string   typedef WCHAR *LPWSTR;
             of 16-bit Unicode characters.

 LRESULT     Signed result of message processing   typedef LONG_PTR LRESULT;

 PCHAR       Pointer to a CHAR                     typedef CHAR *PCHAR;

 PDWORD      Pointer to a DWORD                    typedef DWORD *PDWORD;

 PFLOAT      Pointer to a FLOAT                    typedef FLOAT *PFLOAT;

 PLONG       Pointer to a LONG                     typedef LONG *PLONG;

 PUCHAR      Pointer to a UCHAR                    typedef UCHAR *PUCHAR;

 PUINT       Pointer to a UINT                     typedef UINT *PUINT;

 PULONG      Pointer to a ULONG                    typedef ULONG *PULONG;

 PVOID       Pointer to any type                   typedef void *PVOID;

 PWORD       Pointer to a WORD                     typedef WORD *PWORD;

 SHORT       Short integer (16 bits)               typedef short SHORT;

 UCHAR       Unsigned CHAR                         typedef unsigned char UCHAR;

 UINT        Unsigned INT                          typedef unsigned int UINT;

 UINT_PTR    Unsigned INT_PTR                      typedef unsigned int UINT_PTR;

 ULONG       Unsigned LONG                         typedef unsigned long ULONG;

 USHORT      Unsigned SHORT                        typedef unsigned short USHORT;

 VOID        Any type                              #define VOID void

 WCHAR       16-bit Unicode character              typedef wchar_t WCHAR;

 WINAPI      Calling convention for system         #define WINAPI __stdcall
             functions

 WORD        16-bit unsigned integer               typedef unsigned short WORD;

 WPARAM      Word parameter for passing message    typedef UINT_PTR WPARAM;
             data

Unicode

The default setting for an application's character set in Visual Studio 2010 is UNICODE.  The wchar_t (wide character) type of the C/C++ standard provides enough room for UNICODE characters. 

To define a wide character, we enclose the character in single quotes and preface the quoted character with an uppercase L.  To define a wide-character string, we enclose the string of characters in double quotes and preface the quoted string with an uppercase L:

 wchar_t c        = L'G';
 wchar_t string[] = L"GAM666 and DPS901";

Dialog Sample

Our second sample displays two combo boxes with selectable options.  A combo box is a control that consists of a list and a selection field.  The list holds the available line items while the selection field displays the currently selected item.  The dialog box offers the user a choice of display devices and resolution modes.

Here, we show choices from a predefined set of displays and a predefined set of resolution modes.  (In later samples, we will interrogate the system to determine the configurations available and populate these boxes with those options). 

Implementation

Resource Script

The resource-definition script for this dialog box creates two text controls, two combo boxes, and two pushbuttons, one of which is the default pushbutton.  We add symbolic names to identify the combo boxes and the GO button.  We follow naming and numbering conventions that partition the ID-numbering space and conform to internal Windows standards.  Complying with these conventions avoids unintentional duplication of ID numbers between those assigned by the application and those assigned by the system itself: 

 Prefix          Description

 IDD_            For dialog template resources (for example, IDD_DLG). 
 IDC_            For other dialog controls.

 Prefix  Resource type     Valid range

 IDD_    dialog templates  1 -> 0x6FFF
 IDC_    controls          8 -> 0xDFFF 

By convention, 0 is never used.  Even though the lower limit for IDD_ symbols is 1 and for IDC_ symbols is 8, it is common to start numbering application IDs at 100 or 101.

We define the symbolic names in Translation.h

 // Translation.h

 #define IDD_DLG 101
 #define IDC_DIS 102
 #define IDC_RES 103
 #define IDC_GO  104
 #define COPYRIGHT_LINE_1 "fwk4gps is copyright (c) 2012, Chris Szalwinski."
 #define COPYRIGHT_LINE_2 "PostgreSQL Open Source License (TPL). \
 ../Licenses.txt"
 #define WND_NAME L"fwk4gps"

The resource script is:

 // Dialog.rc

 #include <afxres.h>
 #include "Translation.h" // for IDC_?, IDD_DLG
 IDD_DLG DIALOGEX 200, 100, 200, 140
 STYLE DS_SETFONT | DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU
 CAPTION DLG_NAME
 FONT 8, "MS Sans Serif", 0, 0, 0x0
 BEGIN
     LTEXT           "Display Device", IDC_STATIC, 10, 5, 50, 10
     COMBOBOX        IDC_DIS, 10, 15, 180, 50, CBS_DROPDOWNLIST | \
                     WS_VSCROLL | WS_TABSTOP
     LTEXT           "Resolution", IDC_STATIC, 10, 35, 50, 10
     COMBOBOX        IDC_RES, 10, 45, 180, 50, CBS_DROPDOWNLIST | \
                     WS_DISABLED | WS_VSCROLL | WS_TABSTOP
     DEFPUSHBUTTON   "Go", IDC_GO, 40, 75, 50, 15, WS_DISABLED
     PUSHBUTTON      "Cancel", IDCANCEL, 110, 75, 50, 15
     LTEXT           COPYRIGHT_LINE_1, IDC_STATIC, 8, 100, 200, 10
     LTEXT           COPYRIGHT_LINE_2, IDC_STATIC, 8, 110, 200, 10
 END

The new controls are LTEXT, COMBOBOX, and DEFPUSHBUTTON:

  • The first LTEXT creates a left-aligned 50x10 text control at position {10, 5}.  IDC_STATIC identifies it as a label that doesn't interact with the user 
  • The first COMBOBOX creates a 180x50 combo box control at position {10, 15} and named IDC_DISCBS_DROPDOWNLIST specifies a drop-down list style.  WS_VSCROLL specifies a vertical scroll bar if necessary.  WS_TABSTOP identifies the combo box as a tab stop 
  • The second LTEXT creates a left-aligned 50x10 text control at position {10, 35} 
  • The second COMBOBOX creates a 180x50 combo box at position {10, 45} and named IDC_RESWS_DISABLED initially disables this control 
  • DEFPUSHBUTTON creates a default pushbutton control at position {40, 75} and named IDC_GO 

PUSHBUTTON creates a pushbutton control at position {110, 75}.  The ID associated with it is IDCANCEL.

Window Procedure

The procedure for processing messages associated with this dialog box populates the display combo box with two display options before creating the dialog box.  The procedure also populates the resolution mode combo box with three resolution options the first time that the user selects a display and re-populates the resolution mode combo box whenever the user changes the selected display. 

 // APIUserInput.cpp

 #define WIN32_LEAN_AND_MEAN
 #include <windows.h>
 #include "Translation.h" // for IDC_
 wchar_t* strcat(wchar_t* dest, const wchar_t* src, int sizeDest);

 BOOL CALLBACK dlgProc(HWND hwnd, UINT msg, WPARAM wp, LPARAM lp) {
     BOOL    rc = FALSE;
     int     pd,  // index of selected display lineitem
             pr;  // index of selected resoultion lineitem
     const int sizeDescD = 80;
     const int sizeDescR = 40;
     wchar_t descDisplay[sizeDescD+1], descResolution[sizeDescR+1];
     static  bool firstTime = true;

     switch (msg) {
     case WM_INITDIALOG:
         // Initialize: populate the Display Box with two
         // strings: one for each display
         SendDlgItemMessage(hwnd, IDC_DIS, CB_ADDSTRING, 0,
          (LPARAM)L"Display A");
         SendDlgItemMessage(hwnd, IDC_DIS, CB_ADDSTRING, 0,
          (LPARAM)L"Display B");
         // Select Display A, in case the user doesn't pick one
         SendDlgItemMessage(hwnd, IDC_DIS, CB_SETCURSEL, 0, 0L);
         rc = TRUE;
         break;
     case WM_COMMAND:           // sent when user selects a control
         switch (LOWORD(wp)) {  // which control?
         case IDC_DIS:         // selected combo box for display devices
             // process this message only if it is the first time or the user
             // has changed the display. NOTE: this case resets the static
             // variable "firstTime".
             if (firstTime && HIWORD(wp) == CBN_SETFOCUS ||
              HIWORD(wp) == CBN_SELCHANGE ) {
                 firstTime = false;  // won't ever be the first time again!
                 // Empty the Resolution Box
                 SendDlgItemMessage(hwnd, IDC_RES, CB_RESETCONTENT, 0, 0L);
                 // Populate the Resolution Box with 3 Resolutions
                 SendDlgItemMessage(hwnd, IDC_RES, CB_ADDSTRING, 0,
                  (LPARAM)L"600 x 800");
                 SendDlgItemMessage(hwnd, IDC_RES, CB_ADDSTRING, 0,
                  (LPARAM)L"768 x 1024");
                 SendDlgItemMessage(hwnd, IDC_RES, CB_ADDSTRING, 0,
                  (LPARAM)L"864 x 1152");
                 // Select 1st resolution in case the user doesn't pick one
                 SendDlgItemMessage(hwnd, IDC_RES, CB_SETCURSEL, 0, 0L);
                 // Enable the Resolution Box and the Go Button
                 EnableWindow(GetDlgItem(hwnd, IDC_RES), TRUE);
                 EnableWindow(GetDlgItem(hwnd, IDC_GO), TRUE);
                 rc = TRUE;
             }
             else
                 rc = TRUE;
             break;
         case IDC_GO:           // selected the GO button
             // Retrieve the position of the selected display
             pd = SendDlgItemMessage(hwnd, IDC_DIS, CB_GETCURSEL, 0, 0L);
             // Retrieve the position of the selected resolution
             pr = SendDlgItemMessage(hwnd, IDC_RES, CB_GETCURSEL, 0, 0L);
             if (pd != CB_ERR && pr != CB_ERR) {
                 // Extract the description of the selected display
                 SendDlgItemMessage(hwnd, IDC_DIS, CB_GETLBTEXT, pd,
                  (LPARAM)descDisplay);
                 // Extract the description of the selected resolution
                 SendDlgItemMessage(hwnd, IDC_RES, CB_GETLBTEXT, pr,
                  (LPARAM)descResolution);
                 // Concatenate the descriptions
                 strcat(descDisplay, L" at ", sizeDescD);
                 strcat(descDisplay, descResolution, sizeDescD);
                 MessageBox(hwnd, descDisplay, L"You Selected", MB_OK);
                 rc = TRUE;
             }
             break;
         case IDCANCEL:         // selected the Cancel button
             EndDialog(hwnd, FALSE);
             rc = TRUE;
             break;
         }
         break;
     }
     return rc;
 }

 // strcat catenates src to dest[sizeDest+1] without overflow
 //
 wchar_t* strcat(wchar_t* dest, const wchar_t* str, int sizeDest) {
     wchar_t* rc = dest;
     *(dest + sizeDest) = '\0';
     while (*dest++) sizeDest--;
     dest--;
     while (sizeDest-- && (*dest++ = *str++)) ;
     return rc;
 }

The three Windows API functions introduced here are

  • SendDlgItemMessage(...)
  • GetDlgItem(...)
  • EnableWindow(...)

SendDlgItemMessage(HWND hwnd, int nID, UINT msg, WPARAM wp, LPARAM lp) sends message msg to control nID in dialog box hwndwp holds the index of the lineitem in control nID's list and lp holds the address of the string associated with that lineitem.  CB_RESETCONTENT instructs SendDlgItemMessage() to send a message to the combo box to remove all items from its list.  CB_ADDSTRING instructs SendDlgItemMessage() to send a message to the combo box to add a lineitem to its list.  CB_SETCURSEL instructs SendDlgItemMessage() to send a message to the combo box to select from its list the lineitem associated with the index specified in wp

HIWORD(wp) retrieves the high-order word from wp.  A high-order word equal to CBN_SETFOCUS indicates that the combo box has received the keyboard focus, while a high-order word equal to CBN_SELCHANGE indicates that the user has either clicked in the combo box list or changed the selection using one of the arrow keys. 

GetDlgItem(HWND hwnd, int nID) retrieves a handle to control nID in dialog box hwnd

EnableWindow(HWND hwnd, BOOL enable) enables or disables the control at handle hwnd

CB_GETCURSEL instructs SendDlgItemMessage() to send a message to the combo box to return the index of the currently selected item, if any, in its list.  The combo box returns a value of CB_ERR in the event of an error.  CB_GETLBTEXT instructs SendDlgItemMessage() to send a message to the combo box to fill the string pointed to by lp with the text describing the lineitem associated with the index passed in wp


Exercises




Previous Reading  Previous: Introduction Next: Component Design   Next Reading


  Designed by Chris Szalwinski   Copying From This Site   
Logo