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.

567 lines
17 KiB

  1. #include "stdafx.h"
  2. #include "netplace.h"
  3. #include "pubwiz.h"
  4. #pragma hdrstop
  5. // IEnumShellItems - used to expose the transfer list as a set of IShellItems
  6. class CTransferItemEnum : public IEnumShellItems
  7. {
  8. public:
  9. CTransferItemEnum(LPCTSTR pszPath, IStorage *pstg, CDPA<TRANSFERITEM> *_pdpaItems);
  10. ~CTransferItemEnum();
  11. // IUnknown
  12. STDMETHOD(QueryInterface)(REFIID riid, void **ppvObj);
  13. STDMETHOD_(ULONG,AddRef)(void);
  14. STDMETHOD_(ULONG,Release)(void);
  15. STDMETHOD(Next)(ULONG celt, IShellItem **rgelt, ULONG *pceltFetched);
  16. STDMETHOD(Skip)(ULONG celt)
  17. { return S_OK; }
  18. STDMETHOD(Reset)()
  19. { _iItem = 0; return S_OK; }
  20. STDMETHOD(Clone)(IEnumShellItems **ppenum)
  21. { return S_OK; }
  22. private:
  23. long _cRef;
  24. TCHAR _szPath[MAX_PATH];
  25. int _cchPath;
  26. IStorage *_pstg;
  27. CDPA<TRANSFERITEM> *_pdpaItems;
  28. int _iItem;
  29. BOOL _GetNextItem(TRANSFERITEM **ppti);
  30. LPTSTR _GetNextComponent(LPTSTR pszPath);
  31. };
  32. // A IShellItem that represents an IStorage to the copy engine - limited functionality
  33. class CTransferStgItem : public IShellItem
  34. {
  35. public:
  36. CTransferStgItem(LPCTSTR pszPath, int cchName, IStorage *pstg, CDPA<TRANSFERITEM> *pdpaItems);
  37. ~CTransferStgItem();
  38. // IUnknown
  39. STDMETHOD(QueryInterface)(REFIID riid, void **ppvObj);
  40. STDMETHOD_(ULONG,AddRef)(void);
  41. STDMETHOD_(ULONG,Release)(void);
  42. // IShellItem
  43. STDMETHODIMP BindToHandler(IBindCtx *pbc, REFGUID rguidHandler, REFIID riid, void **ppv);
  44. STDMETHODIMP GetParent(IShellItem **ppsi)
  45. { return E_NOTIMPL; }
  46. STDMETHODIMP GetDisplayName(SIGDN sigdnName, LPOLESTR *ppszName);
  47. STDMETHODIMP GetAttributes(SFGAOF sfgaoMask, SFGAOF *psfgaoFlags);
  48. STDMETHODIMP Compare(IShellItem *psi, SICHINTF hint, int *piOrder)
  49. { return E_NOTIMPL; }
  50. private:
  51. long _cRef;
  52. TCHAR _szPath[MAX_PATH];
  53. IStorage *_pstg;
  54. CDPA<TRANSFERITEM> *_pdpaItems;
  55. };
  56. // IShellItem implementation that will return a storage to anybody
  57. // querying it. We generate the in folder name from the path
  58. // we are initialized from, and the attributes are fixed for the items.
  59. CTransferStgItem::CTransferStgItem(LPCTSTR pszPath, int cchName, IStorage *pstg, CDPA<TRANSFERITEM> *pdpaItems) :
  60. _cRef(1), _pstg(pstg), _pdpaItems(pdpaItems)
  61. {
  62. StrCpyN(_szPath, pszPath, (int)min(ARRAYSIZE(_szPath), cchName));
  63. _pstg->AddRef();
  64. }
  65. CTransferStgItem::~CTransferStgItem()
  66. {
  67. _pstg->Release();
  68. }
  69. ULONG CTransferStgItem::AddRef()
  70. {
  71. return InterlockedIncrement(&_cRef);
  72. }
  73. ULONG CTransferStgItem::Release()
  74. {
  75. ASSERT( 0 != _cRef );
  76. ULONG cRef = InterlockedDecrement(&_cRef);
  77. if ( 0 == cRef )
  78. {
  79. delete this;
  80. }
  81. return cRef;
  82. }
  83. HRESULT CTransferStgItem::QueryInterface(REFIID riid, void **ppv)
  84. {
  85. static const QITAB qit[] =
  86. {
  87. QITABENT(CTransferStgItem, IShellItem), // IID_IShellItem
  88. {0, 0 },
  89. };
  90. return QISearch(this, qit, riid, ppv);
  91. }
  92. HRESULT CTransferStgItem::BindToHandler(IBindCtx *pbc, REFGUID rguidHandler, REFIID riid, void **ppv)
  93. {
  94. HRESULT hr = E_UNEXPECTED;
  95. if (rguidHandler == BHID_StorageEnum)
  96. {
  97. CTransferItemEnum *ptie = new CTransferItemEnum(_szPath, _pstg, _pdpaItems);
  98. if (ptie)
  99. {
  100. hr = ptie->QueryInterface(riid, ppv);
  101. ptie->Release();
  102. }
  103. else
  104. {
  105. hr = E_OUTOFMEMORY;
  106. }
  107. }
  108. return hr;
  109. }
  110. HRESULT CTransferStgItem::GetDisplayName(SIGDN sigdnName, LPOLESTR *ppszName)
  111. {
  112. HRESULT hr = E_UNEXPECTED;
  113. if ((sigdnName == SIGDN_PARENTRELATIVEPARSING) ||
  114. (sigdnName == SIGDN_PARENTRELATIVEEDITING) ||
  115. (sigdnName == SIGDN_PARENTRELATIVEFORADDRESSBAR))
  116. {
  117. hr = SHStrDupW(PathFindFileName(_szPath), ppszName);
  118. }
  119. return hr;
  120. }
  121. HRESULT CTransferStgItem::GetAttributes(SFGAOF sfgaoMask, SFGAOF *psfgaoFlags)
  122. {
  123. *psfgaoFlags = SFGAO_STORAGE;
  124. return S_OK;
  125. }
  126. // enumerator, this takes a DPA and returns IShellItems for the streams and
  127. // storages it finds. the storages are contructed dynamically based on
  128. // the destination paths specified.
  129. CTransferItemEnum::CTransferItemEnum(LPCTSTR pszPath, IStorage *pstg, CDPA<TRANSFERITEM> *pdpaItems) :
  130. _cRef(1), _iItem(0), _pstg(pstg), _pdpaItems(pdpaItems)
  131. {
  132. StrCpyN(_szPath, pszPath, ARRAYSIZE(_szPath));
  133. _cchPath = lstrlen(_szPath);
  134. _pstg->AddRef();
  135. }
  136. CTransferItemEnum::~CTransferItemEnum()
  137. {
  138. _pstg->Release();
  139. }
  140. ULONG CTransferItemEnum::AddRef()
  141. {
  142. return InterlockedIncrement(&_cRef);
  143. }
  144. ULONG CTransferItemEnum::Release()
  145. {
  146. ASSERT( 0 != _cRef );
  147. ULONG cRef = InterlockedDecrement(&_cRef);
  148. if ( 0 == cRef )
  149. {
  150. delete this;
  151. }
  152. return cRef;
  153. }
  154. HRESULT CTransferItemEnum::QueryInterface(REFIID riid, void **ppv)
  155. {
  156. static const QITAB qit[] =
  157. {
  158. QITABENT(CTransferItemEnum, IEnumShellItems), // IID_IEnumShellItems
  159. {0, 0 },
  160. };
  161. return QISearch(this, qit, riid, ppv);
  162. }
  163. // next enumerator for the items that we have in the DPA, this works by comparing the root
  164. // that we have against the items in our list. those who match that criteria can then
  165. BOOL CTransferItemEnum::_GetNextItem(TRANSFERITEM **ppti)
  166. {
  167. BOOL fResult = FALSE;
  168. if (_iItem < _pdpaItems->GetPtrCount())
  169. {
  170. TRANSFERITEM *pti = _pdpaItems->GetPtr(_iItem);
  171. if (StrCmpNI(_szPath, pti->szFilename, _cchPath) == 0)
  172. {
  173. *ppti = pti;
  174. fResult = TRUE;
  175. }
  176. _iItem++;
  177. }
  178. return fResult;
  179. }
  180. LPTSTR CTransferItemEnum::_GetNextComponent(LPTSTR pszPath)
  181. {
  182. LPTSTR pszResult = pszPath;
  183. if (*pszResult == TEXT('\\'))
  184. pszResult++;
  185. while (*pszResult && (*pszResult != TEXT('\\')))
  186. pszResult++;
  187. if (*pszResult == TEXT('\\'))
  188. pszResult++;
  189. return pszResult;
  190. }
  191. HRESULT CTransferItemEnum::Next(ULONG celt, IShellItem **rgelt, ULONG *pceltFetched)
  192. {
  193. if (!celt || !rgelt)
  194. return E_INVALIDARG; // fail bad mojo
  195. if (pceltFetched)
  196. *pceltFetched = 0;
  197. HRESULT hr = S_FALSE;
  198. while (SUCCEEDED(hr) && (celt > 0) && (_iItem < _pdpaItems->GetPtrCount()))
  199. {
  200. // we still have some space in the buffer, and we haven't returned all
  201. // the items yet, so we can still itterate over the data set that we have
  202. // we have.
  203. TRANSFERITEM *pti;
  204. if (_GetNextItem(&pti))
  205. {
  206. TCHAR szFilename[MAX_PATH];
  207. StrCpyN(szFilename, pti->szFilename, ARRAYSIZE(szFilename));
  208. // storage or a stream, storages have trailing component names, if we
  209. // dont have that then we can assume its a create and pass out a IShellItem.
  210. LPTSTR pszNextComponent = _GetNextComponent(szFilename+_cchPath);
  211. if (!*pszNextComponent)
  212. {
  213. // create a wrapped shell item so that we can return the compressed
  214. // object back to the caller.
  215. if (!pti->psi)
  216. {
  217. hr = SHCreateShellItem(NULL, NULL, pti->pidl, &pti->psi);
  218. if (SUCCEEDED(hr) && pti->fResizeOnUpload)
  219. {
  220. IImageRecompress *pir;
  221. hr = CoCreateInstance(CLSID_ImageRecompress, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IImageRecompress, &pir));
  222. if (SUCCEEDED(hr))
  223. {
  224. IStream *pstrm;
  225. hr = pir->RecompressImage(pti->psi, pti->cxResize, pti->cyResize, pti->iQuality, _pstg, &pstrm);
  226. if (hr == S_OK)
  227. {
  228. STATSTG stat;
  229. hr = pstrm->Stat(&stat, STATFLAG_DEFAULT);
  230. if (SUCCEEDED(hr))
  231. {
  232. IDynamicStorage *pdstg;
  233. hr = _pstg->QueryInterface(IID_PPV_ARG(IDynamicStorage, &pdstg));
  234. if (SUCCEEDED(hr))
  235. {
  236. IShellItem *psi;
  237. hr = pdstg->BindToItem(stat.pwcsName, IID_PPV_ARG(IShellItem, &psi));
  238. if (SUCCEEDED(hr))
  239. {
  240. IUnknown_Set((IUnknown**)&pti->psi, psi);
  241. }
  242. pdstg->Release();
  243. }
  244. CoTaskMemFree(stat.pwcsName);
  245. }
  246. pstrm->Release();
  247. }
  248. pir->Release();
  249. }
  250. }
  251. }
  252. if (SUCCEEDED(hr))
  253. {
  254. hr = pti->psi->QueryInterface(IID_PPV_ARG(IShellItem, rgelt));
  255. if (SUCCEEDED(hr))
  256. {
  257. rgelt++;
  258. celt--;
  259. if (pceltFetched)
  260. {
  261. (*pceltFetched)++;
  262. }
  263. }
  264. }
  265. }
  266. else
  267. {
  268. // Its a storage, so lets create a dummy IShellItem that represents this
  269. // and pass it to the caller. Then walk forward until we have skipped
  270. // all the items in this storage.
  271. int cchName = (int)(pszNextComponent-szFilename);
  272. CTransferStgItem *ptsi = new CTransferStgItem(szFilename, cchName, _pstg, _pdpaItems);
  273. if (ptsi)
  274. {
  275. hr = ptsi->QueryInterface(IID_PPV_ARG(IShellItem, rgelt++));
  276. if (SUCCEEDED(hr))
  277. {
  278. celt--;
  279. if (pceltFetched)
  280. {
  281. (*pceltFetched)++;
  282. }
  283. }
  284. ptsi->Release();
  285. }
  286. else
  287. {
  288. hr = E_OUTOFMEMORY;
  289. }
  290. // Skip the children of this storage
  291. TRANSFERITEM *ptiNext;
  292. while (_GetNextItem(&ptiNext))
  293. {
  294. if (0 != StrCmpNI(ptiNext->szFilename, szFilename, cchName))
  295. {
  296. _iItem--; // we hit an item that doesn't match the criteria
  297. break;
  298. }
  299. }
  300. }
  301. }
  302. }
  303. return hr;
  304. }
  305. // all this code relates to using the RDR to transfer items to the destination site
  306. // rather than using the manifest to handle the transfer via a HTTP POST.
  307. class CTransferThread : IUnknown
  308. {
  309. public:
  310. CTransferThread();
  311. STDMETHODIMP_(ULONG) AddRef(void);
  312. STDMETHODIMP_(ULONG) Release(void);
  313. STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
  314. HRESULT BeginTransfer(TRANSFERINFO *pti, CDPA<TRANSFERITEM> *pdpaItems, ITransferAdviseSink *ptas);
  315. protected:
  316. ~CTransferThread();
  317. static DWORD CALLBACK s_ThreadProc(void *pv);
  318. DWORD _ThreadProc();
  319. HRESULT _InitSourceEnum(IEnumShellItems **ppesi);
  320. HRESULT _SetProgress(DWORD dwCompleted, DWORD dwTotal);
  321. LONG _cRef;
  322. TRANSFERINFO _ti;
  323. CDPA<TRANSFERITEM> _dpaItems;
  324. IStream *_pstrmSink;
  325. CNetworkPlace _np;
  326. };
  327. // Main transfer thread object, this calls the shell item processor to copy
  328. // items using the manifest we received back from the site.
  329. CTransferThread::CTransferThread() :
  330. _cRef(1)
  331. {
  332. DllAddRef();
  333. }
  334. CTransferThread::~CTransferThread()
  335. {
  336. ATOMICRELEASE(_pstrmSink);
  337. _dpaItems.DestroyCallback(_FreeTransferItems, NULL);
  338. DllRelease();
  339. }
  340. ULONG CTransferThread::AddRef()
  341. {
  342. return InterlockedIncrement(&_cRef);
  343. }
  344. ULONG CTransferThread::Release()
  345. {
  346. ASSERT( 0 != _cRef );
  347. ULONG cRef = InterlockedDecrement(&_cRef);
  348. if ( 0 == cRef )
  349. {
  350. delete this;
  351. }
  352. return cRef;
  353. }
  354. HRESULT CTransferThread::QueryInterface(REFIID riid, void **ppv)
  355. {
  356. static const QITAB qit[] =
  357. {
  358. { 0 },
  359. };
  360. return QISearch(this, qit, riid, ppv);
  361. }
  362. // being the transfer of items, by creating a background thread which handles the upload.
  363. HRESULT CTransferThread::BeginTransfer(TRANSFERINFO *pti, CDPA<TRANSFERITEM> *pdpaItems, ITransferAdviseSink *ptas)
  364. {
  365. _ti = *pti;
  366. _dpaItems.Attach(pdpaItems->Detach()); // we have ownership of the DPA now
  367. HRESULT hr = CoMarshalInterThreadInterfaceInStream(IID_ITransferAdviseSink, ptas, &_pstrmSink);
  368. if (SUCCEEDED(hr))
  369. {
  370. AddRef();
  371. hr = SHCreateThread(s_ThreadProc, this, CTF_INSIST | CTF_COINIT, NULL) ? S_OK:E_FAIL;
  372. if (FAILED(hr))
  373. {
  374. Release();
  375. }
  376. }
  377. return hr;
  378. }
  379. DWORD CALLBACK CTransferThread::s_ThreadProc(void *pv)
  380. {
  381. CTransferThread *pTransfer = (CTransferThread*)pv;
  382. return pTransfer->_ThreadProc();
  383. }
  384. HRESULT CTransferThread::_InitSourceEnum(IEnumShellItems **ppesi)
  385. {
  386. IStorage *pstg;
  387. HRESULT hr = CoCreateInstance(CLSID_DynamicStorage, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IStorage, &pstg));
  388. {
  389. CTransferItemEnum *ptie = new CTransferItemEnum(L"", pstg, &_dpaItems);
  390. if (ptie)
  391. {
  392. hr = ptie->QueryInterface(IID_PPV_ARG(IEnumShellItems, ppesi));
  393. ptie->Release();
  394. }
  395. else
  396. {
  397. hr = E_OUTOFMEMORY;
  398. }
  399. pstg->Release();
  400. }
  401. return hr;
  402. }
  403. DWORD CTransferThread::_ThreadProc()
  404. {
  405. IEnumShellItems *penum =NULL;
  406. HRESULT hr = _InitSourceEnum(&penum);
  407. if (SUCCEEDED(hr))
  408. {
  409. hr = _np.SetTarget(_ti.hwnd, _ti.szFileTarget, NPTF_SILENT|NPTF_VALIDATE);
  410. if (SUCCEEDED(hr))
  411. {
  412. LPITEMIDLIST pidl;
  413. hr = _np.GetIDList(_ti.hwnd, &pidl);
  414. if (SUCCEEDED(hr))
  415. {
  416. IShellItem *psiDest;
  417. hr = SHCreateShellItem(NULL, NULL, pidl, &psiDest);
  418. if (SUCCEEDED(hr))
  419. {
  420. IStorageProcessor *psp;
  421. hr = CoCreateInstance(CLSID_StorageProcessor, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IStorageProcessor, &psp));
  422. if (SUCCEEDED(hr))
  423. {
  424. DWORD dwCookie = 0;
  425. ITransferAdviseSink *ptas;
  426. hr = CoGetInterfaceAndReleaseStream(_pstrmSink, IID_PPV_ARG(ITransferAdviseSink, &ptas));
  427. _pstrmSink = NULL;
  428. if (SUCCEEDED(hr))
  429. {
  430. hr = psp->Advise(ptas, &dwCookie);
  431. ptas->Release();
  432. }
  433. hr = psp->Run(penum, psiDest, STGOP_COPY, STOPT_NOPROGRESSUI);
  434. if (dwCookie)
  435. psp->Unadvise(dwCookie);
  436. psp->Release();
  437. }
  438. psiDest->Release();
  439. }
  440. ILFree(pidl);
  441. }
  442. }
  443. penum->Release();
  444. }
  445. // notify the fg thread that this has happened.
  446. PostMessage(_ti.hwnd, PWM_TRANSFERCOMPLETE, 0, (LPARAM)hr);
  447. // were done transfering the files so lets start to clear up - in particular
  448. // lets attempt to create the net work place.
  449. if (_ti.szLinkTarget[0] && !(_ti.dwFlags & SHPWHF_NONETPLACECREATE))
  450. {
  451. CNetworkPlace np;
  452. if (SUCCEEDED(np.SetTarget(_ti.hwnd, _ti.szLinkTarget, 0x0)))
  453. {
  454. if (_ti.szLinkName[0])
  455. np.SetName(NULL, _ti.szLinkName);
  456. if (_ti.szLinkDesc[0])
  457. np.SetDescription(_ti.szLinkDesc);
  458. np.CreatePlace(_ti.hwnd, FALSE);
  459. }
  460. }
  461. Release();
  462. return 0;
  463. }
  464. // helper to create and initialize the transfer engine
  465. HRESULT PublishViaCopyEngine(TRANSFERINFO *pti, CDPA<TRANSFERITEM> *pdpaItems, ITransferAdviseSink *ptas)
  466. {
  467. CTransferThread *ptt = new CTransferThread();
  468. if (!ptt)
  469. return E_OUTOFMEMORY;
  470. HRESULT hr = ptt->BeginTransfer(pti, pdpaItems, ptas);
  471. ptt->Release();
  472. return hr;
  473. }