326 lines
8.4 KiB
C++
326 lines
8.4 KiB
C++
#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;
|
|
}
|