Leaked source code of windows server 2003
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.

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