Fall, 2000
Class 9
R. Eckert


Dialog boxes are a popup child windows that Windows creates for special
purpose input then destroys immediately after use. Most often they are used
for obtaining additional input from the user beyond what can be easily
managed through a menu.

All aspects of a dialog box except how to carry out its tasks are
predefined. The application supplies a template describing the contents,
style, and layout of the dialog box and a dialog box procedure to carry
out its tasks.

A dialog box almost always contains several child window controls.
Size and placement of these are specified in a dialog box template in the
resource script file. As with other resources the design of the dialog box
template can be done "visually" using Developer Studio's dialog box editor
or "manually" with a text editor.

The programmer must provide message-processing capability in the form of a
callback function like the main window procedure. But, it's really not the
same; the Window procedure for a dialog box is inside Windows; it calls our
dialog box function with many of the messages it receives. It also
interprets certain keystrokes (tab, etc.).

A good rule of thumb: use dialog boxes for simple popup windows that make
use of normal window control items (buttons, list boxes, etc.); use
popup/child windows if extensive painting on the window is required or the
standard behavior of the window is to be modified.

The main advantage of using dialog boxes over using popup windows is their
ease of construction with the dialog box editor.

There are two types of dialog boxes: modal and modeless.

Modal--When the dialog box is visible, the user can't switch back to the
parent window. (However we can usually change to another application.) The
user must explicitly end the dialog box first (usually by clicking "OK" or
"CANCEL" buttons inside the dialog box). Messages resulting from user
action with the controls inside the dialog box go to the dialog box,
message-processing function.  Modal dialog boxes are most common. For
example, the "About" box that is available with most Windows applications
is a modal dialog box.

[System Modal--a variety of modal dialog box. With these, the user can't
even switch to another program while the dialog box is active.]

Modeless--The user can switch between the dialog box and the parent window.
Theses are more like popup windows and should be used when the dialog box
is to be displayed for some time while the user is doing stuff with the
parent window. An Example is the dialog box resulting from selecting "Find"
or "Replace" from the menu of many Windows applications. The resulting
dialog box stays around while the user does things in the parent window.

Steps in designing, creating, and using a modal dialog box--

1. Determine the child window controls needed in the dialog box.
2. Design the dialog box template (easiest with a dialog box editor).
3. Write the message-processing function--we'll see how soon.
4. Activate the dialog box by calling DialogBox().
5. The resulting dialog box stays on the screen until EndDialog() is called
   from inside dialog box function.

DLG1: A simple example--

Clicking "Dialog Box" on the program's main menu brings up a modal dialog
box (FIRSTDIALOG) containing a static text control (IDC_STATIC), an icon
(IDC_ICON), an "OK" button (IDC_OK), and a "Not OK" button (IDC_NOTOK). The
only way to get back to the parent window is to click on the "OK" button.
Clicking on the "Not OK" button causes a beep.

Designing the Dialog Box (.RC file)--We'll use Developer Studio to design
the dialog template along with the menu and icon for the DLG1 program.
The result will be a resource script (.rc) file.

As we've seen before, Developer Studio coordinates all activities involving
the program's resources, including dialog boxes, menus, icons, cursors,
bitmaps, etc. It assumes you want to put all the resource data into a
single resource file. In addition to the dialog box, we will have an icon
("DIALG1") and a menu ("MYMENU") with items "&Dialog Box" (IDM_DIALOG) and
"&Quit" (IDM_QUIT). The menu, icon, and dialog box identifiers are
referenced in the C++ source program.


Get into Developer Studio, open a new DLG1 workspace, prepare the
DLG1.CPP source file, and add it to the project. (Make sure that the source
file declares both the WndProc() and the DialogProc() callback functions
and that it #includes a "resource.h" file. This file as well as the .rc
file will be generated by Developer Studio.

Use "Insert | Resource", "Icon | New" to bring up the Icon Editor; draw
your icon, and hit <Enter>. Then fill in the resulting dialog box (ID =
"DIALG1" and File name dialg1.ico). Iconify the Icon Editor.

The resources will look like:  Script1/Icon/"DIALG1" (This will appear as a
tree diagram.)

Use "Insert | Resource", "Menu | New" and use the resulting Menu Editor to
generate the menu items: &Dialog Box (ID = IDM_DIALOG) and &Quit (ID =
IDM_QUIT). Iconify the Menu Editor. The Script will now look like:


Right click on IDR_MENU1 and select Properties. Change the ID to "MYMENU".

The script will now look like:

Use "Insert | Resource", "Dialog | New" to bring up the dialog box editor.
You will use the tool bar to the right to modify and fill the dialog box
template that appears on the left. (If you double click on any unoccupied
point inside the dialog box template, you will get a "Dialog Properties"
dialog box that can be used to change a wide range of parameters associated
with the dialog box.)

First click on the "Cancel" button in the template area, and then press
<Delete> from the keyboard. (We don't want that button in our dialog box.)

Drag the OK button to the lower righthand corner of the dialog box
template. Double click it and change its ID to IDC_OK. Leave the default
caption "OK" as it is.

Click the button tool (a little rectangle on the tool bar) and drag the
cursor below the "OK" button in the dialog box template area. Double click
the "button1" button that appears. Set its ID to IDC_NOTOK and its caption
to "Not OK".

Click the Static Text control tool (Aa), and drag the cursor into the top,
right-hand area of the resource box template area. Click and drag the edge
or corner of the resulting rectangle to make it wide enough to hold several
words of text. Double click and set the ID to IDC_STATIC, and set the
caption to "Static Control".

Click the Picture tool (a box with some tiny pictures in it) and drag it
underneath and to the left of the static control containing the text you
just entered. Double click the border of the rectangle that appears and
choose the "General" tab (if it doesn't appear). Set the ID to IDC_ICON,
choose "Icon" from the frame list box, and set Image: to "DIALG1". Iconify
the Dialog box editor. The resource script should now look like:


Right click IDD_DIALG1 and choose Properties. Change the ID to

Select "File | Save As", enter the File name: dlg1, and make sure the file
type is .rc.

Finally select "Project | Add to Project" and "Files" dlg1.rc.

The resource script should now look like:


Build the project.

Notice that when you are using the Dialog Box editor, there are tools that
allow you to generate many different kinds of controls (buttons, list
boxes, combo boxes, edit controls, etc.) inside the dialog box you are

DIALOG BOX TEMPLATE FORMATS (specified in the .rc file) (In case you want
to prepare or change the .rc file with a text editor)--


  ResourceNameID  DIALOG   x, y, w, h
  [Options--e.g., STYLE, CAPTION...]
     Dialog Box Item specifications (of window controls inside)

ResourceNameID--LPSTR used in call to DialogBox() in creating the Dialog

x,y,w,h--the position and size of the dialog box, relative to the upper-
left corner of the window invoking the dialog box. Dialog "base units" are
used (x,w in units of 1/4 an average character width; y,h in units of 1/8
an average character height), so the general dimensions and look of the
dialog box will be the same regardless of video display and font used. (In
the System font, the character height is about two times the average
character width, so the x-axis, y-axis units will be about the same.)

Options--STYLE is the most important one: all WS_*** and DS_*** constants
can be used. CAPTION also important.


CAPTION "Dialog"
     /* Dialog Box Item Specifications go here */

Dialog Box Item Specifications: general syntax--

   CONTROL_ITEM_NAME [item-dependent stuff], id, x, y, w, h, [style]

Some examples:

CTEXT "Centered Text", DLI_STATIC, 10, 10, 100, 8

DLG1.CPP Example Source Program--

WinMain() is pretty standard; no extra window classes are defined (not
necessary with dialog boxes).

The Dialog box is created and displayed when the user selects the menu item
"Dialog Box" (ID=IDM_DIALOG).

The function DialogBox() creates a modal dialog box from the program's
dialog box template resources, displays the dialog box, and switches
message processing to the dialog box function while the dialog box is
visible. Control is not returned until the message-processing function
terminates the dialog box with a call to EndDialog().

The four parameters to DialogBox() are:

1. The program's instance handle--used by Windows to find dialog box resource
   data. (Recall that the resource data is appended to program's executable

2. The ID name of the dialog box definition in the resource data--specified in
   the dialog box template (when the dialog box editor was used to define the
   dialog box).

3. The parent window handle of the dialog box.

4. The address of the dialog box function that will process its messages.
   This is a callback function like we saw with the timer. Under Windows 95
   we just use the name of the callback function. (Under Win16 we would
   need to provide the "procedure instance address"--i.e., invoke
   MakeProcInstance() to assure that the dialog procedure obtains the
   correct data segment for this instance of the program.) If the program is
   being written in C++, you must also type cast this to DLGPROC, or the
   C++ compiler will give an error. (This is not the case if the C compiler
   is being used.)

In the following Win32 code, the name of the dialog box message-processing
function is DialogProc.

HANDLE hInstance;
hInstance = (HINSTANCE)GetWindowLong (hWnd, GWL_HINSTANCE);
DialogBox (hInstance, "FIRSTDIALOG", hWnd, (DLGPROC)DialogProc);

The result of calling DialogBox() -- the dialog box definition is extracted
from program's resources, interpreted by Windows; the dialog box is built
by Windows and displayed on the screen. While the dialog box is visible,
messages for the program pass to the dialog box function. When the dialog box
is destroyed, control passes back to main program window's WndProc() -- to
the statement after the call to DialogBox() which invoked the dialog box.

The Dialog box message-processing function (DialogProc()) in the DLG1.CPP
example) is a callback function called by Windows. It takes the same
parameters as the application's WndProc(), but returns a Boolean (actually
BOOL CALLBACK). This is different from the LRESULT returned by the
WndProc(). Thus the dialog box function returns either TRUE or FALSE to
Windows. These are returned each time a message is sent to the dialog box
function. A value of TRUE should be returned if the message was processed
by the dialog procedure, FALSE if not. There is one exception--after a
WM_INITDIALOG message, you should always return TRUE. A WM_INITDIALOG
message is like an ordinary window's WM_CREATE message. It is processed
before the window is made visible and is therefore a good place to put
initialization code. (e.g., filling list box controls, etc.) In DLG1.CPP
there is no initialization to be done, so the response to WM_INITDIALOG
is just to return.

Dialog box functions do not pass a message to the DefWindowProc(). If the
message is not processed in the function, returning FALSE lets Windows know
the message wasn't processed. Then default message processing happens

Use EndDialog() to destroy the dialog box and return control to the window
function that called the dialog box function. The parameters are:

  1. the window handle passed to the dialog box function (hDlg);

  2. an integer which is the return value of the call to DialogBox(). This
     provides a way of returning a value to the calling program, based on
     the user's actions when dialog box was visible. (We'll see this later.)

We can use a dialog box just about like any other window. Use hDlg to get a
device context for painting on the dialog box or for creating another dialog
box from within the dialog box function.

When the user interacts with Dialog Box Controls, a WM_COMMAND message is
generated. The LOWORD(wParam) contains the control ID (as usual). (If the 
dialog box had a menu, WM_COMMAND messages would also come from menu selections
by the user, but this is kind of unusual. The lParam and wParam contain message
.data (as usual)

In the DLG1 program, the WM_COMMAND message comes when the user interacts
with any non-static control inside the dialog box. In this simple example, when
the user clicks on the "OK" button in the dialog box, a call is made to 
EndDialog(), which effectively causes the dialog box to be destroyed and control
to be transferred back to the main window's WndProc(). If the user clicks on
the "Not OK" button, a call to MessageBeep() is made which just beeps at the
user. The dialog box continues to be displayed.

Exchanging Data with a Dialog Box--

There are two problems in using dialog boxes that actually do something:

1. How is data sent from the dialog box function to a specific control
inside the dialog box? (And, similarly, how is data retrieved from a
specific control inside the dialog box?)

2. How do we get data back and forth between the dialog box function
and the application's WndProc()?

The answer to the first question is to use SendMessage(hControl,...) to
send a message to a specific control inside the dialog box. However, since
Windows actually created the dialog box and the controls inside it
(following the template given in the resource file), we do not know the
handle to any of the controls. (We do, of course, know the ID of all the
controls, since these were specified when we created the dialog box
template.) Fortunately, Windows has provided a function that will return
the handle to any specified control inside a dialog box. The function is:

hControl = GetDlgItem(hDlg, controlID);

We specify the handle to the dialog box and the ID of the desired control,
and the function returns us the handle to the control. We can now send
messages to that control with our SendMessage() function:

SendMessage(hControl, Msg, wParam, lParam);

This process of determining the handle to a control inside a dialog box and
then sending the dialog box a message is so common that the Win32 API has
supplied another function that combines what the two above-metioned
functions do:

SendDlgItemMessage(hDlg, controlID, Msg, wParam, lParam);

As far as the second problem involving data exchange using dialog boxes,
namely, how do we get information between the dialog box function and
the main window function (the WndProc()), the most straightforward
answer is to use global variables. A second alternative is to start the
dialog box with the Win32 API function DialogBoxParam() instead of with


The first four parameters are identical to those used in DialogBox(); the
last parameter is passed in the lParam of the dialog box function when it
receives the WM_INITDIALOG message. We usually set this parameter up to be
a pointer to some sort of structure, so that complex data can be passed.

DLG2: A dialog box that actually does something--

In this application, when the user selects the "Get Info" main menu item, a
modal dialog box appears with an edit control for entering the name of a
person and a list box containing four salary ranges. The user is to enter
his/her name and select the appropriate salary range. When finished, the
user should click the dialog box's "OK" button, which will terminate the
dialog box, return control to the main window's WndProc(). Finally the name
will be displayed in the main window's client area in addition to a string
indicating the salary level. The following is how the dialog box looks
after the user has entered his/her name and selected a salary range:

And the following is what would be displayed after the user hits the "OK"

If the user hits the "Cancel" button in the dialog box, the main program
will display the string: "No Response!"

Creating the dialog box template --

The Developer Studio dialog box editor has been used to create the template
for this dialog box. The procedure is similar to that described above for
the DLG1 application. Here we have included the following controls:

"Name:" and "Salary:"-- static controls as labels for the edit control and
the listbox, respectively. These have both been given the ID "IDC_STATIC".

A single-line edit control with ID "IDC_EDITNAME". (The tool that helps
create an edit control is the one with the "ab|" icon.)

A listbox control with ID "IDC_LISTSALARY". (The tool that helps create a
listbox is the one with the icon containing a tiny list on its left side
and up/down scroll arrows on its right side.) One detail should be
mentioned. When the properties of the listbox are set, you must be sure to
change the default "sort" style by selecting the "Style" tab in the
"ListBox Properties" dialog and then clicking the "Sort" check button to
remove the check mark. If this is not done, the items in the list box will
be sorted alphabetically, which means that the position order will not be
the order in which you place them in the list in the dialog box procedure.

The default "OK" and "Cancel" buttons with their default IDs of "IDOK" and

The dialog box has been given the name: "INFODLG" and the caption

The Developer Studio menu editor has been used to create the main menu, as

The DLG2.CPP Source File--

A. Global variables: name[], nCurSel, and salary[4][20]-- 

These variables will hold the name entered by the user, the position in the 
list  box (0, 1, 2, or 3) of the salary range selected by the user, and the
initialized array of salary range strings. These need to be accessed both in 
the WndProc() and in the dialog box function, declared as InfoDlgProc(). An
alternative would have been to set up a structure with these two members,
and when invoking the dialog box, use DialogBoxParam() instead of DialogBox(),
with the last parameter set as a pointer to the structure, as described above.

B. The WndProc()--

In response to the user selecting the "Get Info" menu item (IDM_GET), we
use DialogBox() to invoke the dialog box, specifying that the dialog box 
procedure name is InfoDlgProc. Note that the return value is saved in the 
variable nRetVal. The way the dialog box procedure is set up, we will return 
a 1 if the user hits the "OK" button and a 0 if he/she hits the "Cancel" 

Next we get a DC and draw an empty rectangle (a quick and dirty way to
make sure that everything in a given area is erased). If the nRetVal is 1,
a switch/case statement on the global variable nCurSel (set in the dialog
box procedure) determines which position in the list box was selected. An
appropriate salary message is then copied into the cBuf string using the
lstrcpy() function. Finally, a series of calls to TextOut() display the
name selected by the user and the appropriate salary message.

If the nRetVal is 0, the "No Response!" string is displayed using

C. The InfoDlgProc() dialog box procedure--

In response to the WM_INITDIALOG message (which is sent when the dialog box
is invoked by the call to DialogBox() in the WndProc(), we first use the
SendDlgItemMessage() function described above to send a LB_RESETCONTENT
message to our IDC_LISTSALARY listbox, thereby assuring that it is empty
initially. Note that for this message, both the lParam and the wParam are
0. We then send it four LB_ADDSTRING messages in which we send it the four
strings in the salary[] array as the lParam. These will be the four items
that will appear in the listbox when the dialog box appears.

Any time the user interacts with any of the controls inside the dialog box,
a WM_COMMAND message is sent to the dialog box procedure. We are
specifically interested in user selection of the "OK" button or the
"Cancel" button. If it is the latter, we just want to terminate the dialog
box and return a value of 0. This is done with the call to EndDialog() with
the second parameter set to 0. If the user selected the "OK" button, we
need to obtain the contents of the edit control and the position in the
list box of the current selection. These are done by sending messages to
the controls with SendDlgItemMessage(). In the first case the message is a
WM_GETLINE message to IDC_EDITNAME edit control, which gets the line of text
in the edit control (a single line since the edit box was not set up to be 
multiline) and copies it into our local cBuf variable. We then copy it into the
name[] global variable. In the second case, the message is a LB_GETCURSEL
message to the IDC_LISTSALARY list box. This returns the position of the
currently-selected item in the list box. We store the value in the global
variable nCurSel. Note that after these calls have been made, all the
information that is needed by the WndProc() is in the two global variables.
Finally we terminate the dialog box with a call to EndDialog() with the
second parameter set to 1.

In passing, it should be mentioned that the data stored in list boxes and
edit controls is purely strings. So, if you had to store non-string data in
either kind of control, it would first of all have to be formatted. For
integer values, this is easily done by using the Win32 function wsprintf().
For example, if we wanted to send the contents of the integer variable n to
the edit control IDC_EDIT in the dialog box whose handle is hDlg, we could
do something like the following:

int  n=95;
char cBuf[]="       ";   // A temporary string buffer
wsprintf(cBuf,"%3d",n);  // Format n as a string in cBuf
SendDlgItemMessage(hDlg,IDC_EDIT,WM_SETTEXT,0,LPARAM(cBuf)); //send it

Unfortunately, wsprintf() cannot format floating point or double precision
variables. For those you can use the C library function sprintf().

It is sometimes necessary to obtain the contents of an edit control or the
selected item in a listbox and interpret it as something that is not a
string. This can be done by using the C library function sscanf(). For
example, suppose we had an edit control (IDC_EDIT) in the dialog box whose
handle is hDlg that supposedly contains a "decimal integer" (e.g., a grade 
in a test) If we wanted to extract the contents of the edit control, but 
store it as an integer (grade) for further processing, we could do the 

int grade;
char cBuf="       ";
SendDlgItemMessage(hDlg,DLI_EDIT,EM_GETLINE,0,(LPARAM)cBuf); // get string
sscanf(cBuf,"%3d",&grade);                            // convert to integer


The examples DLG1 and DLG2 have both used modal dialog boxes. These are
good for prompting the user to make a selection or enter a small amount
data before returning to the rest of the program. Recall, while the modal
dialog box is in existence the user cannot interact with the main program's

MODELESS DIALOG BOXES-- popup windows that remain on the screen for
extended periods. They allow the user to switch to other applications and to
other windows in the application that created the dialog box. They are
frequently used for small "tool" windows, which can be moved on the screen.

A modeless dialog box is defined in a template just like a modal box (i.e.,
there's no special style). We use different functions to create the dialog
box and make it visible on screen--instead of DialogBox() or
DialogBoxParam(), use CreateDialog() or CreateDialogParam().

Messages for modeless dialog boxes are sent to the parent window, not
directly to the dialog box message-processing function. So we must modify
main program's message loop to divert messages to the dialog box function
if the message is intended for the dialog box.

The Win32 API function IsDialogMessage(hDlg, &msg) does this diverting. It
determines if the message is intended for the specified dialog box, and, if
so, dispatches it to the dialog box's message-processing function. Then it
returns TRUE (non-zero) if the message was processed by the dialog box
function. If that is the case, the message should not be dispatched to the
the main window's WndProc(). Thus, our main message loop should be modified
to look like the following:

HWND hModeless=NULL;    /* modeless dialog box window handle */

while (GetMessage(&msg, NULL, 0, 0))
   if (hModeless == NULL || !IsDialogMessage(hModeless, &msg))
      DispatchMessage (&msg);

Here the possibilities are:

(A) hModeless==NULL is TRUE ==> the dialog box doesn't exist so we need to
dispatch the message to the main window's WndProc() with DispatchMessage().

(B) hModeless==NULL is FALSE, so the if statement continues and makes the
call to IsDialogMessage(), checking the return value. If the return value
is FALSE (meaning the message was not processed by the dialog box
function), we also need to dispatch it to the main window's WndProc().

(C) Both conditions in the if clause are false--i.e., the dialog box does
exist (hModeless==NULL is FALSE), and we called the IsDialogMessage() which
returned TRUE (meaning it did process the message). In that case we exit
the if statement without dispatching the message to the main window's
WndProc(). This is exactly what we want, since in this case the message has
already been processed by the dialog box function and cannot be intended
for the WndProc().

To remove a modeless dialog box, you can't use EndDialog() since the
modeless dialog box is not always in control; instead, use DestroyWindow()
as with any other popup or child window.

Modeless dialog boxes should contain a system menu button so that the user
can close them by double clicking that button. This sends a WM_CLOSE
message to the dialog box function, but no default actions occur. Thus to
make the modeless dialog vanish, receipt of WM_CLOSE should initiate a call
to DestroyWindow()--

case WM_CLOSE:
   hModeless = NULL;

We can see that popup windows and modeless dialog boxes are quite similar.
Modeless dialog boxes are better if the desired popup window (the dialog
box) is to be composed entirely of child window controls because it is easy
to design with the dialog box editor. Popups are better if you will be
painting or otherwise modifying the client area of the popup window.


Windows contains a library of functions that invoke standard dialog boxes 
for doing things like: opening/saving files, searching/replacing text, 
choosing colors, choosing fonts, getting/changing information on printers, 

A common dialog box is displayed by calling a single function from the
library instead of having to set up a .rc template and write a dialog box

For each common dialog box, COMMDLG.DLL provides the standard template and
the default dialog box procedure which processes messages from the dialog
box controls.

When using common dialog boxes, the COMMDLG.H header file must be included.
This defines the common dialog box functions and the structures necessary
for using these dialog boxes.

Steps in Setting Up and Using a Common Dialog box--

All of the common dialog box library functions are used in the same way:

  -Initialize the fields of a structure with data needed by the dialog box.
  -Set up a pointer to a structure in the library function.
  -Call the library function, passing it the pointer.
  -The library function creates/displays the dialog box.
  -The user interacts with the dialog box and causes it to be removed.
  -The library function returns control to the application.
  -The application retrieves the information returned in the structure.

Some Common Dialog Box functions (check on-line help for details):

ChooseColor(CHOOSECOLOR* cc) -- Displays dialog box with a palette of
available colors and allows the user to choose one and/or create a new one.
The rgbResult member of cc will contain the RGB (COLORREF) values of the
color selected.

ChooseFont(CHOOSEFONT* cf) -- Displays a dialog box with lists of available
fonts, point sizes; user selects a font, sample text is displayed. Member
variables of cf will contain information on the font selected.

GetOpenFileName(OPENFILENAME* ofn) / GetSaveFileName(OPENFILENAME* ofn) --
Each displays a dialog box with a list of file names, directories, drives
(in the familiar Windows "Open"/"Save" format). The user indicates which file
to open/save; the lpstrFile member of ofn will contain the drive
designator, path, filename, and extension of the selected file. We will see
an example of using these common dialog boxes later in the workshop.

FindText(FINDREPLACE* ft) -- Displays a dialog box with an edit control
the user can use to search for (and optionally replace) a string.

See the Petzold COLORS3.C for a very simple example of using the ChooseColor
common dialog box.