Source code of Windows XP (NT5)
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

  1. #include "stdafx.h"
  2. #include "shimgdata.h"
  3. #include "shui.h"
  4. #include "netplace.h"
  5. #include <Ntquery.h>
  6. #include <shellp.h>
  7. #include "pubwiz.h"
  8. #include "gdiplus\gdiplus.h"
  9. #include "imgprop.h"
  10. #include "shdguid.h"
  11. #include "urlmon.h"
  12. #include "xmldomdid.h"
  13. #include "winnlsp.h"
  14. #pragma hdrstop
  15. // handle the events from the DOM as we load
  16. #define XMLDOC_LOADING 1
  17. #define XMLDOC_LOADED 2
  18. #define XMLDOC_INTERACTIVE 3
  19. #define XMLDOC_COMPLETED 4
  20. // this message is posted to the parent HWND, the lParam parse result
  21. #define MSG_XMLDOC_COMPLETED WM_APP
  22. class CXMLDOMStateChange : public IDispatch
  23. {
  24. public:
  25. CXMLDOMStateChange(IXMLDOMDocument *pdoc, HWND hwnd);
  26. ~CXMLDOMStateChange();
  27. HRESULT Advise(BOOL fAdvise);
  28. // IUnknown
  29. STDMETHODIMP QueryInterface(REFIID riid, void **ppv);
  30. STDMETHODIMP_(ULONG) AddRef();
  31. STDMETHODIMP_(ULONG) Release();
  32. // IDispatch
  33. STDMETHODIMP GetTypeInfoCount( UINT *pctinfo)
  34. { return E_NOTIMPL; }
  35. STDMETHODIMP GetTypeInfo(UINT iTInfo, LCID lcid, ITypeInfo **ppTInfo)
  36. { return E_NOTIMPL; }
  37. STDMETHODIMP GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
  38. { return E_NOTIMPL; }
  39. STDMETHODIMP Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pvar, EXCEPINFO *pExcepInfo, UINT *puArgErr);
  40. private:
  41. long _cRef;
  42. IXMLDOMDocument *_pdoc;
  43. DWORD _dwCookie;
  44. HWND _hwnd;
  45. };
  46. // construction and IUnknown
  47. CXMLDOMStateChange::CXMLDOMStateChange(IXMLDOMDocument *pdoc, HWND hwnd) :
  48. _cRef(1), _dwCookie(0), _hwnd(hwnd)
  49. {
  50. IUnknown_Set((IUnknown**)&_pdoc, pdoc);
  51. }
  52. CXMLDOMStateChange::~CXMLDOMStateChange()
  53. {
  54. IUnknown_Set((IUnknown**)&_pdoc, NULL);
  55. }
  56. ULONG CXMLDOMStateChange::AddRef()
  57. {
  58. return InterlockedIncrement(&_cRef);
  59. }
  60. ULONG CXMLDOMStateChange::Release()
  61. {
  62. if (InterlockedDecrement(&_cRef))
  63. return _cRef;
  64. delete this;
  65. return 0;
  66. }
  67. HRESULT CXMLDOMStateChange::QueryInterface(REFIID riid, void **ppv)
  68. {
  69. static const QITAB qit[] = {
  70. QITABENT(CXMLDOMStateChange, IDispatch),
  71. { 0 },
  72. };
  73. return QISearch(this, qit, riid, ppv);
  74. }
  75. // handle the advise/unadvise to the parent object
  76. HRESULT CXMLDOMStateChange::Advise(BOOL fAdvise)
  77. {
  78. IConnectionPointContainer *pcpc;
  79. HRESULT hr = _pdoc->QueryInterface(IID_PPV_ARG(IConnectionPointContainer, &pcpc));
  80. if (SUCCEEDED(hr))
  81. {
  82. IConnectionPoint *pcp;
  83. hr = pcpc->FindConnectionPoint(DIID_XMLDOMDocumentEvents, &pcp);
  84. if (SUCCEEDED(hr))
  85. {
  86. if (fAdvise)
  87. {
  88. hr = pcp->Advise(SAFECAST(this, IDispatch *), &_dwCookie);
  89. }
  90. else if (_dwCookie)
  91. {
  92. hr = pcp->Unadvise(_dwCookie);
  93. _dwCookie = 0;
  94. }
  95. pcp->Release();
  96. }
  97. pcpc->Release();
  98. }
  99. return hr;
  100. }
  101. // handle the invoke for the doc state changing
  102. HRESULT CXMLDOMStateChange::Invoke(DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pvar, EXCEPINFO *pExcepInfo, UINT *puArgErr)
  103. {
  104. HRESULT hr = S_OK;
  105. switch (dispIdMember)
  106. {
  107. case DISPID_XMLDOMEVENT_ONREADYSTATECHANGE:
  108. {
  109. long lReadyState;
  110. if (SUCCEEDED(_pdoc->get_readyState(&lReadyState)))
  111. {
  112. if (lReadyState == XMLDOC_COMPLETED)
  113. {
  114. IXMLDOMParseError *pdpe;
  115. hr = _pdoc->get_parseError(&pdpe);
  116. if (SUCCEEDED(hr))
  117. {
  118. long lError;
  119. hr = pdpe->get_errorCode(&lError);
  120. if (SUCCEEDED(hr))
  121. {
  122. hr = (HRESULT)lError;
  123. }
  124. PostMessage(_hwnd, MSG_XMLDOC_COMPLETED, 0, (LPARAM)hr);
  125. pdpe->Release();
  126. }
  127. }
  128. }
  129. break;
  130. }
  131. }
  132. return hr;
  133. }
  134. // copied from shell stuff - should be in public header
  135. #define DEFINE_SCID(name, fmtid, pid) const SHCOLUMNID name = { fmtid, pid }
  136. DEFINE_SCID(SCID_NAME, PSGUID_STORAGE, PID_STG_NAME);
  137. DEFINE_SCID(SCID_TYPE, PSGUID_STORAGE, PID_STG_STORAGETYPE);
  138. DEFINE_SCID(SCID_SIZE, PSGUID_STORAGE, PID_STG_SIZE);
  139. DEFINE_SCID(SCID_WRITETIME, PSGUID_STORAGE, PID_STG_WRITETIME);
  140. DEFINE_SCID(SCID_ImageCX, PSGUID_IMAGESUMMARYINFORMATION, PIDISI_CX);
  141. DEFINE_SCID(SCID_ImageCY, PSGUID_IMAGESUMMARYINFORMATION, PIDISI_CY);
  142. // provider XML defines the following properties for each of the
  143. #define DEFAULT_PROVIDER_SCOPE TEXT("PublishingWizard")
  144. #define FMT_PROVIDER TEXT("providermanifest/providers[@scope='%s']")
  145. #define FMT_PROVIDERS TEXT("providermanifest/providers[@scope='%s']/provider")
  146. #define ELEMENT_PROVIDERMANIFEST L"providermanifest"
  147. #define ELEMENT_PROVIDERS L"providers"
  148. #define ELEMENT_PROVIDER L"provider"
  149. #define ATTRIBUTE_ID L"id"
  150. #define ATTRIBUTE_SUPPORTEDTYPES L"supportedtypes"
  151. #define ATTRIBUTE_DISPLAYNAME L"displayname"
  152. #define ATTRIBUTE_DESCRIPTION L"description"
  153. #define ATTRIBUTE_HREF L"href"
  154. #define ATTRIBUTE_ICONPATH L"iconpath"
  155. #define ATTRIBUTE_ICON L"icon"
  156. #define ELEMENT_STRINGS L"strings"
  157. #define ATTRIBUTE_LANGID L"langid"
  158. #define ELEMENT_STRING L"string"
  159. #define ATTRIBUTE_LANGID L"langid"
  160. #define ATTRIBUTE_ID L"id"
  161. // registry state is stored under the this key
  162. #define SZ_REGKEY_PUBWIZ TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\PublishingWizard")
  163. // per machine values in the registry
  164. #define SZ_REGVAL_SERVICEPARTNERID TEXT("PartnerID")
  165. // these are stored per machine under the provider
  166. #define SZ_REGVAL_FILEFILTER TEXT("ContentTypeFilter")
  167. #define SZ_REGVAL_DEFAULTPROVIDERICON TEXT("DefaultIcon")
  168. // per user values in the registry
  169. #define SZ_REGVAL_DEFAULTPROVIDER TEXT("DefaultProvider")
  170. // per provider settings
  171. #define SZ_REGVAL_MRU TEXT("LocationMRU")
  172. #define SZ_REGVAL_ALTPROVIDERS TEXT("Providers")
  173. // Properties exposed by the property bag (from the Web Service)
  174. #define PROPERTY_EXTENSIONCOUNT TEXT("UniqueExtensionCount")
  175. #define PROPERTY_EXTENSION TEXT("UniqueExtension")
  176. #define PROPERTY_TRANSFERMANIFEST TEXT("TransferManifest")
  177. // This is the COM object that exposes the publishing wizard
  178. #define WIZPAGE_WHICHFILE 0 // which file should we publish
  179. #define WIZPAGE_FETCHINGPROVIDERS 1 // provider download page
  180. #define WIZPAGE_PROVIDERS 2 // pick a service provider
  181. #define WIZPAGE_RESIZE 3 // resample the data?
  182. #define WIZPAGE_COPYING 4 // copying page
  183. #define WIZPAGE_LOCATION 5 // location page (advanced)
  184. #define WIZPAGE_FTPUSER 6 // username / password (advanced)
  185. #define WIZPAGE_FRIENDLYNAME 7 // friendly name
  186. #define WIZPAGE_MAX 8
  187. // resize information
  188. struct
  189. {
  190. int cx;
  191. int cy;
  192. int iQuality;
  193. }
  194. _aResizeSettings[] =
  195. {
  196. { 0, 0, 0 },
  197. { 640, 480, 80 }, // low quality
  198. { 800, 600, 80 }, // medium quality
  199. { 1024, 768, 80 }, // high quality
  200. };
  201. typedef enum
  202. {
  203. RESIZE_NONE = 0,
  204. RESIZE_SMALL,
  205. RESIZE_MEDIUM,
  206. RESIZE_LARGE,
  207. } RESIZEOPTION;
  208. class CPublishingWizard : public IServiceProvider, IPublishingWizard, CObjectWithSite, ITransferAdviseSink, ICommDlgBrowser, IOleWindow, IWizardSite
  209. {
  210. public:
  211. CPublishingWizard();
  212. ~CPublishingWizard();
  213. // IUnknown
  214. STDMETHOD(QueryInterface)(REFIID riid, void **ppvObj);
  215. STDMETHOD_(ULONG,AddRef)();
  216. STDMETHOD_(ULONG,Release)();
  217. // IServiceProvider
  218. STDMETHODIMP QueryService(REFGUID guidService, REFIID riid, void **ppv);
  219. // IWizardExtension
  220. STDMETHODIMP AddPages(HPROPSHEETPAGE* aPages, UINT cPages, UINT *pnPages);
  221. STDMETHODIMP GetFirstPage(HPROPSHEETPAGE *phPage);
  222. STDMETHODIMP GetLastPage(HPROPSHEETPAGE *phPage);
  223. // IWizardSite
  224. STDMETHODIMP GetPreviousPage(HPROPSHEETPAGE *phPage);
  225. STDMETHODIMP GetNextPage(HPROPSHEETPAGE *phPage);
  226. STDMETHODIMP GetCancelledPage(HPROPSHEETPAGE *phPage);
  227. // IPublishingWizard
  228. STDMETHODIMP Initialize(IDataObject *pdo, DWORD dwFlags, LPCTSTR pszServiceProvider);
  229. STDMETHODIMP GetTransferManifest(HRESULT *phrFromTransfer, IXMLDOMDocument **pdocManifest);
  230. // IOleWindow
  231. STDMETHODIMP GetWindow(HWND *phwnd)
  232. { *phwnd = _hwndCopyingPage; return S_OK; }
  233. STDMETHODIMP ContextSensitiveHelp(BOOL fEnter)
  234. { return E_NOTIMPL; }
  235. // ICommDlgBrowser
  236. STDMETHOD(OnDefaultCommand)(IShellView *ppshv)
  237. { return E_NOTIMPL; }
  238. STDMETHOD(OnStateChange)(IShellView *ppshv, ULONG uChange);
  239. STDMETHOD(IncludeObject)(IShellView *ppshv, LPCITEMIDLIST lpItem);
  240. // ITransferAdviseSink
  241. STDMETHODIMP PreOperation (const STGOP op, IShellItem *psiItem, IShellItem *psiDest);
  242. STDMETHODIMP ConfirmOperation(IShellItem *psiItem, IShellItem *psiDest, STGTRANSCONFIRMATION stc, LPCUSTOMCONFIRMATION pcc)
  243. { return STRESPONSE_CONTINUE; }
  244. STDMETHODIMP OperationProgress(const STGOP op, IShellItem *psiItem, IShellItem *psiDest, ULONGLONG ulTotal, ULONGLONG ulComplete);
  245. STDMETHODIMP PostOperation(const STGOP op, IShellItem *psiItem, IShellItem *psiDest, HRESULT hrResult)
  246. { return S_OK; }
  247. STDMETHODIMP QueryContinue()
  248. { return _fCancelled ? S_FALSE : S_OK; }
  249. private:
  250. LONG _cRef; // object lifetime count
  251. IDataObject *_pdo; // data object provided by the site
  252. IDataObject *_pdoSelection; // this is the selection IDataObject - used instead of _pdo if defined
  253. DWORD _dwFlags; // flags provided by the site
  254. TCHAR _szProviderScope[MAX_PATH]; // provider scope (eg. Web Publishing)
  255. BOOL _fOfferResize; // show the resize page - pictures/music etc
  256. RESIZEOPTION _ro; // resize setting we will use
  257. BOOL _fUsingTemporaryProviders; // temporary provider listed pull in, replace when we can
  258. BOOL _fRecomputeManifest; // recompute the manifest
  259. BOOL _fRepopulateProviders; // repopulate the providers list
  260. BOOL _fShownCustomLocation; // show the custom locaiton page
  261. BOOL _fShownUserName; // password page was shown
  262. BOOL _fValidating; // validating a server (Advanced path);
  263. BOOL _fCancelled; // operation was cancelled
  264. BOOL _fTransferComplete; // transfer completed.
  265. HWND _hwndSelector; // hwnd for the selector dialog
  266. HWND _hwndCopyingPage;
  267. int _iPercentageComplete; // % compelte of this transfer
  268. DWORD _dwTotal;
  269. DWORD _dwCompleted;
  270. int _cFiles; // maximum number of files
  271. int _iFile; // current file we are on
  272. HRESULT _hrFromTransfer; // result of the transfer performed
  273. HPROPSHEETPAGE _aWizPages[WIZPAGE_MAX]; // page handles for this wizard (so we can navigate)
  274. IPropertyBag *_ppb; // property bag object exposed from the site
  275. IWebWizardExtension *_pwwe; // host for the HTML wizard pages
  276. IResourceMap *_prm; // resource map object we create if we can't query from the host
  277. IXMLDOMDocument *_pdocProviders; // XML dom which exposes the providers
  278. CXMLDOMStateChange *_pdscProviders; // DOMStateChange for the provider list
  279. IXMLDOMDocument *_pdocManifest; // document describing the files to be transfered
  280. LPITEMIDLIST *_aItems; // array of items we copied
  281. UINT _cItems;
  282. IAutoComplete2 *_pac; // auto complete object
  283. IUnknown *_punkACLMulti; // IObjMgr object that exposes all the enumerators
  284. IACLCustomMRU *_pmru; // custom MRU for the objects we want to list
  285. CNetworkPlace _npCustom; // net place object for handling the custom entry
  286. HCURSOR _hCursor;
  287. IFolderView *_pfv; // file selector view object
  288. TCHAR _szFilter[MAX_PATH]; // filter string read from the registry
  289. static CPublishingWizard* s_GetPPW(HWND hwnd, UINT uMsg, LPARAM lParam);
  290. static int s_FreeStringProc(void* pFreeMe, void* pData);
  291. static HRESULT s_SetPropertyFromDisp(IPropertyBag *ppb, LPCWSTR pszID, IDispatch *pdsp);
  292. static DWORD CALLBACK s_ValidateThreadProc(void *pv);
  293. static int s_CompareItems(TRANSFERITEM *pti1, TRANSFERITEM *pti2, CPublishingWizard *ppw);
  294. static UINT s_SelectorPropPageProc(HWND hwndDlg, UINT uMsg, PROPSHEETPAGE *ppsp);
  295. static INT_PTR s_SelectorDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  296. { CPublishingWizard *ppw = s_GetPPW(hwnd, uMsg, lParam); return ppw->_SelectorDlgProc(hwnd, uMsg, wParam, lParam); }
  297. static INT_PTR s_FetchProvidersDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  298. { CPublishingWizard *ppw = s_GetPPW(hwnd, uMsg, lParam); return ppw->_FetchProvidersDlgProc(hwnd, uMsg, wParam, lParam); }
  299. static INT_PTR s_ProviderDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  300. { CPublishingWizard *ppw = s_GetPPW(hwnd, uMsg, lParam); return ppw->_ProviderDlgProc(hwnd, uMsg, wParam, lParam); }
  301. static INT_PTR s_ResizeDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  302. { CPublishingWizard *ppw = s_GetPPW(hwnd, uMsg, lParam); return ppw->_ResizeDlgProc(hwnd, uMsg, wParam, lParam); }
  303. static INT_PTR s_CopyDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  304. { CPublishingWizard *ppw = s_GetPPW(hwnd, uMsg, lParam); return ppw->_CopyDlgProc(hwnd, uMsg, wParam, lParam); }
  305. static INT_PTR s_LocationDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  306. { CPublishingWizard *ppw = s_GetPPW(hwnd, uMsg, lParam); return ppw->_LocationDlgProc(hwnd, uMsg, wParam, lParam); }
  307. static INT_PTR s_UserNameDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  308. { CPublishingWizard *ppw = s_GetPPW(hwnd, uMsg, lParam); return ppw->_UserNameDlgProc(hwnd, uMsg, wParam, lParam); }
  309. static INT_PTR s_FriendlyNameDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  310. { CPublishingWizard *ppw = s_GetPPW(hwnd, uMsg, lParam); return ppw->_FriendlyNameDlgProc(hwnd, uMsg, wParam, lParam); }
  311. // these are used for publishing
  312. INT_PTR _SelectorDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  313. INT_PTR _FetchProvidersDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  314. INT_PTR _ProviderDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  315. INT_PTR _ResizeDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  316. INT_PTR _CopyDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  317. // these are used for ANP
  318. INT_PTR _LocationDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  319. INT_PTR _UserNameDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  320. INT_PTR _FriendlyNameDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
  321. void _FreeProviderList();
  322. HRESULT _GetProviderKey(HKEY hkRoot, DWORD dwAccess, LPCTSTR pszSubKey, HKEY *phkResult);
  323. void _MapDlgItemText(HWND hwnd, UINT idc, LPCTSTR pszDlgID, LPCTSTR pszResourceID);
  324. HRESULT _GetResourceMap(IResourceMap **pprm);
  325. HRESULT _LoadMappedString(LPCTSTR pszDlgID, LPCTSTR pszResourceID, LPTSTR pszBuffer, int cch);
  326. HRESULT _CreateWizardPages();
  327. INT_PTR _WizardNext(HWND hwnd, int iPage);
  328. HRESULT _AddExtenisonToList(HDPA hdpa, LPCTSTR pszExtension);
  329. HRESULT _InitPropertyBag(LPCTSTR pszURL);
  330. int _GetSelectedItem(HWND hwndList);
  331. void _GetDefaultProvider(LPTSTR pszProvider, int cch);
  332. void _SetDefaultProvider(IXMLDOMNode *pdn);
  333. HRESULT _FetchProviderList(HWND hwnd);
  334. HRESULT _MergeLocalProviders();
  335. int _AddProvider(HWND hwnd, IXMLDOMNode *pdn);
  336. void _PopulateProviderList(HWND hwnd);
  337. void _ProviderEnableNext(HWND hwnd);
  338. void _ProviderGetDispInfo(LV_DISPINFO *plvdi);
  339. HRESULT _ProviderNext(HWND hwnd, HPROPSHEETPAGE *phPage);
  340. void _SetWaitCursor(BOOL bOn);
  341. void _ShowExampleTip(HWND hwnd);
  342. void _LocationChanged(HWND hwnd);
  343. void _UserNameChanged(HWND hwnd);
  344. DWORD _GetAutoCompleteFlags(DWORD dwFlags);
  345. HRESULT _InitAutoComplete();
  346. void _InitLocation(HWND hwnd);
  347. HRESULT _AddCommonItemInfo(IXMLDOMNode *pdn, TRANSFERITEM *pti);
  348. HRESULT _AddTransferItem(CDPA<TRANSFERITEM> *pdpaItems, IXMLDOMNode *pdn);
  349. HRESULT _AddPostItem(CDPA<TRANSFERITEM> *pdpaItems, IXMLDOMNode *pdn);
  350. void _FreeTransferManifest();
  351. HRESULT _AddFilesToManifest(IXMLDOMDocument *pdocManifest);
  352. HRESULT _BuildTransferManifest();
  353. HRESULT _GetUniqueTypeList(BOOL fIncludeFolder, HDPA *phdpa);
  354. HRESULT _InitTransferInfo(IXMLDOMDocument *pdocManifest, TRANSFERINFO *pti, CDPA<TRANSFERITEM> *pdpaItems);
  355. void _TryToValidateDestination(HWND hwnd);
  356. void _InitProvidersDialog(HWND hwnd);
  357. void _SetProgress(DWORD dwCompleted, DWORD dwTotal);
  358. BOOL _HasAttributes(IShellItem *psi, SFGAOF flags);
  359. HRESULT _BeginTransfer(HWND hwnd);
  360. HPROPSHEETPAGE _TransferComplete(HRESULT hrFromTransfer);
  361. void _FriendlyNameChanged(HWND hwnd);
  362. HRESULT _CreateFavorite(IXMLDOMNode *pdnUploadInfo);
  363. int _GetRemoteIcon(LPCTSTR pszID, BOOL fCanRefresh);
  364. HRESULT _GetSiteURL(LPTSTR pszBuffer, int cchBuffer, LPCTSTR pszFilenameToCombine);
  365. void _StateChanged();
  366. void _ShowHideFetchProgress(HWND hwnd, BOOL fShow);
  367. void _FetchComplete(HWND hwnd, HRESULT hrFromFetch);
  368. HRESULT _GetProviderString(IXMLDOMNode *pdn, USHORT idPrimary, USHORT idSub, LPCTSTR pszID, LPTSTR pszBuffer, int cch);
  369. HRESULT _GetProviderString(IXMLDOMNode *pdn, LPCTSTR pszID, LPTSTR pszBuffer, int cch);
  370. HRESULT _GeoFromLocaleInfo(LCID lcid, GEOID *pgeoID);
  371. HRESULT _GetProviderListFilename(LPTSTR pszFile, int cchFile);
  372. };
  373. // publishing wizard obj
  374. CPublishingWizard::CPublishingWizard() :
  375. _cRef(1), _fRecomputeManifest(TRUE), _hrFromTransfer(S_FALSE)
  376. {
  377. StrCpyN(_szProviderScope, DEFAULT_PROVIDER_SCOPE, ARRAYSIZE(_szProviderScope)); // fill the default provider scope
  378. DllAddRef();
  379. }
  380. CPublishingWizard::~CPublishingWizard()
  381. {
  382. if (_pwwe)
  383. {
  384. IUnknown_SetSite(_pwwe, NULL);
  385. _pwwe->Release();
  386. }
  387. ATOMICRELEASE(_pdo);
  388. ATOMICRELEASE(_pdoSelection);
  389. ATOMICRELEASE(_prm);
  390. _FreeProviderList();
  391. _FreeTransferManifest();
  392. DllRelease();
  393. }
  394. ULONG CPublishingWizard::AddRef()
  395. {
  396. return InterlockedIncrement(&_cRef);
  397. }
  398. ULONG CPublishingWizard::Release()
  399. {
  400. if (InterlockedDecrement(&_cRef))
  401. return _cRef;
  402. delete this;
  403. return 0;
  404. }
  405. HRESULT CPublishingWizard::QueryInterface(REFIID riid, void **ppv)
  406. {
  407. static const QITAB qit[] =
  408. {
  409. QITABENT(CPublishingWizard, IWizardSite), // IID_IWizardSite
  410. QITABENT(CPublishingWizard, IObjectWithSite), // IID_IObjectWithSite
  411. QITABENT(CPublishingWizard, IServiceProvider), // IID_IServiceProvider
  412. QITABENT(CPublishingWizard, IPublishingWizard), // IID_IPublishingWizard
  413. QITABENT(CPublishingWizard, ITransferAdviseSink), // IID_ITransferAdviseSink
  414. QITABENTMULTI(CPublishingWizard, IQueryContinue, ITransferAdviseSink), // IID_IQueryContinue
  415. QITABENT(CPublishingWizard, IOleWindow), // IID_IOleWindow
  416. QITABENT(CPublishingWizard, ICommDlgBrowser), // IID_ICommDlgBrowser
  417. {0, 0 },
  418. };
  419. return QISearch(this, qit, riid, ppv);
  420. }
  421. STDAPI CPublishingWizard_CreateInstance(IUnknown* pUnkOuter, IUnknown** ppunk, LPCOBJECTINFO poi)
  422. {
  423. CPublishingWizard *pwiz = new CPublishingWizard();
  424. if (!pwiz)
  425. {
  426. *ppunk = NULL; // incase of failure
  427. return E_OUTOFMEMORY;
  428. }
  429. HRESULT hr = pwiz->QueryInterface(IID_PPV_ARG(IUnknown, ppunk));
  430. pwiz->Release();
  431. return hr;
  432. }
  433. // IPublishingWizard methods
  434. HRESULT CPublishingWizard::Initialize(IDataObject *pdo, DWORD dwOptions, LPCTSTR pszServiceProvider)
  435. {
  436. IUnknown_Set((IUnknown**)&_pdo, pdo);
  437. IUnknown_Set((IUnknown**)&_pdoSelection, NULL);
  438. _dwFlags = dwOptions;
  439. _fRecomputeManifest = TRUE; // _fRepopulateProviders set when manifest rebuilt
  440. if (!pszServiceProvider)
  441. pszServiceProvider = DEFAULT_PROVIDER_SCOPE;
  442. StrCpyN(_szProviderScope, pszServiceProvider, ARRAYSIZE(_szProviderScope));
  443. return S_OK;
  444. }
  445. HRESULT CPublishingWizard::GetTransferManifest(HRESULT *phrFromTransfer, IXMLDOMDocument **ppdocManifest)
  446. {
  447. HRESULT hr = E_UNEXPECTED;
  448. if (_ppb)
  449. {
  450. if (phrFromTransfer)
  451. *phrFromTransfer = _hrFromTransfer;
  452. if (ppdocManifest)
  453. {
  454. VARIANT var = {VT_DISPATCH};
  455. hr = _ppb->Read(PROPERTY_TRANSFERMANIFEST, &var, NULL);
  456. if (SUCCEEDED(hr))
  457. {
  458. hr = var.pdispVal->QueryInterface(IID_PPV_ARG(IXMLDOMDocument, ppdocManifest));
  459. VariantClear(&var);
  460. }
  461. }
  462. else
  463. {
  464. hr = S_OK;
  465. }
  466. }
  467. return hr;
  468. }
  469. // Wizard site methods
  470. STDMETHODIMP CPublishingWizard::GetPreviousPage(HPROPSHEETPAGE *phPage)
  471. {
  472. *phPage = _aWizPages[WIZPAGE_FETCHINGPROVIDERS];
  473. return S_OK;
  474. }
  475. STDMETHODIMP CPublishingWizard::GetNextPage(HPROPSHEETPAGE *phPage)
  476. {
  477. // lets get the next page we'd need to show if all else fails.
  478. IWizardSite *pws;
  479. HRESULT hr = _punkSite->QueryInterface(IID_PPV_ARG(IWizardSite, &pws));
  480. if (SUCCEEDED(hr))
  481. {
  482. hr = pws->GetNextPage(phPage);
  483. pws->Release();
  484. }
  485. // if we have not transfered and we have a IDataObject then we should
  486. // advance to one of the special pages we are supposed to show.
  487. if (!_fTransferComplete && _pdo)
  488. {
  489. *phPage = _aWizPages[_fOfferResize ? WIZPAGE_RESIZE:WIZPAGE_COPYING];
  490. }
  491. return hr;
  492. }
  493. STDMETHODIMP CPublishingWizard::GetCancelledPage(HPROPSHEETPAGE *phPage)
  494. {
  495. HRESULT hr = E_NOTIMPL;
  496. if (!_fTransferComplete)
  497. {
  498. *phPage = _TransferComplete(HRESULT_FROM_WIN32(ERROR_CANCELLED));
  499. if (*phPage)
  500. hr = S_OK;
  501. }
  502. else
  503. {
  504. IWizardSite *pws;
  505. hr = _punkSite->QueryInterface(IID_PPV_ARG(IWizardSite, &pws));
  506. if (SUCCEEDED(hr))
  507. {
  508. hr = pws->GetCancelledPage(phPage);
  509. pws->Release();
  510. }
  511. }
  512. return hr;
  513. }
  514. // Service provider object
  515. STDMETHODIMP CPublishingWizard::QueryService(REFGUID guidService, REFIID riid, void **ppv)
  516. {
  517. if (guidService == SID_WebWizardHost)
  518. {
  519. if (riid == IID_IPropertyBag)
  520. {
  521. return _ppb->QueryInterface(riid, ppv);
  522. }
  523. }
  524. else if (guidService == SID_SCommDlgBrowser)
  525. {
  526. return this->QueryInterface(riid, ppv);
  527. }
  528. else if (_punkSite)
  529. {
  530. return IUnknown_QueryService(_punkSite, guidService, riid, ppv);
  531. }
  532. return E_FAIL;
  533. }
  534. // IWizardExtension methods
  535. HRESULT CPublishingWizard::_CreateWizardPages()
  536. {
  537. const struct
  538. {
  539. LPCTSTR pszID;
  540. int idPage;
  541. DLGPROC dlgproc;
  542. UINT idsHeading;
  543. UINT idsSubHeading;
  544. LPFNPSPCALLBACK pfnCallback;
  545. }
  546. _wp[] =
  547. {
  548. {TEXT("wp:selector"), IDD_PUB_SELECTOR, CPublishingWizard::s_SelectorDlgProc, IDS_PUB_SELECTOR, IDS_PUB_SELECTOR_SUB, NULL},
  549. {TEXT("wp:fetching"), IDD_PUB_FETCHPROVIDERS, CPublishingWizard::s_FetchProvidersDlgProc, IDS_PUB_FETCHINGPROVIDERS, IDS_PUB_FETCHINGPROVIDERS_SUB, CPublishingWizard::s_SelectorPropPageProc},
  550. {TEXT("wp:destination"), IDD_PUB_DESTINATION, CPublishingWizard::s_ProviderDlgProc, IDS_PUB_DESTINATION, IDS_PUB_DESTINATION_SUB, NULL},
  551. {TEXT("wp:resize"), IDD_PUB_RESIZE, CPublishingWizard::s_ResizeDlgProc, IDS_PUB_RESIZE, IDS_PUB_RESIZE_SUB, NULL},
  552. {TEXT("wp:copying"), IDD_PUB_COPY, CPublishingWizard::s_CopyDlgProc, IDS_PUB_COPY, IDS_PUB_COPY_SUB, NULL},
  553. {TEXT("wp:location"), IDD_PUB_LOCATION, CPublishingWizard::s_LocationDlgProc, IDS_PUB_LOCATION, IDS_PUB_LOCATION_SUB, NULL},
  554. {TEXT("wp:ftppassword"), IDD_PUB_FTPPASSWORD, CPublishingWizard::s_UserNameDlgProc, IDS_PUB_FTPPASSWORD, IDS_PUB_FTPPASSWORD_SUB, NULL},
  555. {TEXT("wp:friendlyname"),IDD_ANP_FRIENDLYNAME, CPublishingWizard::s_FriendlyNameDlgProc, IDS_ANP_FRIENDLYNAME, IDS_ANP_FRIENDLYNAME_SUB, NULL},
  556. };
  557. // if we haven't created the pages yet, then lets initialize our array of handlers.
  558. HRESULT hr = S_OK;
  559. if (!_aWizPages[0])
  560. {
  561. INITCOMMONCONTROLSEX iccex = { 0 };
  562. iccex.dwSize = sizeof (iccex);
  563. iccex.dwICC = ICC_LISTVIEW_CLASSES | ICC_PROGRESS_CLASS | ICC_LINK_CLASS;
  564. InitCommonControlsEx(&iccex);
  565. LinkWindow_RegisterClass(); // we will use the link window (can this be removed)
  566. for (int i = 0; SUCCEEDED(hr) && (i < ARRAYSIZE(_wp)) ; i++ )
  567. {
  568. TCHAR szHeading[MAX_PATH], szSubHeading[MAX_PATH];
  569. // if we have a resource map then load the heading and sub heading text
  570. // if there is no resource map from the parent object then we must default
  571. // the strings.
  572. IResourceMap *prm;
  573. hr = _GetResourceMap(&prm);
  574. if (SUCCEEDED(hr))
  575. {
  576. IXMLDOMNode *pdn;
  577. hr = prm->SelectResourceScope(TEXT("dialog"), _wp[i].pszID, &pdn);
  578. if (SUCCEEDED(hr))
  579. {
  580. prm->LoadString(pdn, L"heading", szHeading, ARRAYSIZE(szHeading));
  581. prm->LoadString(pdn, L"subheading", szSubHeading, ARRAYSIZE(szSubHeading));
  582. pdn->Release();
  583. }
  584. prm->Release();
  585. }
  586. if (FAILED(hr))
  587. {
  588. LoadString(g_hinst, _wp[i].idsHeading, szHeading, ARRAYSIZE(szHeading));
  589. LoadString(g_hinst, _wp[i].idsSubHeading, szSubHeading, ARRAYSIZE(szSubHeading));
  590. }
  591. // lets create the page now that we have loaded the relevant strings, more mapping
  592. // will occur later (during dialog initialization)
  593. PROPSHEETPAGE psp = { 0 };
  594. psp.dwSize = SIZEOF(PROPSHEETPAGE);
  595. psp.hInstance = g_hinst;
  596. psp.lParam = (LPARAM)this;
  597. psp.dwFlags = PSP_DEFAULT | PSP_USEHEADERTITLE | PSP_USEHEADERSUBTITLE;
  598. psp.pszTemplate = MAKEINTRESOURCE(_wp[i].idPage);
  599. psp.pfnDlgProc = _wp[i].dlgproc;
  600. psp.pszHeaderTitle = szHeading;
  601. psp.pszHeaderSubTitle = szSubHeading;
  602. if (_wp[i].pfnCallback)
  603. {
  604. psp.dwFlags |= PSP_USECALLBACK;
  605. psp.pfnCallback = _wp[i].pfnCallback;
  606. }
  607. _aWizPages[i] = CreatePropertySheetPage(&psp);
  608. hr = _aWizPages[i] ? S_OK:E_FAIL;
  609. }
  610. }
  611. return hr;
  612. }
  613. STDMETHODIMP CPublishingWizard::AddPages(HPROPSHEETPAGE* aPages, UINT cPages, UINT *pnPages)
  614. {
  615. // create our pages and then copy the handles to the buffer
  616. HRESULT hr = _CreateWizardPages();
  617. if (SUCCEEDED(hr))
  618. {
  619. for (int i = 0; i < ARRAYSIZE(_aWizPages); i++)
  620. {
  621. aPages[i] = _aWizPages[i];
  622. }
  623. // we also leverage the HTML host for showing pages from the sites we are
  624. // interacting with.
  625. hr = CoCreateInstance(CLSID_WebWizardHost, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IWebWizardExtension, &_pwwe));
  626. if (SUCCEEDED(hr))
  627. {
  628. // NOTE: this site should be broken into a seperate object so we avoid any circular reference issues
  629. // NOTE: there is code in websvc.cpp that attempts to break this by listening for the page
  630. // NOTE: destruction and then releasing its site.
  631. IUnknown_SetSite(_pwwe, (IObjectWithSite*)this);
  632. UINT nPages;
  633. if (SUCCEEDED(_pwwe->AddPages(&aPages[i], cPages-i, &nPages)))
  634. {
  635. i += nPages;
  636. }
  637. }
  638. *pnPages = i; // the number of pages we added
  639. }
  640. return hr;
  641. }
  642. // navigation pages
  643. STDMETHODIMP CPublishingWizard::GetFirstPage(HPROPSHEETPAGE *phPage)
  644. {
  645. if (_dwFlags & SHPWHF_NOFILESELECTOR)
  646. {
  647. *phPage = _aWizPages[WIZPAGE_FETCHINGPROVIDERS];
  648. }
  649. else
  650. {
  651. *phPage = _aWizPages[WIZPAGE_WHICHFILE];
  652. }
  653. return S_OK;
  654. }
  655. STDMETHODIMP CPublishingWizard::GetLastPage(HPROPSHEETPAGE *phPage)
  656. {
  657. if (_fShownCustomLocation)
  658. {
  659. *phPage = _aWizPages[WIZPAGE_FRIENDLYNAME];
  660. }
  661. else
  662. {
  663. *phPage = _aWizPages[WIZPAGE_FETCHINGPROVIDERS];
  664. }
  665. return S_OK;
  666. }
  667. // computer this pointers for the page objects
  668. CPublishingWizard* CPublishingWizard::s_GetPPW(HWND hwnd, UINT uMsg, LPARAM lParam)
  669. {
  670. if (uMsg == WM_INITDIALOG)
  671. {
  672. PROPSHEETPAGE *ppsp = (PROPSHEETPAGE*)lParam;
  673. SetWindowLongPtr(hwnd, GWLP_USERDATA, ppsp->lParam);
  674. return (CPublishingWizard*)ppsp->lParam;
  675. }
  676. return (CPublishingWizard*)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  677. }
  678. // initialize a property in the property bag from an IUnknown pointer.
  679. HRESULT CPublishingWizard::s_SetPropertyFromDisp(IPropertyBag *ppb, LPCWSTR pszID, IDispatch *pdsp)
  680. {
  681. VARIANT var = { VT_DISPATCH };
  682. HRESULT hr = pdsp->QueryInterface(IID_PPV_ARG(IDispatch, &var.pdispVal));
  683. if (SUCCEEDED(hr))
  684. {
  685. hr = ppb->Write(pszID, &var);
  686. VariantClear(&var);
  687. }
  688. return hr;
  689. }
  690. // get the resource map from the site, if we can get it then us it, otherwise
  691. // we need to load the resouce map local to this DLL.
  692. HRESULT CPublishingWizard::_GetResourceMap(IResourceMap **pprm)
  693. {
  694. HRESULT hr = IUnknown_QueryService(_punkSite, SID_ResourceMap, IID_PPV_ARG(IResourceMap, pprm));
  695. if (FAILED(hr))
  696. {
  697. if (!_prm)
  698. {
  699. hr = CResourceMap_Initialize(L"res://netplwiz.dll/xml/resourcemap.xml", &_prm);
  700. if (SUCCEEDED(hr))
  701. {
  702. hr = _prm->LoadResourceMap(TEXT("wizard"), _szProviderScope);
  703. if (SUCCEEDED(hr))
  704. {
  705. hr = _prm->QueryInterface(IID_PPV_ARG(IResourceMap, pprm));
  706. }
  707. }
  708. }
  709. else
  710. {
  711. hr = _prm->QueryInterface(IID_PPV_ARG(IResourceMap, pprm));
  712. }
  713. }
  714. return hr;
  715. }
  716. // handle loading resource map strings
  717. HRESULT CPublishingWizard::_LoadMappedString(LPCTSTR pszDlgID, LPCTSTR pszResourceID, LPTSTR pszBuffer, int cch)
  718. {
  719. IResourceMap *prm;
  720. HRESULT hr = _GetResourceMap(&prm);
  721. if (SUCCEEDED(hr))
  722. {
  723. IXMLDOMNode *pdn;
  724. hr = prm->SelectResourceScope(TEXT("dialog"), pszDlgID, &pdn);
  725. if (SUCCEEDED(hr))
  726. {
  727. hr = prm->LoadString(pdn, pszResourceID, pszBuffer, cch);
  728. pdn->Release();
  729. }
  730. prm->Release();
  731. }
  732. return hr;
  733. }
  734. void CPublishingWizard::_MapDlgItemText(HWND hwnd, UINT idc, LPCTSTR pszDlgID, LPCTSTR pszResourceID)
  735. {
  736. TCHAR szBuffer[MAX_PATH];
  737. if (SUCCEEDED(_LoadMappedString(pszDlgID, pszResourceID, szBuffer, ARRAYSIZE(szBuffer))))
  738. {
  739. SetDlgItemText(hwnd, idc, szBuffer);
  740. }
  741. }
  742. // Set the wizard next (index to hpage translation)
  743. INT_PTR CPublishingWizard::_WizardNext(HWND hwnd, int iPage)
  744. {
  745. PropSheet_SetCurSel(GetParent(hwnd), _aWizPages[iPage], -1);
  746. SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LPARAM)-1);
  747. return TRUE;
  748. }
  749. // get a provider key from the registry
  750. HRESULT CPublishingWizard::_GetProviderKey(HKEY hkBase, DWORD dwAccess, LPCTSTR pszSubKey, HKEY *phkResult)
  751. {
  752. TCHAR szBuffer[MAX_PATH];
  753. wnsprintf(szBuffer, ARRAYSIZE(szBuffer), (SZ_REGKEY_PUBWIZ TEXT("\\%s")), _szProviderScope);
  754. if (pszSubKey)
  755. {
  756. StrCatBuff(szBuffer, TEXT("\\"), ARRAYSIZE(szBuffer));
  757. StrCatBuff(szBuffer, pszSubKey, ARRAYSIZE(szBuffer));
  758. }
  759. DWORD dwResult = RegOpenKeyEx(hkBase, szBuffer, 0, dwAccess, phkResult);
  760. if ((dwResult != ERROR_SUCCESS) && (dwAccess != KEY_READ))
  761. {
  762. dwResult = RegCreateKey(hkBase, szBuffer, phkResult);
  763. }
  764. return (ERROR_SUCCESS == dwResult) ? S_OK:E_FAIL;
  765. }
  766. // compute the site URL based on the stored information we have
  767. HRESULT CPublishingWizard::_GetSiteURL(LPTSTR pszBuffer, int cchBuffer, LPCTSTR pszFilenameToCombine)
  768. {
  769. DWORD cch = cchBuffer;
  770. return UrlCombine(TEXT("http://shell.windows.com/publishwizard/"), pszFilenameToCombine, pszBuffer, &cch, 0);
  771. }
  772. // get the data object from the site that we have
  773. CLIPFORMAT g_cfHIDA = 0;
  774. void InitClipboardFormats()
  775. {
  776. if (g_cfHIDA == 0)
  777. g_cfHIDA = (CLIPFORMAT)RegisterClipboardFormat(CFSTR_SHELLIDLIST);
  778. }
  779. // DPA helpers for comparing and destroying a TRANSFERITEM structure
  780. int CALLBACK CPublishingWizard::s_CompareItems(TRANSFERITEM *pti1, TRANSFERITEM *pti2, CPublishingWizard *ppw)
  781. {
  782. return StrCmpI(pti1->szFilename, pti2->szFilename);
  783. }
  784. int _FreeFormData(FORMDATA *pfd, void *pvState)
  785. {
  786. VariantClear(&pfd->varName);
  787. VariantClear(&pfd->varValue);
  788. return 1;
  789. }
  790. int _FreeTransferItems(TRANSFERITEM *pti, void *pvState)
  791. {
  792. ILFree(pti->pidl);
  793. if (pti->psi)
  794. pti->psi->Release();
  795. if (pti->pstrm)
  796. pti->pstrm->Release();
  797. if (pti->dsaFormData != NULL)
  798. pti->dsaFormData.DestroyCallback(_FreeFormData, NULL);
  799. LocalFree(pti);
  800. return 1;
  801. }
  802. HRESULT CPublishingWizard::_AddCommonItemInfo(IXMLDOMNode *pdn, TRANSFERITEM *pti)
  803. {
  804. // default to the user selected resize (this will only be set if
  805. // we are using the Web Publishing Wizard).
  806. if (_ro != RESIZE_NONE)
  807. {
  808. pti->fResizeOnUpload = TRUE;
  809. pti->cxResize = _aResizeSettings[_ro].cx;
  810. pti->cyResize = _aResizeSettings[_ro].cy;
  811. pti->iQuality = _aResizeSettings[_ro].iQuality;
  812. }
  813. // give the site ultimate control over the resizing that is performed,
  814. // by checking for the <resize/> element in the manifest.
  815. IXMLDOMNode *pdnResize;
  816. HRESULT hr = pdn->selectSingleNode(ELEMENT_RESIZE, &pdnResize);
  817. if (hr == S_OK)
  818. {
  819. int cx, cy, iQuality;
  820. hr = GetIntFromAttribute(pdnResize, ATTRIBUTE_CX, &cx);
  821. if (SUCCEEDED(hr))
  822. hr = GetIntFromAttribute(pdnResize, ATTRIBUTE_CY, &cy);
  823. if (SUCCEEDED(hr))
  824. hr = GetIntFromAttribute(pdnResize, ATTRIBUTE_QUALITY, &iQuality);
  825. if (SUCCEEDED(hr))
  826. {
  827. pti->fResizeOnUpload = TRUE;
  828. pti->cxResize = cx;
  829. pti->cyResize = cy;
  830. pti->iQuality = iQuality;
  831. }
  832. pdnResize->Release();
  833. }
  834. return S_OK;
  835. }
  836. HRESULT CPublishingWizard::_AddTransferItem(CDPA<TRANSFERITEM> *pdpaItems, IXMLDOMNode *pdn)
  837. {
  838. HRESULT hr = E_OUTOFMEMORY;
  839. TRANSFERITEM *pti = (TRANSFERITEM*)LocalAlloc(LPTR, sizeof(*pti));
  840. if (pti)
  841. {
  842. // copy the destination
  843. hr = GetStrFromAttribute(pdn, ATTRIBUTE_DESTINATION, pti->szFilename, ARRAYSIZE(pti->szFilename));
  844. // copy the source IDList - read the index and use that
  845. if (SUCCEEDED(hr))
  846. {
  847. int iItem;
  848. hr = GetIntFromAttribute(pdn, ATTRIBUTE_ID, &iItem);
  849. if (SUCCEEDED(hr))
  850. {
  851. hr = SHILClone(_aItems[iItem], &pti->pidl);
  852. }
  853. }
  854. // lets add the common transfer item info
  855. if (SUCCEEDED(hr))
  856. hr = _AddCommonItemInfo(pdn, pti);
  857. // if we have a structure then lets append it to the DPA
  858. if (SUCCEEDED(hr))
  859. hr = (-1 == pdpaItems->AppendPtr(pti)) ? E_OUTOFMEMORY:S_OK;
  860. // failed
  861. if (FAILED(hr))
  862. {
  863. _FreeTransferItems(pti);
  864. }
  865. }
  866. return hr;
  867. }
  868. HRESULT CPublishingWizard::_AddPostItem(CDPA<TRANSFERITEM> *pdpaItems, IXMLDOMNode *pdn)
  869. {
  870. HRESULT hr = E_OUTOFMEMORY;
  871. TRANSFERITEM *pti = (TRANSFERITEM*)LocalAlloc(LPTR, sizeof(*pti));
  872. if (pti)
  873. {
  874. // get the post data, from thiswe can work out how to post the data
  875. IXMLDOMNode *pdnPostData;
  876. if (pdn->selectSingleNode(ELEMENT_POSTDATA, &pdnPostData) == S_OK)
  877. {
  878. // we must have a HREF for the post value
  879. hr = GetStrFromAttribute(pdnPostData, ATTRIBUTE_HREF, pti->szURL, ARRAYSIZE(pti->szURL));
  880. if (SUCCEEDED(hr))
  881. {
  882. // we must be able to get a posting name from the element
  883. hr = GetStrFromAttribute(pdnPostData, ATTRIBUTE_NAME, pti->szName, ARRAYSIZE(pti->szName));
  884. if (SUCCEEDED(hr))
  885. {
  886. // lets get the posting name, we get that from the filename attribute, if that
  887. // is not defined then try and compute it from the source information
  888. // if that isn't defined the use the name attribute they gave us earlier.
  889. if (FAILED(GetStrFromAttribute(pdnPostData, ATTRIBUTE_FILENAME, pti->szFilename, ARRAYSIZE(pti->szFilename))))
  890. {
  891. TCHAR szSource[MAX_PATH];
  892. if (SUCCEEDED(GetStrFromAttribute(pdn, ATTRIBUTE_SOURCE, szSource, ARRAYSIZE(szSource))))
  893. {
  894. StrCpyN(pti->szFilename, PathFindFileName(szSource), ARRAYSIZE(pti->szFilename));
  895. }
  896. else
  897. {
  898. StrCpyN(pti->szFilename, pti->szName, ARRAYSIZE(pti->szFilename));
  899. }
  900. }
  901. // lets get the verb we should be using (and default accordingly), therefore
  902. // we can ignore the result.
  903. StrCpyN(pti->szVerb, TEXT("POST"), ARRAYSIZE(pti->szVerb));
  904. GetStrFromAttribute(pdnPostData, ATTRIBUTE_VERB, pti->szVerb, ARRAYSIZE(pti->szVerb));
  905. // pick up the IDLIST for the item
  906. int iItem;
  907. hr = GetIntFromAttribute(pdn, ATTRIBUTE_ID, &iItem);
  908. if (SUCCEEDED(hr))
  909. {
  910. hr = SHILClone(_aItems[iItem], &pti->pidl);
  911. }
  912. // do we have any form data that needs to be passed to the transfer engine
  913. // and therefore to the site. if so lets package it up now.
  914. IXMLDOMNodeList *pnl;
  915. if (SUCCEEDED(hr) && (S_OK == pdnPostData->selectNodes(ELEMENT_FORMDATA, &pnl)))
  916. {
  917. hr = pti->dsaFormData.Create(4) ? S_OK:E_FAIL;
  918. if (SUCCEEDED(hr))
  919. {
  920. // walk the selection filling the DSA, each structure contains
  921. // two VARIANTs which we can push across to the bg thread describing the
  922. // form data we want the site to receive.
  923. long cSelection;
  924. hr = pnl->get_length(&cSelection);
  925. for (long lNode = 0; SUCCEEDED(hr) && (lNode != cSelection); lNode++)
  926. {
  927. IXMLDOMNode *pdnFormData;
  928. hr = pnl->get_item(lNode, &pdnFormData);
  929. if (SUCCEEDED(hr))
  930. {
  931. FORMDATA fd = {0};
  932. hr = pdnFormData->get_nodeTypedValue(&fd.varValue);
  933. if (SUCCEEDED(hr))
  934. {
  935. IXMLDOMElement *pdelFormData;
  936. hr = pdnFormData->QueryInterface(IID_PPV_ARG(IXMLDOMElement, &pdelFormData));
  937. if (SUCCEEDED(hr))
  938. {
  939. hr = pdelFormData->getAttribute(ATTRIBUTE_NAME, &fd.varName);
  940. if (SUCCEEDED(hr))
  941. {
  942. hr = (-1 == pti->dsaFormData.AppendItem(&fd)) ? E_FAIL:S_OK;
  943. }
  944. pdelFormData->Release();
  945. }
  946. }
  947. // failed to fully create the form data, so lets release
  948. if (FAILED(hr))
  949. _FreeFormData(&fd, NULL);
  950. pdnFormData->Release();
  951. }
  952. }
  953. pnl->Release();
  954. }
  955. }
  956. }
  957. }
  958. }
  959. else
  960. {
  961. hr = E_FAIL;
  962. }
  963. // lets add the common transfer item info
  964. if (SUCCEEDED(hr))
  965. hr = _AddCommonItemInfo(pdn, pti);
  966. // if we have a structure then lets append it to the DPA
  967. if (SUCCEEDED(hr))
  968. hr = (-1 == pdpaItems->AppendPtr(pti)) ? E_OUTOFMEMORY:S_OK;
  969. // failed
  970. if (FAILED(hr))
  971. _FreeTransferItems(pti);
  972. }
  973. return hr;
  974. }
  975. HRESULT CPublishingWizard::_InitTransferInfo(IXMLDOMDocument *pdocManifest, TRANSFERINFO *pti, CDPA<TRANSFERITEM> *pdpaItems)
  976. {
  977. // pull the destination and shortcut information from the manifest into the
  978. // transfer info structure.
  979. IXMLDOMNode *pdn;
  980. HRESULT hr = pdocManifest->selectSingleNode(XPATH_UPLOADINFO, &pdn);
  981. if (SUCCEEDED(hr))
  982. {
  983. if (hr == S_OK)
  984. {
  985. // get the friendly name for the site, this is stored in the upload information, this can fail.
  986. if (FAILED(GetStrFromAttribute(pdn, ATTRIBUTE_FRIENDLYNAME, pti->szSiteName, ARRAYSIZE(pti->szSiteName))))
  987. {
  988. // B2: handle this so that MSN still works, we moved the friendly name attribute to
  989. // a to the <uploadinfo/> element, however they were locked down and couldn't take
  990. // that change, therefore ensure that we pick this up from its previous location.
  991. IXMLDOMNode *pdnTarget;
  992. if (S_OK == pdn->selectSingleNode(ELEMENT_TARGET, &pdnTarget))
  993. {
  994. GetStrFromAttribute(pdnTarget, ATTRIBUTE_FRIENDLYNAME, pti->szSiteName, ARRAYSIZE(pti->szSiteName));
  995. pdnTarget->Release();
  996. }
  997. }
  998. // from the manifest lets read the file location and then the net place creation information
  999. // this is then placed into the transfer info strucuture which we used on the bg thread
  1000. // to both upload the files and also create a net place.
  1001. if (FAILED(GetURLFromElement(pdn, ELEMENT_TARGET, pti->szFileTarget, ARRAYSIZE(pti->szFileTarget))))
  1002. {
  1003. pti->fUsePost = TRUE; // if we don't get the target string then we are posting
  1004. }
  1005. // we have the target for upload to, then lets pick up the optional information about
  1006. // the site, and the net place.
  1007. if (SUCCEEDED(GetURLFromElement(pdn, ELEMENT_NETPLACE, pti->szLinkTarget, ARRAYSIZE(pti->szLinkTarget))))
  1008. {
  1009. IXMLDOMNode *pdnNetPlace;
  1010. if (pdn->selectSingleNode(ELEMENT_NETPLACE, &pdnNetPlace) == S_OK)
  1011. {
  1012. GetStrFromAttribute(pdnNetPlace, ATTRIBUTE_FILENAME, pti->szLinkName, ARRAYSIZE(pti->szLinkName));
  1013. GetStrFromAttribute(pdnNetPlace, ATTRIBUTE_COMMENT, pti->szLinkDesc, ARRAYSIZE(pti->szLinkDesc));
  1014. pdnNetPlace->Release();
  1015. }
  1016. // fix up the site name from the link description if its not defined.
  1017. if (!pti->szSiteName[0] && pti->szLinkDesc)
  1018. {
  1019. StrCpyN(pti->szSiteName, pti->szLinkDesc, ARRAYSIZE(pti->szSiteName));
  1020. }
  1021. }
  1022. // get the site URL
  1023. GetURLFromElement(pdn, ELEMENT_HTMLUI, pti->szSiteURL, ARRAYSIZE(pti->szSiteURL));
  1024. }
  1025. else
  1026. {
  1027. hr = E_FAIL;
  1028. }
  1029. }
  1030. // if they want a DPA of items then lets create them one, this is also based on the manifest.
  1031. if (SUCCEEDED(hr) && pdpaItems)
  1032. {
  1033. hr = (pdpaItems->Create(16)) ? S_OK:E_OUTOFMEMORY;
  1034. if (SUCCEEDED(hr))
  1035. {
  1036. IXMLDOMNodeList *pnl;
  1037. hr = pdocManifest->selectNodes(XPATH_ALLFILESTOUPLOAD, &pnl);
  1038. if (hr == S_OK)
  1039. {
  1040. long cSelection;
  1041. hr = pnl->get_length(&cSelection);
  1042. for (long lNode = 0; SUCCEEDED(hr) && (lNode != cSelection); lNode++)
  1043. {
  1044. IXMLDOMNode *pdn;
  1045. hr = pnl->get_item(lNode, &pdn);
  1046. if (SUCCEEDED(hr))
  1047. {
  1048. if (pti->fUsePost)
  1049. hr = _AddPostItem(pdpaItems, pdn);
  1050. else
  1051. hr = _AddTransferItem(pdpaItems, pdn);
  1052. pdn->Release();
  1053. }
  1054. }
  1055. pnl->Release();
  1056. }
  1057. // if we are *NOT* posting then sort the DPA so that we can support
  1058. // enum items correctly.
  1059. if (!pti->fUsePost)
  1060. {
  1061. pdpaItems->SortEx(s_CompareItems, this); // sort the DPA so we can search better
  1062. }
  1063. }
  1064. }
  1065. return hr;
  1066. }
  1067. // File selector dialog
  1068. HRESULT CPublishingWizard::IncludeObject(IShellView *ppshv, LPCITEMIDLIST pidl)
  1069. {
  1070. BOOL fInclude = FALSE;
  1071. LPITEMIDLIST pidlFolder;
  1072. HRESULT hr = SHGetIDListFromUnk(ppshv, &pidlFolder);
  1073. if (SUCCEEDED(hr))
  1074. {
  1075. IShellFolder *psf;
  1076. hr = SHBindToObject(NULL, IID_X_PPV_ARG(IShellFolder, pidlFolder, &psf));
  1077. if (SUCCEEDED(hr))
  1078. {
  1079. // cannot publish folders, but can publish ZIP files (which are both folder and stream at the same time)
  1080. if (!(SHGetAttributes(psf, pidl, SFGAO_FOLDER | SFGAO_STREAM) == SFGAO_FOLDER))
  1081. {
  1082. // filter based on the content type if we are given a filter string
  1083. if (_szFilter[0])
  1084. {
  1085. TCHAR szBuffer[MAX_PATH];
  1086. hr = DisplayNameOf(psf, pidl, SHGDN_FORPARSING, szBuffer, ARRAYSIZE(szBuffer));
  1087. if (SUCCEEDED(hr))
  1088. {
  1089. TCHAR szContentType[MAX_PATH];
  1090. DWORD cch = ARRAYSIZE(szContentType);
  1091. hr = AssocQueryString(0, ASSOCSTR_CONTENTTYPE, szBuffer, NULL, szContentType, &cch);
  1092. fInclude = SUCCEEDED(hr) && PathMatchSpec(szContentType, _szFilter);
  1093. }
  1094. }
  1095. else
  1096. {
  1097. fInclude = TRUE;
  1098. }
  1099. }
  1100. psf->Release();
  1101. }
  1102. ILFree(pidlFolder);
  1103. }
  1104. return fInclude ? S_OK:S_FALSE;
  1105. }
  1106. // handle the state changing in the dialog and therefore us updating the buttons & status
  1107. void CPublishingWizard::_StateChanged()
  1108. {
  1109. int cItemsChecked = 0;
  1110. int cItems = 0;
  1111. if (_pfv)
  1112. {
  1113. _pfv->ItemCount(SVGIO_ALLVIEW, &cItems);
  1114. _pfv->ItemCount(SVGIO_CHECKED, &cItemsChecked);
  1115. }
  1116. // format and display the status bar for this item
  1117. TCHAR szFmt[MAX_PATH];
  1118. if (FAILED(_LoadMappedString(L"wp:selector", L"countfmt", szFmt, ARRAYSIZE(szFmt))))
  1119. {
  1120. LoadString(g_hinst, IDS_PUB_SELECTOR_FMT, szFmt, ARRAYSIZE(szFmt));
  1121. }
  1122. TCHAR szBuffer[MAX_PATH];
  1123. FormatMessageTemplate(szFmt, szBuffer, ARRAYSIZE(szBuffer), cItemsChecked, cItems);
  1124. SetDlgItemText(_hwndSelector, IDC_PUB_SELECTORSTATUS, szBuffer);
  1125. // ensure that Next is only enabled when we have checked some items in the view
  1126. PropSheet_SetWizButtons(GetParent(_hwndSelector), ((cItemsChecked > 0) ? PSWIZB_NEXT:0) | PSWIZB_BACK);
  1127. }
  1128. HRESULT CPublishingWizard::OnStateChange(IShellView *pshv, ULONG uChange)
  1129. {
  1130. if (uChange == CDBOSC_STATECHANGE)
  1131. {
  1132. _StateChanged();
  1133. _fRecomputeManifest = TRUE;
  1134. }
  1135. return S_OK;
  1136. }
  1137. UINT CPublishingWizard::s_SelectorPropPageProc(HWND hwndDlg, UINT uMsg, PROPSHEETPAGE *ppsp)
  1138. {
  1139. CPublishingWizard *ppw = (CPublishingWizard*)ppsp->lParam;
  1140. switch (uMsg)
  1141. {
  1142. case PSPCB_CREATE:
  1143. return TRUE;
  1144. // we are cleaning up the page, lets ensure that we release file view object
  1145. // if we have one. that way our reference count correctly reflects our state
  1146. // rather than us ending up with a circular reference to other objects
  1147. case PSPCB_RELEASE:
  1148. if (ppw->_pfv)
  1149. {
  1150. IUnknown_SetSite(ppw->_pfv, NULL);
  1151. ATOMICRELEASE(ppw->_pfv);
  1152. }
  1153. break;
  1154. }
  1155. return FALSE;
  1156. }
  1157. INT_PTR CPublishingWizard::_SelectorDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1158. {
  1159. switch (uMsg)
  1160. {
  1161. case WM_INITDIALOG:
  1162. {
  1163. _hwndSelector = hwnd;
  1164. // lets read the default state for this provider from a key in the registry
  1165. // this will define the types of files we are going to allow, the format is
  1166. // a spec (eg. image/* means all images), each element can be seperated by a ;
  1167. HKEY hkProvider;
  1168. HRESULT hr = _GetProviderKey(HKEY_LOCAL_MACHINE, KEY_READ, NULL, &hkProvider);
  1169. if (SUCCEEDED(hr))
  1170. {
  1171. DWORD cbFilter = sizeof(TCHAR)*ARRAYSIZE(_szFilter);
  1172. SHGetValue(hkProvider, NULL, SZ_REGVAL_FILEFILTER, NULL, _szFilter, &cbFilter);
  1173. RegCloseKey(hkProvider);
  1174. }
  1175. // create the file picker object, align with the hidden control on the window
  1176. // and initialize with the IDataObject which contains the selection.
  1177. hr = CoCreateInstance(CLSID_FolderViewHost, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IFolderView, &_pfv));
  1178. if (SUCCEEDED(hr))
  1179. {
  1180. IUnknown_SetSite(_pfv, (IObjectWithSite*)this);
  1181. IFolderViewHost *pfvh;
  1182. hr = _pfv->QueryInterface(IID_PPV_ARG(IFolderViewHost, &pfvh));
  1183. if (SUCCEEDED(hr))
  1184. {
  1185. RECT rc;
  1186. GetWindowRect(GetDlgItem(hwnd, IDC_PUB_SELECTOR), &rc);
  1187. MapWindowRect(HWND_DESKTOP, hwnd, &rc);
  1188. InitClipboardFormats(); // initialize walks data object
  1189. hr = pfvh->Initialize(hwnd, _pdo, &rc);
  1190. if (SUCCEEDED(hr))
  1191. {
  1192. HWND hwndPicker;
  1193. hr = IUnknown_GetWindow(_pfv, &hwndPicker);
  1194. if (SUCCEEDED(hr))
  1195. {
  1196. SetWindowPos(hwndPicker, HWND_TOP, 0,0,0,0, SWP_NOMOVE|SWP_NOSIZE);
  1197. }
  1198. }
  1199. pfvh->Release();
  1200. }
  1201. if (FAILED(hr))
  1202. {
  1203. ATOMICRELEASE(_pfv);
  1204. }
  1205. }
  1206. return TRUE;
  1207. }
  1208. case WM_COMMAND:
  1209. {
  1210. if (HIWORD(wParam) == BN_CLICKED)
  1211. {
  1212. switch (LOWORD(wParam))
  1213. {
  1214. case IDC_PUB_ALL:
  1215. case IDC_PUB_NOTHING:
  1216. if (_pfv)
  1217. {
  1218. int cItems;
  1219. HRESULT hr = _pfv->ItemCount(SVGIO_ALLVIEW, &cItems);
  1220. for (int iItem = 0; SUCCEEDED(hr) && (iItem != cItems); iItem++)
  1221. {
  1222. BOOL fSelect = (LOWORD(wParam) == IDC_PUB_ALL);
  1223. hr = _pfv->SelectItem(iItem, SVSI_NOSTATECHANGE | (fSelect ? SVSI_CHECK:0));
  1224. }
  1225. break;
  1226. }
  1227. }
  1228. break;
  1229. }
  1230. }
  1231. case WM_NOTIFY:
  1232. {
  1233. LPNMHDR pnmh = (LPNMHDR)lParam;
  1234. switch (pnmh->code)
  1235. {
  1236. case PSN_SETACTIVE:
  1237. {
  1238. if (_pfv)
  1239. {
  1240. _StateChanged();
  1241. PostMessage(hwnd, WM_APP, 0, 0);
  1242. }
  1243. else
  1244. {
  1245. // no IFolderView, so lets skip this page.
  1246. int i = PropSheet_PageToIndex(GetParent(hwnd), _aWizPages[WIZPAGE_FETCHINGPROVIDERS]);
  1247. SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LPARAM)PropSheet_IndexToId(GetParent(hwnd), i));
  1248. }
  1249. return TRUE;
  1250. }
  1251. case PSN_WIZNEXT:
  1252. {
  1253. if (_fRecomputeManifest && _pfv)
  1254. {
  1255. IDataObject *pdo;
  1256. HRESULT hr = _pfv->Items(SVGIO_CHECKED, IID_PPV_ARG(IDataObject, &pdo));
  1257. if (SUCCEEDED(hr))
  1258. {
  1259. IUnknown_Set((IUnknown**)&_pdoSelection, pdo);
  1260. pdo->Release();
  1261. }
  1262. }
  1263. return _WizardNext(hwnd, WIZPAGE_FETCHINGPROVIDERS);
  1264. }
  1265. case PSN_WIZBACK:
  1266. {
  1267. if (_punkSite)
  1268. {
  1269. IWizardSite *pws;
  1270. if (SUCCEEDED(_punkSite->QueryInterface(IID_PPV_ARG(IWizardSite, &pws))))
  1271. {
  1272. HPROPSHEETPAGE hpage;
  1273. if (SUCCEEDED(pws->GetPreviousPage(&hpage)))
  1274. {
  1275. PropSheet_SetCurSel(GetParent(hwnd), hpage, -1);
  1276. }
  1277. pws->Release();
  1278. }
  1279. }
  1280. SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LPARAM)-1);
  1281. return TRUE;
  1282. }
  1283. }
  1284. break;
  1285. }
  1286. // this is to work around the issue where defview (listview) forces a redraw of itself
  1287. // in a non-async way when it receives a SetFocus, therefore causing it to render
  1288. // incorrectly in the wizard frame. to fix this we post ourselves a WM_APP during the
  1289. // handle of PSN_SETACTIVE, and then turn around and call RedrawWindow.
  1290. case WM_APP:
  1291. {
  1292. HWND hwndPicker;
  1293. if (SUCCEEDED(IUnknown_GetWindow(_pfv, &hwndPicker)))
  1294. {
  1295. RedrawWindow(hwndPicker, NULL, NULL, RDW_INVALIDATE | RDW_ERASE | RDW_ALLCHILDREN);
  1296. }
  1297. break;
  1298. }
  1299. }
  1300. return FALSE;
  1301. }
  1302. // tidy up and release the providers list
  1303. void CPublishingWizard::_FreeProviderList()
  1304. {
  1305. if (_pdscProviders)
  1306. _pdscProviders->Advise(FALSE);
  1307. IUnknown_Set((IUnknown**)&_pdscProviders, NULL);
  1308. IUnknown_Set((IUnknown**)&_pdocProviders, NULL); // discard the previous providers.
  1309. }
  1310. // begin a download of the provider list, we pull the providers list async from the server
  1311. // therefore we need to register a state change monitor so that we can pull the information
  1312. // dynamically and then receive a message to merge in our extra data.
  1313. #define FETCH_TIMERID 1
  1314. #define FETCH_TIMEOUT 1000
  1315. HRESULT CPublishingWizard::_GeoFromLocaleInfo(LCID lcid, GEOID *pgeoID)
  1316. {
  1317. TCHAR szBuf[128] = {0};
  1318. if (GetLocaleInfo(lcid, LOCALE_IGEOID | LOCALE_RETURN_NUMBER, szBuf, ARRAYSIZE(szBuf)) > 0)
  1319. {
  1320. *pgeoID = *((LPDWORD)szBuf);
  1321. return S_OK;
  1322. }
  1323. return E_FAIL;
  1324. }
  1325. HRESULT CPublishingWizard::_GetProviderListFilename(LPTSTR pszFile, int cchFile)
  1326. {
  1327. HRESULT hr = S_OK;
  1328. GEOID idGEO = GetUserGeoID(GEOCLASS_NATION);
  1329. if (idGEO == GEOID_NOT_AVAILABLE)
  1330. {
  1331. hr = _GeoFromLocaleInfo(GetUserDefaultLCID(), &idGEO);
  1332. if (FAILED(hr))
  1333. hr = _GeoFromLocaleInfo(GetSystemDefaultLCID(), &idGEO);
  1334. if (FAILED(hr))
  1335. hr = _GeoFromLocaleInfo((MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)), &idGEO); // default to US English
  1336. }
  1337. if (SUCCEEDED(hr) && (idGEO != GEOID_NOT_AVAILABLE))
  1338. {
  1339. // read the provider prefix from the registry
  1340. int cchProvider = 0;
  1341. DWORD cbFile = sizeof(TCHAR)*cchFile;
  1342. if (ERROR_SUCCESS == SHGetValue(HKEY_LOCAL_MACHINE, SZ_REGKEY_PUBWIZ, SZ_REGVAL_SERVICEPARTNERID, NULL, pszFile, &cbFile))
  1343. {
  1344. StrCatBuff(pszFile, TEXT("."), cchFile);
  1345. cchProvider = lstrlen(pszFile);
  1346. }
  1347. // build <contrycode>.xml into the buffer (as a suffix of the partner if needed)
  1348. GetGeoInfo(idGEO, GEO_ISO3, pszFile + cchProvider, cchFile - cchProvider, 0);
  1349. StrCatBuff(pszFile, TEXT(".xml"), cchFile);
  1350. CharLowerBuff(pszFile, lstrlen(pszFile));
  1351. }
  1352. else if (SUCCEEDED(hr))
  1353. {
  1354. hr = E_FAIL;
  1355. }
  1356. return hr;
  1357. }
  1358. HRESULT CPublishingWizard::_FetchProviderList(HWND hwnd)
  1359. {
  1360. _FreeProviderList();
  1361. HRESULT hr = CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IXMLDOMDocument, &_pdocProviders));
  1362. if (SUCCEEDED(hr))
  1363. {
  1364. TCHAR szFile[MAX_PATH];
  1365. hr = _GetProviderListFilename(szFile, ARRAYSIZE(szFile));
  1366. if (SUCCEEDED(hr))
  1367. {
  1368. TCHAR szBuffer[INTERNET_MAX_URL_LENGTH];
  1369. hr = _GetSiteURL(szBuffer, ARRAYSIZE(szBuffer), szFile);
  1370. if (SUCCEEDED(hr))
  1371. {
  1372. LaunchICW();
  1373. if (InternetGoOnline(szBuffer, hwnd, 0))
  1374. {
  1375. _pdscProviders = new CXMLDOMStateChange(_pdocProviders, hwnd);
  1376. if (_pdscProviders)
  1377. {
  1378. hr = _pdscProviders->Advise(TRUE);
  1379. if (SUCCEEDED(hr))
  1380. {
  1381. VARIANT varName;
  1382. hr = InitVariantFromStr(&varName, szBuffer);
  1383. if (SUCCEEDED(hr))
  1384. {
  1385. VARIANT_BOOL fSuccess;
  1386. hr = _pdocProviders->load(varName, &fSuccess);
  1387. if (FAILED(hr) || (fSuccess != VARIANT_TRUE))
  1388. {
  1389. hr = FAILED(hr) ? hr:E_FAIL;
  1390. }
  1391. VariantClear(&varName);
  1392. }
  1393. }
  1394. }
  1395. else
  1396. {
  1397. hr = E_OUTOFMEMORY;
  1398. }
  1399. }
  1400. else
  1401. {
  1402. hr = E_FAIL;
  1403. }
  1404. }
  1405. }
  1406. }
  1407. // if any of this failed then lets post ourselves the completed message
  1408. // with the failure code, at which point we can then load the default document.
  1409. if (FAILED(hr))
  1410. PostMessage(hwnd, MSG_XMLDOC_COMPLETED, 0, (LPARAM)hr);
  1411. return hr;
  1412. }
  1413. void CPublishingWizard::_FetchComplete(HWND hwnd, HRESULT hr)
  1414. {
  1415. // if we failed to load the document then lets pull in the default provider
  1416. // list from our DLL, this can also fail, but its unlikely to. we recreate
  1417. // the XML DOM object to ensure our state is pure.
  1418. _fUsingTemporaryProviders = FAILED(hr);
  1419. _fRepopulateProviders = TRUE; // provider list will have changed!
  1420. if (FAILED(hr))
  1421. {
  1422. _FreeProviderList();
  1423. hr = CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IXMLDOMDocument, &_pdocProviders));
  1424. if (SUCCEEDED(hr))
  1425. {
  1426. VARIANT varName;
  1427. hr = InitVariantFromStr(&varName, TEXT("res://netplwiz.dll/xml/providers.xml"));
  1428. if (SUCCEEDED(hr))
  1429. {
  1430. VARIANT_BOOL fSuccess = VARIANT_FALSE;
  1431. hr = _pdocProviders->load(varName, &fSuccess);
  1432. if (FAILED(hr) || (fSuccess != VARIANT_TRUE))
  1433. {
  1434. hr = FAILED(hr) ? hr:E_FAIL;
  1435. }
  1436. VariantClear(&varName);
  1437. }
  1438. }
  1439. }
  1440. KillTimer(hwnd, FETCH_TIMERID);
  1441. _ShowHideFetchProgress(hwnd, FALSE);
  1442. _WizardNext(hwnd, WIZPAGE_PROVIDERS);
  1443. }
  1444. void CPublishingWizard::_ShowHideFetchProgress(HWND hwnd, BOOL fShow)
  1445. {
  1446. ShowWindow(GetDlgItem(hwnd, IDC_PUB_SRCHPROVIDERS), fShow ? SW_SHOW:SW_HIDE);
  1447. ShowWindow(GetDlgItem(hwnd, IDC_PUB_SRCHPROVIDERS_STATIC1), fShow ? SW_SHOW:SW_HIDE);
  1448. ShowWindow(GetDlgItem(hwnd, IDC_PUB_SRCHPROVIDERS_STATIC2), fShow ? SW_SHOW:SW_HIDE);
  1449. SendDlgItemMessage(hwnd, IDC_PUB_SRCHPROVIDERS, PBM_SETMARQUEE, (WPARAM)fShow, 0);
  1450. }
  1451. INT_PTR CPublishingWizard::_FetchProvidersDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  1452. {
  1453. switch (uMsg)
  1454. {
  1455. case WM_INITDIALOG:
  1456. _MapDlgItemText(hwnd, IDC_PUB_SRCHPROVIDERS_STATIC1, L"wp:destination", L"downloading");
  1457. break;
  1458. case MSG_XMLDOC_COMPLETED:
  1459. _FetchComplete(hwnd, (HRESULT)lParam);
  1460. break;
  1461. case WM_NOTIFY:
  1462. {
  1463. LPNMHDR pnmh = (LPNMHDR)lParam;
  1464. switch (pnmh->code)
  1465. {
  1466. case PSN_SETACTIVE:
  1467. {
  1468. BOOL fFetch = TRUE;
  1469. if (_pdocProviders && !_fUsingTemporaryProviders)
  1470. {
  1471. long lReadyState;
  1472. HRESULT hr = _pdocProviders->get_readyState(&lReadyState);
  1473. if (SUCCEEDED(hr) && (lReadyState == XMLDOC_COMPLETED))
  1474. {
  1475. _WizardNext(hwnd, WIZPAGE_PROVIDERS);
  1476. fFetch = FALSE;
  1477. }
  1478. }
  1479. if (fFetch)
  1480. {
  1481. SetTimer(hwnd, FETCH_TIMERID, FETCH_TIMEOUT, NULL);
  1482. _FetchProviderList(hwnd);
  1483. PropSheet_SetWizButtons(GetParent(hwnd), 0x0);
  1484. }
  1485. return TRUE;
  1486. }
  1487. }
  1488. break;
  1489. }
  1490. case WM_TIMER:
  1491. {
  1492. KillTimer(hwnd, FETCH_TIMERID);
  1493. _ShowHideFetchProgress(hwnd, TRUE);
  1494. return TRUE;
  1495. }
  1496. }
  1497. return FALSE;
  1498. }
  1499. // Destination page
  1500. int CPublishingWizard::_GetSelectedItem(HWND hwndList)
  1501. {
  1502. int iSelected = ListView_GetNextItem(hwndList, -1, LVNI_FOCUSED|LVNI_SELECTED);
  1503. if (iSelected == -1)
  1504. {
  1505. iSelected = ListView_GetNextItem(hwndList, -1, LVNI_SELECTED);
  1506. }
  1507. return iSelected;
  1508. }
  1509. void CPublishingWizard::_ProviderEnableNext(HWND hwnd)
  1510. {
  1511. DWORD dwButtons = PSWIZB_BACK;
  1512. // there must be an item available in the list, and it must have a ID property defined
  1513. // for it so it can be enabled.
  1514. int iSelected = _GetSelectedItem(GetDlgItem(hwnd, IDC_PUB_PROVIDERS));
  1515. if (iSelected != -1)
  1516. {
  1517. LVITEM lvi = { 0 };
  1518. lvi.iItem = iSelected;
  1519. lvi.mask = LVIF_PARAM;
  1520. if (ListView_GetItem(GetDlgItem(hwnd, IDC_PUB_PROVIDERS), &lvi))
  1521. {
  1522. IXMLDOMNode *pdn = (IXMLDOMNode*)lvi.lParam;
  1523. TCHAR szID[INTERNET_MAX_URL_LENGTH];
  1524. if (SUCCEEDED(GetStrFromAttribute(pdn, ATTRIBUTE_ID, szID, ARRAYSIZE(szID))))
  1525. {
  1526. dwButtons |= PSWIZB_NEXT;
  1527. }
  1528. }
  1529. }
  1530. PropSheet_SetWizButtons(GetParent(hwnd), dwButtons);
  1531. }
  1532. // extract an icon resource from the provider XML documents. the icons are stored as
  1533. // mime encoded bitmaps that we decode into files in the users settings folder. we return
  1534. // an index to the shared image list.
  1535. int CPublishingWizard::_GetRemoteIcon(LPCTSTR pszID, BOOL fCanRefresh)
  1536. {
  1537. int iResult = -1;
  1538. TCHAR szURL[INTERNET_MAX_URL_LENGTH];
  1539. HRESULT hr = _GetSiteURL(szURL, ARRAYSIZE(szURL), pszID);
  1540. if (SUCCEEDED(hr))
  1541. {
  1542. TCHAR szFilename[MAX_PATH];
  1543. hr = URLDownloadToCacheFile(NULL, szURL, szFilename, ARRAYSIZE(szFilename), 0x0, NULL);
  1544. if (SUCCEEDED(hr))
  1545. {
  1546. iResult = Shell_GetCachedImageIndex(szFilename, 0x0, 0x0);
  1547. }
  1548. }
  1549. return iResult;
  1550. }
  1551. // get the provider list from the internet
  1552. struct
  1553. {
  1554. LPTSTR pszAttribute;
  1555. BOOL fIsString;
  1556. }
  1557. aProviderElements[] =
  1558. {
  1559. { ATTRIBUTE_SUPPORTEDTYPES, FALSE },
  1560. { ATTRIBUTE_DISPLAYNAME, TRUE },
  1561. { ATTRIBUTE_DESCRIPTION, TRUE },
  1562. { ATTRIBUTE_HREF, FALSE },
  1563. { ATTRIBUTE_ICONPATH, FALSE },
  1564. { ATTRIBUTE_ICON, FALSE },
  1565. };
  1566. HRESULT CPublishingWizard::_MergeLocalProviders()
  1567. {
  1568. TCHAR szBuffer[MAX_PATH];
  1569. wnsprintf(szBuffer, ARRAYSIZE(szBuffer), FMT_PROVIDER, _szProviderScope);
  1570. IXMLDOMNode *pdn;
  1571. HRESULT hr = _pdocProviders->selectSingleNode(szBuffer, &pdn);
  1572. if (hr == S_OK)
  1573. {
  1574. HKEY hk;
  1575. hr = _GetProviderKey(HKEY_CURRENT_USER, KEY_READ, SZ_REGVAL_ALTPROVIDERS, &hk);
  1576. if (SUCCEEDED(hr))
  1577. {
  1578. for (int i =0; SUCCEEDED(hr) && (RegEnumKey(hk, i, szBuffer, ARRAYSIZE(szBuffer)) == ERROR_SUCCESS); i++)
  1579. {
  1580. // the manifest always overrides the entries that are stored in the registry,
  1581. // therefore if there is an element in the document that has a matching ID to the
  1582. // one in the registry then lets handle it.
  1583. TCHAR szSelectValue[MAX_PATH];
  1584. wnsprintf(szSelectValue, ARRAYSIZE(szSelectValue), TEXT("provider[@id=\"%s\"]"), szBuffer);
  1585. IXMLDOMNode *pdnProvider;
  1586. if (pdn->selectSingleNode(szSelectValue, &pdnProvider) == S_FALSE)
  1587. {
  1588. IPropertyBag *ppb;
  1589. hr = SHCreatePropertyBagOnRegKey(hk, szBuffer, STGM_READ, IID_PPV_ARG(IPropertyBag, &ppb));
  1590. if (SUCCEEDED(hr))
  1591. {
  1592. IXMLDOMElement *pdel;
  1593. hr = _pdocProviders->createElement(ELEMENT_PROVIDER, &pdel);
  1594. if (SUCCEEDED(hr))
  1595. {
  1596. hr = SetAttributeFromStr(pdel, ATTRIBUTE_ID, szBuffer);
  1597. if (SUCCEEDED(hr))
  1598. {
  1599. // loop and replicate all the attributes from the property bag
  1600. // into the element. once we have done that we can add
  1601. // the element to the provider list.
  1602. for (int i = 0; SUCCEEDED(hr) && (i < ARRAYSIZE(aProviderElements)); i++)
  1603. {
  1604. VARIANT var = {0};
  1605. if (SUCCEEDED(ppb->Read(aProviderElements[i].pszAttribute, &var, NULL)))
  1606. {
  1607. hr = pdel->setAttribute(aProviderElements[i].pszAttribute, var);
  1608. VariantClear(&var);
  1609. }
  1610. }
  1611. if (SUCCEEDED(hr))
  1612. {
  1613. hr = pdn->appendChild(pdel, NULL);
  1614. }
  1615. }
  1616. pdel->Release();
  1617. }
  1618. ppb->Release();
  1619. }
  1620. }
  1621. else
  1622. {
  1623. pdnProvider->Release();
  1624. }
  1625. }
  1626. RegCloseKey(hk);
  1627. }
  1628. pdn->Release();
  1629. }
  1630. return hr;
  1631. }
  1632. void CPublishingWizard::_GetDefaultProvider(LPTSTR pszProvider, int cch)
  1633. {
  1634. HKEY hk;
  1635. HRESULT hr = _GetProviderKey(HKEY_CURRENT_USER, KEY_READ, NULL, &hk);
  1636. if (SUCCEEDED(hr))
  1637. {
  1638. DWORD cb = cch*sizeof(*pszProvider);
  1639. SHGetValue(hk, NULL, SZ_REGVAL_DEFAULTPROVIDER, NULL, pszProvider, &cb);
  1640. RegCloseKey(hk);
  1641. }
  1642. }
  1643. void CPublishingWizard::_SetDefaultProvider(IXMLDOMNode *pdn)
  1644. {
  1645. TCHAR szProvider[MAX_PATH];
  1646. HRESULT hr = GetStrFromAttribute(pdn, ATTRIBUTE_ID, szProvider, ARRAYSIZE(szProvider));
  1647. if (SUCCEEDED(hr))
  1648. {
  1649. HKEY hk;
  1650. hr = _GetProviderKey(HKEY_CURRENT_USER, KEY_WRITE, NULL, &hk);
  1651. if (SUCCEEDED(hr))
  1652. {
  1653. // store the default provider value
  1654. DWORD cb = (lstrlen(szProvider)+1)*sizeof(*szProvider);
  1655. SHSetValue(hk, NULL, SZ_REGVAL_DEFAULTPROVIDER, REG_SZ, szProvider, cb);
  1656. // we now need to replicate the properties from the DOM into the registry so that
  1657. // the user can always get to the specified site. to make this easier we
  1658. // will create a property bag that we will copy values using.
  1659. TCHAR szBuffer[MAX_PATH];
  1660. wnsprintf(szBuffer, ARRAYSIZE(szBuffer), (SZ_REGVAL_ALTPROVIDERS TEXT("\\%s")), szProvider);
  1661. IPropertyBag *ppb;
  1662. hr = SHCreatePropertyBagOnRegKey(hk, szBuffer, STGM_CREATE | STGM_WRITE, IID_PPV_ARG(IPropertyBag, &ppb));
  1663. if (SUCCEEDED(hr))
  1664. {
  1665. IXMLDOMElement *pdel;
  1666. hr = pdn->QueryInterface(IID_PPV_ARG(IXMLDOMElement, &pdel));
  1667. if (SUCCEEDED(hr))
  1668. {
  1669. for (int i = 0; SUCCEEDED(hr) && (i < ARRAYSIZE(aProviderElements)); i++)
  1670. {
  1671. if (aProviderElements[i].fIsString)
  1672. {
  1673. hr = _GetProviderString(pdn, aProviderElements[i].pszAttribute, szBuffer, ARRAYSIZE(szBuffer));
  1674. if (SUCCEEDED(hr))
  1675. {
  1676. hr = SHPropertyBag_WriteStr(ppb, aProviderElements[i].pszAttribute, szBuffer);
  1677. }
  1678. }
  1679. else
  1680. {
  1681. VARIANT var = {0};
  1682. if (S_OK == pdel->getAttribute(aProviderElements[i].pszAttribute, &var))
  1683. {
  1684. hr = ppb->Write(aProviderElements[i].pszAttribute, &var);
  1685. VariantClear(&var);
  1686. }
  1687. }
  1688. }
  1689. pdel->Release();
  1690. }
  1691. ppb->Release();
  1692. }
  1693. RegCloseKey(hk);
  1694. }
  1695. }
  1696. }
  1697. // load a localized string from the XML node for the provider
  1698. HRESULT CPublishingWizard::_GetProviderString(IXMLDOMNode *pdn, USHORT idPrimary, USHORT idSub, LPCTSTR pszID, LPTSTR pszBuffer, int cch)
  1699. {
  1700. TCHAR szPath[MAX_PATH];
  1701. wnsprintf(szPath, ARRAYSIZE(szPath), TEXT("strings[@langid='%04x']/string[@id='%s'][@langid='%04x']"), idPrimary, pszID, idSub);
  1702. IXMLDOMNode *pdnString;
  1703. HRESULT hr = pdn->selectSingleNode(szPath, &pdnString);
  1704. if (hr == S_OK)
  1705. {
  1706. VARIANT var = {VT_BSTR};
  1707. hr = pdnString->get_nodeTypedValue(&var);
  1708. if (SUCCEEDED(hr))
  1709. {
  1710. VariantToStr(&var, pszBuffer, cch);
  1711. VariantClear(&var);
  1712. }
  1713. pdnString->Release();
  1714. }
  1715. return hr;
  1716. }
  1717. HRESULT CPublishingWizard::_GetProviderString(IXMLDOMNode *pdn, LPCTSTR pszID, LPTSTR pszBuffer, int cch)
  1718. {
  1719. *pszBuffer = TEXT('\0');
  1720. LANGID idLang = GetUserDefaultLangID();
  1721. HRESULT hr = _GetProviderString(pdn, PRIMARYLANGID(idLang), SUBLANGID(idLang), pszID, pszBuffer, cch);
  1722. if (hr == S_FALSE)
  1723. {
  1724. hr = _GetProviderString(pdn, PRIMARYLANGID(idLang), SUBLANG_NEUTRAL, pszID, pszBuffer, cch);
  1725. if (hr == S_FALSE)
  1726. {
  1727. hr = _GetProviderString(pdn, LANG_NEUTRAL, SUBLANG_NEUTRAL, pszID, pszBuffer, cch);
  1728. if (hr == S_FALSE)
  1729. {
  1730. hr = GetStrFromAttribute(pdn, pszID, pszBuffer, cch);
  1731. }
  1732. }
  1733. }
  1734. SHLoadIndirectString(pszBuffer, pszBuffer, cch, NULL);
  1735. return hr;
  1736. }
  1737. // populate the provider list on the destination page
  1738. #define TILE_DISPLAYNAME 0
  1739. #define TILE_DESCRIPTION 1
  1740. #define TILE_MAX 1
  1741. const UINT c_auTileColumns[] = {TILE_DISPLAYNAME, TILE_DESCRIPTION};
  1742. const UINT c_auTileSubItems[] = {TILE_DESCRIPTION};
  1743. int CPublishingWizard::_AddProvider(HWND hwnd, IXMLDOMNode *pdn)
  1744. {
  1745. // fill out the item information
  1746. LV_ITEM lvi = { 0 };
  1747. lvi.mask = LVIF_TEXT|LVIF_PARAM|LVIF_IMAGE;
  1748. lvi.iItem = ListView_GetItemCount(hwnd); // always append!
  1749. lvi.lParam = (LPARAM)pdn;
  1750. lvi.pszText = LPSTR_TEXTCALLBACK;
  1751. lvi.iImage = -1; // set to the default state
  1752. // read the icon location and put that onto the item
  1753. TCHAR szIcon[MAX_PATH];
  1754. if (SUCCEEDED(GetStrFromAttribute(pdn, ATTRIBUTE_ICONPATH, szIcon, ARRAYSIZE(szIcon))))
  1755. {
  1756. int resid = PathParseIconLocation(szIcon);
  1757. lvi.iImage = Shell_GetCachedImageIndex(szIcon, resid, 0x0);
  1758. }
  1759. else if (SUCCEEDED(GetStrFromAttribute(pdn, ATTRIBUTE_ICON, szIcon, ARRAYSIZE(szIcon))))
  1760. {
  1761. lvi.iImage = _GetRemoteIcon(szIcon, TRUE);
  1762. }
  1763. // if that failed then lets try and compute a sensible default icon for us to use
  1764. if (lvi.iImage == -1)
  1765. {
  1766. // under the provider key for the install lets see if there is a default icon that we
  1767. // should be using. if not, or if that fails to extract then lets use the publishing one.
  1768. HKEY hk;
  1769. if (SUCCEEDED(_GetProviderKey(HKEY_LOCAL_MACHINE, KEY_READ, NULL, &hk)))
  1770. {
  1771. DWORD cb = ARRAYSIZE(szIcon)*sizeof(*szIcon);
  1772. if (ERROR_SUCCESS == SHGetValue(hk, NULL, SZ_REGVAL_DEFAULTPROVIDERICON, NULL, szIcon, &cb))
  1773. {
  1774. int resid = PathParseIconLocation(szIcon);
  1775. lvi.iImage = Shell_GetCachedImageIndex(szIcon, resid, 0x0); // default to the publishing icon
  1776. }
  1777. RegCloseKey(hk);
  1778. }
  1779. if (lvi.iImage == -1)
  1780. lvi.iImage = Shell_GetCachedImageIndex(TEXT("shell32.dll"), -244, 0x0);
  1781. }
  1782. int iResult = ListView_InsertItem(hwnd, &lvi);
  1783. if (iResult != -1)
  1784. {
  1785. pdn->AddRef(); // it was added to the view, so take reference
  1786. LVTILEINFO lvti;
  1787. lvti.cbSize = sizeof(LVTILEINFO);
  1788. lvti.iItem = iResult;
  1789. lvti.cColumns = ARRAYSIZE(c_auTileSubItems);
  1790. lvti.puColumns = (UINT*)c_auTileSubItems;
  1791. ListView_SetTileInfo(hwnd, &lvti);
  1792. }
  1793. return iResult;
  1794. }
  1795. void CPublishingWizard::_PopulateProviderList(HWND hwnd)
  1796. {
  1797. HWND hwndList = GetDlgItem(hwnd, IDC_PUB_PROVIDERS);
  1798. // setup the view with the tiles that we want to show and the
  1799. // icon lists - shared with the shell.
  1800. ListView_DeleteAllItems(hwndList);
  1801. ListView_SetView(hwndList, LV_VIEW_TILE);
  1802. for (int i=0; i<ARRAYSIZE(c_auTileColumns); i++)
  1803. {
  1804. LV_COLUMN col;
  1805. col.mask = LVCF_SUBITEM;
  1806. col.iSubItem = c_auTileColumns[i];
  1807. ListView_InsertColumn(hwndList, i, &col);
  1808. }
  1809. RECT rc;
  1810. GetClientRect(hwndList, &rc);
  1811. LVTILEVIEWINFO lvtvi;
  1812. lvtvi.cbSize = sizeof(LVTILEVIEWINFO);
  1813. lvtvi.dwMask = LVTVIM_TILESIZE | LVTVIM_COLUMNS;
  1814. lvtvi.dwFlags = LVTVIF_FIXEDWIDTH;
  1815. lvtvi.sizeTile.cx = RECTWIDTH(rc) - GetSystemMetrics(SM_CXVSCROLL);
  1816. lvtvi.cLines = ARRAYSIZE(c_auTileSubItems);
  1817. ListView_SetTileViewInfo(hwndList, &lvtvi);
  1818. if (_pdocProviders)
  1819. {
  1820. long lReadyState;
  1821. HRESULT hr = _pdocProviders->get_readyState(&lReadyState);
  1822. if (SUCCEEDED(hr) && (lReadyState == XMLDOC_COMPLETED))
  1823. {
  1824. // lets merge in the local providers, these are local to this user,
  1825. // we check for duplicates so this shouldn't present too much hardship.
  1826. _MergeLocalProviders();
  1827. // format a query to return the providers that match our publishing scope,
  1828. // this will allow the wizard to show different lists of providers for
  1829. // web publishing vs. internet printing
  1830. WCHAR szBuffer[MAX_PATH];
  1831. wnsprintf(szBuffer, ARRAYSIZE(szBuffer), FMT_PROVIDERS, _szProviderScope);
  1832. IXMLDOMNodeList *pnl;
  1833. hr = _pdocProviders->selectNodes(szBuffer, &pnl);
  1834. if (hr == S_OK)
  1835. {
  1836. long cSelection;
  1837. hr = pnl->get_length(&cSelection);
  1838. if (SUCCEEDED(hr) && (cSelection > 0))
  1839. {
  1840. // get the list of unique types from the selection we are going to try and publish
  1841. HDPA hdpaUniqueTypes = NULL;
  1842. _GetUniqueTypeList(FALSE, &hdpaUniqueTypes); // don't care if this fails - ptr is NULL
  1843. // we need the default provider to highlight correctly, using this we can then
  1844. // populate the list from the provider manfiest
  1845. TCHAR szDefaultProvider[MAX_PATH] = {0};
  1846. _GetDefaultProvider(szDefaultProvider, ARRAYSIZE(szDefaultProvider));
  1847. int iDefault = 0;
  1848. for (long lNode = 0; lNode != cSelection; lNode++)
  1849. {
  1850. IXMLDOMNode *pdn;
  1851. hr = pnl->get_item(lNode, &pdn);
  1852. if (SUCCEEDED(hr))
  1853. {
  1854. // filter based on the list of types they support, this is optional
  1855. // if they don't specify anything then they are in the list,
  1856. // otherwise the format is assumed to be a file spec, eg *.bmp;*.jpg; etc.
  1857. BOOL fSupported = TRUE;
  1858. if (hdpaUniqueTypes)
  1859. {
  1860. hr = GetStrFromAttribute(pdn, ATTRIBUTE_SUPPORTEDTYPES, szBuffer, ARRAYSIZE(szBuffer));
  1861. if (SUCCEEDED(hr))
  1862. {
  1863. fSupported = FALSE;
  1864. for (int i = 0; !fSupported && (i < DPA_GetPtrCount(hdpaUniqueTypes)); i++)
  1865. {
  1866. LPCTSTR pszExtension = (LPCTSTR)DPA_GetPtr(hdpaUniqueTypes, i);
  1867. fSupported = PathMatchSpec(pszExtension, szBuffer);
  1868. }
  1869. }
  1870. }
  1871. // if this is a supported item then lets add it to the list
  1872. if (fSupported)
  1873. {
  1874. hr = GetStrFromAttribute(pdn, ATTRIBUTE_ID, szBuffer, ARRAYSIZE(szBuffer));
  1875. if (SUCCEEDED(hr))
  1876. {
  1877. int i = _AddProvider(hwndList, pdn);
  1878. if ((i != -1) && (0 == StrCmpI(szBuffer, szDefaultProvider)))
  1879. {
  1880. iDefault = i;
  1881. }
  1882. }
  1883. }
  1884. pdn->Release();
  1885. }
  1886. }
  1887. ListView_SetItemState(hwndList, iDefault, LVIS_SELECTED, LVIS_SELECTED);
  1888. ListView_EnsureVisible(hwndList, iDefault, FALSE);
  1889. if (hdpaUniqueTypes)
  1890. DPA_DestroyCallback(hdpaUniqueTypes, s_FreeStringProc, 0);
  1891. }
  1892. else
  1893. {
  1894. // we have no providers that match this criteria therefore lets
  1895. // create a dummy one which shows this to the caller
  1896. IXMLDOMElement *pdelProvider;
  1897. hr = _pdocManifest->createElement(ELEMENT_FILE, &pdelProvider);
  1898. if (SUCCEEDED(hr))
  1899. {
  1900. IResourceMap *prm;
  1901. hr = _GetResourceMap(&prm);
  1902. if (SUCCEEDED(hr))
  1903. {
  1904. // get the no providers string
  1905. if (FAILED(_LoadMappedString(L"wp:selector", L"noprovider", szBuffer, ARRAYSIZE(szBuffer))))
  1906. LoadString(g_hinst, IDS_PUB_NOPROVIDER, szBuffer, ARRAYSIZE(szBuffer));
  1907. hr = SetAttributeFromStr(pdelProvider, ATTRIBUTE_DISPLAYNAME, szBuffer);
  1908. // get the sub-text for the no providers
  1909. if (SUCCEEDED(hr))
  1910. {
  1911. if (FAILED(_LoadMappedString(L"wp:selector", L"noproviderdesc", szBuffer, ARRAYSIZE(szBuffer))))
  1912. LoadString(g_hinst, IDS_PUB_NOPROVIDERDESC, szBuffer, ARRAYSIZE(szBuffer));
  1913. hr = SetAttributeFromStr(pdelProvider, ATTRIBUTE_DESCRIPTION, szBuffer);
  1914. }
  1915. // lets put together a resource string for the icon we are going to show
  1916. if (SUCCEEDED(hr))
  1917. {
  1918. wnsprintf(szBuffer, ARRAYSIZE(szBuffer), TEXT("netplwiz.dll,-%d"), IDI_NOPROVIDERS);
  1919. hr = SetAttributeFromStr(pdelProvider, ATTRIBUTE_ICONPATH, szBuffer);
  1920. }
  1921. // lets add a provider from the free standing node
  1922. if (SUCCEEDED(hr))
  1923. {
  1924. IXMLDOMNode *pdnProvider;
  1925. hr = pdelProvider->QueryInterface(IID_PPV_ARG(IXMLDOMNode, &pdnProvider));
  1926. if (SUCCEEDED(hr))
  1927. {
  1928. _AddProvider(hwndList, pdnProvider);
  1929. pdnProvider->Release();
  1930. }
  1931. }
  1932. prm->Release();
  1933. }
  1934. pdelProvider->Release();
  1935. }
  1936. }
  1937. pnl->Release();
  1938. }
  1939. }
  1940. }
  1941. _fRepopulateProviders = FALSE; // providers have been populated
  1942. }
  1943. // handle next in the provider (destination) page
  1944. HRESULT CPublishingWizard::_ProviderNext(HWND hwnd, HPROPSHEETPAGE *phPage)
  1945. {
  1946. HRESULT hr = E_FAIL;
  1947. int iSelected = _GetSelectedItem(GetDlgItem(hwnd, IDC_PUB_PROVIDERS));
  1948. if (iSelected != -1)
  1949. {
  1950. LVITEM lvi = { 0 };
  1951. lvi.iItem = iSelected;
  1952. lvi.mask = LVIF_PARAM;
  1953. if (ListView_GetItem(GetDlgItem(hwnd, IDC_PUB_PROVIDERS), &lvi))
  1954. {
  1955. IXMLDOMNode *pdn = (IXMLDOMNode*)lvi.lParam;
  1956. // set the default provider from the node value
  1957. _SetDefaultProvider(pdn);
  1958. // now try and navigate to the web page, if no URL then show advanced path
  1959. TCHAR szURL[INTERNET_MAX_URL_LENGTH];
  1960. if (SUCCEEDED(GetStrFromAttribute(pdn, ATTRIBUTE_HREF, szURL, ARRAYSIZE(szURL))))
  1961. {
  1962. // get the folder creation flag from the site so that we can set the HTML wizard
  1963. // into the correct state. note that the site doesn't need to specify this
  1964. // and we will default to TRUE - eg. do folder creation, this allows the current
  1965. // hosts to work without modification.
  1966. hr = _InitPropertyBag(szURL);
  1967. if (SUCCEEDED(hr))
  1968. {
  1969. hr = _pwwe->GetFirstPage(phPage);
  1970. }
  1971. }
  1972. else
  1973. {
  1974. // No URL was specified, so lets go through the advanced path where
  1975. // the user gets to type a location and we create connection to that
  1976. // (replaced the old Add Net Place functionality);
  1977. *phPage = _aWizPages[WIZPAGE_LOCATION];
  1978. hr = S_OK;
  1979. }
  1980. }
  1981. }
  1982. return hr;
  1983. }
  1984. void CPublishingWizard::_ProviderGetDispInfo(LV_DISPINFO *plvdi)
  1985. {
  1986. if (plvdi->item.mask & LVIF_TEXT)
  1987. {
  1988. IXMLDOMNode *pdn = (IXMLDOMNode*)plvdi->item.lParam;
  1989. switch (plvdi->item.iSubItem)
  1990. {
  1991. case TILE_DISPLAYNAME:
  1992. _GetProviderString(pdn, ATTRIBUTE_DISPLAYNAME, plvdi->item.pszText, plvdi->item.cchTextMax);
  1993. break;
  1994. case TILE_DESCRIPTION:
  1995. _GetProviderString(pdn, ATTRIBUTE_DESCRIPTION, plvdi->item.pszText, plvdi->item.cchTextMax);
  1996. break;
  1997. default:
  1998. ASSERTMSG(0, "ListView is asking for wrong column in publishing wizard");
  1999. break;
  2000. }
  2001. }
  2002. }
  2003. void CPublishingWizard::_InitProvidersDialog(HWND hwnd)
  2004. {
  2005. // initial the dialog accordingly
  2006. TCHAR szBuffer[MAX_PATH];
  2007. HRESULT hr = _LoadMappedString(L"wp:destination", L"providercaption", szBuffer, ARRAYSIZE(szBuffer));
  2008. if (SUCCEEDED(hr))
  2009. {
  2010. SetDlgItemText(hwnd, IDC_PUB_PROVIDERSCAPTION, szBuffer);
  2011. // lets size the caption area as needed, and move controls around as needed
  2012. UINT ctls[] = { IDC_PUB_PROVIDERSLABEL, IDC_PUB_PROVIDERS};
  2013. int dy = SizeControlFromText(hwnd, IDC_PUB_PROVIDERSCAPTION, szBuffer);
  2014. MoveControls(hwnd, ctls, ARRAYSIZE(ctls), 0, dy);
  2015. // adjust the provider dialog size as needed
  2016. RECT rc;
  2017. GetWindowRect(GetDlgItem(hwnd, IDC_PUB_PROVIDERS), &rc);
  2018. SetWindowPos(GetDlgItem(hwnd, IDC_PUB_PROVIDERS), NULL, 0, 0, RECTWIDTH(rc), RECTHEIGHT(rc)-dy, SWP_NOZORDER|SWP_NOMOVE);
  2019. }
  2020. // set the caption for the providers control
  2021. _MapDlgItemText(hwnd, IDC_PUB_PROVIDERSLABEL, L"wp:destination", L"providerslabel");
  2022. // set the image list to the list view
  2023. HIMAGELIST himlLarge, himlSmall;
  2024. Shell_GetImageLists(&himlLarge, &himlSmall);
  2025. ListView_SetImageList(GetDlgItem(hwnd, IDC_PUB_PROVIDERS), himlLarge, LVSIL_NORMAL);
  2026. ListView_SetImageList(GetDlgItem(hwnd, IDC_PUB_PROVIDERS), himlSmall, LVSIL_SMALL);
  2027. };
  2028. INT_PTR CPublishingWizard::_ProviderDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  2029. {
  2030. switch (uMsg)
  2031. {
  2032. case WM_INITDIALOG:
  2033. _InitProvidersDialog(hwnd);
  2034. return TRUE;
  2035. case WM_NOTIFY:
  2036. {
  2037. LPNMHDR pnmh = (LPNMHDR)lParam;
  2038. switch (pnmh->code)
  2039. {
  2040. case LVN_GETDISPINFO:
  2041. _ProviderGetDispInfo((LV_DISPINFO*)pnmh);
  2042. return TRUE;
  2043. case LVN_ITEMCHANGED:
  2044. _ProviderEnableNext(hwnd);
  2045. return TRUE;
  2046. case LVN_DELETEITEM:
  2047. {
  2048. NMLISTVIEW *nmlv = (NMLISTVIEW*)lParam;
  2049. IXMLDOMNode *pdn = (IXMLDOMNode*)nmlv->lParam;
  2050. pdn->Release();
  2051. return TRUE;
  2052. }
  2053. case PSN_SETACTIVE:
  2054. {
  2055. _fTransferComplete = FALSE; // we haven't started to tranfser yet
  2056. _fShownCustomLocation = FALSE; // we haven't shown the custom location page
  2057. if (_fRecomputeManifest)
  2058. _BuildTransferManifest();
  2059. if (_fRepopulateProviders)
  2060. _PopulateProviderList(hwnd); // if the manifest changes, so might the providers!
  2061. _ProviderEnableNext(hwnd);
  2062. return TRUE;
  2063. }
  2064. // when going back from the destination page, lets determine from the
  2065. // site where we should be going.
  2066. case PSN_WIZBACK:
  2067. {
  2068. if (_dwFlags & SHPWHF_NOFILESELECTOR)
  2069. {
  2070. if (_punkSite)
  2071. {
  2072. IWizardSite *pws;
  2073. if (SUCCEEDED(_punkSite->QueryInterface(IID_PPV_ARG(IWizardSite, &pws))))
  2074. {
  2075. HPROPSHEETPAGE hpage;
  2076. if (SUCCEEDED(pws->GetPreviousPage(&hpage)))
  2077. {
  2078. PropSheet_SetCurSel(GetParent(hwnd), hpage, -1);
  2079. }
  2080. pws->Release();
  2081. }
  2082. }
  2083. SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LPARAM)-1);
  2084. }
  2085. else
  2086. {
  2087. _WizardNext(hwnd, WIZPAGE_WHICHFILE);
  2088. }
  2089. return TRUE;
  2090. }
  2091. // when going forward lets query the next page, set the selection
  2092. // and then let the foreground know whats going on.
  2093. case PSN_WIZNEXT:
  2094. {
  2095. HPROPSHEETPAGE hpage;
  2096. if (SUCCEEDED(_ProviderNext(hwnd, &hpage)))
  2097. {
  2098. PropSheet_SetCurSel(GetParent(hwnd), hpage, -1);
  2099. }
  2100. SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LPARAM)-1);
  2101. return TRUE;
  2102. }
  2103. // the item was activated, therefore we need to goto the next (in this case the page for the provider).
  2104. case LVN_ITEMACTIVATE:
  2105. {
  2106. HPROPSHEETPAGE hpage;
  2107. if (SUCCEEDED(_ProviderNext(hwnd, &hpage)))
  2108. {
  2109. PropSheet_SetCurSel(GetParent(hwnd), hpage, -1);
  2110. }
  2111. return TRUE;
  2112. }
  2113. }
  2114. break;
  2115. }
  2116. }
  2117. return FALSE;
  2118. }
  2119. // Resample/Resize dialog. This dialog is displayed when we determine that there
  2120. // are images that need to be resized.
  2121. INT_PTR CPublishingWizard::_ResizeDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  2122. {
  2123. switch (uMsg)
  2124. {
  2125. case WM_INITDIALOG:
  2126. Button_SetCheck(GetDlgItem(hwnd, IDC_PUB_RESIZE), BST_CHECKED);
  2127. Button_SetCheck(GetDlgItem(hwnd, IDC_PUB_RESIZESMALL), BST_CHECKED);
  2128. return TRUE;
  2129. case WM_NOTIFY:
  2130. {
  2131. LPNMHDR pnmh = (LPNMHDR)lParam;
  2132. switch (pnmh->code)
  2133. {
  2134. case PSN_SETACTIVE:
  2135. PropSheet_SetWizButtons(GetParent(hwnd), PSWIZB_BACK | PSWIZB_NEXT);
  2136. return TRUE;
  2137. case PSN_WIZBACK:
  2138. {
  2139. // if we went through the custom location stuff then navigate back into there.
  2140. if (_fShownCustomLocation)
  2141. return _WizardNext(hwnd, _fShownUserName ? WIZPAGE_FTPUSER:WIZPAGE_LOCATION);
  2142. return _WizardNext(hwnd, WIZPAGE_PROVIDERS);
  2143. }
  2144. case PSN_WIZNEXT:
  2145. {
  2146. if (Button_GetCheck(GetDlgItem(hwnd, IDC_PUB_RESIZE)) == BST_CHECKED)
  2147. {
  2148. if (Button_GetCheck(GetDlgItem(hwnd, IDC_PUB_RESIZESMALL)) == BST_CHECKED)
  2149. _ro = RESIZE_SMALL;
  2150. else if (Button_GetCheck(GetDlgItem(hwnd, IDC_PUB_RESIZEMEDIUM)) == BST_CHECKED)
  2151. _ro = RESIZE_MEDIUM;
  2152. else
  2153. _ro = RESIZE_LARGE;
  2154. }
  2155. else
  2156. {
  2157. _ro = RESIZE_NONE;
  2158. }
  2159. return _WizardNext(hwnd, WIZPAGE_COPYING);
  2160. }
  2161. }
  2162. break;
  2163. }
  2164. case WM_COMMAND:
  2165. {
  2166. if ((HIWORD(wParam) == BN_CLICKED) && (LOWORD(wParam) == IDC_PUB_RESIZE))
  2167. {
  2168. BOOL fEnable = Button_GetCheck(GetDlgItem(hwnd, IDC_PUB_RESIZE)) == BST_CHECKED;
  2169. EnableWindow(GetDlgItem(hwnd, IDC_PUB_RESIZESMALL), fEnable);
  2170. EnableWindow(GetDlgItem(hwnd, IDC_PUB_RESIZEMEDIUM), fEnable);
  2171. EnableWindow(GetDlgItem(hwnd, IDC_PUB_RESIZELARGE), fEnable);
  2172. }
  2173. break;
  2174. }
  2175. }
  2176. return FALSE;
  2177. }
  2178. // this is called before we transfer each item, we look at the IShellItem we have and
  2179. // try to update either our stats, or the indicator that this is a new file we are processing.
  2180. BOOL CPublishingWizard::_HasAttributes(IShellItem *psi, SFGAOF flags)
  2181. {
  2182. BOOL fReturn = FALSE;
  2183. SFGAOF flagsOut;
  2184. if (SUCCEEDED(psi->GetAttributes(flags, &flagsOut)) && (flags & flagsOut))
  2185. {
  2186. fReturn = TRUE;
  2187. }
  2188. return fReturn;
  2189. }
  2190. HRESULT CPublishingWizard::PreOperation(const STGOP op, IShellItem *psiItem, IShellItem *psiDest)
  2191. {
  2192. if (psiItem && _HasAttributes(psiItem, SFGAO_STREAM))
  2193. {
  2194. if (STGOP_COPY == op)
  2195. {
  2196. // lets fill in the details of the file
  2197. LPOLESTR pstrName;
  2198. HRESULT hr = psiItem->GetDisplayName(SIGDN_PARENTRELATIVEEDITING, &pstrName);
  2199. if (SUCCEEDED(hr))
  2200. {
  2201. SetDlgItemText(_hwndCopyingPage, IDC_PUB_COPYFILE, pstrName);
  2202. CoTaskMemFree(pstrName);
  2203. }
  2204. // lets update the progress bar for the number of files we are transfering.
  2205. _iFile++;
  2206. SendDlgItemMessage(_hwndCopyingPage, IDC_PUB_TRANSPROGRESS, PBM_SETRANGE32, 0, (LPARAM)_cFiles);
  2207. SendDlgItemMessage(_hwndCopyingPage, IDC_PUB_TRANSPROGRESS, PBM_SETPOS, (WPARAM)_iFile, 0);
  2208. TCHAR szBuffer[MAX_PATH];
  2209. FormatMessageString(IDS_PUB_COPYINGFMT, szBuffer, ARRAYSIZE(szBuffer), _iFile, _cFiles);
  2210. SetDlgItemText(_hwndCopyingPage, IDC_PUB_LABELTRANSPROG, szBuffer);
  2211. // get the thumbnail and show it.
  2212. IExtractImage *pei;
  2213. hr = psiItem->BindToHandler(NULL, BHID_SFUIObject, IID_PPV_ARG(IExtractImage, &pei));
  2214. if (SUCCEEDED(hr))
  2215. {
  2216. SIZE sz = {120,120};
  2217. WCHAR szImage[MAX_PATH];
  2218. DWORD dwFlags = 0;
  2219. hr = pei->GetLocation(szImage, ARRAYSIZE(szImage), NULL, &sz, 24, &dwFlags);
  2220. if (SUCCEEDED(hr))
  2221. {
  2222. HBITMAP hbmp;
  2223. hr = pei->Extract(&hbmp);
  2224. if (SUCCEEDED(hr))
  2225. {
  2226. if (!PostMessage(_hwndCopyingPage, PWM_UPDATEICON, (WPARAM)IMAGE_BITMAP, (LPARAM)hbmp))
  2227. {
  2228. DeleteObject(hbmp);
  2229. }
  2230. }
  2231. }
  2232. pei->Release();
  2233. }
  2234. // if that failed then lets get the icon for the file and place that into the dialog,
  2235. // this is less likely to fail - I hope.
  2236. if (FAILED(hr))
  2237. {
  2238. IPersistIDList *ppid;
  2239. hr = psiItem->QueryInterface(IID_PPV_ARG(IPersistIDList, &ppid));
  2240. if (SUCCEEDED(hr))
  2241. {
  2242. LPITEMIDLIST pidl;
  2243. hr = ppid->GetIDList(&pidl);
  2244. if (SUCCEEDED(hr))
  2245. {
  2246. SHFILEINFO sfi = {0};
  2247. if (SHGetFileInfo((LPCWSTR)pidl, -1, &sfi, sizeof(sfi), SHGFI_ICON|SHGFI_PIDL|SHGFI_ADDOVERLAYS))
  2248. {
  2249. if (!PostMessage(_hwndCopyingPage, PWM_UPDATEICON, (WPARAM)IMAGE_ICON, (LPARAM)sfi.hIcon))
  2250. {
  2251. DeleteObject(sfi.hIcon);
  2252. }
  2253. }
  2254. ILFree(pidl);
  2255. }
  2256. ppid->Release();
  2257. }
  2258. }
  2259. }
  2260. else if (STGOP_STATS == op)
  2261. {
  2262. _cFiles++;
  2263. }
  2264. }
  2265. return S_OK;
  2266. }
  2267. // while we are moving the bits of the file ensure that we update the progress bar accordingly.
  2268. void CPublishingWizard::_SetProgress(DWORD dwCompleted, DWORD dwTotal)
  2269. {
  2270. if (_dwTotal != dwTotal)
  2271. _dwTotal = dwTotal;
  2272. if (_dwCompleted != dwCompleted)
  2273. _dwCompleted = dwCompleted;
  2274. PostMessage(_hwndCopyingPage, PWM_UPDATE, (WPARAM)dwCompleted, (LPARAM)dwTotal);
  2275. }
  2276. HRESULT CPublishingWizard::OperationProgress(const STGOP op, IShellItem *psiItem, IShellItem *psiDest, ULONGLONG ulTotal, ULONGLONG ulComplete)
  2277. {
  2278. if (psiItem && (op == STGOP_COPY))
  2279. {
  2280. ULARGE_INTEGER uliCompleted, uliTotal;
  2281. uliCompleted.QuadPart = ulComplete;
  2282. uliTotal.QuadPart = ulTotal;
  2283. // If we are using the top 32 bits, scale both numbers down.
  2284. // Note that I'm using the attribute that dwTotalHi is always larger than dwCompleted
  2285. ASSERT(uliTotal.HighPart >= uliCompleted.HighPart);
  2286. while (uliTotal.HighPart)
  2287. {
  2288. uliCompleted.QuadPart >>= 1;
  2289. uliTotal.QuadPart >>= 1;
  2290. }
  2291. ASSERT((0 == uliCompleted.HighPart) && (0 == uliTotal.HighPart)); // Make sure we finished scaling down.
  2292. _SetProgress(uliCompleted.LowPart, uliTotal.LowPart);
  2293. }
  2294. return S_OK;
  2295. }
  2296. // Method to invoke the transfer engine
  2297. HRESULT CPublishingWizard::_BeginTransfer(HWND hwnd)
  2298. {
  2299. // initialize the dialog before we start the copy process.
  2300. _dwCompleted = -1; // progress bars are reset
  2301. _dwTotal = -1;
  2302. _iPercentageComplete = -1;
  2303. _cFiles = 0; // haven't transfered any files yet
  2304. _iFile = 0;
  2305. _hrFromTransfer = S_FALSE;
  2306. _fCancelled = FALSE;
  2307. // set the state of the controls ready to perform the transfer
  2308. SetDlgItemText(hwnd, IDC_PUB_COPYFILE, TEXT(""));
  2309. SendMessage(hwnd, PWM_UPDATE, 0, 0);
  2310. PropSheet_SetWizButtons(GetParent(hwnd), 0x0);
  2311. // initialize the transfer object ready to move the bits to the site
  2312. ITransferAdviseSink *ptas;
  2313. HRESULT hr = this->QueryInterface(IID_PPV_ARG(ITransferAdviseSink, &ptas));
  2314. if (SUCCEEDED(hr))
  2315. {
  2316. // build the list of files for use to transfer to the site, this we
  2317. // key of the transfer manifest which is stored in our property bag.
  2318. IXMLDOMDocument *pdocManifest;
  2319. hr = GetTransferManifest(NULL, &pdocManifest);
  2320. if (SUCCEEDED(hr))
  2321. {
  2322. TRANSFERINFO ti = {0};
  2323. ti.hwnd = hwnd;
  2324. ti.dwFlags = _dwFlags;
  2325. CDPA<TRANSFERITEM> dpaItems;
  2326. hr = _InitTransferInfo(pdocManifest, &ti, &dpaItems);
  2327. if (SUCCEEDED(hr))
  2328. {
  2329. if (ti.fUsePost)
  2330. {
  2331. hr = PublishViaPost(&ti, &dpaItems, ptas);
  2332. }
  2333. else
  2334. {
  2335. hr = PublishViaCopyEngine(&ti, &dpaItems, ptas);
  2336. }
  2337. }
  2338. dpaItems.DestroyCallback(_FreeTransferItems, NULL); // will have been detached by thread if handled
  2339. pdocManifest->Release();
  2340. }
  2341. if (FAILED(hr))
  2342. PostMessage(hwnd, PWM_TRANSFERCOMPLETE, 0, (LPARAM)hr);
  2343. ptas->Release();
  2344. }
  2345. return hr;
  2346. }
  2347. // create a link back to the site, this is keyed off information stored in the manifest.
  2348. HRESULT CPublishingWizard::_CreateFavorite(IXMLDOMNode *pdnUploadInfo)
  2349. {
  2350. // lets pick up the favorite element from the manifest, this should define all
  2351. // that is needed for us to create a link in to the favorites menu.
  2352. IXMLDOMNode *pdn;
  2353. HRESULT hr = pdnUploadInfo->selectSingleNode(ELEMENT_FAVORITE, &pdn);
  2354. if (S_OK == hr)
  2355. {
  2356. // we need an URL to create the link using.
  2357. WCHAR szURL[INTERNET_MAX_URL_LENGTH] = {0};
  2358. hr = GetStrFromAttribute(pdn, ATTRIBUTE_HREF, szURL, ARRAYSIZE(szURL));
  2359. if (SUCCEEDED(hr))
  2360. {
  2361. // we need a name to save the link as.
  2362. WCHAR szName[MAX_PATH] = {0};
  2363. hr = GetStrFromAttribute(pdn, ATTRIBUTE_NAME, szName, ARRAYSIZE(szName));
  2364. if (SUCCEEDED(hr))
  2365. {
  2366. IShellLink *psl;
  2367. hr = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IShellLink, &psl));
  2368. if (SUCCEEDED(hr))
  2369. {
  2370. hr = psl->SetPath(szURL); // set the target
  2371. // if that works then lets try and put a comment onto the link - this is an optional
  2372. // value for the <favorite/> element.
  2373. if (SUCCEEDED(hr))
  2374. {
  2375. WCHAR szComment[MAX_PATH] = {0};
  2376. if (SUCCEEDED(GetStrFromAttribute(pdn, ATTRIBUTE_COMMENT, szComment, ARRAYSIZE(szComment))))
  2377. {
  2378. hr = psl->SetDescription(szComment); // set the comment
  2379. }
  2380. }
  2381. // assuming all that works then lets persist the link into the users
  2382. // favorites folder, this inturn will create it on their favaorites menu.
  2383. if (SUCCEEDED(hr))
  2384. {
  2385. WCHAR szFilename[MAX_PATH];
  2386. if (SHGetSpecialFolderPath(NULL, szFilename, CSIDL_FAVORITES, TRUE))
  2387. {
  2388. PathAppend(szFilename, szName);
  2389. PathRenameExtension(szFilename, TEXT(".lnk"));
  2390. IPersistFile *ppf;
  2391. hr = psl->QueryInterface(IID_PPV_ARG(IPersistFile, &ppf));
  2392. if (SUCCEEDED(hr))
  2393. {
  2394. hr = ppf->Save(szFilename, TRUE);
  2395. ppf->Release();
  2396. }
  2397. }
  2398. }
  2399. psl->Release();
  2400. }
  2401. }
  2402. }
  2403. pdn->Release();
  2404. }
  2405. return hr;
  2406. }
  2407. // When transfer is complete we need to determine which page we are going to show
  2408. // this will either come from the site or it will be a HTML page hosted
  2409. // on the site.
  2410. HPROPSHEETPAGE CPublishingWizard::_TransferComplete(HRESULT hrFromTransfer)
  2411. {
  2412. HPROPSHEETPAGE hpResult = NULL;
  2413. // convert the HRESULT From something that will have come from the
  2414. // transfer engine into something the outside world will understand.
  2415. if (hrFromTransfer == STRESPONSE_CANCEL)
  2416. hrFromTransfer = HRESULT_FROM_WIN32(ERROR_CANCELLED);
  2417. // tag ourselves as in the "completed transfer" state, therefore the site knows where to
  2418. // navigate to next.
  2419. _fTransferComplete = TRUE;
  2420. _hrFromTransfer = hrFromTransfer;
  2421. // get the next page from the site, this will either be the done or
  2422. // cancelled page based on the result of the site.
  2423. IWizardSite *pws;
  2424. HRESULT hr = _punkSite->QueryInterface(IID_PPV_ARG(IWizardSite, &pws));
  2425. if (SUCCEEDED(hr))
  2426. {
  2427. if (_hrFromTransfer == HRESULT_FROM_WIN32(ERROR_CANCELLED))
  2428. {
  2429. hr = pws->GetCancelledPage(&hpResult);
  2430. }
  2431. else
  2432. {
  2433. hr = pws->GetNextPage(&hpResult);
  2434. }
  2435. pws->Release();
  2436. }
  2437. // lets put the result into the manifest that we we can read it back later.
  2438. IXMLDOMDocument *pdocManifest;
  2439. hr = GetTransferManifest(NULL, &pdocManifest);
  2440. if (SUCCEEDED(hr))
  2441. {
  2442. IXMLDOMNode *pdn;
  2443. hr = pdocManifest->selectSingleNode(XPATH_UPLOADINFO, &pdn);
  2444. if (hr == S_OK)
  2445. {
  2446. // if there is a success/failure page defined then lets handle it accordingly
  2447. WCHAR szPageToShow[INTERNET_MAX_URL_LENGTH] = {0};
  2448. if (SUCCEEDED(_hrFromTransfer))
  2449. {
  2450. hr = GetURLFromElement(pdn, ELEMENT_SUCCESSPAGE, szPageToShow, ARRAYSIZE(szPageToShow));
  2451. }
  2452. else
  2453. {
  2454. if (_hrFromTransfer == HRESULT_FROM_WIN32(ERROR_CANCELLED))
  2455. hr = GetURLFromElement(pdn, ELEMENT_CANCELLEDPAGE, szPageToShow, ARRAYSIZE(szPageToShow));
  2456. if ((_hrFromTransfer != HRESULT_FROM_WIN32(ERROR_CANCELLED)) || FAILED(hr))
  2457. hr = GetURLFromElement(pdn, ELEMENT_FAILUREPAGE, szPageToShow, ARRAYSIZE(szPageToShow));
  2458. }
  2459. // if we have the page then lets navigate to it, this will give us the succes
  2460. // failure pages from the site.
  2461. if (SUCCEEDED(hr) && szPageToShow[0])
  2462. {
  2463. hr = _pwwe->SetInitialURL(szPageToShow);
  2464. if (SUCCEEDED(hr))
  2465. {
  2466. hr = _pwwe->GetFirstPage(&hpResult);
  2467. }
  2468. }
  2469. // lets do the final processing of the transfer (creating net places, favorites etc)
  2470. _CreateFavorite(pdn);
  2471. pdn->Release();
  2472. }
  2473. pdocManifest->Release();
  2474. }
  2475. return hpResult;
  2476. }
  2477. // this is the copying dialog. this displays the progress bar and other information as
  2478. // we transfer the files from the users m/c to the site.
  2479. INT_PTR CPublishingWizard::_CopyDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  2480. {
  2481. switch ( uMsg )
  2482. {
  2483. case WM_INITDIALOG:
  2484. _hwndCopyingPage = hwnd;
  2485. return FALSE;
  2486. case WM_NOTIFY:
  2487. {
  2488. LPNMHDR pnmh = (LPNMHDR)lParam;
  2489. switch (pnmh->code)
  2490. {
  2491. case PSN_SETACTIVE:
  2492. _BeginTransfer(hwnd);
  2493. return TRUE;
  2494. case PSN_QUERYCANCEL:
  2495. {
  2496. _fCancelled = TRUE;
  2497. SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LPARAM)TRUE);
  2498. return TRUE;
  2499. }
  2500. }
  2501. break;
  2502. }
  2503. case WM_CTLCOLORSTATIC:
  2504. {
  2505. // we want the preview filled with a white background.
  2506. if (GetDlgCtrlID((HWND)lParam) == IDC_PUB_PREVIEW)
  2507. {
  2508. return (INT_PTR)(COLOR_3DHILIGHT+1);
  2509. }
  2510. return FALSE;
  2511. }
  2512. case PWM_TRANSFERCOMPLETE:
  2513. {
  2514. PropSheet_SetCurSel(GetParent(hwnd), _TransferComplete((HRESULT)lParam), -1);
  2515. break;
  2516. }
  2517. case PWM_UPDATE:
  2518. {
  2519. DWORD dwTotal = (DWORD)lParam;
  2520. DWORD dwCompleted = (DWORD)wParam;
  2521. SendDlgItemMessage(hwnd, IDC_PUB_FILEPROGRESS, PBM_SETRANGE32, 0, (LPARAM)dwTotal);
  2522. SendDlgItemMessage(hwnd, IDC_PUB_FILEPROGRESS, PBM_SETPOS, (WPARAM)dwCompleted, 0);
  2523. // compute the percentage of the file copied.
  2524. int iPercentage = 0;
  2525. if (dwTotal > 0)
  2526. iPercentage = (dwCompleted * 100) / dwTotal;
  2527. if (_iPercentageComplete != iPercentage)
  2528. {
  2529. TCHAR szBuffer[MAX_PATH];
  2530. FormatMessageString(IDS_PUB_COMPLETEFMT, szBuffer, ARRAYSIZE(szBuffer), iPercentage);
  2531. SetDlgItemText(_hwndCopyingPage, IDC_PUB_LABELFILEPROG, szBuffer);
  2532. }
  2533. break;
  2534. }
  2535. case PWM_UPDATEICON:
  2536. {
  2537. HWND hwndThumbnail = GetDlgItem(hwnd, IDC_PUB_PREVIEW);
  2538. DWORD dwStyle = (DWORD)GetWindowLongPtr(hwndThumbnail, GWL_STYLE) & ~(SS_BITMAP|SS_ICON);
  2539. if (wParam == IMAGE_BITMAP)
  2540. {
  2541. SetWindowLongPtr(hwndThumbnail, GWL_STYLE, dwStyle | SS_BITMAP);
  2542. HBITMAP hbmp = (HBITMAP)SendMessage(hwndThumbnail, STM_SETIMAGE, wParam, lParam);
  2543. if (hbmp)
  2544. {
  2545. DeleteObject(hbmp);
  2546. }
  2547. }
  2548. else if (wParam == IMAGE_ICON)
  2549. {
  2550. SetWindowLongPtr(hwndThumbnail, GWL_STYLE, dwStyle | SS_ICON);
  2551. HICON hIcon = (HICON)SendMessage(hwndThumbnail, STM_SETIMAGE, wParam, lParam);
  2552. if (hIcon)
  2553. {
  2554. DeleteObject(hIcon);
  2555. }
  2556. }
  2557. else
  2558. {
  2559. DeleteObject((HGDIOBJ)lParam);
  2560. }
  2561. break;
  2562. }
  2563. }
  2564. return FALSE;
  2565. }
  2566. // Manage the list of file types
  2567. HRESULT CPublishingWizard::_AddExtenisonToList(HDPA hdpa, LPCTSTR pszExtension)
  2568. {
  2569. UINT iItem = 0;
  2570. UINT nItems = DPA_GetPtrCount(hdpa);
  2571. BOOL fFound = FALSE;
  2572. for ( ;(iItem < nItems) && !fFound; iItem++)
  2573. {
  2574. LPCTSTR pszExtensionInDPA = (LPCTSTR) DPA_GetPtr(hdpa, iItem);
  2575. if (pszExtensionInDPA)
  2576. {
  2577. fFound = (0 == StrCmpI(pszExtension, pszExtensionInDPA));
  2578. }
  2579. }
  2580. HRESULT hr = S_OK;
  2581. if (!fFound)
  2582. {
  2583. LPTSTR pszAlloc;
  2584. hr = E_OUTOFMEMORY;
  2585. pszAlloc = StrDup(pszExtension);
  2586. if (pszAlloc)
  2587. {
  2588. if (DPA_ERR == DPA_AppendPtr(hdpa, (void*)pszAlloc))
  2589. {
  2590. LocalFree(pszAlloc);
  2591. }
  2592. else
  2593. {
  2594. hr = S_OK;
  2595. }
  2596. }
  2597. }
  2598. return hr;
  2599. }
  2600. int CPublishingWizard::s_FreeStringProc(void* pFreeMe, void* pData)
  2601. {
  2602. LocalFree(pFreeMe);
  2603. return 1;
  2604. }
  2605. HRESULT CPublishingWizard::_GetUniqueTypeList(BOOL fIncludeFolder, HDPA *phdpa)
  2606. {
  2607. *phdpa = NULL;
  2608. HRESULT hr = (*phdpa = DPA_Create(10)) ? S_OK:E_OUTOFMEMORY;
  2609. if (SUCCEEDED(hr))
  2610. {
  2611. // check for the folders type - eg. we have folders
  2612. if (fIncludeFolder)
  2613. {
  2614. IXMLDOMNode *pdn;
  2615. hr = _pdocManifest->selectSingleNode(XPATH_FILESROOT, &pdn);
  2616. if (hr == S_OK)
  2617. {
  2618. IXMLDOMElement *pdel;
  2619. hr = pdn->QueryInterface(IID_PPV_ARG(IXMLDOMElement, &pdel));
  2620. if (SUCCEEDED(hr))
  2621. {
  2622. VARIANT var;
  2623. if (pdel->getAttribute(ATTRIBUTE_HASFOLDERS, &var) == S_OK)
  2624. {
  2625. if ((var.vt == VT_BOOL) && (var.boolVal == VARIANT_TRUE))
  2626. {
  2627. hr = _AddExtenisonToList(*phdpa, TEXT("Folder"));
  2628. }
  2629. VariantClear(&var);
  2630. }
  2631. pdel->Release();
  2632. }
  2633. pdn->Release();
  2634. }
  2635. }
  2636. // walk the file nodes building the extension list for us
  2637. IXMLDOMNodeList *pnl;
  2638. hr = _pdocManifest->selectNodes(XPATH_ALLFILESTOUPLOAD, &pnl);
  2639. if (hr == S_OK)
  2640. {
  2641. long cSelection;
  2642. hr = pnl->get_length(&cSelection);
  2643. for (long lNode = 0; SUCCEEDED(hr) && (lNode != cSelection); lNode++)
  2644. {
  2645. IXMLDOMNode *pdn;
  2646. hr = pnl->get_item(lNode, &pdn);
  2647. if (SUCCEEDED(hr))
  2648. {
  2649. TCHAR szBuffer[MAX_PATH];
  2650. hr = GetStrFromAttribute(pdn, ATTRIBUTE_EXTENSION, szBuffer, ARRAYSIZE(szBuffer));
  2651. if (SUCCEEDED(hr))
  2652. {
  2653. hr = _AddExtenisonToList(*phdpa, szBuffer);
  2654. }
  2655. pdn->Release();
  2656. }
  2657. }
  2658. pnl->Release();
  2659. }
  2660. // clean up the type DPA if we failed....
  2661. if (FAILED(hr))
  2662. {
  2663. DPA_DestroyCallback(*phdpa, s_FreeStringProc, 0);
  2664. *phdpa = NULL;
  2665. }
  2666. }
  2667. return hr;
  2668. }
  2669. // initialize the property bag we want to give to the site so that
  2670. // they can display the correct HTML and direct the user in the
  2671. // right direction.
  2672. HRESULT CPublishingWizard::_InitPropertyBag(LPCTSTR pszURL)
  2673. {
  2674. HRESULT hr = S_OK;
  2675. // lets initialize the wizard object so that we show the correct
  2676. // pages, to determine this we need to
  2677. if (pszURL)
  2678. hr = _pwwe->SetInitialURL(pszURL);
  2679. // now compile a list of the unique types, this will be placed into the
  2680. // property bag. at this time we can also determine if there
  2681. // are any images in our list, and therefore if we should prompt accordingly.
  2682. _fOfferResize = FALSE; // no resize
  2683. ATOMICRELEASE(_ppb);
  2684. hr = SHCreatePropertyBagOnMemory(STGM_READWRITE, IID_PPV_ARG(IPropertyBag, &_ppb));
  2685. if (SUCCEEDED(hr))
  2686. {
  2687. INT cExtensions = 0;
  2688. // get the list of unique extensions and put those into the
  2689. // property bag for the site to query - this should be removed in time and
  2690. // we should have the site favor the file Manifest
  2691. HDPA hdpa;
  2692. hr = _GetUniqueTypeList(TRUE, &hdpa);
  2693. if (SUCCEEDED(hr))
  2694. {
  2695. for (int i = 0; (i < DPA_GetPtrCount(hdpa)) && (SUCCEEDED(hr)); i++)
  2696. {
  2697. LPCTSTR pszExtension = (LPCTSTR)DPA_GetPtr(hdpa, i);
  2698. if (pszExtension)
  2699. {
  2700. if (!(_dwFlags & SHPWHF_NORECOMPRESS))
  2701. _fOfferResize = (_fOfferResize || PathIsImage(pszExtension));
  2702. TCHAR szProperty[255];
  2703. wnsprintf(szProperty, ARRAYSIZE(szProperty), PROPERTY_EXTENSION TEXT("%d"), PROPERTY_EXTENSION, i);
  2704. hr = SHPropertyBag_WriteStr(_ppb, szProperty, pszExtension);
  2705. if (SUCCEEDED(hr))
  2706. {
  2707. cExtensions++;
  2708. }
  2709. }
  2710. }
  2711. DPA_DestroyCallback(hdpa, s_FreeStringProc, 0);
  2712. }
  2713. // initialize property bag with UI elements (ignoring the error from above, just won't have an
  2714. // extension list to present)
  2715. SHPropertyBag_WriteInt(_ppb, PROPERTY_EXTENSIONCOUNT, cExtensions);
  2716. // we should always have a manifest object, therefore lets put it into the
  2717. // property bag so that the site can extract it.
  2718. IXMLDOMDocument *pdocManifest;
  2719. hr = CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IXMLDOMDocument, &pdocManifest));
  2720. if (SUCCEEDED(hr))
  2721. {
  2722. VARIANT varCurManifest = { VT_DISPATCH };
  2723. hr = _pdocManifest->QueryInterface(IID_PPV_ARG(IDispatch, &varCurManifest.pdispVal));
  2724. if (SUCCEEDED(hr))
  2725. {
  2726. // load the manifest into the new document that we have.
  2727. VARIANT_BOOL fSuccess;
  2728. hr = pdocManifest->load(varCurManifest, &fSuccess);
  2729. if ((fSuccess == VARIANT_TRUE) && (hr == S_OK))
  2730. {
  2731. hr = s_SetPropertyFromDisp(_ppb, PROPERTY_TRANSFERMANIFEST, pdocManifest);
  2732. }
  2733. VariantClear(&varCurManifest);
  2734. }
  2735. }
  2736. }
  2737. return hr;
  2738. }
  2739. // handle building the file manifest from the IDataObject, this consists of walking the list of
  2740. // files and putting together a
  2741. class CPubWizardWalkCB : public INamespaceWalkCB
  2742. {
  2743. public:
  2744. CPubWizardWalkCB(IXMLDOMDocument *pdocManifest);
  2745. ~CPubWizardWalkCB();
  2746. // IUnknown
  2747. STDMETHOD(QueryInterface)(REFIID riid, void **ppvObj);
  2748. STDMETHOD_(ULONG,AddRef)();
  2749. STDMETHOD_(ULONG,Release)();
  2750. // INamespaceWalkCB
  2751. STDMETHODIMP FoundItem(IShellFolder *psf, LPCITEMIDLIST pidl);
  2752. STDMETHODIMP EnterFolder(IShellFolder *psf, LPCITEMIDLIST pidl);
  2753. STDMETHODIMP LeaveFolder(IShellFolder *psf, LPCITEMIDLIST pidl);
  2754. STDMETHODIMP InitializeProgressDialog(LPWSTR *ppszTitle, LPWSTR *ppszCancel)
  2755. { *ppszTitle = NULL; *ppszCancel = NULL; return E_NOTIMPL; }
  2756. private:
  2757. LONG _cRef; // object lifetime count
  2758. TCHAR _szWalkPath[MAX_PATH]; // path of the folder we are walking
  2759. INT _idFile; // id of file we have walked
  2760. IXMLDOMDocument *_pdocManifest; // manifest we are populating
  2761. void _AddImageMetaData(IShellFolder2 *psf2, LPCITEMIDLIST pidl, IXMLDOMElement *pdel);
  2762. };
  2763. CPubWizardWalkCB::CPubWizardWalkCB(IXMLDOMDocument *pdocManifest) :
  2764. _cRef(1), _pdocManifest(pdocManifest)
  2765. {
  2766. _pdocManifest->AddRef();
  2767. _szWalkPath[0] = TEXT('\0'); // no path yet.
  2768. }
  2769. CPubWizardWalkCB::~CPubWizardWalkCB()
  2770. {
  2771. _pdocManifest->Release();
  2772. }
  2773. // IUnknown
  2774. ULONG CPubWizardWalkCB::AddRef()
  2775. {
  2776. return InterlockedIncrement(&_cRef);
  2777. }
  2778. ULONG CPubWizardWalkCB::Release()
  2779. {
  2780. if (InterlockedDecrement(&_cRef))
  2781. return _cRef;
  2782. delete this;
  2783. return 0;
  2784. }
  2785. HRESULT CPubWizardWalkCB::QueryInterface(REFIID riid, void **ppv)
  2786. {
  2787. static const QITAB qit[] =
  2788. {
  2789. QITABENT(CPubWizardWalkCB, INamespaceWalkCB), // IID_INamespaceWalkCB
  2790. {0, 0 },
  2791. };
  2792. return QISearch(this, qit, riid, ppv);
  2793. }
  2794. void CPubWizardWalkCB::_AddImageMetaData(IShellFolder2 *psf2, LPCITEMIDLIST pidl, IXMLDOMElement *pdel)
  2795. {
  2796. struct
  2797. {
  2798. LPWSTR pszID;
  2799. const SHCOLUMNID *pscid;
  2800. }
  2801. _aMetaData[] =
  2802. {
  2803. {L"cx", &SCID_ImageCX},
  2804. {L"cy", &SCID_ImageCY},
  2805. };
  2806. // eventually break this into a helper function, or read this from the info tip
  2807. for (int i = 0; i < ARRAYSIZE(_aMetaData); i++)
  2808. {
  2809. VARIANT var = {0};
  2810. HRESULT hr = psf2->GetDetailsEx(pidl, _aMetaData[i].pscid, &var);
  2811. if (hr == S_OK)
  2812. {
  2813. IXMLDOMElement *pdelProperty;
  2814. hr = CreateAndAppendElement(_pdocManifest, pdel, ELEMENT_IMAGEDATA, &var, &pdelProperty);
  2815. if (SUCCEEDED(hr))
  2816. {
  2817. hr = SetAttributeFromStr(pdelProperty, ATTRIBUTE_ID, _aMetaData[i].pszID);
  2818. pdelProperty->Release();
  2819. }
  2820. VariantClear(&var);
  2821. }
  2822. }
  2823. }
  2824. // INamepsaceWalkCB
  2825. HRESULT CPubWizardWalkCB::FoundItem(IShellFolder *psf, LPCITEMIDLIST pidl)
  2826. {
  2827. IXMLDOMNode *pdn;
  2828. HRESULT hr = _pdocManifest->selectSingleNode(XPATH_FILESROOT, &pdn);
  2829. if (hr == S_OK)
  2830. {
  2831. IXMLDOMElement *pdel;
  2832. hr = _pdocManifest->createElement(ELEMENT_FILE, &pdel);
  2833. if (SUCCEEDED(hr))
  2834. {
  2835. TCHAR szBuffer[MAX_PATH];
  2836. VARIANT var;
  2837. // pass out the unique IDs for each of the elements in the tree
  2838. var.vt = VT_I4;
  2839. var.lVal = _idFile++;
  2840. pdel->setAttribute(ATTRIBUTE_ID, var);
  2841. // must be able to get the path for the item so that we can
  2842. hr = DisplayNameOf(psf, pidl, SHGDN_FORPARSING, szBuffer, ARRAYSIZE(szBuffer));
  2843. if (SUCCEEDED(hr))
  2844. {
  2845. // source path
  2846. hr = SetAttributeFromStr(pdel, ATTRIBUTE_SOURCE, szBuffer);
  2847. // extension = (extension to file)
  2848. hr = SetAttributeFromStr(pdel, ATTRIBUTE_EXTENSION, PathFindExtension(szBuffer));
  2849. // lets put the content type
  2850. TCHAR szContentType[MAX_PATH];
  2851. DWORD cch = ARRAYSIZE(szContentType);
  2852. if (SUCCEEDED(AssocQueryString(0, ASSOCSTR_CONTENTTYPE, szBuffer, NULL, szContentType, &cch)))
  2853. {
  2854. hr = SetAttributeFromStr(pdel, ATTRIBUTE_CONTENTTYPE, szContentType);
  2855. }
  2856. }
  2857. // put the proposed destination into the node
  2858. hr = DisplayNameOf(psf, pidl, SHGDN_FORPARSING|SHGDN_INFOLDER, szBuffer, ARRAYSIZE(szBuffer));
  2859. if (SUCCEEDED(hr))
  2860. {
  2861. TCHAR szPath[MAX_PATH];
  2862. PathCombine(szPath, _szWalkPath, szBuffer);
  2863. hr = SetAttributeFromStr(pdel, ATTRIBUTE_DESTINATION, szBuffer);
  2864. }
  2865. // handle those properties we can get from the shell folder via GetDetailsEx
  2866. IShellFolder2 *psf2;
  2867. if (SUCCEEDED(psf->QueryInterface(IID_PPV_ARG(IShellFolder2, &psf2))))
  2868. {
  2869. // push the size into the attribute list for the item
  2870. if (SUCCEEDED(psf2->GetDetailsEx(pidl, &SCID_SIZE, &var)))
  2871. {
  2872. pdel->setAttribute(ATTRIBUTE_SIZE, var);
  2873. VariantClear(&var);
  2874. }
  2875. // lets inject the meta data
  2876. IXMLDOMElement *pdelMetaData;
  2877. hr = CreateAndAppendElement(_pdocManifest, pdel, ELEMENT_METADATA, NULL, &pdelMetaData);
  2878. if (SUCCEEDED(hr))
  2879. {
  2880. _AddImageMetaData(psf2, pidl, pdelMetaData);
  2881. pdelMetaData->Release();
  2882. }
  2883. psf2->Release();
  2884. }
  2885. // append the node to the list that we already have
  2886. hr = pdn->appendChild(pdel, NULL);
  2887. pdel->Release();
  2888. }
  2889. pdn->Release();
  2890. }
  2891. return S_OK;
  2892. }
  2893. HRESULT CPubWizardWalkCB::EnterFolder(IShellFolder *psf, LPCITEMIDLIST pidl)
  2894. {
  2895. // build the name of the folder we have entered.
  2896. TCHAR szBuffer[MAX_PATH];
  2897. if (SUCCEEDED(DisplayNameOf(psf, pidl, SHGDN_FORPARSING|SHGDN_INFOLDER|SHGDN_FORADDRESSBAR, szBuffer, ARRAYSIZE(szBuffer))))
  2898. {
  2899. PathAppend(_szWalkPath, szBuffer);
  2900. }
  2901. // lets update the files root to indicate that we are going to be using folders.
  2902. IXMLDOMNode *pdn;
  2903. HRESULT hr = _pdocManifest->selectSingleNode(XPATH_FILESROOT, &pdn);
  2904. if (hr == S_OK)
  2905. {
  2906. IXMLDOMElement *pdel;
  2907. hr = pdn->QueryInterface(IID_PPV_ARG(IXMLDOMElement, &pdel));
  2908. if (SUCCEEDED(hr))
  2909. {
  2910. VARIANT var;
  2911. var.vt = VT_BOOL;
  2912. var.boolVal = VARIANT_TRUE;
  2913. hr = pdel->setAttribute(ATTRIBUTE_HASFOLDERS, var);
  2914. pdel->Release();
  2915. }
  2916. pdn->Release();
  2917. }
  2918. // now update the folders list with the new folder that we have just entered, first
  2919. // try to find the folder list, if not found then create it.
  2920. IXMLDOMNode *pdnFolders;
  2921. hr = _pdocManifest->selectSingleNode(XPATH_FOLDERSROOT, &pdnFolders);
  2922. if (hr == S_FALSE)
  2923. {
  2924. IXMLDOMNode *pdnRoot;
  2925. hr = _pdocManifest->selectSingleNode(XPATH_MANIFEST, &pdnRoot);
  2926. if (hr == S_OK)
  2927. {
  2928. IXMLDOMElement *pdelRoot;
  2929. hr = pdnRoot->QueryInterface(IID_PPV_ARG(IXMLDOMElement, &pdelRoot));
  2930. if (SUCCEEDED(hr))
  2931. {
  2932. IXMLDOMElement *pdelFolders;
  2933. hr = CreateAndAppendElement(_pdocManifest, pdelRoot, ELEMENT_FOLDERS, NULL, &pdelFolders);
  2934. if (SUCCEEDED(hr))
  2935. {
  2936. hr = pdelFolders->QueryInterface(IID_PPV_ARG(IXMLDOMNode, &pdnFolders));
  2937. pdelFolders->Release();
  2938. }
  2939. pdelRoot->Release();
  2940. }
  2941. pdnRoot->Release();
  2942. }
  2943. }
  2944. // assuming we now have the folder list, lets now create a new element for this folder.
  2945. if (SUCCEEDED(hr) && pdnFolders)
  2946. {
  2947. IXMLDOMElement *pdelFolder;
  2948. hr = _pdocManifest->createElement(ELEMENT_FOLDER, &pdelFolder);
  2949. if (SUCCEEDED(hr))
  2950. {
  2951. hr = SetAttributeFromStr(pdelFolder, ATTRIBUTE_DESTINATION, _szWalkPath);
  2952. if (SUCCEEDED(hr))
  2953. {
  2954. hr = pdnFolders->appendChild(pdelFolder, NULL);
  2955. }
  2956. pdelFolder->Release();
  2957. }
  2958. }
  2959. return S_OK; // always succeed so we can transfer folders
  2960. }
  2961. HRESULT CPubWizardWalkCB::LeaveFolder(IShellFolder *psf, LPCITEMIDLIST pidl)
  2962. {
  2963. PathRemoveFileSpec(_szWalkPath);
  2964. return S_OK;
  2965. }
  2966. // construct the manifest based on the document we have
  2967. HRESULT CPublishingWizard::_AddFilesToManifest(IXMLDOMDocument *pdocManifest)
  2968. {
  2969. HRESULT hr = S_OK;
  2970. if (_pdo || _pdoSelection)
  2971. {
  2972. CWaitCursor cur; // might take some time
  2973. INamespaceWalk *pnsw;
  2974. hr = CoCreateInstance(CLSID_NamespaceWalker, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(INamespaceWalk, &pnsw));
  2975. if (SUCCEEDED(hr))
  2976. {
  2977. InitClipboardFormats();
  2978. CPubWizardWalkCB *pwcb = new CPubWizardWalkCB(pdocManifest);
  2979. if (pwcb)
  2980. {
  2981. hr = pnsw->Walk(_pdoSelection ? _pdoSelection:_pdo, NSWF_NONE_IMPLIES_ALL, 0, SAFECAST(pwcb, INamespaceWalkCB *));
  2982. if (SUCCEEDED(hr))
  2983. {
  2984. hr = pnsw->GetIDArrayResult(&_cItems, &_aItems);
  2985. }
  2986. pwcb->Release();
  2987. }
  2988. else
  2989. {
  2990. hr = E_OUTOFMEMORY;
  2991. }
  2992. pnsw->Release();
  2993. }
  2994. }
  2995. return hr;
  2996. }
  2997. HRESULT CPublishingWizard::_BuildTransferManifest()
  2998. {
  2999. _FreeTransferManifest();
  3000. HRESULT hr = CoCreateInstance(CLSID_DOMDocument, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IXMLDOMDocument, &_pdocManifest));
  3001. if (SUCCEEDED(hr))
  3002. {
  3003. IXMLDOMElement *pdelDoc;
  3004. hr = CreateElement(_pdocManifest, ELEMENT_TRANSFERMANIFEST, NULL, &pdelDoc);
  3005. if (SUCCEEDED(hr))
  3006. {
  3007. hr = _pdocManifest->putref_documentElement(pdelDoc);
  3008. if (SUCCEEDED(hr))
  3009. {
  3010. hr = CreateAndAppendElement(_pdocManifest, pdelDoc, ELEMENT_FILES, NULL, NULL);
  3011. if (SUCCEEDED(hr))
  3012. {
  3013. hr = _AddFilesToManifest(_pdocManifest);
  3014. }
  3015. }
  3016. pdelDoc->Release();
  3017. }
  3018. }
  3019. _fRecomputeManifest = FALSE; // the manifest has been recomputed, therefore we don't need to this again.
  3020. _fRepopulateProviders = TRUE; // the provider list may have changed b/c the manifest changed.
  3021. return hr;
  3022. }
  3023. void CPublishingWizard::_FreeTransferManifest()
  3024. {
  3025. ATOMICRELEASE(_pdocManifest);
  3026. if (_aItems)
  3027. {
  3028. FreeIDListArray(_aItems, _cItems);
  3029. _aItems = NULL;
  3030. _cItems = 0;
  3031. }
  3032. }
  3033. // Advanced location dialog, including the browse button....
  3034. typedef struct
  3035. {
  3036. LPTSTR pszPath;
  3037. IDataObject *pdo;
  3038. } BROWSEINIT;
  3039. int _BrowseCallback(HWND hwnd, UINT uMsg, LPARAM lParam, LPARAM lpData)
  3040. {
  3041. BROWSEINIT *pbi = (BROWSEINIT *)lpData;
  3042. switch (uMsg)
  3043. {
  3044. case BFFM_INITIALIZED:
  3045. {
  3046. LPTSTR pszPath = pbi->pszPath;
  3047. if (pszPath && pszPath[0])
  3048. {
  3049. int i = lstrlen(pszPath) - 1;
  3050. if ((pszPath[i] == TEXT('\\')) || (pszPath[i] == TEXT('/')))
  3051. {
  3052. pszPath[i] = 0;
  3053. }
  3054. SendMessage(hwnd, BFFM_SETSELECTION, (WPARAM) TRUE, (LPARAM) (LPTSTR)pszPath);
  3055. }
  3056. else
  3057. {
  3058. LPITEMIDLIST pidl;
  3059. HRESULT hr = SHGetSpecialFolderLocation(hwnd, CSIDL_NETWORK, &pidl);
  3060. if (SUCCEEDED(hr))
  3061. {
  3062. SendMessage(hwnd, BFFM_SETSELECTION, (WPARAM)FALSE, (LPARAM)((LPTSTR)pidl));
  3063. ILFree(pidl);
  3064. }
  3065. }
  3066. break;
  3067. }
  3068. case BFFM_SELCHANGED:
  3069. {
  3070. BOOL fEnableOK = FALSE;
  3071. LPCITEMIDLIST pidl = (LPCITEMIDLIST)lParam;
  3072. // if we have a IDataObject then check to see if we can drop it onto the
  3073. // destination we are given. this is used by the publishing process
  3074. // to ensure that we enable/disable the OK.
  3075. if (pbi->pdo)
  3076. {
  3077. IShellFolder *psf;
  3078. LPCITEMIDLIST pidlChild;
  3079. if (SUCCEEDED(SHBindToIDListParent(pidl, IID_PPV_ARG(IShellFolder, &psf), &pidlChild)))
  3080. {
  3081. IDropTarget *pdt;
  3082. if (SUCCEEDED(psf->GetUIObjectOf(NULL, 1, &pidlChild, IID_PPV_ARG_NULL(IDropTarget, &pdt))))
  3083. {
  3084. POINTL ptl = {0};
  3085. DWORD dwEffect = DROPEFFECT_COPY;
  3086. if (SUCCEEDED(pdt->DragEnter(pbi->pdo, 0, ptl, &dwEffect)))
  3087. {
  3088. fEnableOK = (dwEffect & DROPEFFECT_COPY);
  3089. pdt->DragLeave();
  3090. }
  3091. pdt->Release();
  3092. }
  3093. psf->Release();
  3094. }
  3095. }
  3096. else
  3097. {
  3098. ULONG rgInfo = SFGAO_STORAGE;
  3099. if (SUCCEEDED(SHGetNameAndFlags(pidl, 0, NULL, 0, &rgInfo)))
  3100. {
  3101. fEnableOK = (rgInfo & SFGAO_STORAGE);
  3102. }
  3103. else
  3104. {
  3105. fEnableOK = TRUE;
  3106. }
  3107. }
  3108. SendMessage(hwnd, BFFM_ENABLEOK, (WPARAM) 0, (LPARAM)fEnableOK);
  3109. break;
  3110. }
  3111. }
  3112. return 0;
  3113. }
  3114. void CPublishingWizard::_SetWaitCursor(BOOL bOn)
  3115. {
  3116. if (bOn)
  3117. {
  3118. _hCursor = SetCursor(LoadCursor(NULL, IDC_APPSTARTING));
  3119. }
  3120. else if (_hCursor)
  3121. {
  3122. SetCursor(_hCursor);
  3123. _hCursor = NULL;
  3124. }
  3125. }
  3126. // Publishing location pages
  3127. void CPublishingWizard::_ShowExampleTip(HWND hwnd)
  3128. {
  3129. TCHAR szTitle[256], szExamples[256];
  3130. LoadString(g_hinst, IDS_NETPLACE_EXAMPLES_TITLE, szTitle, ARRAYSIZE(szTitle));
  3131. LoadString(g_hinst, IDS_NETPLACE_EXAMPLES, szExamples, ARRAYSIZE(szExamples));
  3132. EDITBALLOONTIP ebt = {0};
  3133. ebt.cbStruct = sizeof(ebt);
  3134. ebt.pszTitle = szTitle;
  3135. ebt.pszText = szExamples;
  3136. SetFocus(GetDlgItem(hwnd, IDC_FOLDER_EDIT)); // set focus before the balloon
  3137. HWND hwndEdit = (HWND)SendDlgItemMessage(hwnd, IDC_FOLDER_EDIT, CBEM_GETEDITCONTROL, 0, 0L);
  3138. Edit_ShowBalloonTip(hwndEdit, &ebt);
  3139. }
  3140. void CPublishingWizard::_LocationChanged(HWND hwnd)
  3141. {
  3142. if (_fValidating)
  3143. {
  3144. PropSheet_SetWizButtons(GetParent(hwnd), 0);
  3145. }
  3146. else
  3147. {
  3148. int cchLocation = FetchTextLength(hwnd, IDC_FOLDER_EDIT);
  3149. PropSheet_SetWizButtons(GetParent(hwnd), PSWIZB_BACK|((cchLocation >0) ? PSWIZB_NEXT:0));
  3150. }
  3151. }
  3152. // auto complete bits
  3153. #define SZ_REGKEY_AUTOCOMPLETE_TAB TEXT("Software\\Microsoft\\Windows\\CurrentVersion\\Explorer\\AutoComplete")
  3154. #define SZ_REGVALUE_AUTOCOMPLETE_TAB TEXT("Always Use Tab")
  3155. #define REGSTR_PATH_AUTOCOMPLETE TEXT("Software\\Microsoft\\windows\\CurrentVersion\\Explorer\\AutoComplete")
  3156. #define REGSTR_VAL_USEAUTOAPPEND TEXT("Append Completion")
  3157. #define REGSTR_VAL_USEAUTOSUGGEST TEXT("AutoSuggest")
  3158. #define BOOL_NOT_SET 0x00000005
  3159. DWORD CPublishingWizard::_GetAutoCompleteFlags(DWORD dwFlags)
  3160. {
  3161. DWORD dwACOptions = 0;
  3162. if (!(SHACF_AUTOAPPEND_FORCE_OFF & dwFlags) &&
  3163. ((SHACF_AUTOAPPEND_FORCE_ON & dwFlags) ||
  3164. SHRegGetBoolUSValue(REGSTR_PATH_AUTOCOMPLETE, REGSTR_VAL_USEAUTOAPPEND, FALSE, FALSE)))
  3165. {
  3166. dwACOptions |= ACO_AUTOAPPEND;
  3167. }
  3168. if (!(SHACF_AUTOSUGGEST_FORCE_OFF & dwFlags) &&
  3169. ((SHACF_AUTOSUGGEST_FORCE_ON & dwFlags) ||
  3170. SHRegGetBoolUSValue(REGSTR_PATH_AUTOCOMPLETE, REGSTR_VAL_USEAUTOSUGGEST, FALSE, TRUE)))
  3171. {
  3172. dwACOptions |= ACO_AUTOSUGGEST;
  3173. }
  3174. if (SHACF_USETAB & dwFlags)
  3175. dwACOptions |= ACO_USETAB;
  3176. // Windows uses the TAB key to move between controls in a dialog. UNIX and other
  3177. // operating systems that use AutoComplete have traditionally used the TAB key to
  3178. // iterate thru the AutoComplete possibilities. We need to default to disable the
  3179. // TAB key (ACO_USETAB) unless the caller specifically wants it. We will also
  3180. // turn it on
  3181. static BOOL s_fAlwaysUseTab = BOOL_NOT_SET;
  3182. if (BOOL_NOT_SET == s_fAlwaysUseTab)
  3183. s_fAlwaysUseTab = SHRegGetBoolUSValue(SZ_REGKEY_AUTOCOMPLETE_TAB, SZ_REGVALUE_AUTOCOMPLETE_TAB, FALSE, FALSE);
  3184. if (s_fAlwaysUseTab)
  3185. dwACOptions |= ACO_USETAB;
  3186. return dwACOptions;
  3187. }
  3188. HRESULT CPublishingWizard::_InitAutoComplete()
  3189. {
  3190. HRESULT hr = CoCreateInstance(CLSID_AutoComplete, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IAutoComplete2, &_pac));
  3191. if (SUCCEEDED(hr))
  3192. {
  3193. hr = CoCreateInstance(CLSID_ACLMulti, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IUnknown, &_punkACLMulti));
  3194. if (SUCCEEDED(hr))
  3195. {
  3196. IObjMgr *pomMulti;
  3197. hr = _punkACLMulti->QueryInterface(IID_PPV_ARG(IObjMgr, &pomMulti));
  3198. if (SUCCEEDED(hr))
  3199. {
  3200. // add the file system auto complete object (for handling UNC's etc)
  3201. IUnknown *punk;
  3202. hr = CoCreateInstance(CLSID_ACListISF, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IUnknown, &punk));
  3203. if (SUCCEEDED(hr))
  3204. {
  3205. pomMulti->Append(punk);
  3206. punk->Release();
  3207. }
  3208. // add the publishing wizard auto complete object (for handling HTTP etc)
  3209. IUnknown *punkCustomACL;
  3210. hr = CoCreateInstance(CLSID_ACLCustomMRU, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IUnknown, &punkCustomACL));
  3211. if (SUCCEEDED(hr))
  3212. {
  3213. hr = punkCustomACL->QueryInterface(IID_PPV_ARG(IACLCustomMRU, &_pmru));
  3214. if (SUCCEEDED(hr))
  3215. {
  3216. TCHAR szKey[MAX_PATH];
  3217. wnsprintf(szKey, ARRAYSIZE(szKey), (SZ_REGKEY_PUBWIZ TEXT("\\%s\\") SZ_REGVAL_MRU), _szProviderScope);
  3218. hr = _pmru->Initialize(szKey, 26);
  3219. if (SUCCEEDED(hr))
  3220. {
  3221. hr = pomMulti->Append(punkCustomACL);
  3222. }
  3223. }
  3224. punkCustomACL->Release();
  3225. }
  3226. pomMulti->Release();
  3227. }
  3228. }
  3229. }
  3230. return hr;
  3231. }
  3232. // handle MRU of places you can publish to
  3233. void CPublishingWizard::_InitLocation(HWND hwnd)
  3234. {
  3235. // lets initialize the auto complete list of folders that we have
  3236. HRESULT hr = _InitAutoComplete();
  3237. if (SUCCEEDED(hr))
  3238. {
  3239. IEnumString *penum;
  3240. hr = _pmru->QueryInterface(IID_PPV_ARG(IEnumString, &penum));
  3241. if (SUCCEEDED(hr))
  3242. {
  3243. penum->Reset(); // reset the enumerator ready for us to populate the list
  3244. LPOLESTR pszEntry;
  3245. ULONG ulFetched;
  3246. while ((penum->Next(1, &pszEntry, &ulFetched) == S_OK) && ulFetched == 1)
  3247. {
  3248. COMBOBOXEXITEM cbei = {0};
  3249. cbei.mask = CBEIF_TEXT;
  3250. cbei.pszText = pszEntry;
  3251. SendDlgItemMessage(hwnd, IDC_FOLDER_EDIT, CBEM_INSERTITEM, 0, (LPARAM)&cbei);
  3252. CoTaskMemFree(pszEntry);
  3253. }
  3254. penum->Release();
  3255. }
  3256. // enable auto complete for this control.
  3257. HWND hwndEdit = (HWND)SendDlgItemMessage(hwnd, IDC_FOLDER_EDIT, CBEM_GETEDITCONTROL, 0, 0L);
  3258. _pac->Init(hwndEdit, _punkACLMulti, NULL, NULL);
  3259. _pac->SetOptions(_GetAutoCompleteFlags(0));
  3260. // limit text on the edit control
  3261. ComboBox_LimitText(GetDlgItem(hwnd, IDC_FOLDER_EDIT), INTERNET_MAX_URL_LENGTH);
  3262. // if the policy says no map drive etc, then lets remove it
  3263. BOOL fHide = SHRestricted(REST_NOENTIRENETWORK) || SHRestricted(REST_NONETCONNECTDISCONNECT);
  3264. ShowWindow(GetDlgItem(hwnd, IDC_BROWSE), fHide ? SW_HIDE:SW_SHOW);
  3265. }
  3266. }
  3267. // validation thread, this is performed on a background thread to compute if
  3268. // the resource is valid.
  3269. #define PWM_VALIDATEDONE (WM_APP) // -> validate done (HRESULT passed in LPARAM)
  3270. typedef struct
  3271. {
  3272. HWND hwnd; // parent HWND
  3273. BOOL fAllowWebFolders; // allow web folders during validation
  3274. TCHAR szFileTarget[INTERNET_MAX_URL_LENGTH]; // destination for file copy
  3275. } VALIDATETHREADDATA;
  3276. DWORD CALLBACK CPublishingWizard::s_ValidateThreadProc(void *pv)
  3277. {
  3278. VALIDATETHREADDATA *pvtd = (VALIDATETHREADDATA*)pv;
  3279. HRESULT hr = E_FAIL;
  3280. // validate the site
  3281. CNetworkPlace np;
  3282. hr = np.SetTarget(pvtd->hwnd, pvtd->szFileTarget, NPTF_VALIDATE | (pvtd->fAllowWebFolders ? NPTF_ALLOWWEBFOLDERS:0));
  3283. np.SetTarget(NULL, NULL, 0);
  3284. PostMessage(pvtd->hwnd, PWM_VALIDATEDONE, 0, (LPARAM)hr);
  3285. LocalFree(pvtd);
  3286. return 0;
  3287. }
  3288. void CPublishingWizard::_TryToValidateDestination(HWND hwnd)
  3289. {
  3290. TCHAR szDestination[INTERNET_MAX_URL_LENGTH];
  3291. FetchText(hwnd, IDC_FOLDER_EDIT, szDestination, ARRAYSIZE(szDestination));
  3292. // lets walk the list source files and try to match to the destination we have.
  3293. // we don't want to let source be the destination
  3294. BOOL fHitItem = FALSE;
  3295. LPITEMIDLIST pidl = ILCreateFromPath(szDestination);
  3296. if (pidl)
  3297. {
  3298. BOOL fUNC = PathIsUNC(szDestination); //only if destination is UNC Path do we need to check if source is a mapped drive
  3299. for (UINT iItem = 0; (iItem != _cItems) && !fHitItem; iItem++)
  3300. {
  3301. LPITEMIDLIST pidlSrcDir = ILClone(_aItems[iItem]);
  3302. if (pidlSrcDir)
  3303. {
  3304. ILRemoveLastID(pidlSrcDir);
  3305. fHitItem = ILIsEqual(pidlSrcDir, pidl) || (!ILIsEmpty(pidlSrcDir) && ILIsParent(pidlSrcDir, pidl, FALSE));
  3306. if (!fHitItem && fUNC)
  3307. {
  3308. WCHAR szPath[MAX_PATH];
  3309. if (SUCCEEDED(SHGetPathFromIDList(pidlSrcDir, szPath)) && !PathIsUNC(szPath))
  3310. {
  3311. WCHAR szSource[MAX_PATH];
  3312. DWORD cchSource = ARRAYSIZE(szSource);
  3313. DWORD dwType = SHWNetGetConnection(szPath, szSource, &cchSource);
  3314. if ((dwType == NO_ERROR) || (dwType == ERROR_CONNECTION_UNAVAIL))
  3315. {
  3316. fHitItem = (StrCmpNI(szSource, szDestination, lstrlen(szSource)) == 0);
  3317. }
  3318. }
  3319. }
  3320. ILFree(pidlSrcDir);
  3321. }
  3322. }
  3323. ILFree(pidl);
  3324. }
  3325. // if we didn't get a hit that way then lets spin up a thread which will do the
  3326. // validation of the server and the connection - this is a lengthy operation
  3327. // and will post a result to the window.
  3328. if (!fHitItem)
  3329. {
  3330. VALIDATETHREADDATA *pvtd = (VALIDATETHREADDATA*)LocalAlloc(LPTR, sizeof(*pvtd));
  3331. if (pvtd)
  3332. {
  3333. pvtd->hwnd = hwnd;
  3334. pvtd->fAllowWebFolders = (_dwFlags & SHPWHF_VALIDATEVIAWEBFOLDERS) != 0;
  3335. // fetch the user typed url
  3336. StrCpy(pvtd->szFileTarget, szDestination);
  3337. // we have the thread data read, so lets begin the validation
  3338. // by creating the thread - our state is set to indicate we are in the
  3339. // validate mode.
  3340. _fValidating = TRUE; // we are going to begin validating
  3341. _SetWaitCursor(TRUE);
  3342. if (!SHCreateThread(s_ValidateThreadProc, pvtd, CTF_INSIST | CTF_COINIT, NULL))
  3343. {
  3344. LocalFree(pvtd);
  3345. _fValidating = FALSE;
  3346. _SetWaitCursor(FALSE);
  3347. }
  3348. }
  3349. }
  3350. else
  3351. {
  3352. ShellMessageBox(g_hinst, hwnd, MAKEINTRESOURCE(IDS_PUB_SAMETARGET), NULL, MB_ICONEXCLAMATION | MB_OK);
  3353. PostMessage(hwnd, PWM_VALIDATEDONE, 0, (LPARAM)E_FAIL);
  3354. }
  3355. // ensure the state of the controls reflects what we are trying to do.
  3356. _LocationChanged(hwnd);
  3357. EnableWindow(GetDlgItem(hwnd, IDC_FOLDER_EDIT), !_fValidating);
  3358. EnableWindow(GetDlgItem(hwnd, IDC_BROWSE), !_fValidating);
  3359. }
  3360. // this is the dialog proc for the location dialog.
  3361. INT_PTR CPublishingWizard::_LocationDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  3362. {
  3363. switch (uMsg)
  3364. {
  3365. case WM_INITDIALOG:
  3366. {
  3367. _MapDlgItemText(hwnd, IDC_PUB_LOCATIONCAPTION, L"wp:location", L"locationcaption");
  3368. _InitLocation(hwnd);
  3369. return TRUE;
  3370. }
  3371. case WM_DESTROY:
  3372. {
  3373. ATOMICRELEASE(_pac);
  3374. ATOMICRELEASE(_punkACLMulti);
  3375. ATOMICRELEASE(_pmru);
  3376. return FALSE;
  3377. }
  3378. case WM_COMMAND:
  3379. {
  3380. switch (LOWORD(wParam))
  3381. {
  3382. case IDC_BROWSE:
  3383. {
  3384. LPITEMIDLIST pidl;
  3385. if (SHGetSpecialFolderLocation(hwnd, CSIDL_NETWORK, &pidl) == S_OK)
  3386. {
  3387. TCHAR szPath[MAX_PATH];
  3388. FetchText(hwnd, IDC_FOLDER_EDIT, szPath, ARRAYSIZE(szPath));
  3389. TCHAR szTitle[MAX_PATH];
  3390. if (FAILED(_LoadMappedString(L"wp:location", L"browsecaption", szTitle, ARRAYSIZE(szTitle))))
  3391. {
  3392. LoadString(g_hinst, IDS_PUB_BROWSETITLE, szTitle, ARRAYSIZE(szTitle));
  3393. }
  3394. // lets initialize our state structure for the browse dialog. based on this we can then
  3395. // attempt to select a network place. from here we will also pass the IDataObject
  3396. // we have (there may not be one of course)
  3397. BROWSEINIT binit = {szPath};
  3398. if (_pdoSelection)
  3399. _pdoSelection->QueryInterface(IID_PPV_ARG(IDataObject, &binit.pdo));
  3400. else if (_pdo)
  3401. _pdo->QueryInterface(IID_PPV_ARG(IDataObject, &binit.pdo));
  3402. BROWSEINFO bi = {0};
  3403. bi.hwndOwner = hwnd;
  3404. bi.pidlRoot = pidl;
  3405. bi.lpszTitle = szTitle;
  3406. bi.ulFlags = BIF_NEWDIALOGSTYLE;
  3407. bi.lpfn = _BrowseCallback;
  3408. bi.lParam = (LPARAM)&binit;
  3409. LPITEMIDLIST pidlReturned = SHBrowseForFolder(&bi);
  3410. if (pidlReturned)
  3411. {
  3412. if (SUCCEEDED(SHGetNameAndFlags(pidlReturned, SHGDN_FORPARSING, szPath, ARRAYSIZE(szPath), NULL)))
  3413. SetDlgItemText(hwnd, IDC_FOLDER_EDIT, szPath);
  3414. ILFree(pidlReturned);
  3415. }
  3416. if (binit.pdo)
  3417. binit.pdo->Release();
  3418. ILFree(pidl);
  3419. }
  3420. return TRUE;
  3421. }
  3422. case IDC_FOLDER_EDIT:
  3423. if (HIWORD(wParam) == CBN_EDITCHANGE)
  3424. {
  3425. _LocationChanged(hwnd);
  3426. }
  3427. return TRUE;
  3428. }
  3429. break;
  3430. }
  3431. case WM_SETCURSOR:
  3432. if (_fValidating)
  3433. {
  3434. SetCursor(LoadCursor(NULL, IDC_APPSTARTING));
  3435. return TRUE;
  3436. }
  3437. return FALSE;
  3438. case PWM_VALIDATEDONE:
  3439. {
  3440. _fValidating = FALSE;
  3441. _LocationChanged(hwnd);
  3442. _SetWaitCursor(FALSE);
  3443. HRESULT hr = _InitPropertyBag(NULL);
  3444. if (SUCCEEDED(hr))
  3445. {
  3446. TCHAR szBuffer[MAX_PATH], szURL[INTERNET_MAX_URL_LENGTH];
  3447. FetchText(hwnd, IDC_FOLDER_EDIT, szURL, ARRAYSIZE(szURL));
  3448. // push the destination site into the property bag, and then initialize
  3449. // our site with the right information
  3450. IXMLDOMDocument *pdocManifest;
  3451. hr = GetTransferManifest(NULL, &pdocManifest);
  3452. if (SUCCEEDED(hr))
  3453. {
  3454. IXMLDOMNode *pdnRoot;
  3455. hr = pdocManifest->selectSingleNode(XPATH_MANIFEST, &pdnRoot);
  3456. if (hr == S_OK)
  3457. {
  3458. IXMLDOMElement *pdelRoot;
  3459. hr = pdnRoot->QueryInterface(IID_PPV_ARG(IXMLDOMElement, &pdelRoot));
  3460. if (SUCCEEDED(hr))
  3461. {
  3462. IXMLDOMElement *pdelUploadInfo;
  3463. hr = CreateAndAppendElement(_pdocManifest, pdelRoot, ELEMENT_UPLOADINFO, NULL, &pdelUploadInfo);
  3464. if (SUCCEEDED(hr))
  3465. {
  3466. IXMLDOMElement *pdelTarget;
  3467. hr = CreateAndAppendElement(_pdocManifest, pdelUploadInfo, ELEMENT_TARGET, NULL, &pdelTarget);
  3468. if (SUCCEEDED(hr))
  3469. {
  3470. hr = SetAttributeFromStr(pdelTarget, ATTRIBUTE_HREF, szURL);
  3471. pdelTarget->Release();
  3472. }
  3473. pdelUploadInfo->Release();
  3474. }
  3475. pdelRoot->Release();
  3476. }
  3477. pdnRoot->Release();
  3478. }
  3479. pdocManifest->Release();
  3480. }
  3481. // lets now process the result
  3482. hr = (HRESULT)lParam;
  3483. if (S_OK == hr)
  3484. {
  3485. BOOL fGotoNextPage = TRUE;
  3486. // fake a return so auto complete can do its thing
  3487. SendMessage(GetDlgItem(hwnd, IDC_FOLDER_EDIT), WM_KEYDOWN, VK_RETURN, 0x1c0001);
  3488. // add the string to the MRU
  3489. if (_pmru)
  3490. _pmru->AddMRUString(szURL);
  3491. // lets sniff the string they entered, if its a URL and its FTP
  3492. // then we must special case the password in the URL, otherwise
  3493. // we jump directly to the friendly name handling.
  3494. URL_COMPONENTS urlComps = {0};
  3495. urlComps.dwStructSize = sizeof(urlComps);
  3496. urlComps.lpszScheme = szBuffer;
  3497. urlComps.dwSchemeLength = ARRAYSIZE(szBuffer);
  3498. if (InternetCrackUrl(szURL, 0, ICU_DECODE, &urlComps)
  3499. && (INTERNET_SCHEME_FTP == urlComps.nScheme))
  3500. {
  3501. URL_COMPONENTS urlComps = {0};
  3502. urlComps.dwStructSize = sizeof(URL_COMPONENTS);
  3503. urlComps.nScheme = INTERNET_SCHEME_FTP;
  3504. urlComps.lpszUserName = szBuffer;
  3505. urlComps.dwUserNameLength = ARRAYSIZE(szBuffer);
  3506. // if the user specified a user name, if not then goto the FTP user
  3507. // page (we known its a FTP location)
  3508. if (!InternetCrackUrl(szURL, 0, 0, &urlComps) || !szBuffer[0])
  3509. {
  3510. _WizardNext(hwnd, WIZPAGE_FTPUSER);
  3511. fGotoNextPage = FALSE;
  3512. }
  3513. }
  3514. if (fGotoNextPage)
  3515. _WizardNext(hwnd, WIZPAGE_FRIENDLYNAME);
  3516. }
  3517. }
  3518. EnableWindow(GetDlgItem(hwnd, IDC_FOLDER_EDIT), TRUE);
  3519. EnableWindow(GetDlgItem(hwnd, IDC_BROWSE), TRUE);
  3520. if (FAILED(((HRESULT)lParam)))
  3521. _ShowExampleTip(hwnd);
  3522. return TRUE;
  3523. }
  3524. case WM_NOTIFY:
  3525. {
  3526. LPNMHDR pnmh = (LPNMHDR)lParam;
  3527. switch (pnmh->code)
  3528. {
  3529. case PSN_SETACTIVE:
  3530. _fShownCustomLocation = TRUE; // so we navigate back to this page
  3531. _fShownUserName = FALSE;
  3532. _LocationChanged(hwnd);
  3533. return TRUE;
  3534. case PSN_WIZBACK:
  3535. return _WizardNext(hwnd, WIZPAGE_PROVIDERS);
  3536. case PSN_WIZNEXT:
  3537. _TryToValidateDestination(hwnd);
  3538. SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LPARAM)-1);
  3539. return TRUE;
  3540. case NM_CLICK:
  3541. case NM_RETURN:
  3542. {
  3543. if (pnmh->idFrom == IDC_EXAMPLESLINK)
  3544. {
  3545. _ShowExampleTip(hwnd);
  3546. return TRUE;
  3547. }
  3548. }
  3549. }
  3550. break;
  3551. }
  3552. }
  3553. return FALSE;
  3554. }
  3555. // FTP login dialog - handle the messages for this
  3556. void CPublishingWizard::_UserNameChanged(HWND hwnd)
  3557. {
  3558. BOOL fAnonymousLogin = IsDlgButtonChecked(hwnd, IDC_PASSWORD_ANONYMOUS);
  3559. ShowWindow(GetDlgItem(hwnd, IDC_USER), (fAnonymousLogin ? SW_HIDE : SW_SHOW));
  3560. ShowWindow(GetDlgItem(hwnd, IDC_USERNAME_LABEL), (fAnonymousLogin ? SW_HIDE : SW_SHOW));
  3561. ShowWindow(GetDlgItem(hwnd, IDC_ANON_USERNAME), (fAnonymousLogin ? SW_SHOW : SW_HIDE));
  3562. ShowWindow(GetDlgItem(hwnd, IDC_ANON_USERNAME_LABEL), (fAnonymousLogin ? SW_SHOW : SW_HIDE));
  3563. // Hide the "You will be prompted for the password when you connect to the FTP server" text on anonymous
  3564. EnableWindow(GetDlgItem(hwnd, IDC_PWD_PROMPT), !fAnonymousLogin);
  3565. ShowWindow(GetDlgItem(hwnd, IDC_PWD_PROMPT), (fAnonymousLogin ? SW_HIDE : SW_SHOW));
  3566. }
  3567. INT_PTR CPublishingWizard::_UserNameDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  3568. {
  3569. switch (uMsg)
  3570. {
  3571. case WM_INITDIALOG:
  3572. {
  3573. CheckDlgButton(hwnd, IDC_PASSWORD_ANONYMOUS, BST_CHECKED);
  3574. EnableWindow(GetDlgItem(hwnd, IDC_ANON_USERNAME), FALSE);
  3575. EnableWindow(GetDlgItem(hwnd, IDC_ANON_USERNAME_LABEL), FALSE);
  3576. SetWindowText(GetDlgItem(hwnd, IDC_ANON_USERNAME), TEXT("Anonymous"));
  3577. return TRUE;
  3578. }
  3579. case WM_COMMAND:
  3580. {
  3581. switch (LOWORD(wParam))
  3582. {
  3583. case IDC_PASSWORD_ANONYMOUS:
  3584. _UserNameChanged(hwnd);
  3585. return TRUE;
  3586. }
  3587. break;
  3588. }
  3589. case WM_NOTIFY:
  3590. {
  3591. LPNMHDR pnmh = (LPNMHDR)lParam;
  3592. switch (pnmh->code)
  3593. {
  3594. case PSN_SETACTIVE:
  3595. {
  3596. _fShownUserName = TRUE; // so we can navigate back properly
  3597. _UserNameChanged(hwnd);
  3598. return TRUE;
  3599. }
  3600. case PSN_WIZBACK:
  3601. return _WizardNext(hwnd, WIZPAGE_LOCATION);
  3602. case PSN_WIZNEXT:
  3603. {
  3604. // if we can get a user name then lets push it into the property
  3605. // bag, a NULL string == anonymous logon
  3606. TCHAR szUserName[INTERNET_MAX_USER_NAME_LENGTH] = {0};
  3607. if (!IsDlgButtonChecked(hwnd, IDC_PASSWORD_ANONYMOUS))
  3608. {
  3609. FetchText(hwnd, IDC_USER, szUserName, ARRAYSIZE(szUserName));
  3610. }
  3611. // get the sites property bag, and persist the string into it,
  3612. // if we have done that then we can go to the next page.
  3613. IXMLDOMDocument *pdocManifest;
  3614. HRESULT hr = GetTransferManifest(NULL, &pdocManifest);
  3615. if (SUCCEEDED(hr))
  3616. {
  3617. IXMLDOMNode *pdn;
  3618. hr = pdocManifest->selectSingleNode(XPATH_UPLOADTARGET, &pdn);
  3619. if (hr == S_OK)
  3620. {
  3621. hr = SetAttributeFromStr(pdn, ATTRIBUTE_USERNAME, szUserName);
  3622. pdn->Release();
  3623. }
  3624. pdocManifest->Release();
  3625. }
  3626. return _WizardNext(hwnd, WIZPAGE_FRIENDLYNAME);
  3627. }
  3628. }
  3629. break;
  3630. }
  3631. }
  3632. return FALSE;
  3633. }
  3634. // set the friendly name for the web place - if it doesn't already exist
  3635. void CPublishingWizard::_FriendlyNameChanged(HWND hwnd)
  3636. {
  3637. int cchLocation = FetchTextLength(hwnd, IDC_NETPLNAME_EDIT);
  3638. PropSheet_SetWizButtons(GetParent(hwnd), PSWIZB_BACK |((cchLocation >0) ? PSWIZB_NEXT:0));
  3639. }
  3640. INT_PTR CPublishingWizard::_FriendlyNameDlgProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  3641. {
  3642. switch (uMsg)
  3643. {
  3644. // lets get the limit information for the nethood folder
  3645. case WM_INITDIALOG:
  3646. {
  3647. LPITEMIDLIST pidlNetHood;
  3648. if (SUCCEEDED(SHGetSpecialFolderLocation(NULL, CSIDL_NETHOOD, &pidlNetHood)))
  3649. {
  3650. IShellFolder *psf;
  3651. if (SUCCEEDED(SHBindToObject(NULL, IID_X_PPV_ARG(IShellFolder, pidlNetHood, &psf))))
  3652. {
  3653. SHLimitInputEdit(GetDlgItem(hwnd, IDC_NETPLNAME_EDIT), psf);
  3654. psf->Release();
  3655. }
  3656. ILFree(pidlNetHood);
  3657. }
  3658. _FriendlyNameChanged(hwnd);
  3659. break;
  3660. }
  3661. case WM_COMMAND:
  3662. {
  3663. switch (LOWORD(wParam))
  3664. {
  3665. case IDC_NETPLNAME_EDIT:
  3666. {
  3667. if (HIWORD(wParam) == EN_CHANGE)
  3668. {
  3669. _FriendlyNameChanged(hwnd);
  3670. return TRUE;
  3671. }
  3672. break;
  3673. }
  3674. }
  3675. break;
  3676. }
  3677. case WM_NOTIFY:
  3678. {
  3679. LPNMHDR pnmh = (LPNMHDR)lParam;
  3680. switch (pnmh->code)
  3681. {
  3682. case PSN_SETACTIVE:
  3683. {
  3684. // read from the manifest the target URL that we are going to be putting the
  3685. // files to, from this we can compute the friendly name information.
  3686. IXMLDOMDocument *pdocManifest;
  3687. HRESULT hr = GetTransferManifest(NULL, &pdocManifest);
  3688. if (SUCCEEDED(hr))
  3689. {
  3690. IXMLDOMNode *pdn;
  3691. hr = pdocManifest->selectSingleNode(XPATH_UPLOADTARGET, &pdn);
  3692. if (hr == S_OK)
  3693. {
  3694. TCHAR szURL[INTERNET_MAX_URL_LENGTH];
  3695. hr = GetStrFromAttribute(pdn, ATTRIBUTE_HREF, szURL, ARRAYSIZE(szURL));
  3696. if (SUCCEEDED(hr))
  3697. {
  3698. _npCustom.SetTarget(hwnd, szURL, (_dwFlags & SHPWHF_VALIDATEVIAWEBFOLDERS) ? NPTF_ALLOWWEBFOLDERS:0);
  3699. TCHAR szUserName[INTERNET_MAX_USER_NAME_LENGTH];
  3700. hr = GetStrFromAttribute(pdn, ATTRIBUTE_USERNAME, szUserName, ARRAYSIZE(szUserName));
  3701. if (SUCCEEDED(hr))
  3702. _npCustom.SetLoginInfo(szUserName, NULL);
  3703. TCHAR szBuffer[MAX_PATH + INTERNET_MAX_URL_LENGTH];
  3704. if (FormatMessageString(IDS_COMPLETION_STATIC, szBuffer, ARRAYSIZE(szBuffer), szURL))
  3705. {
  3706. SetDlgItemText(hwnd, IDC_COMPLETION_STATIC, szBuffer);
  3707. }
  3708. // Create a default name and display it
  3709. hr = _npCustom.GetName(szBuffer, ARRAYSIZE(szBuffer));
  3710. SetDlgItemText(hwnd, IDC_NETPLNAME_EDIT, SUCCEEDED(hr) ? szBuffer:TEXT(""));
  3711. // Update the button state for the page etc.
  3712. _FriendlyNameChanged(hwnd);
  3713. }
  3714. pdn->Release();
  3715. }
  3716. }
  3717. return TRUE;
  3718. }
  3719. case PSN_WIZBACK:
  3720. _WizardNext(hwnd, _fShownUserName ? WIZPAGE_FTPUSER:WIZPAGE_LOCATION);
  3721. return TRUE;
  3722. case PSN_WIZNEXT:
  3723. {
  3724. TCHAR szFriendlyName[MAX_PATH];
  3725. FetchText(hwnd, IDC_NETPLNAME_EDIT, szFriendlyName, ARRAYSIZE(szFriendlyName));
  3726. // set the name of the new place, if this fails then the name is already taken
  3727. // and UI will have been displayed saying so, and they responded with a
  3728. // NO to the overwrite prompt.
  3729. HRESULT hr = _npCustom.SetName(hwnd, szFriendlyName);
  3730. if (SUCCEEDED(hr))
  3731. {
  3732. IXMLDOMDocument *pdocManifest;
  3733. HRESULT hr = GetTransferManifest(NULL, &pdocManifest);
  3734. if (SUCCEEDED(hr))
  3735. {
  3736. IXMLDOMNode *pdn;
  3737. hr = pdocManifest->selectSingleNode(XPATH_UPLOADINFO, &pdn);
  3738. if (hr == S_OK)
  3739. {
  3740. hr = SetAttributeFromStr(pdn, ATTRIBUTE_FRIENDLYNAME, szFriendlyName);
  3741. pdn->Release();
  3742. }
  3743. pdocManifest->Release();
  3744. }
  3745. // Clean up after our custom netplace now.
  3746. // This way everything works for webfolders when the outer ANP netplace
  3747. // creates the webfolder. DSheldon 387476
  3748. _npCustom.SetTarget(NULL, NULL, 0x0);
  3749. if (_pdo)
  3750. {
  3751. _WizardNext(hwnd, _fOfferResize ? WIZPAGE_RESIZE:WIZPAGE_COPYING);
  3752. }
  3753. else
  3754. {
  3755. IWizardSite *pws;
  3756. hr = _punkSite->QueryInterface(IID_PPV_ARG(IWizardSite, &pws));
  3757. if (SUCCEEDED(hr))
  3758. {
  3759. HPROPSHEETPAGE hpage;
  3760. hr = pws->GetNextPage(&hpage);
  3761. if (SUCCEEDED(hr))
  3762. {
  3763. PropSheet_SetCurSel(GetParent(hwnd), hpage, -1);
  3764. }
  3765. pws->Release();
  3766. }
  3767. }
  3768. }
  3769. SetWindowLongPtr(hwnd, DWLP_MSGRESULT, (LPARAM)-1);
  3770. return TRUE;
  3771. }
  3772. }
  3773. break;
  3774. }
  3775. }
  3776. return FALSE;
  3777. }