146 lines
4.8 KiB
C
146 lines
4.8 KiB
C
|
/******************************************************************************
|
||
|
|
||
|
Header File: Property Page.H
|
||
|
|
||
|
This defines the C++ class used to encapsulate property pages. This class
|
||
|
has a static method for the dialog procedure, which automatically caches the
|
||
|
"this" pointer for the class in the DWL_USER field of the windows internal
|
||
|
structure for the dialog used for the property page. This hand-off is
|
||
|
accomplished by setting the lParam field of the PROPSHEETPAGE structure to
|
||
|
the "this" pointer. It also saves the dialog handle in a protected member
|
||
|
for easy access from derived classes.
|
||
|
|
||
|
To create a C++ class for any specific property sheet, derive the class
|
||
|
from this class, providing the dialog ID and instance handle needed to get
|
||
|
the resource in the m_psp member.
|
||
|
|
||
|
The dialog procedure then provides virtual functions for Windows messages
|
||
|
of interest. I've added these as needed. If I were going to a truly
|
||
|
universal class of this sort, I'd just as well go to MFC, and save the
|
||
|
debugging time, so this approach seems reasonable to me.
|
||
|
|
||
|
Copyright (c) 1996 by Microsoft Corporation
|
||
|
|
||
|
A Pretty Penny Enterprises Production
|
||
|
|
||
|
Change History:
|
||
|
|
||
|
11-01-96 a-robkj@microsoft.com- original version
|
||
|
|
||
|
******************************************************************************/
|
||
|
|
||
|
#if !defined(PROPERTY_PAGE)
|
||
|
|
||
|
#define PROPERTY_PAGE
|
||
|
|
||
|
// CPropertyPage class- abstracts a property page for us
|
||
|
|
||
|
class CPropertyPage {
|
||
|
|
||
|
// Basic dialog procedure for all derived classes
|
||
|
|
||
|
static BOOL CALLBACK DialogProc(HWND hwndPage, UINT uMsg, WPARAM wp,
|
||
|
LPARAM lp);
|
||
|
|
||
|
// These elements should be protected (only available to derived classes)
|
||
|
|
||
|
protected:
|
||
|
PROPSHEETPAGE m_psp;
|
||
|
HWND m_hwnd, m_hwndSheet;
|
||
|
HPROPSHEETPAGE m_hpsp;
|
||
|
|
||
|
BOOL m_bChanged;
|
||
|
|
||
|
public:
|
||
|
|
||
|
CPropertyPage(); // Default Constructor
|
||
|
virtual ~CPropertyPage() {}
|
||
|
|
||
|
HPROPSHEETPAGE Handle(); // Calls CreatePropertySheetPage, if needed
|
||
|
|
||
|
VOID EnableApplyButton() {
|
||
|
SendMessage(m_hwndSheet, PSM_CHANGED, (WPARAM) m_hwnd, 0);
|
||
|
}
|
||
|
|
||
|
VOID DisableApplyButton() {
|
||
|
SendMessage(m_hwndSheet, PSM_UNCHANGED, (WPARAM) m_hwnd, 0);
|
||
|
}
|
||
|
|
||
|
BOOL SettingChanged() {
|
||
|
return m_bChanged;
|
||
|
}
|
||
|
|
||
|
VOID SettingChanged(BOOL b) {
|
||
|
m_bChanged = b;
|
||
|
}
|
||
|
|
||
|
// virtual functions- these get redefined on an as needed basis for
|
||
|
// any specialized handling desired by any derived classes.
|
||
|
|
||
|
// The default handling allows one to initially display the sheet with
|
||
|
// no coding beyond the constructor for the derived class
|
||
|
|
||
|
virtual BOOL OnCommand(WORD wNotifyCode, WORD wid, HWND hwndCtl) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
virtual BOOL OnNotify(int idCtrl, LPNMHDR pnmh) {
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
virtual BOOL OnInit() { return TRUE; }
|
||
|
|
||
|
virtual BOOL OnDestroy() { return FALSE; }
|
||
|
|
||
|
virtual BOOL OnHelp(LPHELPINFO pHelp) { return TRUE; }
|
||
|
virtual BOOL OnContextMenu(HWND hwnd) { return TRUE; }
|
||
|
};
|
||
|
|
||
|
/******************************************************************************
|
||
|
|
||
|
Shell Extension property page class
|
||
|
|
||
|
Noteworthy details:
|
||
|
|
||
|
These pages are displayed by the shell. The thread of execution is such that
|
||
|
we create the page, then return to the shell. The shell will then attempt to
|
||
|
unload the extension. It will query CanDllUnloadNow to do this. Since
|
||
|
freeing the library frees the page template and dialog procedure, we can't
|
||
|
allow this to happen while any instances of this class exist.
|
||
|
|
||
|
However, the shell doesn't know this is a class, so it won't destroy it.
|
||
|
|
||
|
What I've done is build a circular chain of all of the instances of this
|
||
|
class, anchored in a private static class member. A public static method
|
||
|
(OKToClose) then walks the chain. If an instance's window handle is no
|
||
|
longer valid, then the shell has finished with it, and we delete it. The
|
||
|
criterion for closing then becomes not finding a valid handle (so we don't
|
||
|
delay unloading by any lazy evaluation, such as requiring an empty chain
|
||
|
on entry).
|
||
|
|
||
|
All Property pages displayed by a property sheet extension should be derived
|
||
|
from this class.
|
||
|
|
||
|
While a mechanism is provided by property sheets for a reference count
|
||
|
maintenance mechanism, this mechanism will not call any class destructor-
|
||
|
this could lead to memory leaks, which is why I've chosen this method.
|
||
|
|
||
|
******************************************************************************/
|
||
|
|
||
|
class CShellExtensionPage: public CPropertyPage {
|
||
|
|
||
|
static CShellExtensionPage *m_pcsepAnchor; // Anchor the chain of these
|
||
|
|
||
|
CShellExtensionPage *m_pcsepPrevious, *m_pcsepNext;
|
||
|
|
||
|
public:
|
||
|
|
||
|
CShellExtensionPage();
|
||
|
~CShellExtensionPage();
|
||
|
|
||
|
static BOOL OKToClose();
|
||
|
};
|
||
|
|
||
|
|
||
|
#endif // Keep us from getting multiply defined
|