Each common dialog box uses the dialog box procedure and dialog box template provided for it in COMMDLG.DLL. The dialog box procedure processes messages and notifications for the common dialog box and its controls. The dialog box template defines the appearance of the dialog box—its dimensions, its location, and the dimensions and locations of controls that appear within it.
In addition to the provided dialog box procedure and dialog box template, a custom dialog box requires a hook function that you provide and, usually, a custom version of the dialog box template.
The dialog box procedure provided in COMMDLG.DLL for a common dialog box calls the application's hook function if the application sets the appropriate flag and pointer in the structure for that common dialog box. The structure for each common dialog box contains a Flags member that specifies whether the application supplies a hook function and contains an lpfnHook member that points to the hook function if one exists. If the application sets the Flags member to indicate that a hook function exists, it must also set the lpfnHook member. The following example sets the Flags and lpfnHook members of an OPENFILENAME structure to support an application's hook function:
#define STRICT
#include <windows.h> /* required for all Windows applications */
#include <commdlg.h>
#include <string.h>
#include "header.h" /* specific to this program */
OPENFILENAME ofn;
/* Get the system directory name, and store in szDirName. */
GetSystemDirectory((LPSTR)szDirName, 255);
/* Initialize the OPENFILENAME members. */
szFile[0] = '\0';
ofn.lStructSize = sizeof(OPENFILENAME);
ofn.hwndOwner = hwnd;
ofn.hInstance = hInst;
ofn.lpstrFilter = szFilter[0];
ofn.lpstrCustomFilter = NULL;
ofn.nMaxCustFilter = 0L;
ofn.nFilterIndex = 1L;
ofn.lpstrFile= szFile;
ofn.nMaxFile = sizeof(szFile);
ofn.lpstrFileTitle = szFileTitle;
ofn.nMaxFileTitle = sizeof(szFileTitle);
ofn.lpstrInitialDir = szDirName;
ofn.lpstrTitle = NULL;
ofn.Flags = OFN_ENABLEHOOK | OFN_ENABLETEMPLATE;
ofn.nFileOffset = 0;
ofn.nFileExtension = 0;
ofn.lpstrDefExt = NULL;
ofn.lpfnHook = MakeProcInstance((FARPROC) FileOpenHookProc, hInst);
ofn.lpTemplateName = "FileOpen";
In the previous example, the MakeProcInstance function is called to create a procedure-instance address for the hook function. This address is assigned to the lpfnHook member of the OPENFILENAME structure. If the hook function is part of a dynamic-link library (rather than an application), the procedure address is obtained by calling the GetProcAddress function (instead of MakeProcInstance).
The hook function processes any messages or notifications that the custom dia-log box requires. With the exception of one message (WM_INITDIALOG), the hook function receives messages and notifications before the dialog box procedure provided in COMMDLG.DLL receives them. In the case of WM_INITDIALOG, the hook function receives the message after the dialog box procedure and should process it as described in the Microsoft Windows Programmer's Reference, Volume 3. When the hook function finishes processing a message, it returns a value that indicates whether the dialog box procedure provided in COMMDLG.DLL should also process the message. If the dialog box proce-dure should process the message, the return value is FALSE; if the dialog box procedure should ignore the message, the return value is TRUE.
To process the message from the OK button after the dialog box procedure processes it, an application must post a message to itself when the OK message is received. When the application receives the message it has posted, the common dialog box procedure will have finished processing messages for the dialog box. This technique is particularly useful when working with the Find and Replace dialog boxes, because the Flags member of the FINDREPLACE structure does not reflect changes to the dialog box until after the messages have been processed by COMMDLG.DLL.
The following example shows a hook function for a custom Open dialog box:
UINT CALLBACK FileOpenHookProc(HWND hdlg, UINT msg, WPARAM wParam,
LPARAM lParam)
{
switch(msg) {
case WM_INITDIALOG:
return TRUE;
case WM_COMMAND:
/* Use IsDlgButtonChecked to set lCustData. */
if (wParam == IDOK) {
/* Set backup flag. */
ofn.lCustData =
(DWORD) IsDlgButtonChecked(hdlg, ID_CUSTCHX);
}
return FALSE; /* Allow standard processing. */
}
/* Allow standard processing. */
return FALSE;
}
This hook function tests a custom check box when the user chooses the OK button. If the check box was selected, the hook function sets the lCustData member of the OPENFILENAME structure to 1; otherwise, it sets the lCustData member to 0.
A hook function should never call the EndDialog function. Instead, if a hook function contains code that abnormally terminates a common dialog box, this code should pass the IDABORT value to the dialog box procedure by using the PostMessage function as shown in the following example:
PostMessage
(hDlg, WM_COMMAND, IDABORT, (LONG) FALSE);
When a hook function posts the IDABORT value, the common dialog box function returns the value contained in the low word of the lParam parameter. For example, if the hook function for GetOpenFileName called the PostMessage function with (LONG) 100 as the last parameter, GetOpenFileName would return 100.
A hook function must be exported in an application's module-definition (.DEF) file as shown in the following example:
NAME cd
EXETYPE WINDOWS
STUB 'WINSTUB.EXE'
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD MOVEABLE MULTIPLE
HEAPSIZE 1024
STACKSIZE 8192
EXPORTS
FILEOPENHOOKPROC @1
The dialog box template provided in COMMDLG.DLL for each common dialog box contains the data that the dialog box procedure uses to display that common dialog box. Most applications that customize a common dialog box also need to create a custom dialog box template to use instead of the dialog box template in COMMDLG.DLL. (A custom dialog box template is not required for all custom dialog boxes. For instance, a template would not be necessary if an application changed a dialog box in a relatively minor way and only in an unusual situation.)
A developer should create a custom dialog box template by modifying the appropriate dialog box template in COMMDLG.DLL. Following are the template filenames and the names of their corresponding common dialog boxes:
Template filename | Corresponding dialog box |
COLOR.DLG | Color |
FILEOPEN.DLG | Open (single selection) |
FILEOPEN.DLG | Open (multiple selection) |
FINDTEXT.DLG | Find |
FINDTEXT.DLG | Replace |
FONT.DLG | Font |
PRNSETUP.DLG | |
PRNSETUP.DLG | Print Setup |
The following excerpt is from a custom dialog box template created for an Open dialog box:
CONTROL "&Backup File", ID_CUSTCHX, "button",
BS_AUTOCHECKBOX | WS_CHILD | WS_TABSTOP | WS_GROUP,
208, 86, 50, 12
END
This entry supports the addition of a new Backup File check box immediately below the existing Read Only check box.
The custom template should be added to the application's resource file.