In OLE, a property page is an in-process object that implements IPropertyPage. Through this interface, the property frame provides the necessary information and commands to each page in the sheet:
interface IPropertyPage : IUnknown
{
HRESULT SetPageSite(IPropertyPageSite *pPageSite);
HRESULT Activate(HWND hWndParent, LPCRECT prc, BOOL fModal);
HRESULT Deactivate(VOID);
HRESULT GetPageInfo(PROPPAGEINFO *pPageInfo);
HRESULT SetObjects(ULONG cObjects, IUnknown **ppUnk);
HRESULT Show(UINT nCmdShow);
HRESULT Move(LPCRECT prc);
HRESULT IsPageDirty(VOID);
HRESULT Apply(VOID);
HRESULT Help(LPCOLESTR pszHelpDir);
HRESULT TranslateAccelerator(LPMSG pMsg);
};
typedef struct tagPROPPAGEINFO
{
size_t cb ;
LPOLESTR pszTitle;
SIZE size;
LPOLESTR pszDocString;
LPOLESTR pszHelpFile;
DWORD dwHelpContext;
} PROPPAGEINFO;
These member functions behave as follows:
Member Function | Description |
SetPageSite | The initialization function for a property page through which the page receives an IPropertyPageSite pointer. This page should make a copy of the pointer and call AddRef through it. A NULL can be passed to this function to instruct the page to release whatever pointer it has. |
Activate | Instructs the page to create its display window as a child of hWndParent and to position it according to prc. The fModal flag indicates that the modality of the dialog frame is always TRUE. This function will be called whenever the user clicks the page's tab in the dialog box. |
Deactivate | Instructs the page to destroy the window created in Activate. |
GetPageInfo | Asks the page to fill a PROPPAGEINFO structure, with the text to show in its tab (such as "Fonts" or "Colors") in pszTitle, the pixel dimensions of the page in size, a help string in pszDocString,* and the name and context ID for a help file in pszHelpFile and dwHelpContext. The property page allocates all strings with CoTaskMemAlloc, and they become the frame's responsibility. If a help filename is given, the frame will enable its Help button. |
SetObjects | Provides the page with the objects being affected by changes. This function will be called after SetPageSite but always before Activate so that the page can retrieve initial values as necessary. The page must make copies of all passed pointers, calling AddRef on each. |
* This is currently not used by the standard property frame, but it could be used in a status line or in a tool tip to describe the page itself.
Member Function | Description |
Show | Asks the page to show or hide its window according to nCmdShow. |
Move | Asks the page to relocate and resize itself to a position other than what was specified through Activate. |
IsPageDirty | Asks the page whether it has changed its state, returning S_OK or S_FALSE. This is used to determine whether to enable the Apply Now button in the dialog, as described in the next section. |
Apply | Instructs the page to send its changes to all the objects passed through SetObjects. The page queries for whatever interface (vtable or dispatch, custom or standard) it requires and informs the objects of new values. |
Help | Instructs the page that the Help button was clicked; pszHelpDir is the default Help directory. If the object wants to invoke its own help information, it should return a success code. If Help returns an error code (E_NOTIMPL), the frame will launch WinHelp using the help information returned through GetPageInfo. |
TranslateAccelerator | Informs the page of keyboard events, allowing it to implement its own keyboard interface. |
The size returned through GetPageInfo specifies the pixel dimensions of the page in question. When multiple pages are involved, the frame will create a page area large enough for the largest page (as shown earlier in Figures 16-1, 16-2, and 16-3). Those dimensions are then used in calculating the rectangle passed to both Activate and Move.
The frame will call the Apply member of each page either when the user clicks the Apply Now button or when the user clicks OK to close the dialog box. How a property page chooses to implement Apply depends entirely on what it knows about the objects that might specify the page. General purpose pages used by different object classes—such as the Fonts and Colors pages shown earlier—must specify in their documentation exactly how they intend to send changes to an object. This is done most often through standard dispIDs for various properties. Other pages that are private to an object class can use whatever mechanism is most convenient—for example, a custom interface. Whatever the means, successfully applying changes should clear the page's dirty flag so that IsPageDirty will return S_FALSE. If errors occur, the state should remain dirty.
The window created in Activate should be a child window of the frame. This child window has no border and no caption, but otherwise, it contains all the controls to display for that page. The most convenient implementation method is to define a dialog template for the page layout specifying the WS_CHILD style bit but without the WS_CAPTION and WS_THICKFRAME bits. You can then implement Activate by creating a modeless dialog box from this template through the Windows function CreateDialog. We'll see an example later in this chapter.