A property sheet is a window that allows the user to view and edit the properties of an item. For example, a spreadsheet application can use a property sheet to allow the user to set the font and border properties of a cell or to view and set the properties of a device, such as a disk drive, printer, or mouse.
This document assumes that you have a thorough understanding of dialog box templates and dialog box procedures. If you don't, read the "Dialog Boxes" chapter in the Platform SDK before continuing with this overview chapter.
To implement property sheets in your application, include the Prsht.h header file in your project. Prsht.h contains all of the identifiers used with property sheets.
A property sheet contains one or more overlapping child windows called pages, each containing control windows for setting a group of related properties. For example, a page can contain the controls for setting the font properties of an item, including the type style, point size, color, and so on. Each page has a tab that the user can select to bring the page to the foreground of the property sheet. For example, the Date-Time control panel application displays the following property sheet:

There is also a special type of property sheet called a wizard. Wizards are designed to present pages one at a time in a sequence that is controlled by the application. Instead of selecting from a group of pages by clicking a tab, users navigate forward and backward through the sequence, one page at a time, by clicking Next or Back buttons located at the bottom of the wizard. For example, this is the compiler wizard that sets the compiler settings in Wedit:

See
A property sheet and the pages it contains are actually dialog boxes. The property sheet is a system-defined dialog box that manages the pages and provides a common container for them. The property sheet dialog box can be modal or modeless. It includes a frame, a title bar, and four buttons: OK, Cancel, Apply, and Help. (The Help button may be hidden as in the preceding illustration.) The dialog box procedures for the pages receive notification messages when the user clicks the buttons.
Each page in a property sheet is an application-defined modeless dialog box that manages the control windows used to view and edit the properties of an item. You provide the dialog box template used to create each page as well as the dialog box procedure that manages the controls and sets the properties of the corresponding item.
A property sheet sends notification messages to the dialog box procedure for
a page when the page is gaining or losing the activation and when the user
clicks the OK, Cancel, Apply, or Help button. The notifications are sent in the
form of
Some notification messages require a page to return either TRUE or FALSE in
response to the WM_NOTIFY message. To do this, the page must use the
A property sheet must contain at least one page, but it cannot contain more than the value of MAXPROPPAGES as defined in the Win32 header files. Each page has a zero-based index that the property sheet assigns according to the order in which the page is added to the property sheet. The indexes are used in messages that you send to the property sheet.
A property page can contain a nested dialog box. If it does, you must include
the WS_EX_CONTROLPARENT style for the top-level dialog box and call the
Each page has a corresponding icon and label. The property sheet creates a tab for each page and displays the icon and label in the tab. All property sheet pages are expected to use a nonbold font. To ensure that the font is not bold, specify the DS_3DLOOK style in the dialog box template.
The dialog box procedure for a page must not call the
The minimum size for a property sheet page is 212 dialog units horizontally and 114 dialog units vertically. If a page dialog is smaller than this, the page will be enlarged until it meets the minimum size. The Prsht.h header file contains three sets of recommended sizes for property sheet pages. PROP_SM_CXDLG and PROP_SM_CYDLG define the recommended dimensions for a small property sheet page. PROP_MED_CXDLG and PROP_MED_CYDLG define the recommended dimensions for a medium-sized property sheet page. PROP_LG_CXDLG and PROP_LG_CYDLG define the recommended dimensions for a large property sheet page. Using these recommended sizes will help ensure visual consistency between your application and other Microsoft® Windows® applications.
Use the following values to set the sizes of the elements in your property sheet pages:
| PROP_SM_CXDLG | Width, in dialog units, of a small property sheet page. |
| PROP_SM_CYDLG | Height, in dialog units, of a small property sheet page. |
| PROP_MED_CXDLG | Width, in dialog units, of a medium-sized property sheet page. |
| PROP_MED_CYDLG | Height, in dialog units, of a medium-sized property sheet page. |
| PROP_LG_CXDLG | Width, in dialog units, of a large property sheet page. |
| PROP_LG_CYDLG | Height, in dialog units, of a large property sheet page. |
Before creating a property sheet, you must define one or more pages. This
involves filling a
To create a property sheet, you specify the address of a
Another way to create a property sheet is to specify an array of PROPSHEETPAGE structures instead of an array of HPROPSHEETPAGE handles. In this case, PropertySheet creates handles for the pages before adding them to the property sheet.
When a page is created, its dialog box procedure receives a
When the system subsequently passes a copy of the page's PROPSHEETPAGE
structure to your application, it uses the same pointer. Any changes to the
structure will be passed along. Because the lParam member is ignored by
the system, it can be modified to send information to other parts of your
application. You can, for instance, use lParam to pass information to the
page's
PropertySheet automatically sets the size and initial position of a property sheet. The position is based on the position of the owner window, and the size is based on the largest page specified in the array of pages when the property sheet was created. If you want the pages to match the width of the four buttons at the bottom of the property sheet, set the width of the widest page to 190 dialog units.
After creating a property sheet, an application can add a page to the end of
the existing set of pages by sending a
When you define a page, you can specify the address of a PropSheetPageProc callback function that the property sheet calls when it is creating or removing the page. Using PropSheetPageProc gives you an opportunity to perform initialization and cleanup operations for individual pages.
If the need to modify a property sheet page arises while you are handling one of these messages or while PropSheetPageProc is in operation, post yourself a private Windows message. Your application will not receive that message until after the property sheet manager has finished its tasks. It will then be safe to modify the list of pages.
When a property sheet is destroyed, it automatically destroys all of the
pages that have been added to it. The pages are destroyed in reverse order from
that specified in the array used to create the pages. To destroy a page that was
created by the CreatePropertySheetPage function but was not added to the
property sheet, use the
You specify the title of a property sheet in the PROPSHEETHEADER
structure used to create the property sheet. If the dwFlags member
includes the PSH_PROPTITLE value, the property sheet adds the "Properties
for" prefix to the specified title string. You can change the title after a
property sheet is created by using the
By default, a property sheet uses the name string specified in the dialog box template as the label for a page. You can override the name string by including the PSP_USETITLE value in the dwFlags member of the PROPSHEETPAGE structure that defines the page. When PSP_USETITLE is specified, the pszTitle member must contain the address of the label string for the page.
A property sheet can have only one active page at a time. The page that has
the activation is at the foreground of the overlapping stack of pages. The user
activates a page by selecting its tab; an application activates a page by using
the
The property sheet sends the PSN_KILLACTIVE notification message to the page that is about to lose the activation. In response, the page must validate any changes that the user has made to the page. If the page requires additional user input before losing the activation, use the SetWindowLong function to set the DWL_MSGRESULT value of the page to TRUE. Also, the page must display a message box that describes the problem and provides the recommended action. Set DWL_MSGRESULT to FALSE when it is okay to lose the activation.
Before the page that is gaining the activation is visible, the property sheet sends the PSN_SETACTIVE notification message to the page. The page must respond by initializing its control windows.
Property sheets can display two Help buttons: a property sheet Help button that is displayed at the bottom of the frame, next to the OK/Cancel/Apply buttons, and a standard caption bar button that provides context-sensitive Help.
The property sheet Help button is optional, and can be enabled on a page by page basis. To display the property sheet Help button for one or more pages:
When the user clicks the Help button, the active page receives a
The caption bar Help button is displayed by default, so that context-sensitive Help is always available for the OK/Cancel/Apply buttons. However, this button can be removed, if necessary. To remove a property sheet's caption bar Help button:
To implement a property sheet callback function that removes the caption bar Help button:
The following sample illustrates how to implement such a callback function:
Example
int CALLBACK RemoveContextHelpProc(HWND hwnd, UINT message, LPARAM lParam)
{
switch (message)
{
case PSCB_PRECREATE:
// Remove the DS_CONTEXTHELP style from the
// dialog box template
if (((LPDLGTEMPLATEEX)lParam)->signature ==
0xFFFF)
{
((LPDLGTEMPLATEEX)lParam)->style
&= ~DS_CONTEXTHELP;
}
else {
((LPDLGTEMPLATE)lParam)->style
&= ~DS_CONTEXTHELP;
}
return TRUE;
}
return TRUE;
}
If the
Example
#include <pshpack1.h>
typedef struct DLGTEMPLATEEX
{
WORD dlgVer;
WORD signature;
DWORD helpID;
DWORD exStyle;
DWORD style;
WORD cDlgItems;
short x;
short y;
short cx;
short cy;
} DLGTEMPLATEEX, *LPDLGTEMPLATEEX;
#include <poppack.h>
The OK and Apply buttons are similar; both direct a property sheet's pages to validate and apply the property changes that the user has made. The only difference is that clicking the OK button causes the property sheet to be destroyed after the changes are applied.
When the user clicks the OK or Apply button, the property sheet sends a PSN_KILLACTIVE notification to the active page, giving it an opportunity to validate the user's changes. If the changes are valid, the page must call the SetWindowLong function with the DWL_MSGRESULT value set to FALSE. If the user's changes are not valid, the page must set DWL_MSGRESULT to TRUE and display a dialog box informing the user of the problem. The page remains active until it sets DWL_MSGRESULT to FALSE in response to a PSN_KILLACTIVE message.
After a page responds to a PSN_KILLACTIVE notification by setting DWL_MSGRESULT to FALSE, the property sheet will send a PSN_APPLY notification to each page. When a page receives this notification, it must apply the new properties to the corresponding item. To indicate to the property sheet that the changes are valid for the page, call SetWindowLong with DWL_MSGRESULT set to PSNRET_NOERROR. If the changes are invalid for the page, return an error. Doing so prevents the property sheet from being destroyed and returns focus to either the page that received the PSN_APPLY notification or the page that had focus when the Apply button was pressed. To return an error, and indicate which page will receive focus, set DWL_MSGRESULT to one of the following values.
An application can use the
The Apply button is initially disabled when a page becomes active, indicating
that there are not yet any property changes to apply. When the page receives
input through one of its controls indicating that the user has edited a
property, the page must send the
Sometimes the Apply button causes a page to make a change to a property
sheet, and the change cannot be undone. When this happens, the page must send
the
Sometimes a page makes a change to the system configuration that requires
Windows to be restarted or the system rebooted before the change can take
effect. After making such a change, a page must send either the
When a user clicks the Cancel button, the property sheet sends the PSN_RESET notification message to all pages, indicating that the property sheet is about to be destroyed. A page must use the notification to perform cleanup operations.
This section contains examples that demonstrate how to create a property sheet and process notification messages.
The example in this section creates a property sheet that contains two pages—one for setting the font properties of a cell in a spreadsheet and another for setting the border properties of the cell. The example defines the pages by filling a pair of PROPSHEETPAGE structures and specifying the address in the PROPSHEETHEADER structure that is passed to the PropertySheet function. The dialog box templates, icons, and labels for the pages are loaded from the resources contained in the application's executable file. The icon for the property sheet is also loaded from the application's resources.
Show Example
// DoPropertySheet - creates a property sheet that
// contains two pages.
// hwndOwner - handle to the owner window of the
// property sheet.
//
// Global variables
// g_hinst - instance handle
extern HINSTANCE g_hinst;
VOID DoPropertySheet(HWND hwndOwner)
{
PROPSHEETPAGE psp[2];
PROPSHEETHEADER psh;
psp[0].dwSize = sizeof(PROPSHEETPAGE);
psp[0].dwFlags = PSP_USEICONID | PSP_USETITLE;
psp[0].hInstance = g_hinst;
psp[0].pszTemplate = MAKEINTRESOURCE(DLG_FONT);
psp[0].pszIcon = MAKEINTRESOURCE(IDI_FONT);
psp[0].pfnDlgProc = FontDialogProc;
psp[0].pszTitle = MAKEINTRESOURCE(IDS_FONT)
psp[0].lParam = 0;
psp[0].pfnCallback = NULL;
psp[1].dwSize = sizeof(PROPSHEETPAGE);
psp[1].dwFlags = PSP_USEICONID | PSP_USETITLE;
psp[1].hInstance = g_hinst;
psp[1].pszTemplate =
MAKEINTRESOURCE(DLG_BORDER);
psp[1].pszIcon = MAKEINTRESOURCE(IDI_BORDER);
psp[1].pfnDlgProc = BorderDialogProc;
psp[1].pszTitle = MAKEINTRESOURCE(IDS_BORDER);
psp[1].lParam = 0;
psp[1].pfnCallback = NULL;
psh.dwSize = sizeof(PROPSHEETHEADER);
psh.dwFlags = PSH_USEICONID | PSH_PROPSHEETPAGE;
psh.hwndParent = hwndOwner;
psh.hInstance = g_hinst;
psh.pszIcon =
MAKEINTRESOURCE(IDI_CELL_PROPERTIES);
psh.pszCaption = (LPSTR) "Cell Properties";
psh.nPages = sizeof(psp) /
sizeof(PROPSHEETPAGE);
psh.nStartPage = 0;
psh.ppsp = (LPCPROPSHEETPAGE) &psp;
psh.pfnCallback = NULL;
PropertySheet(&psh);
return;
}
A property sheet sends WM_NOTIFY messages to retrieve information from the pages and to notify the pages of user actions. The lParam parameter of the message is the address of an NMHDR structure, which contains the handle to the property sheet dialog box, the handle to the page dialog box, and a notification code. The page must respond to some notification messages by setting the DWL_MSGRESULT value of the page to either TRUE or FALSE.
The following example is a code fragment from the dialog box procedure for a page. It shows how to process the PSN_HELP notification message.
Example
case WM_NOTIFY:
switch (((NMHDR FAR *) lParam)->code)
{
case PSN_HELP:
{
char szBuf[FILE_LEN]; // Buffer for
// name of Help file
// Display Help for the font properties
// page.
LoadString(g_hinst, IDS_HELPFILE, &szBuf,
sizeof(szBuf)/sizeof(szBuf[0]));
WinHelp(((NMHDR FAR *) lParam)->hwndFrom,
&szBuf, HELP_CONTEXT, IDH_FONT_PROPERTIES);
break;
}
.
. // Process other property sheet
// notifications here.
.
}
Property sheets in Microsoft® Internet Explorer support the following new features.
| New Notification | The |
|---|---|
| Updated Structures | The PROPSHEETHEADER and PROPSHEETPAGE structures have been updated to support new features. See the references for these structures for more information. |