Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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