#include "stdafx.h" #include "shimgdata.h" #include "shui.h" #include "netplace.h" #include #include #include "pubwiz.h" #include "gdiplus\gdiplus.h" #include "imgprop.h" #include "shdguid.h" #include "urlmon.h" #include "xmldomdid.h" #include "winnlsp.h" #pragma hdrstop // handle the events from the DOM as we load #define XMLDOC_LOADING 1 #define XMLDOC_LOADED 2 #define XMLDOC_INTERACTIVE 3 #define XMLDOC_COMPLETED 4 // this message is posted to the parent HWND, the lParam parse result #define MSG_XMLDOC_COMPLETED WM_APP class CXMLDOMStateChange : public IDispatch { public: CXMLDOMStateChange(IXMLDOMDocument *pdoc, HWND hwnd); ~CXMLDOMStateChange(); HRESULT Advise(BOOL fAdvise); // IUnknown STDMETHODIMP QueryInterface(REFIID riid, void **ppv); STDMETHODIMP_(ULONG) AddRef(); STDMETHODIMP_(ULONG) Release(); // IDispatch STDMETHODIMP GetTypeInfoCount( UINT *pctinfo) { return E_NOTIMPL; } STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo) { return E_NOTIMPL; } STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) { return E_NOTIMPL; } STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pvar, EXCEPINFO *pExcepInfo, UINT *puArgErr); private: long _cRef; IXMLDOMDocument *_pdoc; DWORD _dwCookie; HWND _hwnd; }; // construction and IUnknown CXMLDOMStateChange::CXMLDOMStateChange(IXMLDOMDocument *pdoc, HWND hwnd) : _cRef(1), _dwCookie(0), _hwnd(hwnd) { IUnknown_Set((IUnknown**)&_pdoc, pdoc); } CXMLDOMStateChange::~CXMLDOMStateChange() { IUnknown_Set((IUnknown**)&_pdoc, NULL); } ULONG CXMLDOMStateChange::AddRef() { return InterlockedIncrement(&_cRef); } ULONG CXMLDOMStateChange::Release() { if (InterlockedDecrement(&_cRef)) return _cRef; delete this; return 0; } HRESULT CXMLDOMStateChange::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(CXMLDOMStateChange, IDispatch), { 0 }, }; return QISearch(this, qit, riid, ppv); } // handle the advise/unadvise to the parent object HRESULT CXMLDOMStateChange::Advise(BOOL fAdvise) { IConnectionPointContainer *pcpc; HRESULT hr = _pdoc->QueryInterface(IID_PPV_ARG(IConnectionPointContainer, &pcpc)); if (SUCCEEDED(hr)) { IConnectionPoint *pcp; hr = pcpc->FindConnectionPoint(DIID_XMLDOMDocumentEvents, &pcp); if (SUCCEEDED(hr)) { if (fAdvise) { hr = pcp->Advise(SAFECAST(this, IDispatch *), &_dwCookie); } else if (_dwCookie) { hr = pcp->Unadvise(_dwCookie); _dwCookie = 0; } pcp->Release(); } pcpc->Release(); } return hr; } // handle the invoke for the doc state changing HRESULT CXMLDOMStateChange::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pvar, EXCEPINFO *pExcepInfo, UINT *puArgErr) { HRESULT hr = S_OK; switch (dispIdMember) { case DISPID_XMLDOMEVENT_ONREADYSTATECHANGE: { long lReadyState; if (SUCCEEDED(_pdoc->get_readyState(&lReadyState))) { if (lReadyState == XMLDOC_COMPLETED) { IXMLDOMParseError *pdpe; hr = _pdoc->get_parseError(&pdpe); if (SUCCEEDED(hr)) { long lError; hr = pdpe->get_errorCode(&lError); if (SUCCEEDED(hr)) { hr = (HRESULT)lError; } PostMessage(_hwnd, MSG_XMLDOC_COMPLETED, 0, (LPARAM)hr); pdpe->Release(); } } } break; } } return hr; } // copied from shell stuff - should be in public header #define DEFINE_SCID(name, fmtid, pid) const SHCOLUMNID name = { fmtid, pid } DEFINE_SCID(SCID_NAME, PSGUID_STORAGE, PID_STG_NAME); DEFINE_SCID(SCID_TYPE, PSGUID_STORAGE, PID_STG_STORAGETYPE); DEFINE_SCID(SCID_SIZE, PSGUID_STORAGE, PID_STG_SIZE); DEFINE_SCID(SCID_WRITETIME, PSGUID_STORAGE, PID_STG_WRITETIME); DEFINE_SCID(SCID_ImageCX, PSGUID_IMAGESUMMARYINFORMATION, PIDISI_CX); DEFINE_SCID(SCID_ImageCY, PSGUID_IMAGESUMMARYINFORMATION, PIDISI_CY); // provider XML defines the following properties for each of the #define DEFAULT_PROVIDER_SCOPE TEXT("PublishingWizard") #define FMT_PROVIDER TEXT("providermanifest/providers[@scope='%s']") #define FMT_PROVIDERS TEXT("providermanifest/providers[@scope='%s']/provider") #define ELEMENT_PROVIDERMANIFEST L"providermanifest" #define ELEMENT_PROVIDERS L"providers" #define ELEMENT_PROVIDER L"provider" #define ATTRIBUTE_ID L"id" #define ATTRIBUTE_SUPPORTEDTYPES L"supportedtypes" #define ATTRIBUTE_DISPLAYNAME L"displayname" #define ATTRIBUTE_DESCRIPTION L"description" #define ATTRIBUTE_HREF L"href" #define ATTRIBUTE_ICONPATH L"iconpath" #define ATTRIBUTE_ICON L"icon" #define ELEMENT_STRINGS L"strings" #define ATTRIBUTE_LANGID L"langid" #define ELEMENT_STRING L"string" #define ATTRIBUTE_LANGID L"langid" #define ATTRIBUTE_ID L"id" // registry state is stored under the this key #define SZ_REGKEY_PUBWIZ TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\PublishingWizard") // per machine values in the registry #define SZ_REGVAL_SERVICEPARTNERID TEXT("PartnerID") // these are stored per machine under the provider #define SZ_REGVAL_FILEFILTER TEXT("ContentTypeFilter") #define SZ_REGVAL_DEFAULTPROVIDERICON TEXT("DefaultIcon") // per user values in the registry #define SZ_REGVAL_DEFAULTPROVIDER TEXT("DefaultProvider") // per provider settings #define SZ_REGVAL_MRU TEXT("LocationMRU") #define SZ_REGVAL_ALTPROVIDERS TEXT("Providers") // Properties exposed by the property bag (from the Web Service) #define PROPERTY_EXTENSIONCOUNT TEXT("UniqueExtensionCount") #define PROPERTY_EXTENSION TEXT("UniqueExtension") #define PROPERTY_TRANSFERMANIFEST TEXT("TransferManifest") // This is the COM object that exposes the publishing wizard #define WIZPAGE_WHICHFILE 0 // which file should we publish #define WIZPAGE_FETCHINGPROVIDERS 1 // provider download page #define WIZPAGE_PROVIDERS 2 // pick a service provider #define WIZPAGE_RESIZE 3 // resample the data? #define WIZPAGE_COPYING 4 // copying page #define WIZPAGE_LOCATION 5 // location page (advanced) #define WIZPAGE_FTPUSER 6 // username / password (advanced) #define WIZPAGE_FRIENDLYNAME 7 // friendly name #define WIZPAGE_MAX 8 // resize information struct { int cx; int cy; int iQuality; } _aResizeSettings[] = { { 0, 0, 0 }, { 640, 480, 80 }, // low quality { 800, 600, 80 }, // medium quality { 1024, 768, 80 }, // high quality }; typedef enum { RESIZE_NONE = 0, RESIZE_SMALL, RESIZE_MEDIUM, RESIZE_LARGE, } RESIZEOPTION; class CPublishingWizard : public IServiceProvider, IPublishingWizard, CObjectWithSite, ITransferAdviseSink, ICommDlgBrowser, IOleWindow, IWizardSite { public: CPublishingWizard(); ~CPublishingWizard(); // IUnknown STDMETHOD(QueryInterface)(REFIID riid, void **ppvObj); STDMETHOD_(ULONG,AddRef)(); STDMETHOD_(ULONG,Release)(); // IServiceProvider STDMETHODIMP QueryService(REFGUID guidService, REFIID riid, void **ppv); // IWizardExtension STDMETHODIMP AddPages(HPROPSHEETPAGE* aPages, UINT cPages, UINT *pnPages); STDMETHODIMP GetFirstPage(HPROPSHEETPAGE *phPage); STDMETHODIMP GetLastPage(HPROPSHEETPAGE *phPage); // IWizardSite STDMETHODIMP GetPreviousPage(HPROPSHEETPAGE *phPage); STDMETHODIMP GetNextPage(HPROPSHEETPAGE *phPage); STDMETHODIMP GetCancelledPage(HPROPSHEETPAGE *phPage); // IPublishingWizard STDMETHODIMP Initialize(IDataObject *pdo, DWORD dwFlags, LPCTSTR pszServiceProvider); STDMETHODIMP GetTransferManifest(HRESULT *phrFromTransfer, IXMLDOMDocument **pdocManifest); // IOleWindow STDMETHODIMP GetWindow(HWND *phwnd) { *phwnd = _hwndCopyingPage; return S_OK; } STDMETHODIMP ContextSensitiveHelp(BOOL fEnter) { return E_NOTIMPL; } // ICommDlgBrowser STDMETHOD(OnDefaultCommand)(IShellView *ppshv) { return E_NOTIMPL; } STDMETHOD(OnStateChange)(IShellView *ppshv, ULONG uChange); STDMETHOD(IncludeObject)(IShellView *ppshv, LPCITEMIDLIST lpItem); // ITransferAdviseSink STDMETHODIMP PreOperation (const STGOP op, IShellItem *psiItem, IShellItem *psiDest); STDMETHODIMP ConfirmOperation(IShellItem *psiItem, IShellItem *psiDest, STGTRANSCONFIRMATION stc, LPCUSTOMCONFIRMATION pcc) { return STRESPONSE_CONTINUE; } STDMETHODIMP OperationProgress(const STGOP op, IShellItem *psiItem, IShellItem *psiDest, ULONGLONG ulTotal, ULONGLONG ulComplete); STDMETHODIMP PostOperation(const STGOP op, IShellItem *psiItem, IShellItem *psiDest, HRESULT hrResult) { return S_OK; } STDMETHODIMP QueryContinue() { return _fCancelled ? S_FALSE : S_OK; } private: LONG _cRef; // object lifetime count IDataObject *_pdo; // data object provided by the site IDataObject *_pdoSelection; // this is the selection IDataObject - used instead of _pdo if defined DWORD _dwFlags; // flags provided by the site TCHAR _szProviderScope[MAX_PATH]; // provider scope (eg. Web Publishing) BOOL _fOfferResize; // show the resize page - pictures/music etc RESIZEOPTION _ro; // resize setting we will use BOOL _fUsingTemporaryProviders; // temporary provider listed pull in, replace when we can BOOL _fRecomputeManifest; // recompute the manifest BOOL _fRepopulateProviders; // repopulate the providers list BOOL _fShownCustomLocation; // show the custom locaiton page BOOL _fShownUserName; // password page was shown BOOL _fValidating; // validating a server (Advanced path); BOOL _fCancelled; // operation was cancelled BOOL _fTransferComplete; // transfer completed. HWND _hwndSelector; // hwnd for the selector dialog HWND _hwndCopyingPage; int _iPercentageComplete; // % compelte of this transfer DWORD _dwTotal; DWORD _dwCompleted; int _cFiles; // maximum number of files int _iFile; // current file we are on HRESULT _hrFromTransfer; // result of the transfer performed HPROPSHEETPAGE _aWizPages[WIZPAGE_MAX]; // page handles for this wizard (so we can navigate) IPropertyBag *_ppb; // property bag object exposed from the site IWebWizardExtension *_pwwe; // host for the HTML wizard pages IResourceMap *_prm; // resource map object we create if we can't query from the host IXMLDOMDocument *_pdocProviders; // XML dom which exposes the providers CXMLDOMStateChange *_pdscProviders; // DOMStateChange for the provider list IXMLDOMDocument *_pdocManifest; // document describing the files to be transfered LPITEMIDLIST *_aItems; // array of items we copied UINT _cItems; IAutoComplete2 *_pac; // auto complete object IUnknown *_punkACLMulti; // IObjMgr object that exposes all the enumerators IACLCustomMRU *_pmru; // custom MRU for the objects we want to list CNetworkPlace _npCustom; // net place object for handling the custom entry HCURSOR _hCursor; IFolderView *_pfv; // file selector view object TCHAR _szFilter[MAX_PATH]; // filter string read from the registry static CPublishingWizard* s_GetPPW(HWND hwnd, UINT uMsg, LPARAM lParam); static int s_FreeStringProc(void* pFreeMe, void* pData); static HRESULT s_SetPropertyFromDisp(IPropertyBag *ppb, LPCWSTR pszID, IDispatch *pdsp); static DWORD CALLBACK s_ValidateThreadProc(void *pv); static int s_CompareItems(TRANSFERITEM *pti1, TRANSFERITEM *pti2, CPublishingWizard *ppw); static UINT s_SelectorPropPageProc(HWND hwndDlg, UINT uMsg, PROPSHEETPAGE *ppsp); static INT_PTR s_SelectorDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CPublishingWizard *ppw = s_GetPPW(hwnd, uMsg, lParam); return ppw->_SelectorDlgProc(hwnd, uMsg, wParam, lParam); } static INT_PTR s_FetchProvidersDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CPublishingWizard *ppw = s_GetPPW(hwnd, uMsg, lParam); return ppw->_FetchProvidersDlgProc(hwnd, uMsg, wParam, lParam); } static INT_PTR s_ProviderDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CPublishingWizard *ppw = s_GetPPW(hwnd, uMsg, lParam); return ppw->_ProviderDlgProc(hwnd, uMsg, wParam, lParam); } static INT_PTR s_ResizeDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CPublishingWizard *ppw = s_GetPPW(hwnd, uMsg, lParam); return ppw->_ResizeDlgProc(hwnd, uMsg, wParam, lParam); } static INT_PTR s_CopyDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CPublishingWizard *ppw = s_GetPPW(hwnd, uMsg, lParam); return ppw->_CopyDlgProc(hwnd, uMsg, wParam, lParam); } static INT_PTR s_LocationDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CPublishingWizard *ppw = s_GetPPW(hwnd, uMsg, lParam); return ppw->_LocationDlgProc(hwnd, uMsg, wParam, lParam); } static INT_PTR s_UserNameDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CPublishingWizard *ppw = s_GetPPW(hwnd, uMsg, lParam); return ppw->_UserNameDlgProc(hwnd, uMsg, wParam, lParam); } static INT_PTR s_FriendlyNameDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { CPublishingWizard *ppw = s_GetPPW(hwnd, uMsg, lParam); return ppw->_FriendlyNameDlgProc(hwnd, uMsg, wParam, lParam); } // these are used for publishing INT_PTR _SelectorDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); INT_PTR _FetchProvidersDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); INT_PTR _ProviderDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); INT_PTR _ResizeDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); INT_PTR _CopyDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); // these are used for ANP INT_PTR _LocationDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); INT_PTR _UserNameDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); INT_PTR _FriendlyNameDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam); void _FreeProviderList(); HRESULT _GetProviderKey(HKEY hkRoot, DWORD dwAccess, LPCTSTR pszSubKey, HKEY *phkResult); void _MapDlgItemText(HWND hwnd, UINT idc, LPCTSTR pszDlgID, LPCTSTR pszResourceID); HRESULT _GetResourceMap(IResourceMap **pprm); HRESULT _LoadMappedString(LPCTSTR pszDlgID, LPCTSTR pszResourceID, LPTSTR pszBuffer, int cch); HRESULT _CreateWizardPages(); INT_PTR _WizardNext(HWND hwnd, int iPage); HRESULT _AddExtenisonToList(HDPA hdpa, LPCTSTR pszExtension); HRESULT _InitPropertyBag(LPCTSTR pszURL); int _GetSelectedItem(HWND hwndList); void _GetDefaultProvider(LPTSTR pszProvider, int cch); void _SetDefaultProvider(IXMLDOMNode *pdn); HRESULT _FetchProviderList(HWND hwnd); HRESULT _MergeLocalProviders(); int _AddProvider(HWND hwnd, IXMLDOMNode *pdn); void _PopulateProviderList(HWND hwnd); void _ProviderEnableNext(HWND hwnd); void _ProviderGetDispInfo(LV_DISPINFO *plvdi); HRESULT _ProviderNext(HWND hwnd, HPROPSHEETPAGE *phPage); void _SetWaitCursor(BOOL bOn); void _ShowExampleTip(HWND hwnd); void _LocationChanged(HWND hwnd); void _UserNameChanged(HWND hwnd); DWORD _GetAutoCompleteFlags(DWORD dwFlags); HRESULT _InitAutoComplete(); void _InitLocation(HWND hwnd); HRESULT _AddCommonItemInfo(IXMLDOMNode *pdn, TRANSFERITEM *pti); HRESULT _AddTransferItem(CDPA *pdpaItems, IXMLDOMNode *pdn); HRESULT _AddPostItem(CDPA *pdpaItems, IXMLDOMNode *pdn); void _FreeTransferManifest(); HRESULT _AddFilesToManifest(IXMLDOMDocument *pdocManifest); HRESULT _BuildTransferManifest(); HRESULT _GetUniqueTypeList(BOOL fIncludeFolder, HDPA *phdpa); HRESULT _InitTransferInfo(IXMLDOMDocument *pdocManifest, TRANSFERINFO *pti, CDPA *pdpaItems); void _TryToValidateDestination(HWND hwnd); void _InitProvidersDialog(HWND hwnd); void _SetProgress(DWORD dwCompleted, DWORD dwTotal); BOOL _HasAttributes(IShellItem *psi, SFGAOF flags); HRESULT _BeginTransfer(HWND hwnd); HPROPSHEETPAGE _TransferComplete(HRESULT hrFromTransfer); void _FriendlyNameChanged(HWND hwnd); HRESULT _CreateFavorite(IXMLDOMNode *pdnUploadInfo); int _GetRemoteIcon(LPCTSTR pszID, BOOL fCanRefresh); HRESULT _GetSiteURL(LPTSTR pszBuffer, int cchBuffer, LPCTSTR pszFilenameToCombine); void _StateChanged(); void _ShowHideFetchProgress(HWND hwnd, BOOL fShow); void _FetchComplete(HWND hwnd, HRESULT hrFromFetch); HRESULT _GetProviderString(IXMLDOMNode *pdn, USHORT idPrimary, USHORT idSub, LPCTSTR pszID, LPTSTR pszBuffer, int cch); HRESULT _GetProviderString(IXMLDOMNode *pdn, LPCTSTR pszID, LPTSTR pszBuffer, int cch); HRESULT _GeoFromLocaleInfo(LCID lcid, GEOID *pgeoID); HRESULT _GetProviderListFilename(LPTSTR pszFile, int cchFile); }; // publishing wizard obj CPublishingWizard::CPublishingWizard() : _cRef(1), _fRecomputeManifest(TRUE), _hrFromTransfer(S_FALSE) { StrCpyN(_szProviderScope, DEFAULT_PROVIDER_SCOPE, ARRAYSIZE(_szProviderScope)); // fill the default provider scope DllAddRef(); } CPublishingWizard::~CPublishingWizard() { if (_pwwe) { IUnknown_SetSite(_pwwe, NULL); _pwwe->Release(); } ATOMICRELEASE(_pdo); ATOMICRELEASE(_pdoSelection); ATOMICRELEASE(_prm); _FreeProviderList(); _FreeTransferManifest(); DllRelease(); } ULONG CPublishingWizard::AddRef() { return InterlockedIncrement(&_cRef); } ULONG CPublishingWizard::Release() { if (InterlockedDecrement(&_cRef)) return _cRef; delete this; return 0; } HRESULT CPublishingWizard::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(CPublishingWizard, IWizardSite), // IID_IWizardSite QITABENT(CPublishingWizard, IObjectWithSite), // IID_IObjectWithSite QITABENT(CPublishingWizard, IServiceProvider), // IID_IServiceProvider QITABENT(CPublishingWizard, IPublishingWizard), // IID_IPublishingWizard QITABENT(CPublishingWizard, ITransferAdviseSink), // IID_ITransferAdviseSink QITABENTMULTI(CPublishingWizard, IQueryContinue, ITransferAdviseSink), // IID_IQueryContinue QITABENT(CPublishingWizard, IOleWindow), // IID_IOleWindow QITABENT(CPublishingWizard, ICommDlgBrowser), // IID_ICommDlgBrowser {0, 0 }, }; return QISearch(this, qit, riid, ppv); } STDAPI CPublishingWizard_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi) { CPublishingWizard *pwiz = new CPublishingWizard(); if (!pwiz) { *ppunk = NULL; // incase of failure return E_OUTOFMEMORY; } HRESULT hr = pwiz->QueryInterface(IID_PPV_ARG(IUnknown, ppunk)); pwiz->Release(); return hr; } // IPublishingWizard methods HRESULT CPublishingWizard::Initialize(IDataObject *pdo, DWORD dwOptions, LPCTSTR pszServiceProvider) { IUnknown_Set((IUnknown**)&_pdo, pdo); IUnknown_Set((IUnknown**)&_pdoSelection, NULL); _dwFlags = dwOptions; _fRecomputeManifest = TRUE; // _fRepopulateProviders set when manifest rebuilt if (!pszServiceProvider) pszServiceProvider = DEFAULT_PROVIDER_SCOPE; StrCpyN(_szProviderScope, pszServiceProvider, ARRAYSIZE(_szProviderScope)); return S_OK; } HRESULT CPublishingWizard::GetTransferManifest(HRESULT *phrFromTransfer, IXMLDOMDocument **ppdocManifest) { HRESULT hr = E_UNEXPECTED; if (_ppb) { if (phrFromTransfer) *phrFromTransfer = _hrFromTransfer; if (ppdocManifest) { VARIANT var = {VT_DISPATCH}; hr = _ppb->Read(PROPERTY_TRANSFERMANIFEST, &var, NULL); if (SUCCEEDED(hr)) { hr = var.pdispVal->QueryInterface(IID_PPV_ARG(IXMLDOMDocument, ppdocManifest)); VariantClear(&var); } } else { hr = S_OK; } } return hr; } // Wizard site methods STDMETHODIMP CPublishingWizard::GetPreviousPage(HPROPSHEETPAGE *phPage) { *phPage = _aWizPages[WIZPAGE_FETCHINGPROVIDERS]; return S_OK; } STDMETHODIMP CPublishingWizard::GetNextPage(HPROPSHEETPAGE *phPage) { // lets get the next page we'd need to show if all else fails. IWizardSite *pws; HRESULT hr = _punkSite->QueryInterface(IID_PPV_ARG(IWizardSite, &pws)); if (SUCCEEDED(hr)) { hr = pws->GetNextPage(phPage); pws->Release(); } // if we have not transfered and we have a IDataObject then we should // advance to one of the special pages we are supposed to show. if (!_fTransferComplete && _pdo) { *phPage = _aWizPages[_fOfferResize ? WIZPAGE_RESIZE:WIZPAGE_COPYING]; } return hr; } STDMETHODIMP CPublishingWizard::GetCancelledPage(HPROPSHEETPAGE *phPage) { HRESULT hr = E_NOTIMPL; if (!_fTransferComplete) { *phPage = _TransferComplete(HRESULT_FROM_WIN32(ERROR_CANCELLED)); if (*phPage) hr = S_OK; } else { IWizardSite *pws; hr = _punkSite->QueryInterface(IID_PPV_ARG(IWizardSite, &pws)); if (SUCCEEDED(hr)) { hr = pws->GetCancelledPage(phPage); pws->Release(); } } return hr; } // Service provider object STDMETHODIMP CPublishingWizard::QueryService(REFGUID guidService, REFIID riid, void **ppv) { if (guidService == SID_WebWizardHost) { if (riid == IID_IPropertyBag) { return _ppb->QueryInterface(riid, ppv); } } else if (guidService == SID_SCommDlgBrowser) { return this->QueryInterface(riid, ppv); } else if (_punkSite) { return IUnknown_QueryService(_punkSite, guidService, riid, ppv); } return E_FAIL; } // IWizardExtension methods HRESULT CPublishingWizard::_CreateWizardPages() { const struct { LPCTSTR pszID; int idPage; DLGPROC dlgproc; UINT idsHeading; UINT idsSubHeading; LPFNPSPCALLBACK pfnCallback; } _wp[] = { {TEXT("wp:selector"), IDD_PUB_SELECTOR, CPublishingWizard::s_SelectorDlgProc, IDS_PUB_SELECTOR, IDS_PUB_SELECTOR_SUB, NULL}, {TEXT("wp:fetching"), IDD_PUB_FETCHPROVIDERS, CPublishingWizard::s_FetchProvidersDlgProc, IDS_PUB_FETCHINGPROVIDERS, IDS_PUB_FETCHINGPROVIDERS_SUB, CPublishingWizard::s_SelectorPropPageProc}, {TEXT("wp:destination"), IDD_PUB_DESTINATION, CPublishingWizard::s_ProviderDlgProc, IDS_PUB_DESTINATION, IDS_PUB_DESTINATION_SUB, NULL}, {TEXT("wp:resize"), IDD_PUB_RESIZE, CPublishingWizard::s_ResizeDlgProc, IDS_PUB_RESIZE, IDS_PUB_RESIZE_SUB, NULL}, {TEXT("wp:copying"), IDD_PUB_COPY, CPublishingWizard::s_CopyDlgProc, IDS_PUB_COPY, IDS_PUB_COPY_SUB, NULL}, {TEXT("wp:location"), IDD_PUB_LOCATION, CPublishingWizard::s_LocationDlgProc, IDS_PUB_LOCATION, IDS_PUB_LOCATION_SUB, NULL}, {TEXT("wp:ftppassword"), IDD_PUB_FTPPASSWORD, CPublishingWizard::s_UserNameDlgProc, IDS_PUB_FTPPASSWORD, IDS_PUB_FTPPASSWORD_SUB, NULL}, {TEXT("wp:friendlyname"),IDD_ANP_FRIENDLYNAME, CPublishingWizard::s_FriendlyNameDlgProc, IDS_ANP_FRIENDLYNAME, IDS_ANP_FRIENDLYNAME_SUB, NULL}, }; // if we haven't created the pages yet, then lets initialize our array of handlers. HRESULT hr = S_OK; if (!_aWizPages[0]) { INITCOMMONCONTROLSEX iccex = { 0 }; iccex.dwSize = sizeof (iccex); iccex.dwICC = ICC_LISTVIEW_CLASSES | ICC_PROGRESS_CLASS | ICC_LINK_CLASS; InitCommonControlsEx(&iccex); LinkWindow_RegisterClass(); // we will use the link window (can this be removed) for (int i = 0; SUCCEEDED(hr) && (i < ARRAYSIZE(_wp)) ; i++ ) { TCHAR szHeading[MAX_PATH], szSubHeading[MAX_PATH]; // if we have a resource map then load the heading and sub heading text // if there is no resource map from the parent object then we must default // the strings. IResourceMap *prm; hr = _GetResourceMap(&prm); if (SUCCEEDED(hr)) { IXMLDOMNode *pdn; hr = prm->SelectResourceScope(TEXT("dialog"), _wp[i].pszID, &pdn); if (SUCCEEDED(hr)) { prm->LoadString(pdn, L"heading", szHeading, ARRAYSIZE(szHeading)); prm->LoadString(pdn, L"subheading", szSubHeading, ARRAYSIZE(szSubHeading)); pdn->Release(); } prm->Release(); } if (FAILED(hr)) { LoadString(g_hinst, _wp[i].idsHeading, szHeading, ARRAYSIZE(szHeading)); LoadString(g_hinst, _wp[i].idsSubHeading, szSubHeading, ARRAYSIZE(szSubHeading)); } // lets create the page now that we have loaded the relevant strings, more mapping // will occur later (during dialog initialization) PROPSHEETPAGE psp = { 0 }; psp.dwSize = SIZEOF(PROPSHEETPAGE); psp.hInstance = g_hinst; psp.lParam = (LPARAM)this; psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE; psp.pszTemplate = MAKEINTRESOURCE(_wp[i].idPage); psp.pfnDlgProc = _wp[i].dlgproc; psp.pszHeaderTitle = szHeading; psp.pszHeaderSubTitle = szSubHeading; if (_wp[i].pfnCallback) { psp.dwFlags |= PSP_USECALLBACK; psp.pfnCallback = _wp[i].pfnCallback; } _aWizPages[i] = CreatePropertySheetPage(&psp); hr = _aWizPages[i] ? S_OK:E_FAIL; } } return hr; } STDMETHODIMP CPublishingWizard::AddPages(HPROPSHEETPAGE* aPages, UINT cPages, UINT *pnPages) { // create our pages and then copy the handles to the buffer HRESULT hr = _CreateWizardPages(); if (SUCCEEDED(hr)) { for (int i = 0; i < ARRAYSIZE(_aWizPages); i++) { aPages[i] = _aWizPages[i]; } // we also leverage the HTML host for showing pages from the sites we are // interacting with. hr = CoCreateInstance(CLSID_WebWizardHost, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IWebWizardExtension, &_pwwe)); if (SUCCEEDED(hr)) { // NOTE: this site should be broken into a seperate object so we avoid any circular reference issues // NOTE: there is code in websvc.cpp that attempts to break this by listening for the page // NOTE: destruction and then releasing its site. IUnknown_SetSite(_pwwe, (IObjectWithSite*)this); UINT nPages; if (SUCCEEDED(_pwwe->AddPages(&aPages[i], cPages-i, &nPages))) { i += nPages; } } *pnPages = i; // the number of pages we added } return hr; } // navigation pages STDMETHODIMP CPublishingWizard::GetFirstPage(HPROPSHEETPAGE *phPage) { if (_dwFlags & SHPWHF_NOFILESELECTOR) { *phPage = _aWizPages[WIZPAGE_FETCHINGPROVIDERS]; } else { *phPage = _aWizPages[WIZPAGE_WHICHFILE]; } return S_OK; } STDMETHODIMP CPublishingWizard::GetLastPage(HPROPSHEETPAGE *phPage) { if (_fShownCustomLocation) { *phPage = _aWizPages[WIZPAGE_FRIENDLYNAME]; } else { *phPage = _aWizPages[WIZPAGE_FETCHINGPROVIDERS]; } return S_OK; } // computer this pointers for the page objects CPublishingWizard* CPublishingWizard::s_GetPPW(HWND hwnd, UINT uMsg, LPARAM lParam) { if (uMsg == WM_INITDIALOG) { PROPSHEETPAGE *ppsp = (PROPSHEETPAGE*)lParam; SetWindowLongPtr(hwnd, GWLP_USERDATA, ppsp->lParam); return (CPublishingWizard*)ppsp->lParam; } return (CPublishingWizard*)GetWindowLongPtr(hwnd, GWLP_USERDATA); } // initialize a property in the property bag from an IUnknown pointer. HRESULT CPublishingWizard::s_SetPropertyFromDisp(IPropertyBag *ppb, LPCWSTR pszID, IDispatch *pdsp) { VARIANT var = { VT_DISPATCH }; HRESULT hr = pdsp->QueryInterface(IID_PPV_ARG(IDispatch, &var.pdispVal)); if (SUCCEEDED(hr)) { hr = ppb->Write(pszID, &var); VariantClear(&var); } return hr; } // get the resource map from the site, if we can get it then us it, otherwise // we need to load the resouce map local to this DLL. HRESULT CPublishingWizard::_GetResourceMap(IResourceMap **pprm) { HRESULT hr = IUnknown_QueryService(_punkSite, SID_ResourceMap, IID_PPV_ARG(IResourceMap, pprm)); if (FAILED(hr)) { if (!_prm) { hr = CResourceMap_Initialize(L"res://netplwiz.dll/xml/resourcemap.xml", &_prm); if (SUCCEEDED(hr)) { hr = _prm->LoadResourceMap(TEXT("wizard"), _szProviderScope); if (SUCCEEDED(hr)) { hr = _prm->QueryInterface(IID_PPV_ARG(IResourceMap, pprm)); } } } else { hr = _prm->QueryInterface(IID_PPV_ARG(IResourceMap, pprm)); } } return hr; } // handle loading resource map strings HRESULT CPublishingWizard::_LoadMappedString(LPCTSTR pszDlgID, LPCTSTR pszResourceID, LPTSTR pszBuffer, int cch) { IResourceMap *prm; HRESULT hr = _GetResourceMap(&prm); if (SUCCEEDED(hr)) { IXMLDOMNode *pdn; hr = prm->SelectResourceScope(TEXT("dialog"), pszDlgID, &pdn); if (SUCCEEDED(hr)) { hr = prm->LoadString(pdn, pszResourceID, pszBuffer, cch); pdn->Release(); } prm->Release(); } return hr; } void CPublishingWizard::_MapDlgItemText(HWND hwnd, UINT idc, LPCTSTR pszDlgID, LPCTSTR pszResourceID) { TCHAR szBuffer[MAX_PATH]; if (SUCCEEDED(_LoadMappedString(pszDlgID, pszResourceID, szBuffer, ARRAYSIZE(szBuffer)))) { SetDlgItemText(hwnd, idc, szBuffer); } } // Set the wizard next (index to hpage translation) INT_PTR CPublishingWizard::_WizardNext(HWND hwnd, int iPage) { PropSheet_SetCurSel(GetParent(hwnd), _aWizPages[iPage], -1); SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LPARAM)-1); return TRUE; } // get a provider key from the registry HRESULT CPublishingWizard::_GetProviderKey(HKEY hkBase, DWORD dwAccess, LPCTSTR pszSubKey, HKEY *phkResult) { TCHAR szBuffer[MAX_PATH]; wnsprintf(szBuffer, ARRAYSIZE(szBuffer), (SZ_REGKEY_PUBWIZ TEXT("\\%s")), _szProviderScope); if (pszSubKey) { StrCatBuff(szBuffer, TEXT("\\"), ARRAYSIZE(szBuffer)); StrCatBuff(szBuffer, pszSubKey, ARRAYSIZE(szBuffer)); } DWORD dwResult = RegOpenKeyEx(hkBase, szBuffer, 0, dwAccess, phkResult); if ((dwResult != ERROR_SUCCESS) && (dwAccess != KEY_READ)) { dwResult = RegCreateKey(hkBase, szBuffer, phkResult); } return (ERROR_SUCCESS == dwResult) ? S_OK:E_FAIL; } // compute the site URL based on the stored information we have HRESULT CPublishingWizard::_GetSiteURL(LPTSTR pszBuffer, int cchBuffer, LPCTSTR pszFilenameToCombine) { DWORD cch = cchBuffer; return UrlCombine(TEXT("http://shell.windows.com/publishwizard/"), pszFilenameToCombine, pszBuffer, &cch, 0); } // get the data object from the site that we have CLIPFORMAT g_cfHIDA = 0; void InitClipboardFormats() { if (g_cfHIDA == 0) g_cfHIDA = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_SHELLIDLIST); } // DPA helpers for comparing and destroying a TRANSFERITEM structure int CALLBACK CPublishingWizard::s_CompareItems(TRANSFERITEM *pti1, TRANSFERITEM *pti2, CPublishingWizard *ppw) { return StrCmpI(pti1->szFilename, pti2->szFilename); } int _FreeFormData(FORMDATA *pfd, void *pvState) { VariantClear(&pfd->varName); VariantClear(&pfd->varValue); return 1; } int _FreeTransferItems(TRANSFERITEM *pti, void *pvState) { ILFree(pti->pidl); if (pti->psi) pti->psi->Release(); if (pti->pstrm) pti->pstrm->Release(); if (pti->dsaFormData != NULL) pti->dsaFormData.DestroyCallback(_FreeFormData, NULL); LocalFree(pti); return 1; } HRESULT CPublishingWizard::_AddCommonItemInfo(IXMLDOMNode *pdn, TRANSFERITEM *pti) { // default to the user selected resize (this will only be set if // we are using the Web Publishing Wizard). if (_ro != RESIZE_NONE) { pti->fResizeOnUpload = TRUE; pti->cxResize = _aResizeSettings[_ro].cx; pti->cyResize = _aResizeSettings[_ro].cy; pti->iQuality = _aResizeSettings[_ro].iQuality; } // give the site ultimate control over the resizing that is performed, // by checking for the element in the manifest. IXMLDOMNode *pdnResize; HRESULT hr = pdn->selectSingleNode(ELEMENT_RESIZE, &pdnResize); if (hr == S_OK) { int cx, cy, iQuality; hr = GetIntFromAttribute(pdnResize, ATTRIBUTE_CX, &cx); if (SUCCEEDED(hr)) hr = GetIntFromAttribute(pdnResize, ATTRIBUTE_CY, &cy); if (SUCCEEDED(hr)) hr = GetIntFromAttribute(pdnResize, ATTRIBUTE_QUALITY, &iQuality); if (SUCCEEDED(hr)) { pti->fResizeOnUpload = TRUE; pti->cxResize = cx; pti->cyResize = cy; pti->iQuality = iQuality; } pdnResize->Release(); } return S_OK; } HRESULT CPublishingWizard::_AddTransferItem(CDPA *pdpaItems, IXMLDOMNode *pdn) { HRESULT hr = E_OUTOFMEMORY; TRANSFERITEM *pti = (TRANSFERITEM*)LocalAlloc(LPTR, sizeof(*pti)); if (pti) { // copy the destination hr = GetStrFromAttribute(pdn, ATTRIBUTE_DESTINATION, pti->szFilename, ARRAYSIZE(pti->szFilename)); // copy the source IDList - read the index and use that if (SUCCEEDED(hr)) { int iItem; hr = GetIntFromAttribute(pdn, ATTRIBUTE_ID, &iItem); if (SUCCEEDED(hr)) { hr = SHILClone(_aItems[iItem], &pti->pidl); } } // lets add the common transfer item info if (SUCCEEDED(hr)) hr = _AddCommonItemInfo(pdn, pti); // if we have a structure then lets append it to the DPA if (SUCCEEDED(hr)) hr = (-1 == pdpaItems->AppendPtr(pti)) ? E_OUTOFMEMORY:S_OK; // failed if (FAILED(hr)) { _FreeTransferItems(pti); } } return hr; } HRESULT CPublishingWizard::_AddPostItem(CDPA *pdpaItems, IXMLDOMNode *pdn) { HRESULT hr = E_OUTOFMEMORY; TRANSFERITEM *pti = (TRANSFERITEM*)LocalAlloc(LPTR, sizeof(*pti)); if (pti) { // get the post data, from thiswe can work out how to post the data IXMLDOMNode *pdnPostData; if (pdn->selectSingleNode(ELEMENT_POSTDATA, &pdnPostData) == S_OK) { // we must have a HREF for the post value hr = GetStrFromAttribute(pdnPostData, ATTRIBUTE_HREF, pti->szURL, ARRAYSIZE(pti->szURL)); if (SUCCEEDED(hr)) { // we must be able to get a posting name from the element hr = GetStrFromAttribute(pdnPostData, ATTRIBUTE_NAME, pti->szName, ARRAYSIZE(pti->szName)); if (SUCCEEDED(hr)) { // lets get the posting name, we get that from the filename attribute, if that // is not defined then try and compute it from the source information // if that isn't defined the use the name attribute they gave us earlier. if (FAILED(GetStrFromAttribute(pdnPostData, ATTRIBUTE_FILENAME, pti->szFilename, ARRAYSIZE(pti->szFilename)))) { TCHAR szSource[MAX_PATH]; if (SUCCEEDED(GetStrFromAttribute(pdn, ATTRIBUTE_SOURCE, szSource, ARRAYSIZE(szSource)))) { StrCpyN(pti->szFilename, PathFindFileName(szSource), ARRAYSIZE(pti->szFilename)); } else { StrCpyN(pti->szFilename, pti->szName, ARRAYSIZE(pti->szFilename)); } } // lets get the verb we should be using (and default accordingly), therefore // we can ignore the result. StrCpyN(pti->szVerb, TEXT("POST"), ARRAYSIZE(pti->szVerb)); GetStrFromAttribute(pdnPostData, ATTRIBUTE_VERB, pti->szVerb, ARRAYSIZE(pti->szVerb)); // pick up the IDLIST for the item int iItem; hr = GetIntFromAttribute(pdn, ATTRIBUTE_ID, &iItem); if (SUCCEEDED(hr)) { hr = SHILClone(_aItems[iItem], &pti->pidl); } // do we have any form data that needs to be passed to the transfer engine // and therefore to the site. if so lets package it up now. IXMLDOMNodeList *pnl; if (SUCCEEDED(hr) && (S_OK == pdnPostData->selectNodes(ELEMENT_FORMDATA, &pnl))) { hr = pti->dsaFormData.Create(4) ? S_OK:E_FAIL; if (SUCCEEDED(hr)) { // walk the selection filling the DSA, each structure contains // two VARIANTs which we can push across to the bg thread describing the // form data we want the site to receive. long cSelection; hr = pnl->get_length(&cSelection); for (long lNode = 0; SUCCEEDED(hr) && (lNode != cSelection); lNode++) { IXMLDOMNode *pdnFormData; hr = pnl->get_item(lNode, &pdnFormData); if (SUCCEEDED(hr)) { FORMDATA fd = {0}; hr = pdnFormData->get_nodeTypedValue(&fd.varValue); if (SUCCEEDED(hr)) { IXMLDOMElement *pdelFormData; hr = pdnFormData->QueryInterface(IID_PPV_ARG(IXMLDOMElement, &pdelFormData)); if (SUCCEEDED(hr)) { hr = pdelFormData->getAttribute(ATTRIBUTE_NAME, &fd.varName); if (SUCCEEDED(hr)) { hr = (-1 == pti->dsaFormData.AppendItem(&fd)) ? E_FAIL:S_OK; } pdelFormData->Release(); } } // failed to fully create the form data, so lets release if (FAILED(hr)) _FreeFormData(&fd, NULL); pdnFormData->Release(); } } pnl->Release(); } } } } } else { hr = E_FAIL; } // lets add the common transfer item info if (SUCCEEDED(hr)) hr = _AddCommonItemInfo(pdn, pti); // if we have a structure then lets append it to the DPA if (SUCCEEDED(hr)) hr = (-1 == pdpaItems->AppendPtr(pti)) ? E_OUTOFMEMORY:S_OK; // failed if (FAILED(hr)) _FreeTransferItems(pti); } return hr; } HRESULT CPublishingWizard::_InitTransferInfo(IXMLDOMDocument *pdocManifest, TRANSFERINFO *pti, CDPA *pdpaItems) { // pull the destination and shortcut information from the manifest into the // transfer info structure. IXMLDOMNode *pdn; HRESULT hr = pdocManifest->selectSingleNode(XPATH_UPLOADINFO, &pdn); if (SUCCEEDED(hr)) { if (hr == S_OK) { // get the friendly name for the site, this is stored in the upload information, this can fail. if (FAILED(GetStrFromAttribute(pdn, ATTRIBUTE_FRIENDLYNAME, pti->szSiteName, ARRAYSIZE(pti->szSiteName)))) { // B2: handle this so that MSN still works, we moved the friendly name attribute to // a to the element, however they were locked down and couldn't take // that change, therefore ensure that we pick this up from its previous location. IXMLDOMNode *pdnTarget; if (S_OK == pdn->selectSingleNode(ELEMENT_TARGET, &pdnTarget)) { GetStrFromAttribute(pdnTarget, ATTRIBUTE_FRIENDLYNAME, pti->szSiteName, ARRAYSIZE(pti->szSiteName)); pdnTarget->Release(); } } // from the manifest lets read the file location and then the net place creation information // this is then placed into the transfer info strucuture which we used on the bg thread // to both upload the files and also create a net place. if (FAILED(GetURLFromElement(pdn, ELEMENT_TARGET, pti->szFileTarget, ARRAYSIZE(pti->szFileTarget)))) { pti->fUsePost = TRUE; // if we don't get the target string then we are posting } // we have the target for upload to, then lets pick up the optional information about // the site, and the net place. if (SUCCEEDED(GetURLFromElement(pdn, ELEMENT_NETPLACE, pti->szLinkTarget, ARRAYSIZE(pti->szLinkTarget)))) { IXMLDOMNode *pdnNetPlace; if (pdn->selectSingleNode(ELEMENT_NETPLACE, &pdnNetPlace) == S_OK) { GetStrFromAttribute(pdnNetPlace, ATTRIBUTE_FILENAME, pti->szLinkName, ARRAYSIZE(pti->szLinkName)); GetStrFromAttribute(pdnNetPlace, ATTRIBUTE_COMMENT, pti->szLinkDesc, ARRAYSIZE(pti->szLinkDesc)); pdnNetPlace->Release(); } // fix up the site name from the link description if its not defined. if (!pti->szSiteName[0] && pti->szLinkDesc) { StrCpyN(pti->szSiteName, pti->szLinkDesc, ARRAYSIZE(pti->szSiteName)); } } // get the site URL GetURLFromElement(pdn, ELEMENT_HTMLUI, pti->szSiteURL, ARRAYSIZE(pti->szSiteURL)); } else { hr = E_FAIL; } } // if they want a DPA of items then lets create them one, this is also based on the manifest. if (SUCCEEDED(hr) && pdpaItems) { hr = (pdpaItems->Create(16)) ? S_OK:E_OUTOFMEMORY; if (SUCCEEDED(hr)) { IXMLDOMNodeList *pnl; hr = pdocManifest->selectNodes(XPATH_ALLFILESTOUPLOAD, &pnl); if (hr == S_OK) { long cSelection; hr = pnl->get_length(&cSelection); for (long lNode = 0; SUCCEEDED(hr) && (lNode != cSelection); lNode++) { IXMLDOMNode *pdn; hr = pnl->get_item(lNode, &pdn); if (SUCCEEDED(hr)) { if (pti->fUsePost) hr = _AddPostItem(pdpaItems, pdn); else hr = _AddTransferItem(pdpaItems, pdn); pdn->Release(); } } pnl->Release(); } // if we are *NOT* posting then sort the DPA so that we can support // enum items correctly. if (!pti->fUsePost) { pdpaItems->SortEx(s_CompareItems, this); // sort the DPA so we can search better } } } return hr; } // File selector dialog HRESULT CPublishingWizard::IncludeObject(IShellView *ppshv, LPCITEMIDLIST pidl) { BOOL fInclude = FALSE; LPITEMIDLIST pidlFolder; HRESULT hr = SHGetIDListFromUnk(ppshv, &pidlFolder); if (SUCCEEDED(hr)) { IShellFolder *psf; hr = SHBindToObject(NULL, IID_X_PPV_ARG(IShellFolder, pidlFolder, &psf)); if (SUCCEEDED(hr)) { // cannot publish folders, but can publish ZIP files (which are both folder and stream at the same time) if (!(SHGetAttributes(psf, pidl, SFGAO_FOLDER | SFGAO_STREAM) == SFGAO_FOLDER)) { // filter based on the content type if we are given a filter string if (_szFilter[0]) { TCHAR szBuffer[MAX_PATH]; hr = DisplayNameOf(psf, pidl, SHGDN_FORPARSING, szBuffer, ARRAYSIZE(szBuffer)); if (SUCCEEDED(hr)) { TCHAR szContentType[MAX_PATH]; DWORD cch = ARRAYSIZE(szContentType); hr = AssocQueryString(0, ASSOCSTR_CONTENTTYPE, szBuffer, NULL, szContentType, &cch); fInclude = SUCCEEDED(hr) && PathMatchSpec(szContentType, _szFilter); } } else { fInclude = TRUE; } } psf->Release(); } ILFree(pidlFolder); } return fInclude ? S_OK:S_FALSE; } // handle the state changing in the dialog and therefore us updating the buttons & status void CPublishingWizard::_StateChanged() { int cItemsChecked = 0; int cItems = 0; if (_pfv) { _pfv->ItemCount(SVGIO_ALLVIEW, &cItems); _pfv->ItemCount(SVGIO_CHECKED, &cItemsChecked); } // format and display the status bar for this item TCHAR szFmt[MAX_PATH]; if (FAILED(_LoadMappedString(L"wp:selector", L"countfmt", szFmt, ARRAYSIZE(szFmt)))) { LoadString(g_hinst, IDS_PUB_SELECTOR_FMT, szFmt, ARRAYSIZE(szFmt)); } TCHAR szBuffer[MAX_PATH]; FormatMessageTemplate(szFmt, szBuffer, ARRAYSIZE(szBuffer), cItemsChecked, cItems); SetDlgItemText(_hwndSelector, IDC_PUB_SELECTORSTATUS, szBuffer); // ensure that Next is only enabled when we have checked some items in the view PropSheet_SetWizButtons(GetParent(_hwndSelector), ((cItemsChecked > 0) ? PSWIZB_NEXT:0) | PSWIZB_BACK); } HRESULT CPublishingWizard::OnStateChange(IShellView *pshv, ULONG uChange) { if (uChange == CDBOSC_STATECHANGE) { _StateChanged(); _fRecomputeManifest = TRUE; } return S_OK; } UINT CPublishingWizard::s_SelectorPropPageProc(HWND hwndDlg, UINT uMsg, PROPSHEETPAGE *ppsp) { CPublishingWizard *ppw = (CPublishingWizard*)ppsp->lParam; switch (uMsg) { case PSPCB_CREATE: return TRUE; // we are cleaning up the page, lets ensure that we release file view object // if we have one. that way our reference count correctly reflects our state // rather than us ending up with a circular reference to other objects case PSPCB_RELEASE: if (ppw->_pfv) { IUnknown_SetSite(ppw->_pfv, NULL); ATOMICRELEASE(ppw->_pfv); } break; } return FALSE; } INT_PTR CPublishingWizard::_SelectorDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_INITDIALOG: { _hwndSelector = hwnd; // lets read the default state for this provider from a key in the registry // this will define the types of files we are going to allow, the format is // a spec (eg. image/* means all images), each element can be seperated by a ; HKEY hkProvider; HRESULT hr = _GetProviderKey(HKEY_LOCAL_MACHINE, KEY_READ, NULL, &hkProvider); if (SUCCEEDED(hr)) { DWORD cbFilter = sizeof(TCHAR)*ARRAYSIZE(_szFilter); SHGetValue(hkProvider, NULL, SZ_REGVAL_FILEFILTER, NULL, _szFilter, &cbFilter); RegCloseKey(hkProvider); } // create the file picker object, align with the hidden control on the window // and initialize with the IDataObject which contains the selection. hr = CoCreateInstance(CLSID_FolderViewHost, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IFolderView, &_pfv)); if (SUCCEEDED(hr)) { IUnknown_SetSite(_pfv, (IObjectWithSite*)this); IFolderViewHost *pfvh; hr = _pfv->QueryInterface(IID_PPV_ARG(IFolderViewHost, &pfvh)); if (SUCCEEDED(hr)) { RECT rc; GetWindowRect(GetDlgItem(hwnd, IDC_PUB_SELECTOR), &rc); MapWindowRect(HWND_DESKTOP, hwnd, &rc); InitClipboardFormats(); // initialize walks data object hr = pfvh->Initialize(hwnd, _pdo, &rc); if (SUCCEEDED(hr)) { HWND hwndPicker; hr = IUnknown_GetWindow(_pfv, &hwndPicker); if (SUCCEEDED(hr)) { SetWindowPos(hwndPicker, HWND_TOP, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE); } } pfvh->Release(); } if (FAILED(hr)) { ATOMICRELEASE(_pfv); } } return TRUE; } case WM_COMMAND: { if (HIWORD(wParam) == BN_CLICKED) { switch (LOWORD(wParam)) { case IDC_PUB_ALL: case IDC_PUB_NOTHING: if (_pfv) { int cItems; HRESULT hr = _pfv->ItemCount(SVGIO_ALLVIEW, &cItems); for (int iItem = 0; SUCCEEDED(hr) && (iItem != cItems); iItem++) { BOOL fSelect = (LOWORD(wParam) == IDC_PUB_ALL); hr = _pfv->SelectItem(iItem, SVSI_NOSTATECHANGE | (fSelect ? SVSI_CHECK:0)); } break; } } break; } } case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR)lParam; switch (pnmh->code) { case PSN_SETACTIVE: { if (_pfv) { _StateChanged(); PostMessage(hwnd, WM_APP, 0, 0); } else { // no IFolderView, so lets skip this page. int i = PropSheet_PageToIndex(GetParent(hwnd), _aWizPages[WIZPAGE_FETCHINGPROVIDERS]); SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LPARAM)PropSheet_IndexToId(GetParent(hwnd), i)); } return TRUE; } case PSN_WIZNEXT: { if (_fRecomputeManifest && _pfv) { IDataObject *pdo; HRESULT hr = _pfv->Items(SVGIO_CHECKED, IID_PPV_ARG(IDataObject, &pdo)); if (SUCCEEDED(hr)) { IUnknown_Set((IUnknown**)&_pdoSelection, pdo); pdo->Release(); } } return _WizardNext(hwnd, WIZPAGE_FETCHINGPROVIDERS); } case PSN_WIZBACK: { if (_punkSite) { IWizardSite *pws; if (SUCCEEDED(_punkSite->QueryInterface(IID_PPV_ARG(IWizardSite, &pws)))) { HPROPSHEETPAGE hpage; if (SUCCEEDED(pws->GetPreviousPage(&hpage))) { PropSheet_SetCurSel(GetParent(hwnd), hpage, -1); } pws->Release(); } } SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LPARAM)-1); return TRUE; } } break; } // this is to work around the issue where defview (listview) forces a redraw of itself // in a non-async way when it receives a SetFocus, therefore causing it to render // incorrectly in the wizard frame. to fix this we post ourselves a WM_APP during the // handle of PSN_SETACTIVE, and then turn around and call RedrawWindow. case WM_APP: { HWND hwndPicker; if (SUCCEEDED(IUnknown_GetWindow(_pfv, &hwndPicker))) { RedrawWindow(hwndPicker, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN); } break; } } return FALSE; } // tidy up and release the providers list void CPublishingWizard::_FreeProviderList() { if (_pdscProviders) _pdscProviders->Advise(FALSE); IUnknown_Set((IUnknown**)&_pdscProviders, NULL); IUnknown_Set((IUnknown**)&_pdocProviders, NULL); // discard the previous providers. } // begin a download of the provider list, we pull the providers list async from the server // therefore we need to register a state change monitor so that we can pull the information // dynamically and then receive a message to merge in our extra data. #define FETCH_TIMERID 1 #define FETCH_TIMEOUT 1000 HRESULT CPublishingWizard::_GeoFromLocaleInfo(LCID lcid, GEOID *pgeoID) { TCHAR szBuf[128] = {0}; if (GetLocaleInfo(lcid, LOCALE_IGEOID | LOCALE_RETURN_NUMBER, szBuf, ARRAYSIZE(szBuf)) > 0) { *pgeoID = *((LPDWORD)szBuf); return S_OK; } return E_FAIL; } HRESULT CPublishingWizard::_GetProviderListFilename(LPTSTR pszFile, int cchFile) { HRESULT hr = S_OK; GEOID idGEO = GetUserGeoID(GEOCLASS_NATION); if (idGEO == GEOID_NOT_AVAILABLE) { hr = _GeoFromLocaleInfo(GetUserDefaultLCID(), &idGEO); if (FAILED(hr)) hr = _GeoFromLocaleInfo(GetSystemDefaultLCID(), &idGEO); if (FAILED(hr)) hr = _GeoFromLocaleInfo((MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)), &idGEO); // default to US English } if (SUCCEEDED(hr) && (idGEO != GEOID_NOT_AVAILABLE)) { // read the provider prefix from the registry int cchProvider = 0; DWORD cbFile = sizeof(TCHAR)*cchFile; if (ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, SZ_REGKEY_PUBWIZ, SZ_REGVAL_SERVICEPARTNERID, NULL, pszFile, &cbFile)) { StrCatBuff(pszFile, TEXT("."), cchFile); cchProvider = lstrlen(pszFile); } // build .xml into the buffer (as a suffix of the partner if needed) GetGeoInfo(idGEO, GEO_ISO3, pszFile + cchProvider, cchFile - cchProvider, 0); StrCatBuff(pszFile, TEXT(".xml"), cchFile); CharLowerBuff(pszFile, lstrlen(pszFile)); } else if (SUCCEEDED(hr)) { hr = E_FAIL; } return hr; } HRESULT CPublishingWizard::_FetchProviderList(HWND hwnd) { _FreeProviderList(); HRESULT hr = CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IXMLDOMDocument, &_pdocProviders)); if (SUCCEEDED(hr)) { TCHAR szFile[MAX_PATH]; hr = _GetProviderListFilename(szFile, ARRAYSIZE(szFile)); if (SUCCEEDED(hr)) { TCHAR szBuffer[INTERNET_MAX_URL_LENGTH]; hr = _GetSiteURL(szBuffer, ARRAYSIZE(szBuffer), szFile); if (SUCCEEDED(hr)) { LaunchICW(); if (InternetGoOnline(szBuffer, hwnd, 0)) { _pdscProviders = new CXMLDOMStateChange(_pdocProviders, hwnd); if (_pdscProviders) { hr = _pdscProviders->Advise(TRUE); if (SUCCEEDED(hr)) { VARIANT varName; hr = InitVariantFromStr(&varName, szBuffer); if (SUCCEEDED(hr)) { VARIANT_BOOL fSuccess; hr = _pdocProviders->load(varName, &fSuccess); if (FAILED(hr) || (fSuccess != VARIANT_TRUE)) { hr = FAILED(hr) ? hr:E_FAIL; } VariantClear(&varName); } } } else { hr = E_OUTOFMEMORY; } } else { hr = E_FAIL; } } } } // if any of this failed then lets post ourselves the completed message // with the failure code, at which point we can then load the default document. if (FAILED(hr)) PostMessage(hwnd, MSG_XMLDOC_COMPLETED, 0, (LPARAM)hr); return hr; } void CPublishingWizard::_FetchComplete(HWND hwnd, HRESULT hr) { // if we failed to load the document then lets pull in the default provider // list from our DLL, this can also fail, but its unlikely to. we recreate // the XML DOM object to ensure our state is pure. _fUsingTemporaryProviders = FAILED(hr); _fRepopulateProviders = TRUE; // provider list will have changed! if (FAILED(hr)) { _FreeProviderList(); hr = CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IXMLDOMDocument, &_pdocProviders)); if (SUCCEEDED(hr)) { VARIANT varName; hr = InitVariantFromStr(&varName, TEXT("res://netplwiz.dll/xml/providers.xml")); if (SUCCEEDED(hr)) { VARIANT_BOOL fSuccess = VARIANT_FALSE; hr = _pdocProviders->load(varName, &fSuccess); if (FAILED(hr) || (fSuccess != VARIANT_TRUE)) { hr = FAILED(hr) ? hr:E_FAIL; } VariantClear(&varName); } } } KillTimer(hwnd, FETCH_TIMERID); _ShowHideFetchProgress(hwnd, FALSE); _WizardNext(hwnd, WIZPAGE_PROVIDERS); } void CPublishingWizard::_ShowHideFetchProgress(HWND hwnd, BOOL fShow) { ShowWindow(GetDlgItem(hwnd, IDC_PUB_SRCHPROVIDERS), fShow ? SW_SHOW:SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_PUB_SRCHPROVIDERS_STATIC1), fShow ? SW_SHOW:SW_HIDE); ShowWindow(GetDlgItem(hwnd, IDC_PUB_SRCHPROVIDERS_STATIC2), fShow ? SW_SHOW:SW_HIDE); SendDlgItemMessage(hwnd, IDC_PUB_SRCHPROVIDERS, PBM_SETMARQUEE, (WPARAM)fShow, 0); } INT_PTR CPublishingWizard::_FetchProvidersDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_INITDIALOG: _MapDlgItemText(hwnd, IDC_PUB_SRCHPROVIDERS_STATIC1, L"wp:destination", L"downloading"); break; case MSG_XMLDOC_COMPLETED: _FetchComplete(hwnd, (HRESULT)lParam); break; case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR)lParam; switch (pnmh->code) { case PSN_SETACTIVE: { BOOL fFetch = TRUE; if (_pdocProviders && !_fUsingTemporaryProviders) { long lReadyState; HRESULT hr = _pdocProviders->get_readyState(&lReadyState); if (SUCCEEDED(hr) && (lReadyState == XMLDOC_COMPLETED)) { _WizardNext(hwnd, WIZPAGE_PROVIDERS); fFetch = FALSE; } } if (fFetch) { SetTimer(hwnd, FETCH_TIMERID, FETCH_TIMEOUT, NULL); _FetchProviderList(hwnd); PropSheet_SetWizButtons(GetParent(hwnd), 0x0); } return TRUE; } } break; } case WM_TIMER: { KillTimer(hwnd, FETCH_TIMERID); _ShowHideFetchProgress(hwnd, TRUE); return TRUE; } } return FALSE; } // Destination page int CPublishingWizard::_GetSelectedItem(HWND hwndList) { int iSelected = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED|LVNI_SELECTED); if (iSelected == -1) { iSelected = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED); } return iSelected; } void CPublishingWizard::_ProviderEnableNext(HWND hwnd) { DWORD dwButtons = PSWIZB_BACK; // there must be an item available in the list, and it must have a ID property defined // for it so it can be enabled. int iSelected = _GetSelectedItem(GetDlgItem(hwnd, IDC_PUB_PROVIDERS)); if (iSelected != -1) { LVITEM lvi = { 0 }; lvi.iItem = iSelected; lvi.mask = LVIF_PARAM; if (ListView_GetItem(GetDlgItem(hwnd, IDC_PUB_PROVIDERS), &lvi)) { IXMLDOMNode *pdn = (IXMLDOMNode*)lvi.lParam; TCHAR szID[INTERNET_MAX_URL_LENGTH]; if (SUCCEEDED(GetStrFromAttribute(pdn, ATTRIBUTE_ID, szID, ARRAYSIZE(szID)))) { dwButtons |= PSWIZB_NEXT; } } } PropSheet_SetWizButtons(GetParent(hwnd), dwButtons); } // extract an icon resource from the provider XML documents. the icons are stored as // mime encoded bitmaps that we decode into files in the users settings folder. we return // an index to the shared image list. int CPublishingWizard::_GetRemoteIcon(LPCTSTR pszID, BOOL fCanRefresh) { int iResult = -1; TCHAR szURL[INTERNET_MAX_URL_LENGTH]; HRESULT hr = _GetSiteURL(szURL, ARRAYSIZE(szURL), pszID); if (SUCCEEDED(hr)) { TCHAR szFilename[MAX_PATH]; hr = URLDownloadToCacheFile(NULL, szURL, szFilename, ARRAYSIZE(szFilename), 0x0, NULL); if (SUCCEEDED(hr)) { iResult = Shell_GetCachedImageIndex(szFilename, 0x0, 0x0); } } return iResult; } // get the provider list from the internet struct { LPTSTR pszAttribute; BOOL fIsString; } aProviderElements[] = { { ATTRIBUTE_SUPPORTEDTYPES, FALSE }, { ATTRIBUTE_DISPLAYNAME, TRUE }, { ATTRIBUTE_DESCRIPTION, TRUE }, { ATTRIBUTE_HREF, FALSE }, { ATTRIBUTE_ICONPATH, FALSE }, { ATTRIBUTE_ICON, FALSE }, }; HRESULT CPublishingWizard::_MergeLocalProviders() { TCHAR szBuffer[MAX_PATH]; wnsprintf(szBuffer, ARRAYSIZE(szBuffer), FMT_PROVIDER, _szProviderScope); IXMLDOMNode *pdn; HRESULT hr = _pdocProviders->selectSingleNode(szBuffer, &pdn); if (hr == S_OK) { HKEY hk; hr = _GetProviderKey(HKEY_CURRENT_USER, KEY_READ, SZ_REGVAL_ALTPROVIDERS, &hk); if (SUCCEEDED(hr)) { for (int i =0; SUCCEEDED(hr) && (RegEnumKey(hk, i, szBuffer, ARRAYSIZE(szBuffer)) == ERROR_SUCCESS); i++) { // the manifest always overrides the entries that are stored in the registry, // therefore if there is an element in the document that has a matching ID to the // one in the registry then lets handle it. TCHAR szSelectValue[MAX_PATH]; wnsprintf(szSelectValue, ARRAYSIZE(szSelectValue), TEXT("provider[@id=\"%s\"]"), szBuffer); IXMLDOMNode *pdnProvider; if (pdn->selectSingleNode(szSelectValue, &pdnProvider) == S_FALSE) { IPropertyBag *ppb; hr = SHCreatePropertyBagOnRegKey(hk, szBuffer, STGM_READ, IID_PPV_ARG(IPropertyBag, &ppb)); if (SUCCEEDED(hr)) { IXMLDOMElement *pdel; hr = _pdocProviders->createElement(ELEMENT_PROVIDER, &pdel); if (SUCCEEDED(hr)) { hr = SetAttributeFromStr(pdel, ATTRIBUTE_ID, szBuffer); if (SUCCEEDED(hr)) { // loop and replicate all the attributes from the property bag // into the element. once we have done that we can add // the element to the provider list. for (int i = 0; SUCCEEDED(hr) && (i < ARRAYSIZE(aProviderElements)); i++) { VARIANT var = {0}; if (SUCCEEDED(ppb->Read(aProviderElements[i].pszAttribute, &var, NULL))) { hr = pdel->setAttribute(aProviderElements[i].pszAttribute, var); VariantClear(&var); } } if (SUCCEEDED(hr)) { hr = pdn->appendChild(pdel, NULL); } } pdel->Release(); } ppb->Release(); } } else { pdnProvider->Release(); } } RegCloseKey(hk); } pdn->Release(); } return hr; } void CPublishingWizard::_GetDefaultProvider(LPTSTR pszProvider, int cch) { HKEY hk; HRESULT hr = _GetProviderKey(HKEY_CURRENT_USER, KEY_READ, NULL, &hk); if (SUCCEEDED(hr)) { DWORD cb = cch*sizeof(*pszProvider); SHGetValue(hk, NULL, SZ_REGVAL_DEFAULTPROVIDER, NULL, pszProvider, &cb); RegCloseKey(hk); } } void CPublishingWizard::_SetDefaultProvider(IXMLDOMNode *pdn) { TCHAR szProvider[MAX_PATH]; HRESULT hr = GetStrFromAttribute(pdn, ATTRIBUTE_ID, szProvider, ARRAYSIZE(szProvider)); if (SUCCEEDED(hr)) { HKEY hk; hr = _GetProviderKey(HKEY_CURRENT_USER, KEY_WRITE, NULL, &hk); if (SUCCEEDED(hr)) { // store the default provider value DWORD cb = (lstrlen(szProvider)+1)*sizeof(*szProvider); SHSetValue(hk, NULL, SZ_REGVAL_DEFAULTPROVIDER, REG_SZ, szProvider, cb); // we now need to replicate the properties from the DOM into the registry so that // the user can always get to the specified site. to make this easier we // will create a property bag that we will copy values using. TCHAR szBuffer[MAX_PATH]; wnsprintf(szBuffer, ARRAYSIZE(szBuffer), (SZ_REGVAL_ALTPROVIDERS TEXT("\\%s")), szProvider); IPropertyBag *ppb; hr = SHCreatePropertyBagOnRegKey(hk, szBuffer, STGM_CREATE | STGM_WRITE, IID_PPV_ARG(IPropertyBag, &ppb)); if (SUCCEEDED(hr)) { IXMLDOMElement *pdel; hr = pdn->QueryInterface(IID_PPV_ARG(IXMLDOMElement, &pdel)); if (SUCCEEDED(hr)) { for (int i = 0; SUCCEEDED(hr) && (i < ARRAYSIZE(aProviderElements)); i++) { if (aProviderElements[i].fIsString) { hr = _GetProviderString(pdn, aProviderElements[i].pszAttribute, szBuffer, ARRAYSIZE(szBuffer)); if (SUCCEEDED(hr)) { hr = SHPropertyBag_WriteStr(ppb, aProviderElements[i].pszAttribute, szBuffer); } } else { VARIANT var = {0}; if (S_OK == pdel->getAttribute(aProviderElements[i].pszAttribute, &var)) { hr = ppb->Write(aProviderElements[i].pszAttribute, &var); VariantClear(&var); } } } pdel->Release(); } ppb->Release(); } RegCloseKey(hk); } } } // load a localized string from the XML node for the provider HRESULT CPublishingWizard::_GetProviderString(IXMLDOMNode *pdn, USHORT idPrimary, USHORT idSub, LPCTSTR pszID, LPTSTR pszBuffer, int cch) { TCHAR szPath[MAX_PATH]; wnsprintf(szPath, ARRAYSIZE(szPath), TEXT("strings[@langid='%04x']/string[@id='%s'][@langid='%04x']"), idPrimary, pszID, idSub); IXMLDOMNode *pdnString; HRESULT hr = pdn->selectSingleNode(szPath, &pdnString); if (hr == S_OK) { VARIANT var = {VT_BSTR}; hr = pdnString->get_nodeTypedValue(&var); if (SUCCEEDED(hr)) { VariantToStr(&var, pszBuffer, cch); VariantClear(&var); } pdnString->Release(); } return hr; } HRESULT CPublishingWizard::_GetProviderString(IXMLDOMNode *pdn, LPCTSTR pszID, LPTSTR pszBuffer, int cch) { *pszBuffer = TEXT('\0'); LANGID idLang = GetUserDefaultLangID(); HRESULT hr = _GetProviderString(pdn, PRIMARYLANGID(idLang), SUBLANGID(idLang), pszID, pszBuffer, cch); if (hr == S_FALSE) { hr = _GetProviderString(pdn, PRIMARYLANGID(idLang), SUBLANG_NEUTRAL, pszID, pszBuffer, cch); if (hr == S_FALSE) { hr = _GetProviderString(pdn, LANG_NEUTRAL, SUBLANG_NEUTRAL, pszID, pszBuffer, cch); if (hr == S_FALSE) { hr = GetStrFromAttribute(pdn, pszID, pszBuffer, cch); } } } SHLoadIndirectString(pszBuffer, pszBuffer, cch, NULL); return hr; } // populate the provider list on the destination page #define TILE_DISPLAYNAME 0 #define TILE_DESCRIPTION 1 #define TILE_MAX 1 const UINT c_auTileColumns[] = {TILE_DISPLAYNAME, TILE_DESCRIPTION}; const UINT c_auTileSubItems[] = {TILE_DESCRIPTION}; int CPublishingWizard::_AddProvider(HWND hwnd, IXMLDOMNode *pdn) { // fill out the item information LV_ITEM lvi = { 0 }; lvi.mask = LVIF_TEXT|LVIF_PARAM|LVIF_IMAGE; lvi.iItem = ListView_GetItemCount(hwnd); // always append! lvi.lParam = (LPARAM)pdn; lvi.pszText = LPSTR_TEXTCALLBACK; lvi.iImage = -1; // set to the default state // read the icon location and put that onto the item TCHAR szIcon[MAX_PATH]; if (SUCCEEDED(GetStrFromAttribute(pdn, ATTRIBUTE_ICONPATH, szIcon, ARRAYSIZE(szIcon)))) { int resid = PathParseIconLocation(szIcon); lvi.iImage = Shell_GetCachedImageIndex(szIcon, resid, 0x0); } else if (SUCCEEDED(GetStrFromAttribute(pdn, ATTRIBUTE_ICON, szIcon, ARRAYSIZE(szIcon)))) { lvi.iImage = _GetRemoteIcon(szIcon, TRUE); } // if that failed then lets try and compute a sensible default icon for us to use if (lvi.iImage == -1) { // under the provider key for the install lets see if there is a default icon that we // should be using. if not, or if that fails to extract then lets use the publishing one. HKEY hk; if (SUCCEEDED(_GetProviderKey(HKEY_LOCAL_MACHINE, KEY_READ, NULL, &hk))) { DWORD cb = ARRAYSIZE(szIcon)*sizeof(*szIcon); if (ERROR_SUCCESS == SHGetValue(hk, NULL, SZ_REGVAL_DEFAULTPROVIDERICON, NULL, szIcon, &cb)) { int resid = PathParseIconLocation(szIcon); lvi.iImage = Shell_GetCachedImageIndex(szIcon, resid, 0x0); // default to the publishing icon } RegCloseKey(hk); } if (lvi.iImage == -1) lvi.iImage = Shell_GetCachedImageIndex(TEXT("shell32.dll"), -244, 0x0); } int iResult = ListView_InsertItem(hwnd, &lvi); if (iResult != -1) { pdn->AddRef(); // it was added to the view, so take reference LVTILEINFO lvti; lvti.cbSize = sizeof(LVTILEINFO); lvti.iItem = iResult; lvti.cColumns = ARRAYSIZE(c_auTileSubItems); lvti.puColumns = (UINT*)c_auTileSubItems; ListView_SetTileInfo(hwnd, &lvti); } return iResult; } void CPublishingWizard::_PopulateProviderList(HWND hwnd) { HWND hwndList = GetDlgItem(hwnd, IDC_PUB_PROVIDERS); // setup the view with the tiles that we want to show and the // icon lists - shared with the shell. ListView_DeleteAllItems(hwndList); ListView_SetView(hwndList, LV_VIEW_TILE); for (int i=0; iget_readyState(&lReadyState); if (SUCCEEDED(hr) && (lReadyState == XMLDOC_COMPLETED)) { // lets merge in the local providers, these are local to this user, // we check for duplicates so this shouldn't present too much hardship. _MergeLocalProviders(); // format a query to return the providers that match our publishing scope, // this will allow the wizard to show different lists of providers for // web publishing vs. internet printing WCHAR szBuffer[MAX_PATH]; wnsprintf(szBuffer, ARRAYSIZE(szBuffer), FMT_PROVIDERS, _szProviderScope); IXMLDOMNodeList *pnl; hr = _pdocProviders->selectNodes(szBuffer, &pnl); if (hr == S_OK) { long cSelection; hr = pnl->get_length(&cSelection); if (SUCCEEDED(hr) && (cSelection > 0)) { // get the list of unique types from the selection we are going to try and publish HDPA hdpaUniqueTypes = NULL; _GetUniqueTypeList(FALSE, &hdpaUniqueTypes); // don't care if this fails - ptr is NULL // we need the default provider to highlight correctly, using this we can then // populate the list from the provider manfiest TCHAR szDefaultProvider[MAX_PATH] = {0}; _GetDefaultProvider(szDefaultProvider, ARRAYSIZE(szDefaultProvider)); int iDefault = 0; for (long lNode = 0; lNode != cSelection; lNode++) { IXMLDOMNode *pdn; hr = pnl->get_item(lNode, &pdn); if (SUCCEEDED(hr)) { // filter based on the list of types they support, this is optional // if they don't specify anything then they are in the list, // otherwise the format is assumed to be a file spec, eg *.bmp;*.jpg; etc. BOOL fSupported = TRUE; if (hdpaUniqueTypes) { hr = GetStrFromAttribute(pdn, ATTRIBUTE_SUPPORTEDTYPES, szBuffer, ARRAYSIZE(szBuffer)); if (SUCCEEDED(hr)) { fSupported = FALSE; for (int i = 0; !fSupported && (i < DPA_GetPtrCount(hdpaUniqueTypes)); i++) { LPCTSTR pszExtension = (LPCTSTR)DPA_GetPtr(hdpaUniqueTypes, i); fSupported = PathMatchSpec(pszExtension, szBuffer); } } } // if this is a supported item then lets add it to the list if (fSupported) { hr = GetStrFromAttribute(pdn, ATTRIBUTE_ID, szBuffer, ARRAYSIZE(szBuffer)); if (SUCCEEDED(hr)) { int i = _AddProvider(hwndList, pdn); if ((i != -1) && (0 == StrCmpI(szBuffer, szDefaultProvider))) { iDefault = i; } } } pdn->Release(); } } ListView_SetItemState(hwndList, iDefault, LVIS_SELECTED, LVIS_SELECTED); ListView_EnsureVisible(hwndList, iDefault, FALSE); if (hdpaUniqueTypes) DPA_DestroyCallback(hdpaUniqueTypes, s_FreeStringProc, 0); } else { // we have no providers that match this criteria therefore lets // create a dummy one which shows this to the caller IXMLDOMElement *pdelProvider; hr = _pdocManifest->createElement(ELEMENT_FILE, &pdelProvider); if (SUCCEEDED(hr)) { IResourceMap *prm; hr = _GetResourceMap(&prm); if (SUCCEEDED(hr)) { // get the no providers string if (FAILED(_LoadMappedString(L"wp:selector", L"noprovider", szBuffer, ARRAYSIZE(szBuffer)))) LoadString(g_hinst, IDS_PUB_NOPROVIDER, szBuffer, ARRAYSIZE(szBuffer)); hr = SetAttributeFromStr(pdelProvider, ATTRIBUTE_DISPLAYNAME, szBuffer); // get the sub-text for the no providers if (SUCCEEDED(hr)) { if (FAILED(_LoadMappedString(L"wp:selector", L"noproviderdesc", szBuffer, ARRAYSIZE(szBuffer)))) LoadString(g_hinst, IDS_PUB_NOPROVIDERDESC, szBuffer, ARRAYSIZE(szBuffer)); hr = SetAttributeFromStr(pdelProvider, ATTRIBUTE_DESCRIPTION, szBuffer); } // lets put together a resource string for the icon we are going to show if (SUCCEEDED(hr)) { wnsprintf(szBuffer, ARRAYSIZE(szBuffer), TEXT("netplwiz.dll,-%d"), IDI_NOPROVIDERS); hr = SetAttributeFromStr(pdelProvider, ATTRIBUTE_ICONPATH, szBuffer); } // lets add a provider from the free standing node if (SUCCEEDED(hr)) { IXMLDOMNode *pdnProvider; hr = pdelProvider->QueryInterface(IID_PPV_ARG(IXMLDOMNode, &pdnProvider)); if (SUCCEEDED(hr)) { _AddProvider(hwndList, pdnProvider); pdnProvider->Release(); } } prm->Release(); } pdelProvider->Release(); } } pnl->Release(); } } } _fRepopulateProviders = FALSE; // providers have been populated } // handle next in the provider (destination) page HRESULT CPublishingWizard::_ProviderNext(HWND hwnd, HPROPSHEETPAGE *phPage) { HRESULT hr = E_FAIL; int iSelected = _GetSelectedItem(GetDlgItem(hwnd, IDC_PUB_PROVIDERS)); if (iSelected != -1) { LVITEM lvi = { 0 }; lvi.iItem = iSelected; lvi.mask = LVIF_PARAM; if (ListView_GetItem(GetDlgItem(hwnd, IDC_PUB_PROVIDERS), &lvi)) { IXMLDOMNode *pdn = (IXMLDOMNode*)lvi.lParam; // set the default provider from the node value _SetDefaultProvider(pdn); // now try and navigate to the web page, if no URL then show advanced path TCHAR szURL[INTERNET_MAX_URL_LENGTH]; if (SUCCEEDED(GetStrFromAttribute(pdn, ATTRIBUTE_HREF, szURL, ARRAYSIZE(szURL)))) { // get the folder creation flag from the site so that we can set the HTML wizard // into the correct state. note that the site doesn't need to specify this // and we will default to TRUE - eg. do folder creation, this allows the current // hosts to work without modification. hr = _InitPropertyBag(szURL); if (SUCCEEDED(hr)) { hr = _pwwe->GetFirstPage(phPage); } } else { // No URL was specified, so lets go through the advanced path where // the user gets to type a location and we create connection to that // (replaced the old Add Net Place functionality); *phPage = _aWizPages[WIZPAGE_LOCATION]; hr = S_OK; } } } return hr; } void CPublishingWizard::_ProviderGetDispInfo(LV_DISPINFO *plvdi) { if (plvdi->item.mask & LVIF_TEXT) { IXMLDOMNode *pdn = (IXMLDOMNode*)plvdi->item.lParam; switch (plvdi->item.iSubItem) { case TILE_DISPLAYNAME: _GetProviderString(pdn, ATTRIBUTE_DISPLAYNAME, plvdi->item.pszText, plvdi->item.cchTextMax); break; case TILE_DESCRIPTION: _GetProviderString(pdn, ATTRIBUTE_DESCRIPTION, plvdi->item.pszText, plvdi->item.cchTextMax); break; default: ASSERTMSG(0, "ListView is asking for wrong column in publishing wizard"); break; } } } void CPublishingWizard::_InitProvidersDialog(HWND hwnd) { // initial the dialog accordingly TCHAR szBuffer[MAX_PATH]; HRESULT hr = _LoadMappedString(L"wp:destination", L"providercaption", szBuffer, ARRAYSIZE(szBuffer)); if (SUCCEEDED(hr)) { SetDlgItemText(hwnd, IDC_PUB_PROVIDERSCAPTION, szBuffer); // lets size the caption area as needed, and move controls around as needed UINT ctls[] = { IDC_PUB_PROVIDERSLABEL, IDC_PUB_PROVIDERS}; int dy = SizeControlFromText(hwnd, IDC_PUB_PROVIDERSCAPTION, szBuffer); MoveControls(hwnd, ctls, ARRAYSIZE(ctls), 0, dy); // adjust the provider dialog size as needed RECT rc; GetWindowRect(GetDlgItem(hwnd, IDC_PUB_PROVIDERS), &rc); SetWindowPos(GetDlgItem(hwnd, IDC_PUB_PROVIDERS), NULL, 0, 0, RECTWIDTH(rc), RECTHEIGHT(rc)-dy, SWP_NOZORDER|SWP_NOMOVE); } // set the caption for the providers control _MapDlgItemText(hwnd, IDC_PUB_PROVIDERSLABEL, L"wp:destination", L"providerslabel"); // set the image list to the list view HIMAGELIST himlLarge, himlSmall; Shell_GetImageLists(&himlLarge, &himlSmall); ListView_SetImageList(GetDlgItem(hwnd, IDC_PUB_PROVIDERS), himlLarge, LVSIL_NORMAL); ListView_SetImageList(GetDlgItem(hwnd, IDC_PUB_PROVIDERS), himlSmall, LVSIL_SMALL); }; INT_PTR CPublishingWizard::_ProviderDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_INITDIALOG: _InitProvidersDialog(hwnd); return TRUE; case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR)lParam; switch (pnmh->code) { case LVN_GETDISPINFO: _ProviderGetDispInfo((LV_DISPINFO*)pnmh); return TRUE; case LVN_ITEMCHANGED: _ProviderEnableNext(hwnd); return TRUE; case LVN_DELETEITEM: { NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam; IXMLDOMNode *pdn = (IXMLDOMNode*)nmlv->lParam; pdn->Release(); return TRUE; } case PSN_SETACTIVE: { _fTransferComplete = FALSE; // we haven't started to tranfser yet _fShownCustomLocation = FALSE; // we haven't shown the custom location page if (_fRecomputeManifest) _BuildTransferManifest(); if (_fRepopulateProviders) _PopulateProviderList(hwnd); // if the manifest changes, so might the providers! _ProviderEnableNext(hwnd); return TRUE; } // when going back from the destination page, lets determine from the // site where we should be going. case PSN_WIZBACK: { if (_dwFlags & SHPWHF_NOFILESELECTOR) { if (_punkSite) { IWizardSite *pws; if (SUCCEEDED(_punkSite->QueryInterface(IID_PPV_ARG(IWizardSite, &pws)))) { HPROPSHEETPAGE hpage; if (SUCCEEDED(pws->GetPreviousPage(&hpage))) { PropSheet_SetCurSel(GetParent(hwnd), hpage, -1); } pws->Release(); } } SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LPARAM)-1); } else { _WizardNext(hwnd, WIZPAGE_WHICHFILE); } return TRUE; } // when going forward lets query the next page, set the selection // and then let the foreground know whats going on. case PSN_WIZNEXT: { HPROPSHEETPAGE hpage; if (SUCCEEDED(_ProviderNext(hwnd, &hpage))) { PropSheet_SetCurSel(GetParent(hwnd), hpage, -1); } SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LPARAM)-1); return TRUE; } // the item was activated, therefore we need to goto the next (in this case the page for the provider). case LVN_ITEMACTIVATE: { HPROPSHEETPAGE hpage; if (SUCCEEDED(_ProviderNext(hwnd, &hpage))) { PropSheet_SetCurSel(GetParent(hwnd), hpage, -1); } return TRUE; } } break; } } return FALSE; } // Resample/Resize dialog. This dialog is displayed when we determine that there // are images that need to be resized. INT_PTR CPublishingWizard::_ResizeDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_INITDIALOG: Button_SetCheck(GetDlgItem(hwnd, IDC_PUB_RESIZE), BST_CHECKED); Button_SetCheck(GetDlgItem(hwnd, IDC_PUB_RESIZESMALL), BST_CHECKED); return TRUE; case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR)lParam; switch (pnmh->code) { case PSN_SETACTIVE: PropSheet_SetWizButtons(GetParent(hwnd), PSWIZB_BACK | PSWIZB_NEXT); return TRUE; case PSN_WIZBACK: { // if we went through the custom location stuff then navigate back into there. if (_fShownCustomLocation) return _WizardNext(hwnd, _fShownUserName ? WIZPAGE_FTPUSER:WIZPAGE_LOCATION); return _WizardNext(hwnd, WIZPAGE_PROVIDERS); } case PSN_WIZNEXT: { if (Button_GetCheck(GetDlgItem(hwnd, IDC_PUB_RESIZE)) == BST_CHECKED) { if (Button_GetCheck(GetDlgItem(hwnd, IDC_PUB_RESIZESMALL)) == BST_CHECKED) _ro = RESIZE_SMALL; else if (Button_GetCheck(GetDlgItem(hwnd, IDC_PUB_RESIZEMEDIUM)) == BST_CHECKED) _ro = RESIZE_MEDIUM; else _ro = RESIZE_LARGE; } else { _ro = RESIZE_NONE; } return _WizardNext(hwnd, WIZPAGE_COPYING); } } break; } case WM_COMMAND: { if ((HIWORD(wParam) == BN_CLICKED) && (LOWORD(wParam) == IDC_PUB_RESIZE)) { BOOL fEnable = Button_GetCheck(GetDlgItem(hwnd, IDC_PUB_RESIZE)) == BST_CHECKED; EnableWindow(GetDlgItem(hwnd, IDC_PUB_RESIZESMALL), fEnable); EnableWindow(GetDlgItem(hwnd, IDC_PUB_RESIZEMEDIUM), fEnable); EnableWindow(GetDlgItem(hwnd, IDC_PUB_RESIZELARGE), fEnable); } break; } } return FALSE; } // this is called before we transfer each item, we look at the IShellItem we have and // try to update either our stats, or the indicator that this is a new file we are processing. BOOL CPublishingWizard::_HasAttributes(IShellItem *psi, SFGAOF flags) { BOOL fReturn = FALSE; SFGAOF flagsOut; if (SUCCEEDED(psi->GetAttributes(flags, &flagsOut)) && (flags & flagsOut)) { fReturn = TRUE; } return fReturn; } HRESULT CPublishingWizard::PreOperation(const STGOP op, IShellItem *psiItem, IShellItem *psiDest) { if (psiItem && _HasAttributes(psiItem, SFGAO_STREAM)) { if (STGOP_COPY == op) { // lets fill in the details of the file LPOLESTR pstrName; HRESULT hr = psiItem->GetDisplayName(SIGDN_PARENTRELATIVEEDITING, &pstrName); if (SUCCEEDED(hr)) { SetDlgItemText(_hwndCopyingPage, IDC_PUB_COPYFILE, pstrName); CoTaskMemFree(pstrName); } // lets update the progress bar for the number of files we are transfering. _iFile++; SendDlgItemMessage(_hwndCopyingPage, IDC_PUB_TRANSPROGRESS, PBM_SETRANGE32, 0, (LPARAM)_cFiles); SendDlgItemMessage(_hwndCopyingPage, IDC_PUB_TRANSPROGRESS, PBM_SETPOS, (WPARAM)_iFile, 0); TCHAR szBuffer[MAX_PATH]; FormatMessageString(IDS_PUB_COPYINGFMT, szBuffer, ARRAYSIZE(szBuffer), _iFile, _cFiles); SetDlgItemText(_hwndCopyingPage, IDC_PUB_LABELTRANSPROG, szBuffer); // get the thumbnail and show it. IExtractImage *pei; hr = psiItem->BindToHandler(NULL, BHID_SFUIObject, IID_PPV_ARG(IExtractImage, &pei)); if (SUCCEEDED(hr)) { SIZE sz = {120,120}; WCHAR szImage[MAX_PATH]; DWORD dwFlags = 0; hr = pei->GetLocation(szImage, ARRAYSIZE(szImage), NULL, &sz, 24, &dwFlags); if (SUCCEEDED(hr)) { HBITMAP hbmp; hr = pei->Extract(&hbmp); if (SUCCEEDED(hr)) { if (!PostMessage(_hwndCopyingPage, PWM_UPDATEICON, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp)) { DeleteObject(hbmp); } } } pei->Release(); } // if that failed then lets get the icon for the file and place that into the dialog, // this is less likely to fail - I hope. if (FAILED(hr)) { IPersistIDList *ppid; hr = psiItem->QueryInterface(IID_PPV_ARG(IPersistIDList, &ppid)); if (SUCCEEDED(hr)) { LPITEMIDLIST pidl; hr = ppid->GetIDList(&pidl); if (SUCCEEDED(hr)) { SHFILEINFO sfi = {0}; if (SHGetFileInfo((LPCWSTR)pidl, -1, &sfi, sizeof(sfi), SHGFI_ICON|SHGFI_PIDL|SHGFI_ADDOVERLAYS)) { if (!PostMessage(_hwndCopyingPage, PWM_UPDATEICON, (WPARAM)IMAGE_ICON, (LPARAM)sfi.hIcon)) { DeleteObject(sfi.hIcon); } } ILFree(pidl); } ppid->Release(); } } } else if (STGOP_STATS == op) { _cFiles++; } } return S_OK; } // while we are moving the bits of the file ensure that we update the progress bar accordingly. void CPublishingWizard::_SetProgress(DWORD dwCompleted, DWORD dwTotal) { if (_dwTotal != dwTotal) _dwTotal = dwTotal; if (_dwCompleted != dwCompleted) _dwCompleted = dwCompleted; PostMessage(_hwndCopyingPage, PWM_UPDATE, (WPARAM)dwCompleted, (LPARAM)dwTotal); } HRESULT CPublishingWizard::OperationProgress(const STGOP op, IShellItem *psiItem, IShellItem *psiDest, ULONGLONG ulTotal, ULONGLONG ulComplete) { if (psiItem && (op == STGOP_COPY)) { ULARGE_INTEGER uliCompleted, uliTotal; uliCompleted.QuadPart = ulComplete; uliTotal.QuadPart = ulTotal; // If we are using the top 32 bits, scale both numbers down. // Note that I'm using the attribute that dwTotalHi is always larger than dwCompleted ASSERT(uliTotal.HighPart >= uliCompleted.HighPart); while (uliTotal.HighPart) { uliCompleted.QuadPart >>= 1; uliTotal.QuadPart >>= 1; } ASSERT((0 == uliCompleted.HighPart) && (0 == uliTotal.HighPart)); // Make sure we finished scaling down. _SetProgress(uliCompleted.LowPart, uliTotal.LowPart); } return S_OK; } // Method to invoke the transfer engine HRESULT CPublishingWizard::_BeginTransfer(HWND hwnd) { // initialize the dialog before we start the copy process. _dwCompleted = -1; // progress bars are reset _dwTotal = -1; _iPercentageComplete = -1; _cFiles = 0; // haven't transfered any files yet _iFile = 0; _hrFromTransfer = S_FALSE; _fCancelled = FALSE; // set the state of the controls ready to perform the transfer SetDlgItemText(hwnd, IDC_PUB_COPYFILE, TEXT("")); SendMessage(hwnd, PWM_UPDATE, 0, 0); PropSheet_SetWizButtons(GetParent(hwnd), 0x0); // initialize the transfer object ready to move the bits to the site ITransferAdviseSink *ptas; HRESULT hr = this->QueryInterface(IID_PPV_ARG(ITransferAdviseSink, &ptas)); if (SUCCEEDED(hr)) { // build the list of files for use to transfer to the site, this we // key of the transfer manifest which is stored in our property bag. IXMLDOMDocument *pdocManifest; hr = GetTransferManifest(NULL, &pdocManifest); if (SUCCEEDED(hr)) { TRANSFERINFO ti = {0}; ti.hwnd = hwnd; ti.dwFlags = _dwFlags; CDPA dpaItems; hr = _InitTransferInfo(pdocManifest, &ti, &dpaItems); if (SUCCEEDED(hr)) { if (ti.fUsePost) { hr = PublishViaPost(&ti, &dpaItems, ptas); } else { hr = PublishViaCopyEngine(&ti, &dpaItems, ptas); } } dpaItems.DestroyCallback(_FreeTransferItems, NULL); // will have been detached by thread if handled pdocManifest->Release(); } if (FAILED(hr)) PostMessage(hwnd, PWM_TRANSFERCOMPLETE, 0, (LPARAM)hr); ptas->Release(); } return hr; } // create a link back to the site, this is keyed off information stored in the manifest. HRESULT CPublishingWizard::_CreateFavorite(IXMLDOMNode *pdnUploadInfo) { // lets pick up the favorite element from the manifest, this should define all // that is needed for us to create a link in to the favorites menu. IXMLDOMNode *pdn; HRESULT hr = pdnUploadInfo->selectSingleNode(ELEMENT_FAVORITE, &pdn); if (S_OK == hr) { // we need an URL to create the link using. WCHAR szURL[INTERNET_MAX_URL_LENGTH] = {0}; hr = GetStrFromAttribute(pdn, ATTRIBUTE_HREF, szURL, ARRAYSIZE(szURL)); if (SUCCEEDED(hr)) { // we need a name to save the link as. WCHAR szName[MAX_PATH] = {0}; hr = GetStrFromAttribute(pdn, ATTRIBUTE_NAME, szName, ARRAYSIZE(szName)); if (SUCCEEDED(hr)) { IShellLink *psl; hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellLink, &psl)); if (SUCCEEDED(hr)) { hr = psl->SetPath(szURL); // set the target // if that works then lets try and put a comment onto the link - this is an optional // value for the element. if (SUCCEEDED(hr)) { WCHAR szComment[MAX_PATH] = {0}; if (SUCCEEDED(GetStrFromAttribute(pdn, ATTRIBUTE_COMMENT, szComment, ARRAYSIZE(szComment)))) { hr = psl->SetDescription(szComment); // set the comment } } // assuming all that works then lets persist the link into the users // favorites folder, this inturn will create it on their favaorites menu. if (SUCCEEDED(hr)) { WCHAR szFilename[MAX_PATH]; if (SHGetSpecialFolderPath(NULL, szFilename, CSIDL_FAVORITES, TRUE)) { PathAppend(szFilename, szName); PathRenameExtension(szFilename, TEXT(".lnk")); IPersistFile *ppf; hr = psl->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf)); if (SUCCEEDED(hr)) { hr = ppf->Save(szFilename, TRUE); ppf->Release(); } } } psl->Release(); } } } pdn->Release(); } return hr; } // When transfer is complete we need to determine which page we are going to show // this will either come from the site or it will be a HTML page hosted // on the site. HPROPSHEETPAGE CPublishingWizard::_TransferComplete(HRESULT hrFromTransfer) { HPROPSHEETPAGE hpResult = NULL; // convert the HRESULT From something that will have come from the // transfer engine into something the outside world will understand. if (hrFromTransfer == STRESPONSE_CANCEL) hrFromTransfer = HRESULT_FROM_WIN32(ERROR_CANCELLED); // tag ourselves as in the "completed transfer" state, therefore the site knows where to // navigate to next. _fTransferComplete = TRUE; _hrFromTransfer = hrFromTransfer; // get the next page from the site, this will either be the done or // cancelled page based on the result of the site. IWizardSite *pws; HRESULT hr = _punkSite->QueryInterface(IID_PPV_ARG(IWizardSite, &pws)); if (SUCCEEDED(hr)) { if (_hrFromTransfer == HRESULT_FROM_WIN32(ERROR_CANCELLED)) { hr = pws->GetCancelledPage(&hpResult); } else { hr = pws->GetNextPage(&hpResult); } pws->Release(); } // lets put the result into the manifest that we we can read it back later. IXMLDOMDocument *pdocManifest; hr = GetTransferManifest(NULL, &pdocManifest); if (SUCCEEDED(hr)) { IXMLDOMNode *pdn; hr = pdocManifest->selectSingleNode(XPATH_UPLOADINFO, &pdn); if (hr == S_OK) { // if there is a success/failure page defined then lets handle it accordingly WCHAR szPageToShow[INTERNET_MAX_URL_LENGTH] = {0}; if (SUCCEEDED(_hrFromTransfer)) { hr = GetURLFromElement(pdn, ELEMENT_SUCCESSPAGE, szPageToShow, ARRAYSIZE(szPageToShow)); } else { if (_hrFromTransfer == HRESULT_FROM_WIN32(ERROR_CANCELLED)) hr = GetURLFromElement(pdn, ELEMENT_CANCELLEDPAGE, szPageToShow, ARRAYSIZE(szPageToShow)); if ((_hrFromTransfer != HRESULT_FROM_WIN32(ERROR_CANCELLED)) || FAILED(hr)) hr = GetURLFromElement(pdn, ELEMENT_FAILUREPAGE, szPageToShow, ARRAYSIZE(szPageToShow)); } // if we have the page then lets navigate to it, this will give us the succes // failure pages from the site. if (SUCCEEDED(hr) && szPageToShow[0]) { hr = _pwwe->SetInitialURL(szPageToShow); if (SUCCEEDED(hr)) { hr = _pwwe->GetFirstPage(&hpResult); } } // lets do the final processing of the transfer (creating net places, favorites etc) _CreateFavorite(pdn); pdn->Release(); } pdocManifest->Release(); } return hpResult; } // this is the copying dialog. this displays the progress bar and other information as // we transfer the files from the users m/c to the site. INT_PTR CPublishingWizard::_CopyDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch ( uMsg ) { case WM_INITDIALOG: _hwndCopyingPage = hwnd; return FALSE; case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR)lParam; switch (pnmh->code) { case PSN_SETACTIVE: _BeginTransfer(hwnd); return TRUE; case PSN_QUERYCANCEL: { _fCancelled = TRUE; SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LPARAM)TRUE); return TRUE; } } break; } case WM_CTLCOLORSTATIC: { // we want the preview filled with a white background. if (GetDlgCtrlID((HWND)lParam) == IDC_PUB_PREVIEW) { return (INT_PTR)(COLOR_3DHILIGHT+1); } return FALSE; } case PWM_TRANSFERCOMPLETE: { PropSheet_SetCurSel(GetParent(hwnd), _TransferComplete((HRESULT)lParam), -1); break; } case PWM_UPDATE: { DWORD dwTotal = (DWORD)lParam; DWORD dwCompleted = (DWORD)wParam; SendDlgItemMessage(hwnd, IDC_PUB_FILEPROGRESS, PBM_SETRANGE32, 0, (LPARAM)dwTotal); SendDlgItemMessage(hwnd, IDC_PUB_FILEPROGRESS, PBM_SETPOS, (WPARAM)dwCompleted, 0); // compute the percentage of the file copied. int iPercentage = 0; if (dwTotal > 0) iPercentage = (dwCompleted * 100) / dwTotal; if (_iPercentageComplete != iPercentage) { TCHAR szBuffer[MAX_PATH]; FormatMessageString(IDS_PUB_COMPLETEFMT, szBuffer, ARRAYSIZE(szBuffer), iPercentage); SetDlgItemText(_hwndCopyingPage, IDC_PUB_LABELFILEPROG, szBuffer); } break; } case PWM_UPDATEICON: { HWND hwndThumbnail = GetDlgItem(hwnd, IDC_PUB_PREVIEW); DWORD dwStyle = (DWORD)GetWindowLongPtr(hwndThumbnail, GWL_STYLE) & ~(SS_BITMAP|SS_ICON); if (wParam == IMAGE_BITMAP) { SetWindowLongPtr(hwndThumbnail, GWL_STYLE, dwStyle | SS_BITMAP); HBITMAP hbmp = (HBITMAP)SendMessage(hwndThumbnail, STM_SETIMAGE, wParam, lParam); if (hbmp) { DeleteObject(hbmp); } } else if (wParam == IMAGE_ICON) { SetWindowLongPtr(hwndThumbnail, GWL_STYLE, dwStyle | SS_ICON); HICON hIcon = (HICON)SendMessage(hwndThumbnail, STM_SETIMAGE, wParam, lParam); if (hIcon) { DeleteObject(hIcon); } } else { DeleteObject((HGDIOBJ)lParam); } break; } } return FALSE; } // Manage the list of file types HRESULT CPublishingWizard::_AddExtenisonToList(HDPA hdpa, LPCTSTR pszExtension) { UINT iItem = 0; UINT nItems = DPA_GetPtrCount(hdpa); BOOL fFound = FALSE; for ( ;(iItem < nItems) && !fFound; iItem++) { LPCTSTR pszExtensionInDPA = (LPCTSTR) DPA_GetPtr(hdpa, iItem); if (pszExtensionInDPA) { fFound = (0 == StrCmpI(pszExtension, pszExtensionInDPA)); } } HRESULT hr = S_OK; if (!fFound) { LPTSTR pszAlloc; hr = E_OUTOFMEMORY; pszAlloc = StrDup(pszExtension); if (pszAlloc) { if (DPA_ERR == DPA_AppendPtr(hdpa, (void*)pszAlloc)) { LocalFree(pszAlloc); } else { hr = S_OK; } } } return hr; } int CPublishingWizard::s_FreeStringProc(void* pFreeMe, void* pData) { LocalFree(pFreeMe); return 1; } HRESULT CPublishingWizard::_GetUniqueTypeList(BOOL fIncludeFolder, HDPA *phdpa) { *phdpa = NULL; HRESULT hr = (*phdpa = DPA_Create(10)) ? S_OK:E_OUTOFMEMORY; if (SUCCEEDED(hr)) { // check for the folders type - eg. we have folders if (fIncludeFolder) { IXMLDOMNode *pdn; hr = _pdocManifest->selectSingleNode(XPATH_FILESROOT, &pdn); if (hr == S_OK) { IXMLDOMElement *pdel; hr = pdn->QueryInterface(IID_PPV_ARG(IXMLDOMElement, &pdel)); if (SUCCEEDED(hr)) { VARIANT var; if (pdel->getAttribute(ATTRIBUTE_HASFOLDERS, &var) == S_OK) { if ((var.vt == VT_BOOL) && (var.boolVal == VARIANT_TRUE)) { hr = _AddExtenisonToList(*phdpa, TEXT("Folder")); } VariantClear(&var); } pdel->Release(); } pdn->Release(); } } // walk the file nodes building the extension list for us IXMLDOMNodeList *pnl; hr = _pdocManifest->selectNodes(XPATH_ALLFILESTOUPLOAD, &pnl); if (hr == S_OK) { long cSelection; hr = pnl->get_length(&cSelection); for (long lNode = 0; SUCCEEDED(hr) && (lNode != cSelection); lNode++) { IXMLDOMNode *pdn; hr = pnl->get_item(lNode, &pdn); if (SUCCEEDED(hr)) { TCHAR szBuffer[MAX_PATH]; hr = GetStrFromAttribute(pdn, ATTRIBUTE_EXTENSION, szBuffer, ARRAYSIZE(szBuffer)); if (SUCCEEDED(hr)) { hr = _AddExtenisonToList(*phdpa, szBuffer); } pdn->Release(); } } pnl->Release(); } // clean up the type DPA if we failed.... if (FAILED(hr)) { DPA_DestroyCallback(*phdpa, s_FreeStringProc, 0); *phdpa = NULL; } } return hr; } // initialize the property bag we want to give to the site so that // they can display the correct HTML and direct the user in the // right direction. HRESULT CPublishingWizard::_InitPropertyBag(LPCTSTR pszURL) { HRESULT hr = S_OK; // lets initialize the wizard object so that we show the correct // pages, to determine this we need to if (pszURL) hr = _pwwe->SetInitialURL(pszURL); // now compile a list of the unique types, this will be placed into the // property bag. at this time we can also determine if there // are any images in our list, and therefore if we should prompt accordingly. _fOfferResize = FALSE; // no resize ATOMICRELEASE(_ppb); hr = SHCreatePropertyBagOnMemory(STGM_READWRITE, IID_PPV_ARG(IPropertyBag, &_ppb)); if (SUCCEEDED(hr)) { INT cExtensions = 0; // get the list of unique extensions and put those into the // property bag for the site to query - this should be removed in time and // we should have the site favor the file Manifest HDPA hdpa; hr = _GetUniqueTypeList(TRUE, &hdpa); if (SUCCEEDED(hr)) { for (int i = 0; (i < DPA_GetPtrCount(hdpa)) && (SUCCEEDED(hr)); i++) { LPCTSTR pszExtension = (LPCTSTR)DPA_GetPtr(hdpa, i); if (pszExtension) { if (!(_dwFlags & SHPWHF_NORECOMPRESS)) _fOfferResize = (_fOfferResize || PathIsImage(pszExtension)); TCHAR szProperty[255]; wnsprintf(szProperty, ARRAYSIZE(szProperty), PROPERTY_EXTENSION TEXT("%d"), PROPERTY_EXTENSION, i); hr = SHPropertyBag_WriteStr(_ppb, szProperty, pszExtension); if (SUCCEEDED(hr)) { cExtensions++; } } } DPA_DestroyCallback(hdpa, s_FreeStringProc, 0); } // initialize property bag with UI elements (ignoring the error from above, just won't have an // extension list to present) SHPropertyBag_WriteInt(_ppb, PROPERTY_EXTENSIONCOUNT, cExtensions); // we should always have a manifest object, therefore lets put it into the // property bag so that the site can extract it. IXMLDOMDocument *pdocManifest; hr = CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IXMLDOMDocument, &pdocManifest)); if (SUCCEEDED(hr)) { VARIANT varCurManifest = { VT_DISPATCH }; hr = _pdocManifest->QueryInterface(IID_PPV_ARG(IDispatch, &varCurManifest.pdispVal)); if (SUCCEEDED(hr)) { // load the manifest into the new document that we have. VARIANT_BOOL fSuccess; hr = pdocManifest->load(varCurManifest, &fSuccess); if ((fSuccess == VARIANT_TRUE) && (hr == S_OK)) { hr = s_SetPropertyFromDisp(_ppb, PROPERTY_TRANSFERMANIFEST, pdocManifest); } VariantClear(&varCurManifest); } } } return hr; } // handle building the file manifest from the IDataObject, this consists of walking the list of // files and putting together a class CPubWizardWalkCB : public INamespaceWalkCB { public: CPubWizardWalkCB(IXMLDOMDocument *pdocManifest); ~CPubWizardWalkCB(); // IUnknown STDMETHOD(QueryInterface)(REFIID riid, void **ppvObj); STDMETHOD_(ULONG,AddRef)(); STDMETHOD_(ULONG,Release)(); // INamespaceWalkCB STDMETHODIMP FoundItem(IShellFolder *psf, LPCITEMIDLIST pidl); STDMETHODIMP EnterFolder(IShellFolder *psf, LPCITEMIDLIST pidl); STDMETHODIMP LeaveFolder(IShellFolder *psf, LPCITEMIDLIST pidl); STDMETHODIMP InitializeProgressDialog(LPWSTR *ppszTitle, LPWSTR *ppszCancel) { *ppszTitle = NULL; *ppszCancel = NULL; return E_NOTIMPL; } private: LONG _cRef; // object lifetime count TCHAR _szWalkPath[MAX_PATH]; // path of the folder we are walking INT _idFile; // id of file we have walked IXMLDOMDocument *_pdocManifest; // manifest we are populating void _AddImageMetaData(IShellFolder2 *psf2, LPCITEMIDLIST pidl, IXMLDOMElement *pdel); }; CPubWizardWalkCB::CPubWizardWalkCB(IXMLDOMDocument *pdocManifest) : _cRef(1), _pdocManifest(pdocManifest) { _pdocManifest->AddRef(); _szWalkPath[0] = TEXT('\0'); // no path yet. } CPubWizardWalkCB::~CPubWizardWalkCB() { _pdocManifest->Release(); } // IUnknown ULONG CPubWizardWalkCB::AddRef() { return InterlockedIncrement(&_cRef); } ULONG CPubWizardWalkCB::Release() { if (InterlockedDecrement(&_cRef)) return _cRef; delete this; return 0; } HRESULT CPubWizardWalkCB::QueryInterface(REFIID riid, void **ppv) { static const QITAB qit[] = { QITABENT(CPubWizardWalkCB, INamespaceWalkCB), // IID_INamespaceWalkCB {0, 0 }, }; return QISearch(this, qit, riid, ppv); } void CPubWizardWalkCB::_AddImageMetaData(IShellFolder2 *psf2, LPCITEMIDLIST pidl, IXMLDOMElement *pdel) { struct { LPWSTR pszID; const SHCOLUMNID *pscid; } _aMetaData[] = { {L"cx", &SCID_ImageCX}, {L"cy", &SCID_ImageCY}, }; // eventually break this into a helper function, or read this from the info tip for (int i = 0; i < ARRAYSIZE(_aMetaData); i++) { VARIANT var = {0}; HRESULT hr = psf2->GetDetailsEx(pidl, _aMetaData[i].pscid, &var); if (hr == S_OK) { IXMLDOMElement *pdelProperty; hr = CreateAndAppendElement(_pdocManifest, pdel, ELEMENT_IMAGEDATA, &var, &pdelProperty); if (SUCCEEDED(hr)) { hr = SetAttributeFromStr(pdelProperty, ATTRIBUTE_ID, _aMetaData[i].pszID); pdelProperty->Release(); } VariantClear(&var); } } } // INamepsaceWalkCB HRESULT CPubWizardWalkCB::FoundItem(IShellFolder *psf, LPCITEMIDLIST pidl) { IXMLDOMNode *pdn; HRESULT hr = _pdocManifest->selectSingleNode(XPATH_FILESROOT, &pdn); if (hr == S_OK) { IXMLDOMElement *pdel; hr = _pdocManifest->createElement(ELEMENT_FILE, &pdel); if (SUCCEEDED(hr)) { TCHAR szBuffer[MAX_PATH]; VARIANT var; // pass out the unique IDs for each of the elements in the tree var.vt = VT_I4; var.lVal = _idFile++; pdel->setAttribute(ATTRIBUTE_ID, var); // must be able to get the path for the item so that we can hr = DisplayNameOf(psf, pidl, SHGDN_FORPARSING, szBuffer, ARRAYSIZE(szBuffer)); if (SUCCEEDED(hr)) { // source path hr = SetAttributeFromStr(pdel, ATTRIBUTE_SOURCE, szBuffer); // extension = (extension to file) hr = SetAttributeFromStr(pdel, ATTRIBUTE_EXTENSION, PathFindExtension(szBuffer)); // lets put the content type TCHAR szContentType[MAX_PATH]; DWORD cch = ARRAYSIZE(szContentType); if (SUCCEEDED(AssocQueryString(0, ASSOCSTR_CONTENTTYPE, szBuffer, NULL, szContentType, &cch))) { hr = SetAttributeFromStr(pdel, ATTRIBUTE_CONTENTTYPE, szContentType); } } // put the proposed destination into the node hr = DisplayNameOf(psf, pidl, SHGDN_FORPARSING|SHGDN_INFOLDER, szBuffer, ARRAYSIZE(szBuffer)); if (SUCCEEDED(hr)) { TCHAR szPath[MAX_PATH]; PathCombine(szPath, _szWalkPath, szBuffer); hr = SetAttributeFromStr(pdel, ATTRIBUTE_DESTINATION, szBuffer); } // handle those properties we can get from the shell folder via GetDetailsEx IShellFolder2 *psf2; if (SUCCEEDED(psf->QueryInterface(IID_PPV_ARG(IShellFolder2, &psf2)))) { // push the size into the attribute list for the item if (SUCCEEDED(psf2->GetDetailsEx(pidl, &SCID_SIZE, &var))) { pdel->setAttribute(ATTRIBUTE_SIZE, var); VariantClear(&var); } // lets inject the meta data IXMLDOMElement *pdelMetaData; hr = CreateAndAppendElement(_pdocManifest, pdel, ELEMENT_METADATA, NULL, &pdelMetaData); if (SUCCEEDED(hr)) { _AddImageMetaData(psf2, pidl, pdelMetaData); pdelMetaData->Release(); } psf2->Release(); } // append the node to the list that we already have hr = pdn->appendChild(pdel, NULL); pdel->Release(); } pdn->Release(); } return S_OK; } HRESULT CPubWizardWalkCB::EnterFolder(IShellFolder *psf, LPCITEMIDLIST pidl) { // build the name of the folder we have entered. TCHAR szBuffer[MAX_PATH]; if (SUCCEEDED(DisplayNameOf(psf, pidl, SHGDN_FORPARSING|SHGDN_INFOLDER|SHGDN_FORADDRESSBAR, szBuffer, ARRAYSIZE(szBuffer)))) { PathAppend(_szWalkPath, szBuffer); } // lets update the files root to indicate that we are going to be using folders. IXMLDOMNode *pdn; HRESULT hr = _pdocManifest->selectSingleNode(XPATH_FILESROOT, &pdn); if (hr == S_OK) { IXMLDOMElement *pdel; hr = pdn->QueryInterface(IID_PPV_ARG(IXMLDOMElement, &pdel)); if (SUCCEEDED(hr)) { VARIANT var; var.vt = VT_BOOL; var.boolVal = VARIANT_TRUE; hr = pdel->setAttribute(ATTRIBUTE_HASFOLDERS, var); pdel->Release(); } pdn->Release(); } // now update the folders list with the new folder that we have just entered, first // try to find the folder list, if not found then create it. IXMLDOMNode *pdnFolders; hr = _pdocManifest->selectSingleNode(XPATH_FOLDERSROOT, &pdnFolders); if (hr == S_FALSE) { IXMLDOMNode *pdnRoot; hr = _pdocManifest->selectSingleNode(XPATH_MANIFEST, &pdnRoot); if (hr == S_OK) { IXMLDOMElement *pdelRoot; hr = pdnRoot->QueryInterface(IID_PPV_ARG(IXMLDOMElement, &pdelRoot)); if (SUCCEEDED(hr)) { IXMLDOMElement *pdelFolders; hr = CreateAndAppendElement(_pdocManifest, pdelRoot, ELEMENT_FOLDERS, NULL, &pdelFolders); if (SUCCEEDED(hr)) { hr = pdelFolders->QueryInterface(IID_PPV_ARG(IXMLDOMNode, &pdnFolders)); pdelFolders->Release(); } pdelRoot->Release(); } pdnRoot->Release(); } } // assuming we now have the folder list, lets now create a new element for this folder. if (SUCCEEDED(hr) && pdnFolders) { IXMLDOMElement *pdelFolder; hr = _pdocManifest->createElement(ELEMENT_FOLDER, &pdelFolder); if (SUCCEEDED(hr)) { hr = SetAttributeFromStr(pdelFolder, ATTRIBUTE_DESTINATION, _szWalkPath); if (SUCCEEDED(hr)) { hr = pdnFolders->appendChild(pdelFolder, NULL); } pdelFolder->Release(); } } return S_OK; // always succeed so we can transfer folders } HRESULT CPubWizardWalkCB::LeaveFolder(IShellFolder *psf, LPCITEMIDLIST pidl) { PathRemoveFileSpec(_szWalkPath); return S_OK; } // construct the manifest based on the document we have HRESULT CPublishingWizard::_AddFilesToManifest(IXMLDOMDocument *pdocManifest) { HRESULT hr = S_OK; if (_pdo || _pdoSelection) { CWaitCursor cur; // might take some time INamespaceWalk *pnsw; hr = CoCreateInstance(CLSID_NamespaceWalker, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(INamespaceWalk, &pnsw)); if (SUCCEEDED(hr)) { InitClipboardFormats(); CPubWizardWalkCB *pwcb = new CPubWizardWalkCB(pdocManifest); if (pwcb) { hr = pnsw->Walk(_pdoSelection ? _pdoSelection:_pdo, NSWF_NONE_IMPLIES_ALL, 0, SAFECAST(pwcb, INamespaceWalkCB *)); if (SUCCEEDED(hr)) { hr = pnsw->GetIDArrayResult(&_cItems, &_aItems); } pwcb->Release(); } else { hr = E_OUTOFMEMORY; } pnsw->Release(); } } return hr; } HRESULT CPublishingWizard::_BuildTransferManifest() { _FreeTransferManifest(); HRESULT hr = CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IXMLDOMDocument, &_pdocManifest)); if (SUCCEEDED(hr)) { IXMLDOMElement *pdelDoc; hr = CreateElement(_pdocManifest, ELEMENT_TRANSFERMANIFEST, NULL, &pdelDoc); if (SUCCEEDED(hr)) { hr = _pdocManifest->putref_documentElement(pdelDoc); if (SUCCEEDED(hr)) { hr = CreateAndAppendElement(_pdocManifest, pdelDoc, ELEMENT_FILES, NULL, NULL); if (SUCCEEDED(hr)) { hr = _AddFilesToManifest(_pdocManifest); } } pdelDoc->Release(); } } _fRecomputeManifest = FALSE; // the manifest has been recomputed, therefore we don't need to this again. _fRepopulateProviders = TRUE; // the provider list may have changed b/c the manifest changed. return hr; } void CPublishingWizard::_FreeTransferManifest() { ATOMICRELEASE(_pdocManifest); if (_aItems) { FreeIDListArray(_aItems, _cItems); _aItems = NULL; _cItems = 0; } } // Advanced location dialog, including the browse button.... typedef struct { LPTSTR pszPath; IDataObject *pdo; } BROWSEINIT; int _BrowseCallback(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData) { BROWSEINIT *pbi = (BROWSEINIT *)lpData; switch (uMsg) { case BFFM_INITIALIZED: { LPTSTR pszPath = pbi->pszPath; if (pszPath && pszPath[0]) { int i = lstrlen(pszPath) - 1; if ((pszPath[i] == TEXT('\\')) || (pszPath[i] == TEXT('/'))) { pszPath[i] = 0; } SendMessage(hwnd, BFFM_SETSELECTION, (WPARAM) TRUE, (LPARAM) (LPTSTR)pszPath); } else { LPITEMIDLIST pidl; HRESULT hr = SHGetSpecialFolderLocation(hwnd, CSIDL_NETWORK, &pidl); if (SUCCEEDED(hr)) { SendMessage(hwnd, BFFM_SETSELECTION, (WPARAM)FALSE, (LPARAM)((LPTSTR)pidl)); ILFree(pidl); } } break; } case BFFM_SELCHANGED: { BOOL fEnableOK = FALSE; LPCITEMIDLIST pidl = (LPCITEMIDLIST)lParam; // if we have a IDataObject then check to see if we can drop it onto the // destination we are given. this is used by the publishing process // to ensure that we enable/disable the OK. if (pbi->pdo) { IShellFolder *psf; LPCITEMIDLIST pidlChild; if (SUCCEEDED(SHBindToIDListParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlChild))) { IDropTarget *pdt; if (SUCCEEDED(psf->GetUIObjectOf(NULL, 1, &pidlChild, IID_PPV_ARG_NULL(IDropTarget, &pdt)))) { POINTL ptl = {0}; DWORD dwEffect = DROPEFFECT_COPY; if (SUCCEEDED(pdt->DragEnter(pbi->pdo, 0, ptl, &dwEffect))) { fEnableOK = (dwEffect & DROPEFFECT_COPY); pdt->DragLeave(); } pdt->Release(); } psf->Release(); } } else { ULONG rgInfo = SFGAO_STORAGE; if (SUCCEEDED(SHGetNameAndFlags(pidl, 0, NULL, 0, &rgInfo))) { fEnableOK = (rgInfo & SFGAO_STORAGE); } else { fEnableOK = TRUE; } } SendMessage(hwnd, BFFM_ENABLEOK, (WPARAM) 0, (LPARAM)fEnableOK); break; } } return 0; } void CPublishingWizard::_SetWaitCursor(BOOL bOn) { if (bOn) { _hCursor = SetCursor(LoadCursor(NULL, IDC_APPSTARTING)); } else if (_hCursor) { SetCursor(_hCursor); _hCursor = NULL; } } // Publishing location pages void CPublishingWizard::_ShowExampleTip(HWND hwnd) { TCHAR szTitle[256], szExamples[256]; LoadString(g_hinst, IDS_NETPLACE_EXAMPLES_TITLE, szTitle, ARRAYSIZE(szTitle)); LoadString(g_hinst, IDS_NETPLACE_EXAMPLES, szExamples, ARRAYSIZE(szExamples)); EDITBALLOONTIP ebt = {0}; ebt.cbStruct = sizeof(ebt); ebt.pszTitle = szTitle; ebt.pszText = szExamples; SetFocus(GetDlgItem(hwnd, IDC_FOLDER_EDIT)); // set focus before the balloon HWND hwndEdit = (HWND)SendDlgItemMessage(hwnd, IDC_FOLDER_EDIT, CBEM_GETEDITCONTROL, 0, 0L); Edit_ShowBalloonTip(hwndEdit, &ebt); } void CPublishingWizard::_LocationChanged(HWND hwnd) { if (_fValidating) { PropSheet_SetWizButtons(GetParent(hwnd), 0); } else { int cchLocation = FetchTextLength(hwnd, IDC_FOLDER_EDIT); PropSheet_SetWizButtons(GetParent(hwnd), PSWIZB_BACK|((cchLocation >0) ? PSWIZB_NEXT:0)); } } // auto complete bits #define SZ_REGKEY_AUTOCOMPLETE_TAB TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoComplete") #define SZ_REGVALUE_AUTOCOMPLETE_TAB TEXT("Always Use Tab") #define REGSTR_PATH_AUTOCOMPLETE TEXT("Software\\Microsoft\\windows\\CurrentVersion\\Explorer\\AutoComplete") #define REGSTR_VAL_USEAUTOAPPEND TEXT("Append Completion") #define REGSTR_VAL_USEAUTOSUGGEST TEXT("AutoSuggest") #define BOOL_NOT_SET 0x00000005 DWORD CPublishingWizard::_GetAutoCompleteFlags(DWORD dwFlags) { DWORD dwACOptions = 0; if (!(SHACF_AUTOAPPEND_FORCE_OFF & dwFlags) && ((SHACF_AUTOAPPEND_FORCE_ON & dwFlags) || SHRegGetBoolUSValue(REGSTR_PATH_AUTOCOMPLETE, REGSTR_VAL_USEAUTOAPPEND, FALSE, FALSE))) { dwACOptions |= ACO_AUTOAPPEND; } if (!(SHACF_AUTOSUGGEST_FORCE_OFF & dwFlags) && ((SHACF_AUTOSUGGEST_FORCE_ON & dwFlags) || SHRegGetBoolUSValue(REGSTR_PATH_AUTOCOMPLETE, REGSTR_VAL_USEAUTOSUGGEST, FALSE, TRUE))) { dwACOptions |= ACO_AUTOSUGGEST; } if (SHACF_USETAB & dwFlags) dwACOptions |= ACO_USETAB; // Windows uses the TAB key to move between controls in a dialog. UNIX and other // operating systems that use AutoComplete have traditionally used the TAB key to // iterate thru the AutoComplete possibilities. We need to default to disable the // TAB key (ACO_USETAB) unless the caller specifically wants it. We will also // turn it on static BOOL s_fAlwaysUseTab = BOOL_NOT_SET; if (BOOL_NOT_SET == s_fAlwaysUseTab) s_fAlwaysUseTab = SHRegGetBoolUSValue(SZ_REGKEY_AUTOCOMPLETE_TAB, SZ_REGVALUE_AUTOCOMPLETE_TAB, FALSE, FALSE); if (s_fAlwaysUseTab) dwACOptions |= ACO_USETAB; return dwACOptions; } HRESULT CPublishingWizard::_InitAutoComplete() { HRESULT hr = CoCreateInstance(CLSID_AutoComplete, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IAutoComplete2, &_pac)); if (SUCCEEDED(hr)) { hr = CoCreateInstance(CLSID_ACLMulti, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IUnknown, &_punkACLMulti)); if (SUCCEEDED(hr)) { IObjMgr *pomMulti; hr = _punkACLMulti->QueryInterface(IID_PPV_ARG(IObjMgr, &pomMulti)); if (SUCCEEDED(hr)) { // add the file system auto complete object (for handling UNC's etc) IUnknown *punk; hr = CoCreateInstance(CLSID_ACListISF, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IUnknown, &punk)); if (SUCCEEDED(hr)) { pomMulti->Append(punk); punk->Release(); } // add the publishing wizard auto complete object (for handling HTTP etc) IUnknown *punkCustomACL; hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IUnknown, &punkCustomACL)); if (SUCCEEDED(hr)) { hr = punkCustomACL->QueryInterface(IID_PPV_ARG(IACLCustomMRU, &_pmru)); if (SUCCEEDED(hr)) { TCHAR szKey[MAX_PATH]; wnsprintf(szKey, ARRAYSIZE(szKey), (SZ_REGKEY_PUBWIZ TEXT("\\%s\\") SZ_REGVAL_MRU), _szProviderScope); hr = _pmru->Initialize(szKey, 26); if (SUCCEEDED(hr)) { hr = pomMulti->Append(punkCustomACL); } } punkCustomACL->Release(); } pomMulti->Release(); } } } return hr; } // handle MRU of places you can publish to void CPublishingWizard::_InitLocation(HWND hwnd) { // lets initialize the auto complete list of folders that we have HRESULT hr = _InitAutoComplete(); if (SUCCEEDED(hr)) { IEnumString *penum; hr = _pmru->QueryInterface(IID_PPV_ARG(IEnumString, &penum)); if (SUCCEEDED(hr)) { penum->Reset(); // reset the enumerator ready for us to populate the list LPOLESTR pszEntry; ULONG ulFetched; while ((penum->Next(1, &pszEntry, &ulFetched) == S_OK) && ulFetched == 1) { COMBOBOXEXITEM cbei = {0}; cbei.mask = CBEIF_TEXT; cbei.pszText = pszEntry; SendDlgItemMessage(hwnd, IDC_FOLDER_EDIT, CBEM_INSERTITEM, 0, (LPARAM)&cbei); CoTaskMemFree(pszEntry); } penum->Release(); } // enable auto complete for this control. HWND hwndEdit = (HWND)SendDlgItemMessage(hwnd, IDC_FOLDER_EDIT, CBEM_GETEDITCONTROL, 0, 0L); _pac->Init(hwndEdit, _punkACLMulti, NULL, NULL); _pac->SetOptions(_GetAutoCompleteFlags(0)); // limit text on the edit control ComboBox_LimitText(GetDlgItem(hwnd, IDC_FOLDER_EDIT), INTERNET_MAX_URL_LENGTH); // if the policy says no map drive etc, then lets remove it BOOL fHide = SHRestricted(REST_NOENTIRENETWORK) || SHRestricted(REST_NONETCONNECTDISCONNECT); ShowWindow(GetDlgItem(hwnd, IDC_BROWSE), fHide ? SW_HIDE:SW_SHOW); } } // validation thread, this is performed on a background thread to compute if // the resource is valid. #define PWM_VALIDATEDONE (WM_APP) // -> validate done (HRESULT passed in LPARAM) typedef struct { HWND hwnd; // parent HWND BOOL fAllowWebFolders; // allow web folders during validation TCHAR szFileTarget[INTERNET_MAX_URL_LENGTH]; // destination for file copy } VALIDATETHREADDATA; DWORD CALLBACK CPublishingWizard::s_ValidateThreadProc(void *pv) { VALIDATETHREADDATA *pvtd = (VALIDATETHREADDATA*)pv; HRESULT hr = E_FAIL; // validate the site CNetworkPlace np; hr = np.SetTarget(pvtd->hwnd, pvtd->szFileTarget, NPTF_VALIDATE | (pvtd->fAllowWebFolders ? NPTF_ALLOWWEBFOLDERS:0)); np.SetTarget(NULL, NULL, 0); PostMessage(pvtd->hwnd, PWM_VALIDATEDONE, 0, (LPARAM)hr); LocalFree(pvtd); return 0; } void CPublishingWizard::_TryToValidateDestination(HWND hwnd) { TCHAR szDestination[INTERNET_MAX_URL_LENGTH]; FetchText(hwnd, IDC_FOLDER_EDIT, szDestination, ARRAYSIZE(szDestination)); // lets walk the list source files and try to match to the destination we have. // we don't want to let source be the destination BOOL fHitItem = FALSE; LPITEMIDLIST pidl = ILCreateFromPath(szDestination); if (pidl) { BOOL fUNC = PathIsUNC(szDestination); //only if destination is UNC Path do we need to check if source is a mapped drive for (UINT iItem = 0; (iItem != _cItems) && !fHitItem; iItem++) { LPITEMIDLIST pidlSrcDir = ILClone(_aItems[iItem]); if (pidlSrcDir) { ILRemoveLastID(pidlSrcDir); fHitItem = ILIsEqual(pidlSrcDir, pidl) || (!ILIsEmpty(pidlSrcDir) && ILIsParent(pidlSrcDir, pidl, FALSE)); if (!fHitItem && fUNC) { WCHAR szPath[MAX_PATH]; if (SUCCEEDED(SHGetPathFromIDList(pidlSrcDir, szPath)) && !PathIsUNC(szPath)) { WCHAR szSource[MAX_PATH]; DWORD cchSource = ARRAYSIZE(szSource); DWORD dwType = SHWNetGetConnection(szPath, szSource, &cchSource); if ((dwType == NO_ERROR) || (dwType == ERROR_CONNECTION_UNAVAIL)) { fHitItem = (StrCmpNI(szSource, szDestination, lstrlen(szSource)) == 0); } } } ILFree(pidlSrcDir); } } ILFree(pidl); } // if we didn't get a hit that way then lets spin up a thread which will do the // validation of the server and the connection - this is a lengthy operation // and will post a result to the window. if (!fHitItem) { VALIDATETHREADDATA *pvtd = (VALIDATETHREADDATA*)LocalAlloc(LPTR, sizeof(*pvtd)); if (pvtd) { pvtd->hwnd = hwnd; pvtd->fAllowWebFolders = (_dwFlags & SHPWHF_VALIDATEVIAWEBFOLDERS) != 0; // fetch the user typed url StrCpy(pvtd->szFileTarget, szDestination); // we have the thread data read, so lets begin the validation // by creating the thread - our state is set to indicate we are in the // validate mode. _fValidating = TRUE; // we are going to begin validating _SetWaitCursor(TRUE); if (!SHCreateThread(s_ValidateThreadProc, pvtd, CTF_INSIST | CTF_COINIT, NULL)) { LocalFree(pvtd); _fValidating = FALSE; _SetWaitCursor(FALSE); } } } else { ShellMessageBox(g_hinst, hwnd, MAKEINTRESOURCE(IDS_PUB_SAMETARGET), NULL, MB_ICONEXCLAMATION | MB_OK); PostMessage(hwnd, PWM_VALIDATEDONE, 0, (LPARAM)E_FAIL); } // ensure the state of the controls reflects what we are trying to do. _LocationChanged(hwnd); EnableWindow(GetDlgItem(hwnd, IDC_FOLDER_EDIT), !_fValidating); EnableWindow(GetDlgItem(hwnd, IDC_BROWSE), !_fValidating); } // this is the dialog proc for the location dialog. INT_PTR CPublishingWizard::_LocationDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_INITDIALOG: { _MapDlgItemText(hwnd, IDC_PUB_LOCATIONCAPTION, L"wp:location", L"locationcaption"); _InitLocation(hwnd); return TRUE; } case WM_DESTROY: { ATOMICRELEASE(_pac); ATOMICRELEASE(_punkACLMulti); ATOMICRELEASE(_pmru); return FALSE; } case WM_COMMAND: { switch (LOWORD(wParam)) { case IDC_BROWSE: { LPITEMIDLIST pidl; if (SHGetSpecialFolderLocation(hwnd, CSIDL_NETWORK, &pidl) == S_OK) { TCHAR szPath[MAX_PATH]; FetchText(hwnd, IDC_FOLDER_EDIT, szPath, ARRAYSIZE(szPath)); TCHAR szTitle[MAX_PATH]; if (FAILED(_LoadMappedString(L"wp:location", L"browsecaption", szTitle, ARRAYSIZE(szTitle)))) { LoadString(g_hinst, IDS_PUB_BROWSETITLE, szTitle, ARRAYSIZE(szTitle)); } // lets initialize our state structure for the browse dialog. based on this we can then // attempt to select a network place. from here we will also pass the IDataObject // we have (there may not be one of course) BROWSEINIT binit = {szPath}; if (_pdoSelection) _pdoSelection->QueryInterface(IID_PPV_ARG(IDataObject, &binit.pdo)); else if (_pdo) _pdo->QueryInterface(IID_PPV_ARG(IDataObject, &binit.pdo)); BROWSEINFO bi = {0}; bi.hwndOwner = hwnd; bi.pidlRoot = pidl; bi.lpszTitle = szTitle; bi.ulFlags = BIF_NEWDIALOGSTYLE; bi.lpfn = _BrowseCallback; bi.lParam = (LPARAM)&binit; LPITEMIDLIST pidlReturned = SHBrowseForFolder(&bi); if (pidlReturned) { if (SUCCEEDED(SHGetNameAndFlags(pidlReturned, SHGDN_FORPARSING, szPath, ARRAYSIZE(szPath), NULL))) SetDlgItemText(hwnd, IDC_FOLDER_EDIT, szPath); ILFree(pidlReturned); } if (binit.pdo) binit.pdo->Release(); ILFree(pidl); } return TRUE; } case IDC_FOLDER_EDIT: if (HIWORD(wParam) == CBN_EDITCHANGE) { _LocationChanged(hwnd); } return TRUE; } break; } case WM_SETCURSOR: if (_fValidating) { SetCursor(LoadCursor(NULL, IDC_APPSTARTING)); return TRUE; } return FALSE; case PWM_VALIDATEDONE: { _fValidating = FALSE; _LocationChanged(hwnd); _SetWaitCursor(FALSE); HRESULT hr = _InitPropertyBag(NULL); if (SUCCEEDED(hr)) { TCHAR szBuffer[MAX_PATH], szURL[INTERNET_MAX_URL_LENGTH]; FetchText(hwnd, IDC_FOLDER_EDIT, szURL, ARRAYSIZE(szURL)); // push the destination site into the property bag, and then initialize // our site with the right information IXMLDOMDocument *pdocManifest; hr = GetTransferManifest(NULL, &pdocManifest); if (SUCCEEDED(hr)) { IXMLDOMNode *pdnRoot; hr = pdocManifest->selectSingleNode(XPATH_MANIFEST, &pdnRoot); if (hr == S_OK) { IXMLDOMElement *pdelRoot; hr = pdnRoot->QueryInterface(IID_PPV_ARG(IXMLDOMElement, &pdelRoot)); if (SUCCEEDED(hr)) { IXMLDOMElement *pdelUploadInfo; hr = CreateAndAppendElement(_pdocManifest, pdelRoot, ELEMENT_UPLOADINFO, NULL, &pdelUploadInfo); if (SUCCEEDED(hr)) { IXMLDOMElement *pdelTarget; hr = CreateAndAppendElement(_pdocManifest, pdelUploadInfo, ELEMENT_TARGET, NULL, &pdelTarget); if (SUCCEEDED(hr)) { hr = SetAttributeFromStr(pdelTarget, ATTRIBUTE_HREF, szURL); pdelTarget->Release(); } pdelUploadInfo->Release(); } pdelRoot->Release(); } pdnRoot->Release(); } pdocManifest->Release(); } // lets now process the result hr = (HRESULT)lParam; if (S_OK == hr) { BOOL fGotoNextPage = TRUE; // fake a return so auto complete can do its thing SendMessage(GetDlgItem(hwnd, IDC_FOLDER_EDIT), WM_KEYDOWN, VK_RETURN, 0x1c0001); // add the string to the MRU if (_pmru) _pmru->AddMRUString(szURL); // lets sniff the string they entered, if its a URL and its FTP // then we must special case the password in the URL, otherwise // we jump directly to the friendly name handling. URL_COMPONENTS urlComps = {0}; urlComps.dwStructSize = sizeof(urlComps); urlComps.lpszScheme = szBuffer; urlComps.dwSchemeLength = ARRAYSIZE(szBuffer); if (InternetCrackUrl(szURL, 0, ICU_DECODE, &urlComps) && (INTERNET_SCHEME_FTP == urlComps.nScheme)) { URL_COMPONENTS urlComps = {0}; urlComps.dwStructSize = sizeof(URL_COMPONENTS); urlComps.nScheme = INTERNET_SCHEME_FTP; urlComps.lpszUserName = szBuffer; urlComps.dwUserNameLength = ARRAYSIZE(szBuffer); // if the user specified a user name, if not then goto the FTP user // page (we known its a FTP location) if (!InternetCrackUrl(szURL, 0, 0, &urlComps) || !szBuffer[0]) { _WizardNext(hwnd, WIZPAGE_FTPUSER); fGotoNextPage = FALSE; } } if (fGotoNextPage) _WizardNext(hwnd, WIZPAGE_FRIENDLYNAME); } } EnableWindow(GetDlgItem(hwnd, IDC_FOLDER_EDIT), TRUE); EnableWindow(GetDlgItem(hwnd, IDC_BROWSE), TRUE); if (FAILED(((HRESULT)lParam))) _ShowExampleTip(hwnd); return TRUE; } case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR)lParam; switch (pnmh->code) { case PSN_SETACTIVE: _fShownCustomLocation = TRUE; // so we navigate back to this page _fShownUserName = FALSE; _LocationChanged(hwnd); return TRUE; case PSN_WIZBACK: return _WizardNext(hwnd, WIZPAGE_PROVIDERS); case PSN_WIZNEXT: _TryToValidateDestination(hwnd); SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LPARAM)-1); return TRUE; case NM_CLICK: case NM_RETURN: { if (pnmh->idFrom == IDC_EXAMPLESLINK) { _ShowExampleTip(hwnd); return TRUE; } } } break; } } return FALSE; } // FTP login dialog - handle the messages for this void CPublishingWizard::_UserNameChanged(HWND hwnd) { BOOL fAnonymousLogin = IsDlgButtonChecked(hwnd, IDC_PASSWORD_ANONYMOUS); ShowWindow(GetDlgItem(hwnd, IDC_USER), (fAnonymousLogin ? SW_HIDE : SW_SHOW)); ShowWindow(GetDlgItem(hwnd, IDC_USERNAME_LABEL), (fAnonymousLogin ? SW_HIDE : SW_SHOW)); ShowWindow(GetDlgItem(hwnd, IDC_ANON_USERNAME), (fAnonymousLogin ? SW_SHOW : SW_HIDE)); ShowWindow(GetDlgItem(hwnd, IDC_ANON_USERNAME_LABEL), (fAnonymousLogin ? SW_SHOW : SW_HIDE)); // Hide the "You will be prompted for the password when you connect to the FTP server" text on anonymous EnableWindow(GetDlgItem(hwnd, IDC_PWD_PROMPT), !fAnonymousLogin); ShowWindow(GetDlgItem(hwnd, IDC_PWD_PROMPT), (fAnonymousLogin ? SW_HIDE : SW_SHOW)); } INT_PTR CPublishingWizard::_UserNameDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { case WM_INITDIALOG: { CheckDlgButton(hwnd, IDC_PASSWORD_ANONYMOUS, BST_CHECKED); EnableWindow(GetDlgItem(hwnd, IDC_ANON_USERNAME), FALSE); EnableWindow(GetDlgItem(hwnd, IDC_ANON_USERNAME_LABEL), FALSE); SetWindowText(GetDlgItem(hwnd, IDC_ANON_USERNAME), TEXT("Anonymous")); return TRUE; } case WM_COMMAND: { switch (LOWORD(wParam)) { case IDC_PASSWORD_ANONYMOUS: _UserNameChanged(hwnd); return TRUE; } break; } case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR)lParam; switch (pnmh->code) { case PSN_SETACTIVE: { _fShownUserName = TRUE; // so we can navigate back properly _UserNameChanged(hwnd); return TRUE; } case PSN_WIZBACK: return _WizardNext(hwnd, WIZPAGE_LOCATION); case PSN_WIZNEXT: { // if we can get a user name then lets push it into the property // bag, a NULL string == anonymous logon TCHAR szUserName[INTERNET_MAX_USER_NAME_LENGTH] = {0}; if (!IsDlgButtonChecked(hwnd, IDC_PASSWORD_ANONYMOUS)) { FetchText(hwnd, IDC_USER, szUserName, ARRAYSIZE(szUserName)); } // get the sites property bag, and persist the string into it, // if we have done that then we can go to the next page. IXMLDOMDocument *pdocManifest; HRESULT hr = GetTransferManifest(NULL, &pdocManifest); if (SUCCEEDED(hr)) { IXMLDOMNode *pdn; hr = pdocManifest->selectSingleNode(XPATH_UPLOADTARGET, &pdn); if (hr == S_OK) { hr = SetAttributeFromStr(pdn, ATTRIBUTE_USERNAME, szUserName); pdn->Release(); } pdocManifest->Release(); } return _WizardNext(hwnd, WIZPAGE_FRIENDLYNAME); } } break; } } return FALSE; } // set the friendly name for the web place - if it doesn't already exist void CPublishingWizard::_FriendlyNameChanged(HWND hwnd) { int cchLocation = FetchTextLength(hwnd, IDC_NETPLNAME_EDIT); PropSheet_SetWizButtons(GetParent(hwnd), PSWIZB_BACK |((cchLocation >0) ? PSWIZB_NEXT:0)); } INT_PTR CPublishingWizard::_FriendlyNameDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) { switch (uMsg) { // lets get the limit information for the nethood folder case WM_INITDIALOG: { LPITEMIDLIST pidlNetHood; if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_NETHOOD, &pidlNetHood))) { IShellFolder *psf; if (SUCCEEDED(SHBindToObject(NULL, IID_X_PPV_ARG(IShellFolder, pidlNetHood, &psf)))) { SHLimitInputEdit(GetDlgItem(hwnd, IDC_NETPLNAME_EDIT), psf); psf->Release(); } ILFree(pidlNetHood); } _FriendlyNameChanged(hwnd); break; } case WM_COMMAND: { switch (LOWORD(wParam)) { case IDC_NETPLNAME_EDIT: { if (HIWORD(wParam) == EN_CHANGE) { _FriendlyNameChanged(hwnd); return TRUE; } break; } } break; } case WM_NOTIFY: { LPNMHDR pnmh = (LPNMHDR)lParam; switch (pnmh->code) { case PSN_SETACTIVE: { // read from the manifest the target URL that we are going to be putting the // files to, from this we can compute the friendly name information. IXMLDOMDocument *pdocManifest; HRESULT hr = GetTransferManifest(NULL, &pdocManifest); if (SUCCEEDED(hr)) { IXMLDOMNode *pdn; hr = pdocManifest->selectSingleNode(XPATH_UPLOADTARGET, &pdn); if (hr == S_OK) { TCHAR szURL[INTERNET_MAX_URL_LENGTH]; hr = GetStrFromAttribute(pdn, ATTRIBUTE_HREF, szURL, ARRAYSIZE(szURL)); if (SUCCEEDED(hr)) { _npCustom.SetTarget(hwnd, szURL, (_dwFlags & SHPWHF_VALIDATEVIAWEBFOLDERS) ? NPTF_ALLOWWEBFOLDERS:0); TCHAR szUserName[INTERNET_MAX_USER_NAME_LENGTH]; hr = GetStrFromAttribute(pdn, ATTRIBUTE_USERNAME, szUserName, ARRAYSIZE(szUserName)); if (SUCCEEDED(hr)) _npCustom.SetLoginInfo(szUserName, NULL); TCHAR szBuffer[MAX_PATH + INTERNET_MAX_URL_LENGTH]; if (FormatMessageString(IDS_COMPLETION_STATIC, szBuffer, ARRAYSIZE(szBuffer), szURL)) { SetDlgItemText(hwnd, IDC_COMPLETION_STATIC, szBuffer); } // Create a default name and display it hr = _npCustom.GetName(szBuffer, ARRAYSIZE(szBuffer)); SetDlgItemText(hwnd, IDC_NETPLNAME_EDIT, SUCCEEDED(hr) ? szBuffer:TEXT("")); // Update the button state for the page etc. _FriendlyNameChanged(hwnd); } pdn->Release(); } } return TRUE; } case PSN_WIZBACK: _WizardNext(hwnd, _fShownUserName ? WIZPAGE_FTPUSER:WIZPAGE_LOCATION); return TRUE; case PSN_WIZNEXT: { TCHAR szFriendlyName[MAX_PATH]; FetchText(hwnd, IDC_NETPLNAME_EDIT, szFriendlyName, ARRAYSIZE(szFriendlyName)); // set the name of the new place, if this fails then the name is already taken // and UI will have been displayed saying so, and they responded with a // NO to the overwrite prompt. HRESULT hr = _npCustom.SetName(hwnd, szFriendlyName); if (SUCCEEDED(hr)) { IXMLDOMDocument *pdocManifest; HRESULT hr = GetTransferManifest(NULL, &pdocManifest); if (SUCCEEDED(hr)) { IXMLDOMNode *pdn; hr = pdocManifest->selectSingleNode(XPATH_UPLOADINFO, &pdn); if (hr == S_OK) { hr = SetAttributeFromStr(pdn, ATTRIBUTE_FRIENDLYNAME, szFriendlyName); pdn->Release(); } pdocManifest->Release(); } // Clean up after our custom netplace now. // This way everything works for webfolders when the outer ANP netplace // creates the webfolder. DSheldon 387476 _npCustom.SetTarget(NULL, NULL, 0x0); if (_pdo) { _WizardNext(hwnd, _fOfferResize ? WIZPAGE_RESIZE:WIZPAGE_COPYING); } else { IWizardSite *pws; hr = _punkSite->QueryInterface(IID_PPV_ARG(IWizardSite, &pws)); if (SUCCEEDED(hr)) { HPROPSHEETPAGE hpage; hr = pws->GetNextPage(&hpage); if (SUCCEEDED(hr)) { PropSheet_SetCurSel(GetParent(hwnd), hpage, -1); } pws->Release(); } } } SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LPARAM)-1); return TRUE; } } break; } } return FALSE; }