mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4508 lines
157 KiB
4508 lines
157 KiB
#include "stdafx.h"
|
|
#include "shimgdata.h"
|
|
#include "shui.h"
|
|
#include "netplace.h"
|
|
#include <Ntquery.h>
|
|
#include <shellp.h>
|
|
#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<TRANSFERITEM> *pdpaItems, IXMLDOMNode *pdn);
|
|
HRESULT _AddPostItem(CDPA<TRANSFERITEM> *pdpaItems, IXMLDOMNode *pdn);
|
|
void _FreeTransferManifest();
|
|
HRESULT _AddFilesToManifest(IXMLDOMDocument *pdocManifest);
|
|
HRESULT _BuildTransferManifest();
|
|
HRESULT _GetUniqueTypeList(BOOL fIncludeFolder, HDPA *phdpa);
|
|
HRESULT _InitTransferInfo(IXMLDOMDocument *pdocManifest, TRANSFERINFO *pti, CDPA<TRANSFERITEM> *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 <resize/> 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<TRANSFERITEM> *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<TRANSFERITEM> *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<TRANSFERITEM> *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 <uploadinfo/> 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 <contrycode>.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; i<ARRAYSIZE(c_auTileColumns); i++)
|
|
{
|
|
LV_COLUMN col;
|
|
col.mask = LVCF_SUBITEM;
|
|
col.iSubItem = c_auTileColumns[i];
|
|
ListView_InsertColumn(hwndList, i, &col);
|
|
}
|
|
|
|
RECT rc;
|
|
GetClientRect(hwndList, &rc);
|
|
|
|
LVTILEVIEWINFO lvtvi;
|
|
lvtvi.cbSize = sizeof(LVTILEVIEWINFO);
|
|
lvtvi.dwMask = LVTVIM_TILESIZE | LVTVIM_COLUMNS;
|
|
lvtvi.dwFlags = LVTVIF_FIXEDWIDTH;
|
|
lvtvi.sizeTile.cx = RECTWIDTH(rc) - GetSystemMetrics(SM_CXVSCROLL);
|
|
lvtvi.cLines = ARRAYSIZE(c_auTileSubItems);
|
|
ListView_SetTileViewInfo(hwndList, &lvtvi);
|
|
|
|
if (_pdocProviders)
|
|
{
|
|
long lReadyState;
|
|
HRESULT hr = _pdocProviders->get_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<TRANSFERITEM> 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 <favorite/> 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;
|
|
}
|