#include "windows.h" #include "shlwapi.h" #include "shpriv.h" #include "commctrl.h" #include "resource.h" #include "ccstock.h" #include "shlguid.h" // globals and classes HINSTANCE g_hAppInst; // instance information for the wizard HWND g_hwndFrame; // wizard frame (cached on startup) IWebWizardExtension *g_pwe; // IWizardExtension (we want to show) // IWizardSite // ----------- // // This object is used by the wizard extension to navigate in and out of the // main wizard. When the wizard extension has finished displaying its set // of pages (and recieves its final PSN_WIZNEXT or PSN_WIZBACK) it is // responsible for calling the site to navigate in and out of the // stack of pages. class CWizSite : public IWizardSite, IServiceProvider { public: CWizSite(IPropertyBag *ppb); ~CWizSite(); // IUnknown STDMETHOD(QueryInterface)(REFIID riid, void **ppvObj); STDMETHOD_(ULONG,AddRef)(void); STDMETHOD_(ULONG,Release)(void); // IWizardSite STDMETHODIMP GetPreviousPage(HPROPSHEETPAGE *phPage); STDMETHODIMP GetNextPage(HPROPSHEETPAGE *phPage); STDMETHODIMP GetCancelledPage(HPROPSHEETPAGE *phPage) { return E_NOTIMPL; } // IServiceProvider STDMETHODIMP QueryService(REFGUID guidService, REFIID riid, void **ppv); private: LONG _cRef; IPropertyBag *_ppb; }; // reference counting of the object ULONG CWizSite::AddRef() { return InterlockedIncrement(&_cRef); } ULONG CWizSite::Release() { if (InterlockedDecrement(&_cRef)) return _cRef; delete this; return 0; } HRESULT CWizSite::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(CWizSite, IWizardSite), // IID_IWizardSite QITABENT(CWizSite, IServiceProvider), // IID_IServiceProvider {0}, }; return QISearch(this, qit, riid, ppv); } // instance creation CWizSite::CWizSite(IPropertyBag *ppb) : _cRef(1), _ppb(ppb) { ppb->AddRef(); } CWizSite::~CWizSite() { ATOMICRELEASE(_ppb); } HRESULT CWizSite_CreateInstance(IPropertyBag *ppb, REFIID riid, void **ppv) { CWizSite *pws = new CWizSite(ppb); if (!pws) return E_OUTOFMEMORY; HRESULT hr = pws->QueryInterface(riid, ppv); pws->Release(); return hr; } // methods for returning our page range HRESULT CWizSite::GetPreviousPage(HPROPSHEETPAGE *phPage) { int i = PropSheet_IdToIndex(g_hwndFrame, IDD_WELCOME); *phPage = PropSheet_IndexToPage(g_hwndFrame, i); return S_OK; } HRESULT CWizSite::GetNextPage(HPROPSHEETPAGE *phPage) { int i = PropSheet_IdToIndex(g_hwndFrame, IDD_DONE); *phPage = PropSheet_IndexToPage(g_hwndFrame, i); return S_OK; } // Service provider object HRESULT CWizSite::QueryService(REFGUID guidService, REFIID riid, void **ppv) { *ppv = NULL; // no result yet if (guidService == SID_PublishingWizard) { if (riid == IID_IPropertyBag) return _ppb->QueryInterface(riid, ppv); } return E_FAIL; } // Sample dialog proc's for the welcome and done pages (these then call into // the wizard extension to show their pages). BOOL _HandleWizNextBack(HWND hwnd, HPROPSHEETPAGE hpage) { PropSheet_SetCurSel(GetParent(hwnd), hpage, -1); SetWindowLongPtr(hwnd, DWLP_MSGRESULT, -1); return TRUE; } INT_PTR _WelcomeDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch ( uMsg ) { case WM_INITDIALOG: g_hwndFrame = GetParent(hwnd); return TRUE; case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR)lParam; switch (pnmh->code) { case PSN_SETACTIVE: PropSheet_SetWizButtons(g_hwndFrame, PSWIZB_NEXT); return TRUE; case PSN_WIZNEXT: { HPROPSHEETPAGE hpage; g_pwe->GetFirstPage(&hpage); return _HandleWizNextBack(hwnd, hpage); } } break; } } return FALSE; } INT_PTR _DoneDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch ( uMsg ) { case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR)lParam; switch (pnmh->code) { case PSN_SETACTIVE: PropSheet_SetWizButtons(g_hwndFrame, PSWIZB_FINISH | PSWIZB_BACK); return TRUE; case PSN_WIZBACK: { HPROPSHEETPAGE hpage; g_pwe->GetLastPage(&hpage); return _HandleWizNextBack(hwnd, hpage); } } break; } } return FALSE; } // Our Wizard, its very simple. #define WIZDLG(name, dlgproc, dwFlags) \ { MAKEINTRESOURCE(IDD_##name##), dlgproc, MAKEINTRESOURCE(IDS_##name##), MAKEINTRESOURCE(IDS_##name##_SUB), dwFlags } const struct { LPCWSTR idPage; DLGPROC pDlgProc; LPCWSTR pHeading; LPCWSTR pSubHeading; DWORD dwFlags; } c_pages[] = { WIZDLG(WELCOME, _WelcomeDlgProc, 0x0), WIZDLG(DONE, _DoneDlgProc, 0x0), }; HRESULT _InitExtensionSite(IWizardExtension *pwe) { IPropertyBag *ppb; HRESULT hr = SHCreatePropertyBagOnMemory(STGM_READWRITE, IID_PPV_ARG(IPropertyBag, &ppb)); if (SUCCEEDED(hr)) { IWizardSite *pws; hr = CWizSite_CreateInstance(ppb, IID_PPV_ARG(IWizardSite, &pws)); if (SUCCEEDED(hr)) { IUnknown_SetSite(pwe, pws); pws->Release(); } ppb->Release(); } return hr; } int APIENTRY WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) { g_hAppInst = hInstance; CoInitialize(NULL); InitCommonControls(); // For our example we will create the Publishing Wizard, it supports IWizardExtension and // we will host its pages within ours. HRESULT hr = CoCreateInstance(CLSID_WebWizardHost, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IWebWizardExtension, &g_pwe)); if (SUCCEEDED(hr)) { hr = _InitExtensionSite(g_pwe); if (SUCCEEDED(hr)) { // Create our pages, these are placed at the top of the array, // the extensions are placed after. HPROPSHEETPAGE hpages[10] = { 0 }; for (int i = 0; i < ARRAYSIZE(c_pages) ; i++ ) { PROPSHEETPAGE psp = { 0 }; psp.dwSize = sizeof(psp); psp.hInstance = g_hAppInst; psp.dwFlags = PSP_USETITLE | PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE | c_pages[i].dwFlags; psp.pszTemplate = c_pages[i].idPage; psp.pfnDlgProc = c_pages[i].pDlgProc; psp.pszTitle = TEXT("Wizard Hosting Example"); psp.pszHeaderTitle = c_pages[i].pHeading; psp.pszHeaderSubTitle = c_pages[i].pSubHeading; hpages[i] = CreatePropertySheetPage(&psp); } // Fill out the structure for the property sheet, we indicate // that we want this to behave like a wizard. PROPSHEETHEADER psh = { 0 }; psh.dwSize = sizeof(psh); psh.hInstance = g_hAppInst; psh.dwFlags = PSH_WIZARD | PSH_WIZARD97 | PSH_HEADER; psh.pszbmHeader = MAKEINTRESOURCE(IDB_BANNER); psh.phpage = hpages; psh.nPages = i; // Let the extension add its pages it will append an array of // HPROPSHEETPAGE to the structure, it also return the count. UINT nPages; hr = g_pwe->AddPages(&hpages[i], ARRAYSIZE(hpages)-i, &nPages); if (SUCCEEDED(hr)) { psh.nPages = i+nPages; TCHAR szPath[MAX_PATH]; GetModuleFileName(NULL, szPath, ARRAYSIZE(szPath)); PathRenameExtension(szPath, TEXT(".htm")); WCHAR szURL[128]; DWORD cch = ARRAYSIZE(szURL); UrlCreateFromPath(szPath, szURL, &cch, 0); g_pwe->SetInitialURL(szURL); PropertySheet(&psh); } } g_pwe->Release(); g_pwe = NULL; } CoUninitialize(); return 0; }