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.

748 lines
22 KiB

  1. #include "stdafx.h"
  2. #include "pubwiz.h"
  3. #include "netplace.h"
  4. #pragma hdrstop
  5. // this code works by building a multi-part post
  6. LARGE_INTEGER g_li0 = {0};
  7. // IStream class that wraps up the multi-part post into a single object.
  8. #define BOUNDARY TEXT("------WindowsPublishWizard")
  9. LPCTSTR c_pszBoundary = (TEXT("--") BOUNDARY);
  10. LPCTSTR c_pszBoundaryEOF = (TEXT("\r\n") TEXT("--") BOUNDARY TEXT("--"));
  11. LPWSTR c_pszContentType = (TEXT("multipart/form-data; boundary=") BOUNDARY);
  12. LPCTSTR c_szFmtContent = (TEXT("content-disposition: form-data; name=\"%s\""));
  13. LPCTSTR c_szFmtFilename = (TEXT("; filename=\"%s\""));
  14. LPCTSTR c_szCRLF = (TEXT("\r\n"));
  15. /* 8c1e9993-7a84-431d-8c03-527f0fb147c5 */
  16. CLSID IID_IPostStream = {0x8c1e9993, 0x7a84, 0x431d, {0x8c, 0x03, 0x52, 0x7f, 0x0f, 0xb1, 0x47, 0xc5}};
  17. DECLARE_INTERFACE_(IPostStream, IStream)
  18. {
  19. // *** IUnknown methods ***
  20. STDMETHOD(QueryInterface) (THIS_ REFIID riid, LPVOID * ppvObj) PURE;
  21. STDMETHOD_(ULONG,AddRef) (THIS) PURE;
  22. STDMETHOD_(ULONG,Release) (THIS) PURE;
  23. // **** IPostStream ****
  24. STDMETHOD(SetTransferSink)(ITransferAdviseSink *ptas, ULONGLONG ulTotal, ULONGLONG ulCurrent);
  25. };
  26. // stream wrapper that expoes the binary data for the file as a multi-part stream object
  27. class CPostStream : public IPostStream
  28. {
  29. public:
  30. CPostStream();
  31. HRESULT Initialize(IStorage *pstg, TRANSFERITEM *pti);
  32. // *** IUnknown methods ***
  33. STDMETHOD(QueryInterface)( REFIID riid, void **ppv);
  34. STDMETHOD_(ULONG,AddRef)();
  35. STDMETHOD_(ULONG,Release)();
  36. // *** IStream methods ***
  37. STDMETHOD(Read)(void *pv, ULONG cb, ULONG *pcbRead);
  38. STDMETHOD(Write)(VOID const *pv, ULONG cb, ULONG *pcbWritten)
  39. { return E_NOTIMPL; }
  40. STDMETHOD(Seek)(LARGE_INTEGER dlibMove, DWORD dwOrigin, ULARGE_INTEGER *plibNewPosition)
  41. { return E_NOTIMPL; }
  42. STDMETHOD(SetSize)(ULARGE_INTEGER libNewSize)
  43. { return E_NOTIMPL; }
  44. STDMETHOD(CopyTo)(IStream *pstm, ULARGE_INTEGER cb, ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten)
  45. { return E_NOTIMPL; }
  46. STDMETHOD(Commit)(DWORD grfCommitFlags)
  47. { return E_NOTIMPL; }
  48. STDMETHOD(Revert)()
  49. { return E_NOTIMPL; }
  50. STDMETHOD(LockRegion)(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
  51. { return E_NOTIMPL; }
  52. STDMETHOD(UnlockRegion)(ULARGE_INTEGER libOffset, ULARGE_INTEGER cb, DWORD dwLockType)
  53. { return E_NOTIMPL; }
  54. STDMETHOD(Stat)(STATSTG *pstatstg, DWORD grfStatFlag);
  55. STDMETHOD(Clone)(IStream **ppstm)
  56. { return E_NOTIMPL; }
  57. STDMETHOD(SetTransferSink)(ITransferAdviseSink *ptas, ULONGLONG ulTotal, ULONGLONG ulCurrent);
  58. protected:
  59. ~CPostStream();
  60. static int s_ReleaseStream(IStream *pstrm, void *pv);
  61. HRESULT _WriteString(IStream *pstrm, LPCTSTR pszString);
  62. HRESULT _WriteStringCRLF(IStream *pstrm, LPCTSTR pszString);
  63. HRESULT _AddBoundaryMarker(IStream *pstrm, BOOL fLeadingCRLF, LPCTSTR pszName, LPCTSTR pszFilename);
  64. HRESULT _AddStream(IStream *pstrm);
  65. HRESULT _CreateMemoryStream(REFIID riid, void **ppv);
  66. LONG _cRef;
  67. IShellItem *_psi;
  68. ITransferAdviseSink *_ptas;
  69. // stream array we use to transfer the bits
  70. CDPA<IStream> _dpaStreams;
  71. int _iCurStream;
  72. // current seek pointers into the stream
  73. ULONGLONG _ulCurrent;
  74. ULONGLONG _ulTotal;
  75. // current seek pointers overal into the transfer
  76. ULONGLONG _ulOverallCurrent;
  77. ULONGLONG _ulOverallTotal;
  78. };
  79. // unknown / qi handler
  80. CPostStream::CPostStream() :
  81. _cRef(1)
  82. {
  83. }
  84. CPostStream::~CPostStream()
  85. {
  86. if (_dpaStreams != NULL)
  87. {
  88. _dpaStreams.DestroyCallback(s_ReleaseStream, this);
  89. _iCurStream = 0;
  90. }
  91. if (_ptas)
  92. _ptas->Release();
  93. }
  94. // handle IUnknown
  95. ULONG CPostStream::AddRef()
  96. {
  97. return InterlockedIncrement(&_cRef);
  98. }
  99. ULONG CPostStream::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 CPostStream::QueryInterface(REFIID riid, void **ppv)
  110. {
  111. static const QITAB qit[] =
  112. {
  113. QITABENT(CPostStream, IStream), // IID_IStream
  114. QITABENT(CPostStream, IPostStream), // IID_IPostStream
  115. { 0 },
  116. };
  117. return QISearch(this, qit, riid, ppv);
  118. }
  119. // handle writing data into a stream for building the post
  120. HRESULT CPostStream::_WriteString(IStream *pstrm, LPCTSTR pszString)
  121. {
  122. // T2A conversion, can we do a UTF8 encode at this point?
  123. USES_CONVERSION;
  124. ULONG cb = lstrlen(pszString) * sizeof(CHAR);
  125. return pstrm->Write(T2A(pszString), cb, NULL);
  126. }
  127. HRESULT CPostStream::_WriteStringCRLF(IStream *pstrm, LPCTSTR pszString)
  128. {
  129. HRESULT hr = _WriteString(pstrm, pszString);
  130. if (SUCCEEDED(hr))
  131. {
  132. hr = _WriteString(pstrm, c_szCRLF);
  133. }
  134. return hr;
  135. }
  136. HRESULT CPostStream::_AddBoundaryMarker(IStream *pstrm, BOOL fLeadingCRLF, LPCTSTR pszName, LPCTSTR pszFilename)
  137. {
  138. HRESULT hr = S_OK;
  139. // add the boundary marker
  140. if (fLeadingCRLF)
  141. hr = _WriteString(pstrm, c_szCRLF);
  142. if (SUCCEEDED(hr))
  143. {
  144. hr = _WriteStringCRLF(pstrm, c_pszBoundary);
  145. if (SUCCEEDED(hr))
  146. {
  147. TCHAR szBuffer[MAX_PATH];
  148. // format up the content disp + name attribute
  149. wnsprintf(szBuffer, ARRAYSIZE(szBuffer), c_szFmtContent, pszName);
  150. hr = _WriteString(pstrm, szBuffer);
  151. // if we have a filename then lets put that into the line also
  152. if (SUCCEEDED(hr) && pszFilename)
  153. {
  154. wnsprintf(szBuffer, ARRAYSIZE(szBuffer), c_szFmtFilename, pszFilename);
  155. hr = _WriteString(pstrm, szBuffer);
  156. }
  157. // finish it off with a CR/LF
  158. if (SUCCEEDED(hr))
  159. {
  160. _WriteString(pstrm, c_szCRLF);
  161. _WriteString(pstrm, c_szCRLF);
  162. }
  163. }
  164. }
  165. return hr;
  166. }
  167. // stream management functions
  168. int CPostStream::s_ReleaseStream(IStream *pstrm, void *pv)
  169. {
  170. pstrm->Release();
  171. return 1;
  172. }
  173. HRESULT CPostStream::_AddStream(IStream *pstrm)
  174. {
  175. HRESULT hr = (-1 == _dpaStreams.AppendPtr(pstrm)) ? E_FAIL:S_OK;
  176. if (SUCCEEDED(hr))
  177. {
  178. pstrm->AddRef();
  179. }
  180. return hr;
  181. }
  182. HRESULT CPostStream::_CreateMemoryStream(REFIID riid, void **ppv)
  183. {
  184. IStream *pstrm = SHCreateMemStream(NULL, 0);
  185. if (!pstrm)
  186. return E_OUTOFMEMORY;
  187. // lets add it to our list and return a refernce if needed
  188. HRESULT hr = _AddStream(pstrm);
  189. if (SUCCEEDED(hr))
  190. {
  191. hr = pstrm->QueryInterface(riid, ppv);
  192. }
  193. pstrm->Release();
  194. return hr;
  195. }
  196. // handle initialising the handler
  197. HRESULT CPostStream::Initialize(IStorage *pstg, TRANSFERITEM *pti)
  198. {
  199. HRESULT hr = pti->psi->QueryInterface(IID_PPV_ARG(IShellItem, &_psi));
  200. if (SUCCEEDED(hr))
  201. {
  202. hr = _dpaStreams.Create(4) ? S_OK:E_FAIL;
  203. if (SUCCEEDED(hr))
  204. {
  205. // first comes the file bits, this consists of two stream:
  206. //
  207. // 1) boundary marker
  208. // 2) file bits (reference to real bits on file system)
  209. IStream *pstrm;
  210. hr = _CreateMemoryStream(IID_PPV_ARG(IStream, &pstrm));
  211. if (SUCCEEDED(hr))
  212. {
  213. hr = _AddBoundaryMarker(pstrm, FALSE, pti->szName, pti->szFilename);
  214. if (SUCCEEDED(hr))
  215. {
  216. IStream *pstrmFile;
  217. // if we are recompressing this stream then apply it accordingly by
  218. // creating an in memory stream that represents the file bits.
  219. if (pti->fResizeOnUpload)
  220. {
  221. IImageRecompress *pir;
  222. hr = CoCreateInstance(CLSID_ImageRecompress, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IImageRecompress, &pir));
  223. if (SUCCEEDED(hr))
  224. {
  225. hr = pir->RecompressImage(_psi, pti->cxResize, pti->cyResize, pti->iQuality, pstg, &pstrmFile);
  226. pir->Release();
  227. }
  228. }
  229. if (!pti->fResizeOnUpload || (hr != S_OK))
  230. hr = _psi->BindToHandler(NULL, BHID_Stream, IID_PPV_ARG(IStream, &pstrmFile));
  231. if (SUCCEEDED(hr))
  232. {
  233. hr = _AddStream(pstrmFile);
  234. pstrmFile->Release();
  235. }
  236. }
  237. pstrm->Release();
  238. }
  239. // now do we have any form data we need to write into the stream?
  240. if (pti->dsaFormData != NULL)
  241. {
  242. for (int iFormData = 0; SUCCEEDED(hr) && (iFormData < pti->dsaFormData.GetItemCount()); iFormData++)
  243. {
  244. FORMDATA *pfd = pti->dsaFormData.GetItemPtr(iFormData);
  245. ASSERT(pfd != NULL);
  246. IStream *pstrm;
  247. hr = _CreateMemoryStream(IID_PPV_ARG(IStream, &pstrm));
  248. if (SUCCEEDED(hr))
  249. {
  250. TCHAR szBuffer[MAX_PATH];
  251. // convert the variants - useful for passing across thread boundary
  252. // to strings and form into a stream.
  253. VariantToStr(&pfd->varName, szBuffer, ARRAYSIZE(szBuffer));
  254. hr = _AddBoundaryMarker(pstrm, TRUE, szBuffer, NULL);
  255. if (SUCCEEDED(hr))
  256. {
  257. VariantToStr(&pfd->varValue, szBuffer, ARRAYSIZE(szBuffer));
  258. hr = _WriteString(pstrm, szBuffer);
  259. }
  260. pstrm->Release();
  261. }
  262. }
  263. }
  264. // write EOF into a stream which will be returned.
  265. if (SUCCEEDED(hr))
  266. {
  267. IStream *pstrm;
  268. hr = _CreateMemoryStream(IID_PPV_ARG(IStream, &pstrm));
  269. if (SUCCEEDED(hr))
  270. {
  271. hr = _WriteStringCRLF(pstrm, c_pszBoundaryEOF);
  272. pstrm->Release();
  273. }
  274. }
  275. // now handle our prep for post, this consists of walking all the streams
  276. // and processing the data.
  277. if (SUCCEEDED(hr))
  278. {
  279. // now get the total for the stream object that we are going to upload to the site
  280. STATSTG ststg;
  281. hr = this->Stat(&ststg, STATFLAG_NONAME);
  282. if (SUCCEEDED(hr))
  283. {
  284. _ulTotal = ststg.cbSize.QuadPart;
  285. }
  286. // seek all the streams to the begining so that we can read from them
  287. for (int iStream = 0; iStream < _dpaStreams.GetPtrCount(); iStream++)
  288. {
  289. IStream *pstrm = _dpaStreams.GetPtr(iStream);
  290. ASSERT(pstrm != NULL);
  291. pstrm->Seek(g_li0, 0, NULL);
  292. }
  293. }
  294. }
  295. }
  296. return hr;
  297. }
  298. HRESULT CPostStream::SetTransferSink(ITransferAdviseSink *ptas, ULONGLONG ulMax, ULONGLONG ulCurrent)
  299. {
  300. _ulOverallTotal = ulMax;
  301. _ulOverallCurrent = ulCurrent;
  302. return ptas->QueryInterface(IID_PPV_ARG(ITransferAdviseSink, &_ptas));
  303. }
  304. // IStream methods
  305. HRESULT CPostStream::Read(void *pv, ULONG cb, ULONG *pcbRead)
  306. {
  307. HRESULT hr = S_OK;
  308. ULONG cbReadTotal = 0;
  309. ULONG cbLeftToRead = cb;
  310. // cancel the stream
  311. if (_ptas && (_ptas->QueryContinue() == S_FALSE))
  312. {
  313. hr = ERROR_CANCELLED;
  314. }
  315. // loop over the streams reading the bits from them
  316. while ((SUCCEEDED(hr) && hr != S_FALSE) && cbLeftToRead && (_iCurStream < _dpaStreams.GetPtrCount()))
  317. {
  318. IStream *pstrm = _dpaStreams.GetPtr(_iCurStream);
  319. ASSERT(pstrm != NULL);
  320. ULONG cbReadThisStream;
  321. hr = pstrm->Read(pv, cbLeftToRead, &cbReadThisStream);
  322. if (SUCCEEDED(hr))
  323. {
  324. cbLeftToRead -= cbReadThisStream;
  325. cbReadTotal += cbReadThisStream;
  326. pv = (char *)pv + cbReadThisStream;
  327. if (cbLeftToRead)
  328. {
  329. _iCurStream++;
  330. hr = S_OK;
  331. }
  332. }
  333. }
  334. // update our seek pointer so we know where we are and notify the progress object
  335. _ulCurrent = min(_ulTotal, (_ulCurrent + cbReadTotal));
  336. _ulOverallCurrent = min(_ulOverallTotal, (_ulOverallCurrent + cbReadTotal));
  337. if (_ptas)
  338. {
  339. _ptas->OperationProgress(STGOP_COPY, NULL, NULL, _ulOverallTotal, _ulOverallCurrent);
  340. _ptas->OperationProgress(STGOP_COPY, _psi, NULL, _ulTotal, _ulCurrent);
  341. }
  342. // write back the count for the caller
  343. if (pcbRead)
  344. *pcbRead = cbReadTotal;
  345. return hr;
  346. }
  347. HRESULT CPostStream::Stat(STATSTG *pstatstg, DWORD grfStatFlag)
  348. {
  349. if (grfStatFlag != STATFLAG_NONAME)
  350. return E_INVALIDARG;
  351. ZeroMemory(pstatstg, sizeof(*pstatstg));
  352. HRESULT hr = S_OK;
  353. for (int iStream = 0 ; SUCCEEDED(hr) && (iStream < _dpaStreams.GetPtrCount()); iStream++)
  354. {
  355. IStream *pstrm = _dpaStreams.GetPtr(iStream);
  356. ASSERT(pstrm != NULL);
  357. STATSTG ststg;
  358. hr = pstrm->Stat(&ststg, STATFLAG_NONAME);
  359. if (SUCCEEDED(hr))
  360. {
  361. pstatstg->cbSize.QuadPart += ststg.cbSize.QuadPart;
  362. }
  363. }
  364. return hr;
  365. }
  366. // create wrapper, this initializes the object and returns a reference to it.
  367. HRESULT CreatePostStream(TRANSFERITEM *pti, IStorage *pstg, IStream **ppstrm)
  368. {
  369. CPostStream *pps = new CPostStream();
  370. if (!pps)
  371. return E_OUTOFMEMORY;
  372. HRESULT hr = pps->Initialize(pstg, pti);
  373. if (SUCCEEDED(hr))
  374. {
  375. hr = pps->QueryInterface(IID_PPV_ARG(IStream, ppstrm));
  376. }
  377. pps->Release();
  378. return hr;
  379. }
  380. // this engine posts the files to the site using the manifest
  381. class CPostThread : public IUnknown
  382. {
  383. public:
  384. CPostThread(TRANSFERINFO *pti);
  385. STDMETHODIMP_(ULONG) AddRef(void);
  386. STDMETHODIMP_(ULONG) Release(void);
  387. STDMETHODIMP QueryInterface(REFIID riid, LPVOID * ppvObj);
  388. HRESULT BeginTransfer(CDPA<TRANSFERITEM> *pdpaItems, ITransferAdviseSink *ptas);
  389. protected:
  390. ~CPostThread();
  391. static DWORD CALLBACK s_ThreadProc(void *pv);
  392. DWORD _ThreadProc();
  393. LONG _cRef;
  394. TRANSFERINFO _ti; // transfer info structure
  395. CDPA<TRANSFERITEM> _dpaItems;
  396. IStream *_pstrmSink;
  397. IStorage *_pstg;
  398. ULONGLONG _ulTotal;
  399. ULONGLONG _ulCurrent;
  400. };
  401. // construction destruction
  402. CPostThread::CPostThread(TRANSFERINFO *pti) :
  403. _cRef(1),
  404. _ti(*pti)
  405. {
  406. DllAddRef();
  407. }
  408. CPostThread::~CPostThread()
  409. {
  410. if (_pstrmSink)
  411. _pstrmSink->Release();
  412. if (_pstg)
  413. _pstg->Release();
  414. _dpaItems.DestroyCallback(_FreeTransferItems, NULL);
  415. DllRelease();
  416. }
  417. ULONG CPostThread::AddRef()
  418. {
  419. return InterlockedIncrement(&_cRef);
  420. }
  421. ULONG CPostThread::Release()
  422. {
  423. ASSERT( 0 != _cRef );
  424. ULONG cRef = InterlockedDecrement(&_cRef);
  425. if ( 0 == cRef )
  426. {
  427. delete this;
  428. }
  429. return cRef;
  430. }
  431. HRESULT CPostThread::QueryInterface(REFIID riid, void **ppv)
  432. {
  433. static const QITAB qit[] =
  434. {
  435. { 0 },
  436. };
  437. return QISearch(this, qit, riid, ppv);
  438. }
  439. // thread which handles the posting of the files to the site we walk the DPA that we
  440. // have and post each individual file.
  441. DWORD CPostThread::s_ThreadProc(void *pv)
  442. {
  443. CPostThread *ppt = (CPostThread*)pv;
  444. return ppt->_ThreadProc();
  445. }
  446. DWORD CPostThread::_ThreadProc()
  447. {
  448. ITransferAdviseSink *ptas;
  449. HRESULT hr = CoGetInterfaceAndReleaseStream(_pstrmSink, IID_PPV_ARG(ITransferAdviseSink, &ptas));
  450. _pstrmSink = NULL;
  451. if (SUCCEEDED(hr))
  452. {
  453. _ulTotal = 0;
  454. _ulCurrent = 0;
  455. // lets create a dyanmic storage that we can use for building the post
  456. // data into, this will be passed to the stream creator to us.
  457. hr = CoCreateInstance(CLSID_DynamicStorage, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IStorage, &_pstg));
  458. // our pre flight sets the global size of the transfer and creates streams for
  459. // the objects we want to move over. now get the advise sink and start
  460. // processing the files.
  461. for (int iItem = 0 ; SUCCEEDED(hr) && (iItem < _dpaItems.GetPtrCount()); iItem++)
  462. {
  463. TRANSFERITEM *pti = _dpaItems.GetPtr(iItem);
  464. hr = SHCreateShellItem(NULL, NULL, pti->pidl, &pti->psi);
  465. if (SUCCEEDED(hr))
  466. {
  467. ptas->PreOperation(STGOP_STATS, pti->psi, NULL);
  468. hr = CreatePostStream(pti, _pstg, &pti->pstrm);
  469. if (SUCCEEDED(hr))
  470. {
  471. hr = pti->pstrm->Stat(&pti->ststg, STATFLAG_NONAME);
  472. if (SUCCEEDED(hr))
  473. {
  474. _ulTotal += pti->ststg.cbSize.QuadPart;
  475. }
  476. }
  477. ptas->PostOperation(STGOP_STATS, pti->psi, NULL, hr);
  478. }
  479. }
  480. for (int iItem = 0 ; SUCCEEDED(hr) && (iItem < _dpaItems.GetPtrCount()); iItem++)
  481. {
  482. TRANSFERITEM *pti = _dpaItems.GetPtr(iItem);
  483. if (ptas->QueryContinue() == S_FALSE)
  484. {
  485. hr = STRESPONSE_CANCEL;
  486. }
  487. if (SUCCEEDED(hr))
  488. {
  489. // notify the object that we are going to transfer
  490. ptas->PreOperation(STGOP_COPY, pti->psi, NULL);
  491. IPostStream *pps;
  492. if (ptas && SUCCEEDED(pti->pstrm->QueryInterface(IID_PPV_ARG(IPostStream, &pps))))
  493. {
  494. pps->SetTransferSink(ptas, _ulTotal, _ulCurrent);
  495. pps->Release();
  496. }
  497. IXMLHttpRequest *preq;
  498. hr = CoCreateInstance(CLSID_XMLHTTPRequest, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARG(IXMLHttpRequest, &preq));
  499. if (SUCCEEDED(hr))
  500. {
  501. VARIANT varNULL = {0};
  502. VARIANT varAsync = {VT_BOOL};
  503. varAsync.boolVal = VARIANT_FALSE;
  504. // open a post request to the destination that we have
  505. hr = preq->open(pti->szVerb, pti->szURL, varAsync, varNULL, varNULL);
  506. if (SUCCEEDED(hr))
  507. {
  508. // set it up to post with a multi-part
  509. hr = preq->setRequestHeader(L"content-type", c_pszContentType);
  510. if (SUCCEEDED(hr))
  511. {
  512. VARIANT varBody = {VT_UNKNOWN};
  513. varBody.punkVal = pti->pstrm;
  514. hr = preq->send(varBody);
  515. if (SUCCEEDED(hr))
  516. {
  517. long lStatus;
  518. hr = preq->get_status(&lStatus);
  519. if (SUCCEEDED(hr))
  520. {
  521. switch (lStatus)
  522. {
  523. case HTTP_STATUS_OK:
  524. case HTTP_STATUS_CREATED:
  525. hr = S_OK;
  526. break;
  527. default:
  528. hr = E_FAIL;
  529. break;
  530. }
  531. }
  532. }
  533. }
  534. }
  535. preq->Release();
  536. }
  537. // notify the site that the transfer is complete
  538. ptas->PostOperation(STGOP_COPY, pti->psi, NULL, hr);
  539. // update our seek pointer for progress
  540. _ulCurrent = min((_ulCurrent + pti->ststg.cbSize.QuadPart), _ulTotal);
  541. }
  542. }
  543. // notify the foreground that the wizard has finished uploading the bits to the site.
  544. PostMessage(_ti.hwnd, PWM_TRANSFERCOMPLETE, 0, (LPARAM)hr);
  545. // if that succeeded then lets try and create a net place that points to the place
  546. // we are uploading the files to. of course we can only do this if they place
  547. // a shortcut entry into the
  548. if (_ti.szLinkTarget[0] && !(_ti.dwFlags & SHPWHF_NONETPLACECREATE))
  549. {
  550. CNetworkPlace np;
  551. if (SUCCEEDED(np.SetTarget(_ti.hwnd, _ti.szLinkTarget, 0x0)))
  552. {
  553. if (_ti.szLinkName[0])
  554. np.SetName(NULL, _ti.szLinkName);
  555. if (_ti.szLinkDesc[0])
  556. np.SetDescription(_ti.szLinkDesc);
  557. np.CreatePlace(_ti.hwnd, FALSE);
  558. }
  559. }
  560. ptas->Release();
  561. }
  562. Release();
  563. return 0L;
  564. }
  565. // handle initializing and kicking off the post thread which will handle the transter of the bits.
  566. HRESULT CPostThread::BeginTransfer(CDPA<TRANSFERITEM> *pdpaItems, ITransferAdviseSink *ptas)
  567. {
  568. _dpaItems.Attach(pdpaItems->Detach()); // we have ownership of the DPA now
  569. HRESULT hr = CoMarshalInterThreadInterfaceInStream(IID_ITransferAdviseSink, ptas, &_pstrmSink);
  570. if (SUCCEEDED(hr))
  571. {
  572. AddRef();
  573. hr = SHCreateThread(s_ThreadProc, this, CTF_INSIST | CTF_COINIT, NULL) ? S_OK:E_FAIL;
  574. if (FAILED(hr))
  575. {
  576. Release();
  577. }
  578. }
  579. return hr;
  580. }
  581. // create the posting object and initialize it
  582. HRESULT PublishViaPost(TRANSFERINFO *pti, CDPA<TRANSFERITEM> *pdpaItems, ITransferAdviseSink *ptas)
  583. {
  584. CPostThread *ppt = new CPostThread(pti);
  585. if (!ppt)
  586. return E_OUTOFMEMORY;
  587. HRESULT hr = ppt->BeginTransfer(pdpaItems, ptas);
  588. ppt->Release();
  589. return hr;
  590. }