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.

1614 lines
45 KiB

  1. /******************************************************************************
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. ProtocolRoot.cpp
  5. Abstract:
  6. This file contains the implementation of the CPAData class, which is
  7. used to specify a single problem area
  8. Revision History:
  9. Davide Massarenti (Dmassare) 07/05/99
  10. created
  11. ******************************************************************************/
  12. #include "stdafx.h"
  13. #include <Debug.h>
  14. /////////////////////////////////////////////////////////////////////////////
  15. // BINDSTATUS_FINDINGRESOURCE 01
  16. // BINDSTATUS_CONNECTING 02
  17. // BINDSTATUS_REDIRECTING 03
  18. // BINDSTATUS_BEGINDOWNLOADDATA 04
  19. // BINDSTATUS_DOWNLOADINGDATA 05
  20. // BINDSTATUS_ENDDOWNLOADDATA 06
  21. // BINDSTATUS_BEGINDOWNLOADCOMPONENTS 07
  22. // BINDSTATUS_INSTALLINGCOMPONENTS 08
  23. // BINDSTATUS_ENDDOWNLOADCOMPONENTS 09
  24. // BINDSTATUS_USINGCACHEDCOPY 10
  25. // BINDSTATUS_SENDINGREQUEST 11
  26. // BINDSTATUS_CLASSIDAVAILABLE 12
  27. // BINDSTATUS_MIMETYPEAVAILABLE 13
  28. // BINDSTATUS_CACHEFILENAMEAVAILABLE 14
  29. // BINDSTATUS_BEGINSYNCOPERATION 15
  30. // BINDSTATUS_ENDSYNCOPERATION 16
  31. // BINDSTATUS_BEGINUPLOADDATA 17
  32. // BINDSTATUS_UPLOADINGDATA 18
  33. // BINDSTATUS_ENDUPLOADDATA 19
  34. // BINDSTATUS_PROTOCOLCLASSID 20
  35. // BINDSTATUS_ENCODING 21
  36. // BINDSTATUS_VERIFIEDMIMETYPEAVAILABLE 22
  37. // BINDSTATUS_CLASSINSTALLLOCATION 23
  38. // BINDSTATUS_DECODING 24
  39. // BINDSTATUS_LOADINGMIMEHANDLER 25
  40. // BINDSTATUS_CONTENTDISPOSITIONATTACH 26
  41. // BINDSTATUS_FILTERREPORTMIMETYPE 27
  42. // BINDSTATUS_CLSIDCANINSTANTIATE 28
  43. // BINDSTATUS_DLLNAMEAVAILABLE 29
  44. // BINDSTATUS_DIRECTBIND 30
  45. // BINDSTATUS_RAWMIMETYPE 31
  46. // BINDSTATUS_PROXYDETECTING 32
  47. /////////////////////////////////////////////////////////////////////////////
  48. static const WCHAR c_szContent [] = L"Content Type";
  49. static const WCHAR c_szSystem [] = L"hcp://system/";
  50. static const WCHAR c_szHelp [] = L"hcp://help/";
  51. static const WCHAR c_szRoot [] = L"hcp://";
  52. static const WCHAR c_szSharedCSS[] = L"hcp://system/css/shared.css";
  53. static const WCHAR c_szSystemDir [] = HC_HELPSET_SUB_SYSTEM L"\\";
  54. static const WCHAR c_szSystemOEMDir[] = HC_HELPSET_SUB_SYSTEM_OEM L"\\";
  55. static const WCHAR c_szVendorDir [] = HC_HELPSET_SUB_VENDORS L"\\";
  56. typedef struct
  57. {
  58. LPCWSTR szPrefix;
  59. int iPrefix;
  60. LPCWSTR szRealSubDir;
  61. bool fRelocate;
  62. bool fCSS;
  63. bool fSkipIfMissing;
  64. } Lookup_Virtual_To_Real;
  65. static const Lookup_Virtual_To_Real c_lookup[] =
  66. {
  67. { c_szSharedCSS, MAXSTRLEN(c_szSharedCSS), NULL , false, true , true },
  68. { c_szHelp , MAXSTRLEN(c_szHelp ), NULL , true , false, false },
  69. ///////////////////////////////////////////////////////////////////////////////////
  70. { c_szSystem , MAXSTRLEN(c_szSystem ), c_szSystemOEMDir, true , false, true }, // First try the OEM directory...
  71. { c_szSystem , MAXSTRLEN(c_szSystem ), c_szSystemDir , true , false, true },
  72. { c_szRoot , MAXSTRLEN(c_szRoot ), c_szVendorDir , true , false, true },
  73. ///////////////////////////////////////////////////////////////////////////////////
  74. { c_szSystem , MAXSTRLEN(c_szSystem ), c_szSystemOEMDir, false, false, true }, // First try the OEM directory...
  75. { c_szSystem , MAXSTRLEN(c_szSystem ), c_szSystemDir , false, false, false },
  76. { c_szRoot , MAXSTRLEN(c_szRoot ), c_szVendorDir , false, false, false }
  77. };
  78. typedef struct
  79. {
  80. LPCWSTR szExt;
  81. LPCWSTR szMIME;
  82. } Lookup_Ext_To_Mime;
  83. static const Lookup_Ext_To_Mime c_lookupMIME[] =
  84. {
  85. { L".htm" , L"text/html" },
  86. { L".html", L"text/html" },
  87. { L".css" , L"text/css" },
  88. { L".xml" , L"text/xml" },
  89. { L".js" , L"application/x-javascript" },
  90. { L".gif" , L"image/gif" },
  91. { L".jpg" , L"image/jpeg" },
  92. { L".bmp" , L"image/bmp" },
  93. };
  94. /////////////////////////////////////////////////////////////////////////////
  95. HRESULT GetMimeFromExt( LPCWSTR pszExt ,
  96. LPWSTR pszMime ,
  97. DWORD cchMime )
  98. {
  99. __HCP_FUNC_ENTRY("::GetMimeFromExt");
  100. HRESULT hr;
  101. MPC::wstring szMime;
  102. bool fFound;
  103. hr = MPC::RegKey_Value_Read( szMime, fFound, pszExt, c_szContent, HKEY_CLASSES_ROOT );
  104. if(SUCCEEDED(hr) && fFound)
  105. {
  106. StringCchCopyW( pszMime, cchMime, szMime.c_str() );
  107. }
  108. else
  109. {
  110. pszMime[0] = L'\0';
  111. for(int i=0; i<ARRAYSIZE(c_lookupMIME); i++)
  112. {
  113. if(!MPC::StrICmp( c_lookupMIME[i].szExt, pszExt ))
  114. {
  115. StringCchCopyW( pszMime, cchMime, c_lookupMIME[i].szMIME );
  116. break;
  117. }
  118. }
  119. }
  120. __HCP_FUNC_EXIT(S_OK);
  121. }
  122. static LPCWSTR UnescapeFileName( CComBSTR& bstrFile ,
  123. LPCWSTR szUrl )
  124. {
  125. WCHAR* rgTmpLarge;
  126. WCHAR rgTmpSmall[MAX_PATH+1];
  127. DWORD dwSize = MAX_PATH;
  128. if(::InternetCanonicalizeUrlW( szUrl, rgTmpSmall, &dwSize, ICU_DECODE | ICU_NO_ENCODE ))
  129. {
  130. bstrFile = rgTmpSmall;
  131. }
  132. else
  133. {
  134. rgTmpLarge = new WCHAR[dwSize+1];
  135. if(rgTmpLarge)
  136. {
  137. if(::InternetCanonicalizeUrlW( szUrl, rgTmpLarge, &dwSize, ICU_DECODE | ICU_NO_ENCODE ))
  138. {
  139. bstrFile = rgTmpLarge;
  140. }
  141. delete [] rgTmpLarge;
  142. }
  143. }
  144. return bstrFile;
  145. }
  146. /////////////////////////////////////////////////////////////////////////////
  147. #ifdef DEBUG_PROTOCOLLEAK
  148. #include <Debug.h>
  149. DEBUG_ProtocolLeak::DEBUG_ProtocolLeak()
  150. {
  151. m_num = 0;
  152. m_numOut = 0;
  153. m_numStart = 0;
  154. m_numComplete = 0;
  155. }
  156. DEBUG_ProtocolLeak::~DEBUG_ProtocolLeak()
  157. {
  158. Iter it;
  159. for(it=m_set.begin(); it != m_set.end(); it++)
  160. {
  161. CHCPProtocol* ptr = *it;
  162. bool fGot = m_setStart .count( ptr ) != 0;
  163. bool fDone = m_setComplete.count( ptr ) != 0;
  164. DebugLog( L"Protocol Leakage: %08x %s %s %s\n", ptr, fGot ? L"STARTED" : L"NOT STARTED", fDone ? L"DONE" : L"RECEIVING", ptr->m_bstrUrlComplete );
  165. }
  166. }
  167. void DEBUG_ProtocolLeak::Add( CHCPProtocol* ptr )
  168. {
  169. DebugLog( L"Protocol Leakage: %08x CREATED %s\n", ptr, ptr->m_bstrUrlComplete );
  170. if(m_set.count( ptr ) != 0)
  171. {
  172. DebugBreak();
  173. }
  174. m_set.insert( ptr ); m_numOut++; m_num++;
  175. }
  176. void DEBUG_ProtocolLeak::Del( CHCPProtocol* ptr )
  177. {
  178. DebugLog( L"Protocol Leakage: %08x RELEASED %s\n", ptr, ptr->m_bstrUrlComplete );
  179. if(m_setStart.erase( ptr ) == 1)
  180. {
  181. m_numStart += 0x10000;
  182. }
  183. if(m_setComplete.erase( ptr ) == 1)
  184. {
  185. m_numComplete += 0x10000;
  186. }
  187. if(m_set.erase( ptr ) == 1)
  188. {
  189. m_numOut--;
  190. }
  191. else
  192. {
  193. DebugBreak();
  194. }
  195. }
  196. void DEBUG_ProtocolLeak::CheckStart( CHCPProtocol* ptr )
  197. {
  198. DebugLog( L"Protocol Leakage: %08x STARTED %s\n", ptr, ptr->m_bstrUrlComplete );
  199. if(m_setStart.count( ptr ) != 0)
  200. {
  201. DebugBreak();
  202. }
  203. m_setStart.insert( ptr ); m_numStart++;
  204. }
  205. void DEBUG_ProtocolLeak::Completed( CHCPProtocol* ptr )
  206. {
  207. DebugLog( L"Protocol Leakage: %08x DONE %s\n", ptr, ptr->m_bstrUrlComplete );
  208. m_setComplete.insert( ptr ); m_numComplete++;
  209. }
  210. static DEBUG_ProtocolLeak leaker;
  211. #endif
  212. CHCPProtocol::CHCPProtocol()
  213. {
  214. #ifdef DEBUG_PROTOCOLLEAK
  215. leaker.Add( this );
  216. #endif
  217. __HCP_FUNC_ENTRY("CHCPProtocol::CHCPProtocol");
  218. m_fDone = false; // bool m_fDone;
  219. m_fReportResult = false; // bool m_fReportResult;
  220. //
  221. m_cbAvailableSize = 0; // DWORD m_cbAvailableSize;
  222. m_cbTotalSize = 0; // DWORD m_cbTotalSize;
  223. //
  224. // CComPtr<IStream> m_pstrmRead;
  225. // CComPtr<IStream> m_pstrmWrite;
  226. //
  227. // CComPtr<IInternetProtocolSink> m_pIProtSink;
  228. // CComPtr<IInternetBindInfo> m_pIBindInfo;
  229. m_grfSTI = 0; // DWORD m_grfSTI;
  230. // BINDINFO m_bindinfo;
  231. m_bindf = 0; // DWORD m_bindf;
  232. //
  233. // CComBSTR m_bstrUrlComplete;
  234. // CComBSTR m_bstrUrlRedirected;
  235. m_pDownloader = NULL; // InnerDownloader* m_pDownloader;
  236. //
  237. m_fRedirected = false; // bool m_fRedirected;
  238. m_fCSS = false; // bool m_fCSS;
  239. m_fBypass = false; // bool m_fBypass;
  240. //
  241. // CComPtr<IInternetProtocol> m_ipiBypass;
  242. //
  243. // CComBSTR m_bstrMimeType;
  244. m_dwContentLength = 0; // DWORD m_dwContentLength;
  245. //
  246. m_hCache = NULL; // HANDLE m_hCache;
  247. m_szCacheFileName[0] = 0; // WCHAR m_szCacheFileName[MAX_PATH];
  248. memset( &m_bindinfo, 0, sizeof( m_bindinfo ) );
  249. m_bindinfo.cbSize = sizeof( m_bindinfo );
  250. }
  251. CHCPProtocol::~CHCPProtocol()
  252. {
  253. #ifdef DEBUG_PROTOCOLLEAK
  254. leaker.Del( this );
  255. #endif
  256. __HCP_FUNC_ENTRY("CHCPProtocol::~CHCPProtocol");
  257. Shutdown();
  258. }
  259. ////////////////////////////////////////////////////////////////////////////////
  260. bool CHCPProtocol::OpenCacheEntry()
  261. {
  262. __HCP_FUNC_ENTRY("CHCPProtocol::OpenCacheEntry");
  263. bool fRes = false;
  264. LPCWSTR szUrl = m_bstrUrlComplete;
  265. LPCWSTR szExt;
  266. if((szExt = wcsrchr( szUrl, '.' ))) szExt++;
  267. CloseCacheEntry( true );
  268. if(::CreateUrlCacheEntryW( szUrl, 0, szExt, m_szCacheFileName, 0) )
  269. {
  270. if(m_szCacheFileName[0])
  271. {
  272. m_hCache = ::CreateFileW( m_szCacheFileName ,
  273. GENERIC_WRITE ,
  274. FILE_SHARE_WRITE | FILE_SHARE_READ, NULL,
  275. CREATE_ALWAYS ,
  276. FILE_ATTRIBUTE_NORMAL , NULL);
  277. if(m_hCache == INVALID_HANDLE_VALUE)
  278. {
  279. m_hCache = NULL;
  280. }
  281. else
  282. {
  283. fRes = true;
  284. }
  285. }
  286. }
  287. __HCP_FUNC_EXIT(fRes);
  288. }
  289. void CHCPProtocol::WriteCacheEntry( /*[in]*/ void *pv ,
  290. /*[in]*/ ULONG cbRead )
  291. {
  292. if(m_hCache && cbRead)
  293. {
  294. DWORD cbWritten;
  295. if(::WriteFile( m_hCache, pv, cbRead, &cbWritten, NULL ) == FALSE || cbRead != cbWritten)
  296. {
  297. CloseCacheEntry( true );
  298. }
  299. }
  300. }
  301. void CHCPProtocol::CloseCacheEntry( /*[in]*/ bool fDelete )
  302. {
  303. if(m_hCache)
  304. {
  305. ::CloseHandle( m_hCache ); m_hCache = NULL;
  306. if(fDelete)
  307. {
  308. ::DeleteUrlCacheEntryW( m_bstrUrlComplete );
  309. }
  310. else
  311. {
  312. WCHAR szHeader[256];
  313. FILETIME ftZero = { 0, 0 };
  314. StringCchPrintfW( szHeader, ARRAYSIZE(szHeader), L"HTTP/1.0 200 OK \r\n Content-Length: %d \r\n Content-Type: %s \r\n\r\n", m_dwContentLength, (BSTR)m_bstrMimeType );
  315. ::CommitUrlCacheEntryW( m_bstrUrlComplete, m_szCacheFileName,
  316. ftZero, ftZero, NORMAL_CACHE_ENTRY,
  317. szHeader, wcslen( szHeader ), NULL, 0 );
  318. }
  319. }
  320. }
  321. ////////////////////////////////////////////////////////////////////////////////
  322. HRESULT CHCPProtocol::InnerReportProgress( /*[in]*/ ULONG ulStatusCode ,
  323. /*[in]*/ LPCWSTR szStatusText )
  324. {
  325. __HCP_FUNC_ENTRY("CHCPProtocol::InnerReportProgress");
  326. HRESULT hr;
  327. if(m_pIProtSink)
  328. {
  329. __MPC_EXIT_IF_METHOD_FAILS(hr, m_pIProtSink->ReportProgress( ulStatusCode, szStatusText ));
  330. }
  331. hr = S_OK;
  332. __HCP_FUNC_CLEANUP;
  333. __HCP_FUNC_EXIT(hr);
  334. }
  335. HRESULT CHCPProtocol::InnerReportData( /*[in]*/ DWORD grfBSCF ,
  336. /*[in]*/ ULONG ulProgress ,
  337. /*[in]*/ ULONG ulProgressMax )
  338. {
  339. __HCP_FUNC_ENTRY("CHCPProtocol::InnerReportData");
  340. HRESULT hr;
  341. if(m_pIProtSink)
  342. {
  343. __MPC_EXIT_IF_METHOD_FAILS(hr, m_pIProtSink->ReportData( grfBSCF, ulProgress, ulProgressMax ));
  344. }
  345. //
  346. // On the last data notification, also send a ReportResult.
  347. //
  348. if(grfBSCF & BSCF_LASTDATANOTIFICATION)
  349. {
  350. __MPC_EXIT_IF_METHOD_FAILS(hr, InnerReportResult( S_OK, 0, 0 ));
  351. }
  352. hr = S_OK;
  353. __HCP_FUNC_CLEANUP;
  354. __HCP_FUNC_EXIT(hr);
  355. }
  356. HRESULT CHCPProtocol::InnerReportResult( /*[in]*/ HRESULT hrResult ,
  357. /*[in]*/ DWORD dwError ,
  358. /*[in]*/ LPCWSTR szResult )
  359. {
  360. __HCP_FUNC_ENTRY("CHCPProtocol::InnerReportResult");
  361. HRESULT hr;
  362. if(m_fReportResult == false)
  363. {
  364. m_fReportResult = true;
  365. #ifdef DEBUG_PROTOCOLLEAK
  366. leaker.Completed( this );
  367. #endif
  368. DEBUG_AppendPerf( DEBUG_PERF_PROTOCOL, L"CHCPProtocol::InnerReportResult : %s", SAFEBSTR( m_bstrUrlComplete ) );
  369. if(m_pIProtSink)
  370. {
  371. __MPC_EXIT_IF_METHOD_FAILS(hr, m_pIProtSink->ReportResult( hrResult, dwError, szResult ));
  372. }
  373. //
  374. // Release the references to the ProtSink and BindInfo objects, but not the references to the streams.
  375. //
  376. Shutdown( false );
  377. }
  378. hr = S_OK;
  379. __HCP_FUNC_CLEANUP;
  380. __HCP_FUNC_EXIT(hr);
  381. }
  382. ////////////////////////////////////////////////////////////////////////////////
  383. void CHCPProtocol::Shutdown( /*[in]*/ bool fAll )
  384. {
  385. __HCP_FUNC_ENTRY("CHCPProtocol::Shutdown");
  386. m_pIBindInfo.Release();
  387. m_pIProtSink.Release();
  388. CloseCacheEntry( true );
  389. if(m_pDownloader)
  390. {
  391. m_pDownloader->Release();
  392. m_pDownloader = NULL;
  393. }
  394. if(fAll)
  395. {
  396. m_pstrmRead .Release();
  397. m_pstrmWrite.Release();
  398. // Release BINDINFO contents
  399. ::ReleaseBindInfo( &m_bindinfo );
  400. }
  401. }
  402. /////////////////////////////////////////////////////////////////////////////
  403. STDMETHODIMP CHCPProtocol::Start( /*[in]*/ LPCWSTR szUrl ,
  404. /*[in]*/ IInternetProtocolSink *pIProtSink ,
  405. /*[in]*/ IInternetBindInfo *pIBindInfo ,
  406. /*[in]*/ DWORD grfSTI ,
  407. /*[in]*/ HANDLE_PTR dwReserved )
  408. {
  409. #ifdef DEBUG_PROTOCOLLEAK
  410. leaker.CheckStart( this );
  411. #endif
  412. __HCP_FUNC_ENTRY("CHCPProtocol::Start");
  413. HRESULT hr;
  414. DEBUG_AppendPerf( DEBUG_PERF_PROTOCOL, L"CHCPProtocol::Start : %s", szUrl );
  415. //
  416. // Initialize variables for new download.
  417. //
  418. Shutdown();
  419. m_fDone = false;
  420. m_cbAvailableSize = 0;
  421. m_cbTotalSize = 0;
  422. m_pIProtSink = pIProtSink;
  423. m_pIBindInfo = pIBindInfo;
  424. m_grfSTI = grfSTI;
  425. m_bstrUrlComplete = (LPCOLESTR)NULL;
  426. m_bstrUrlRedirected = (LPCOLESTR)NULL;
  427. //
  428. // Get URLMoniker BINDINFO structure from IInternetBindInfo
  429. //
  430. m_bindinfo.cbSize = sizeof( m_bindinfo );
  431. if(pIBindInfo)
  432. {
  433. __MPC_EXIT_IF_METHOD_FAILS(hr, pIBindInfo->GetBindInfo( &m_bindf, &m_bindinfo ));
  434. }
  435. // Parse URL and store results inside
  436. hr = DoParse( szUrl );
  437. if(grfSTI & PI_PARSE_URL)
  438. {
  439. if(FAILED(hr))
  440. {
  441. __MPC_SET_ERROR_AND_EXIT(hr, S_FALSE);
  442. }
  443. else
  444. {
  445. __MPC_SET_ERROR_AND_EXIT(hr, S_OK);
  446. }
  447. }
  448. if(FAILED(hr)) __MPC_FUNC_LEAVE;
  449. // TODO: We could always spawn a worker thread to be more truly asynchronous.
  450. // Rather than complicate this code as multithreading scenarios tend to do,
  451. // we do everything on the main apartment thread and only pretend to be
  452. // working on a secondary thread if we get PI_FORCE_ASYNC
  453. if(!(grfSTI & PI_FORCE_ASYNC))
  454. {
  455. __MPC_EXIT_IF_METHOD_FAILS(hr, DoBind());
  456. }
  457. else // Wait for Continue to DoBind()
  458. {
  459. PROTOCOLDATA protdata;
  460. hr = E_PENDING;
  461. protdata.grfFlags = PI_FORCE_ASYNC;
  462. protdata.dwState = 1;
  463. protdata.pData = NULL;
  464. protdata.cbData = 0;
  465. // TODO: Actually, we should spawn a new worker thread and have it do the
  466. // bind process, then when done, it could use Switch / Continue to
  467. // pass data back to the apartment thread
  468. if(m_pIProtSink)
  469. {
  470. m_pIProtSink->Switch( &protdata );
  471. }
  472. else
  473. {
  474. __MPC_SET_ERROR_AND_EXIT(hr, E_INVALIDARG);
  475. }
  476. }
  477. __HCP_FUNC_CLEANUP;
  478. if(FAILED(hr))
  479. {
  480. (void)InnerReportResult( hr, 0, 0 );
  481. }
  482. __HCP_FUNC_EXIT(hr);
  483. }
  484. STDMETHODIMP CHCPProtocol::Continue( /*[in]*/ PROTOCOLDATA *pStateInfo )
  485. {
  486. __HCP_FUNC_ENTRY("CHCPProtocol::Continue");
  487. HRESULT hr;
  488. if(m_fBypass)
  489. {
  490. __MPC_SET_ERROR_AND_EXIT(hr, m_ipiBypass->Continue( pStateInfo ));
  491. }
  492. // We're faking what it would be like to have a worker thread
  493. // communicating with the apartment thread
  494. // If we really did spawn off a worker thread, we should do the
  495. // bind there, and just use Switch/Continue to echo UI data back
  496. // to this thread
  497. if(pStateInfo->dwState == 1)
  498. {
  499. __MPC_SET_ERROR_AND_EXIT(hr, DoBind());
  500. }
  501. hr = S_OK;
  502. __HCP_FUNC_CLEANUP;
  503. __HCP_FUNC_EXIT(hr);
  504. }
  505. STDMETHODIMP CHCPProtocol::Abort( /*[in]*/ HRESULT hrReason ,
  506. /*[in]*/ DWORD dwOptions )
  507. {
  508. __HCP_FUNC_ENTRY("CHCPProtocol::Abort");
  509. HRESULT hr = E_FAIL;
  510. if(m_fBypass)
  511. {
  512. __MPC_EXIT_IF_METHOD_FAILS(hr, m_ipiBypass->Abort( hrReason, dwOptions ));
  513. }
  514. // Stop our own internal download process
  515. // TODO: If we call Abort too early on the Binding object,
  516. // this won't abort the download. (Too early is OnStartBinding
  517. // or before.) We won't bother checking, though, for clarity.
  518. // TODO: Make sure we set m_pDownloader to NULL when the
  519. // downloader object is destructed or finished.
  520. if(m_pDownloader)
  521. {
  522. m_pDownloader->Abort();
  523. }
  524. if(SUCCEEDED(hrReason)) // Possibly Abort could get called with 0?
  525. {
  526. hrReason = E_ABORT;
  527. }
  528. // Notify Sink of abort
  529. __MPC_EXIT_IF_METHOD_FAILS(hr, InnerReportResult( hrReason, 0, 0 ));
  530. hr = S_OK;
  531. __HCP_FUNC_CLEANUP;
  532. __HCP_FUNC_EXIT(hr);
  533. }
  534. STDMETHODIMP CHCPProtocol::Terminate( /*[in]*/ DWORD dwOptions )
  535. {
  536. __HCP_FUNC_ENTRY("CHCPProtocol::Terminate");
  537. HRESULT hr;
  538. if(m_fBypass)
  539. {
  540. (void)m_ipiBypass->Terminate( dwOptions );
  541. }
  542. hr = S_OK;
  543. __HCP_FUNC_EXIT(hr);
  544. }
  545. STDMETHODIMP CHCPProtocol::Suspend()
  546. {
  547. __HCP_FUNC_ENTRY("CHCPProtocol::Suspend");
  548. if(m_fBypass)
  549. {
  550. (void)m_ipiBypass->Suspend();
  551. }
  552. __HCP_FUNC_EXIT(E_NOTIMPL);
  553. }
  554. STDMETHODIMP CHCPProtocol::Resume()
  555. {
  556. __HCP_FUNC_ENTRY("CHCPProtocol::Resume");
  557. if(m_fBypass)
  558. {
  559. (void)m_ipiBypass->Resume();
  560. }
  561. __HCP_FUNC_EXIT(E_NOTIMPL);
  562. }
  563. // IInternetProtocol methods
  564. STDMETHODIMP CHCPProtocol::Read( /*[in] */ void *pv ,
  565. /*[in] */ ULONG cb ,
  566. /*[out]*/ ULONG *pcbRead )
  567. {
  568. __HCP_FUNC_ENTRY("CHCPProtocol::Read");
  569. HRESULT hr = S_OK;
  570. DEBUG_AppendPerf( DEBUG_PERF_PROTOCOL_READ, L"CHCPProtocolRoot::Read : Enter %s %d", SAFEBSTR( m_bstrUrlComplete ), (int)cb );
  571. if(m_fBypass)
  572. {
  573. __MPC_SET_ERROR_AND_EXIT(hr, m_ipiBypass->Read( pv, cb, pcbRead ));
  574. }
  575. if(m_pstrmRead == 0)
  576. {
  577. __MPC_SET_ERROR_AND_EXIT(hr, S_FALSE); // We've hit the end of the road, jack
  578. }
  579. // One might expect URLMON to Read only the amount of data that we specified we have.
  580. // However, it actually reads in blocks and will go far beyond the data we have
  581. // specified unless we slap it around a little.
  582. // We must only return S_FALSE when we have hit the absolute end of the stream
  583. // If we think there is more data coming down the wire, then we return E_PENDING
  584. // here. Even if we return S_OK and no data, URLMON will still think we've hit
  585. // the end of the stream.
  586. // ASSERTION: End of data means we've received BSCF_LASTDATANOTIFICATION
  587. __MPC_EXIT_IF_METHOD_FAILS(hr, m_pstrmRead->Read( pv, cb, pcbRead ));
  588. if(hr == S_FALSE)
  589. {
  590. CloseCacheEntry( false );
  591. __MPC_SET_ERROR_AND_EXIT(hr, S_FALSE); // We've hit the end of the road, jack
  592. }
  593. else if(*pcbRead == 0)
  594. {
  595. if(m_fDone)
  596. {
  597. CloseCacheEntry( false );
  598. __MPC_SET_ERROR_AND_EXIT(hr, S_FALSE); // We've hit the end of the road, jack
  599. }
  600. else
  601. {
  602. __MPC_SET_ERROR_AND_EXIT(hr, E_PENDING);
  603. }
  604. }
  605. else
  606. {
  607. WriteCacheEntry( pv, *pcbRead );
  608. }
  609. hr = S_OK;
  610. __HCP_FUNC_CLEANUP;
  611. __HCP_FUNC_EXIT(hr);
  612. }
  613. STDMETHODIMP CHCPProtocol::Seek( /*[in] */ LARGE_INTEGER dlibMove ,
  614. /*[in] */ DWORD dwOrigin ,
  615. /*[out]*/ ULARGE_INTEGER *plibNewPosition )
  616. {
  617. __HCP_FUNC_ENTRY("CHCPProtocol::Seek");
  618. if(m_fBypass)
  619. {
  620. (void)m_ipiBypass->Seek( dlibMove, dwOrigin, plibNewPosition );
  621. }
  622. __HCP_FUNC_EXIT(E_NOTIMPL);
  623. }
  624. STDMETHODIMP CHCPProtocol::LockRequest( /*[in]*/ DWORD dwOptions )
  625. {
  626. __HCP_FUNC_ENTRY("CHCPProtocol::LockRequest");
  627. if(m_fBypass)
  628. {
  629. (void)m_ipiBypass->LockRequest( dwOptions );
  630. }
  631. __HCP_FUNC_EXIT(S_OK);
  632. }
  633. STDMETHODIMP CHCPProtocol::UnlockRequest()
  634. {
  635. __HCP_FUNC_ENTRY("CHCPProtocol::UnlockRequest");
  636. if(m_fBypass)
  637. {
  638. (void)m_ipiBypass->UnlockRequest();
  639. }
  640. //
  641. // Release all the pointers to objects.
  642. //
  643. Shutdown();
  644. __HCP_FUNC_EXIT(S_OK);
  645. }
  646. ////////////////////////////////////////////////////////////////////////////////
  647. STDMETHODIMP CHCPProtocol::QueryOption( DWORD dwOption, LPVOID pBuffer, DWORD *pcbBuf )
  648. {
  649. __HCP_FUNC_ENTRY( "CHCPProtocol::QueryOption" );
  650. HRESULT hr;
  651. if(dwOption == INTERNET_OPTION_REQUEST_FLAGS && *pcbBuf == sizeof(DWORD))
  652. {
  653. *((DWORD*)pBuffer) = INTERNET_REQFLAG_FROM_CACHE;
  654. hr = S_OK;
  655. }
  656. else
  657. {
  658. hr = E_NOTIMPL;
  659. }
  660. __HCP_FUNC_EXIT(hr);
  661. }
  662. /////////////////////////////////////////////////////////////////////////////
  663. bool CHCPProtocol::IsHCPRedirection( /*[in]*/ LPCWSTR szURL )
  664. {
  665. __HCP_FUNC_ENTRY("CHCPProtocol::IsHCPRedirection");
  666. CComBSTR bstrURLCopy;
  667. LPCWSTR szURLCopy = ::UnescapeFileName( bstrURLCopy, szURL ); if(!szURLCopy) return false;
  668. // Check if hcp://system/ or hcp://help/
  669. if ( !_wcsnicmp( szURLCopy, c_szSystem, wcslen(c_szSystem)) ||
  670. !_wcsnicmp( szURLCopy, c_szHelp, wcslen(c_szHelp)) )
  671. {
  672. return false;
  673. }
  674. // Not hcp://system/ or hcp://help/, check if it's hcp://<vendor>/
  675. bool bRedir = true;
  676. for(int i=0; i<2; i++)
  677. {
  678. // Extract vendor name
  679. LPCWSTR szVendor = szURLCopy + wcslen(c_szRoot);
  680. LPCWSTR szVendorEnd = wcschr(szVendor, L'/');
  681. int nVendorLen = szVendorEnd ? szVendorEnd - szVendor : wcslen(szVendor);
  682. // Construct vendor dir
  683. MPC::wstring strDir = i == 0 ? CHCPProtocolEnvironment::s_GLOBAL->System() : HC_HELPSET_ROOT;
  684. strDir += c_szVendorDir;
  685. MPC::SubstituteEnvVariables( strDir );
  686. strDir.append(szVendor, nVendorLen);
  687. if (MPC::FileSystemObject::IsDirectory(strDir.c_str()))
  688. {
  689. // Is a valid vendor dir, no redirection
  690. bRedir = false;
  691. break;
  692. }
  693. }
  694. return bRedir;
  695. }
  696. /////////////////////////////////////////////////////////////////////////////
  697. HRESULT CHCPProtocol::DoParse( /*[in]*/ LPCWSTR szURL )
  698. {
  699. __HCP_FUNC_ENTRY("CHCPProtocol::DoParse");
  700. HRESULT hr;
  701. CComBSTR bstrURLCopy;
  702. LPCWSTR szURLCopy;
  703. LPWSTR szQuery;
  704. LPCWSTR szRedirect;
  705. bool fHCP;
  706. m_bstrUrlComplete = szURL;
  707. m_bstrUrlRedirected = (LPCOLESTR)NULL;
  708. fHCP = CHCPProtocolInfo::LookForHCP( szURL, m_fRedirected, szRedirect );
  709. m_fRedirected = false; // redirection should never happen here
  710. if(m_fRedirected)
  711. {
  712. m_bstrUrlRedirected = szRedirect;
  713. }
  714. else
  715. {
  716. const Lookup_Virtual_To_Real* ptr;
  717. int i;
  718. MPC::wstring strDir;
  719. LPOLESTR szTmp;
  720. szURLCopy = ::UnescapeFileName( bstrURLCopy, szURL ); if(!szURLCopy) __MPC_SET_ERROR_AND_EXIT(hr, E_OUTOFMEMORY);
  721. //
  722. // Remove the query part of the URL.
  723. //
  724. if(szQuery = wcschr( szURLCopy, L'?' ))
  725. {
  726. szQuery[0] = 0;
  727. }
  728. //
  729. // Do the mapping between virtual paths and real ones.
  730. //
  731. for(ptr=c_lookup, i=0; i<ARRAYSIZE(c_lookup); i++, ptr++)
  732. {
  733. if(!_wcsnicmp( szURLCopy, ptr->szPrefix, ptr->iPrefix ))
  734. {
  735. if(ptr->fCSS)
  736. {
  737. m_bstrUrlRedirected = szURL;
  738. m_fCSS = true;
  739. break;
  740. }
  741. if(!ptr->szRealSubDir)
  742. {
  743. strDir = ptr->fRelocate ? CHCPProtocolEnvironment::s_GLOBAL->HelpLocation() : HC_HELPSVC_HELPFILES_DEFAULT;
  744. strDir += L"\\";
  745. }
  746. else
  747. {
  748. strDir = ptr->fRelocate ? CHCPProtocolEnvironment::s_GLOBAL->System() : HC_HELPSET_ROOT;
  749. strDir += ptr->szRealSubDir;
  750. }
  751. MPC::SubstituteEnvVariables( strDir );
  752. m_bstrUrlRedirected = strDir.c_str();
  753. m_bstrUrlRedirected += &szURLCopy[ ptr->iPrefix ];
  754. //
  755. // Convert the slashes to backslashes.
  756. //
  757. while((szTmp = wcschr( m_bstrUrlRedirected, L'/' ))) szTmp[0] = L'\\';
  758. //
  759. // Remove any trailing slash.
  760. //
  761. while((szTmp = wcsrchr( m_bstrUrlRedirected, L'/' )) && szTmp[1] == 0) szTmp[0] = 0;
  762. while((szTmp = wcsrchr( m_bstrUrlRedirected, L'\\' )) && szTmp[1] == 0) szTmp[0] = 0;
  763. CHCPProtocolEnvironment::s_GLOBAL->ReformatURL( m_bstrUrlRedirected );
  764. if(ptr->fSkipIfMissing && MPC::FileSystemObject::IsFile( m_bstrUrlRedirected ) == false) continue;
  765. break;
  766. }
  767. }
  768. }
  769. if(!m_bstrUrlRedirected) __MPC_SET_ERROR_AND_EXIT(hr, E_OUTOFMEMORY);
  770. hr = S_OK;
  771. __HCP_FUNC_CLEANUP;
  772. __HCP_FUNC_EXIT(hr);
  773. }
  774. HRESULT CHCPProtocol::DoBind()
  775. {
  776. __HCP_FUNC_ENTRY("CHCPProtocol::DoBind");
  777. HRESULT hr;
  778. __MPC_EXIT_IF_METHOD_FAILS(hr, InnerReportProgress( BINDSTATUS_FINDINGRESOURCE, SAFEBSTR( m_bstrUrlRedirected ) ));
  779. if(m_fRedirected)
  780. {
  781. if(MPC::MSITS::IsCHM( SAFEBSTR( m_bstrUrlRedirected ) ))
  782. {
  783. __MPC_EXIT_IF_METHOD_FAILS(hr, DoBind_Redirect_MSITS());
  784. }
  785. else
  786. {
  787. __MPC_EXIT_IF_METHOD_FAILS(hr, DoBind_Redirect_UrlMoniker());
  788. }
  789. }
  790. else if(m_fCSS)
  791. {
  792. __MPC_EXIT_IF_METHOD_FAILS(hr, DoBind_CSS());
  793. }
  794. else
  795. {
  796. MPC::wstring szPage = SAFEBSTR(m_bstrUrlRedirected);
  797. MPC::FileSystemObject fso = szPage.c_str();
  798. bool fFound;
  799. bool fIsAFile;
  800. __MPC_EXIT_IF_METHOD_FAILS(hr, DoBind_Exists( fso, fFound, fIsAFile ));
  801. if(fFound && fIsAFile)
  802. {
  803. //
  804. // The file exists, so load its content.
  805. //
  806. __MPC_EXIT_IF_METHOD_FAILS(hr, DoBind_File());
  807. }
  808. else
  809. {
  810. //
  811. // The file, as is, doesn't exist, so try to find a .chm on the path.
  812. //
  813. while(1)
  814. {
  815. MPC::wstring szParent;
  816. MPC::wstring szCHM;
  817. __MPC_EXIT_IF_METHOD_FAILS(hr, fso.get_Parent( szParent ));
  818. if(szParent.length() == 0)
  819. {
  820. //
  821. // No parent, so exit with error.
  822. //
  823. __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
  824. }
  825. //
  826. // Point the FileSystemObject to its parent.
  827. //
  828. fso = szParent.c_str();
  829. __MPC_EXIT_IF_METHOD_FAILS(hr, DoBind_Exists( fso, fFound, fIsAFile ));
  830. //
  831. // Parent exists, so it cannot exist a .CHM file. Exit with error.
  832. //
  833. if(fFound)
  834. {
  835. __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
  836. }
  837. //
  838. // Add the .CHM extension and look for it.
  839. //
  840. szCHM = szParent; szCHM.append( L".chm" );
  841. fso = szCHM.c_str();
  842. __MPC_EXIT_IF_METHOD_FAILS(hr, DoBind_Exists( fso, fFound, fIsAFile ));
  843. //
  844. // No .CHM file, recurse up to the root.
  845. //
  846. if(fFound == false)
  847. {
  848. continue;
  849. }
  850. //
  851. // The .CHM is not a file, exit with error.
  852. //
  853. if(fIsAFile == false)
  854. {
  855. __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
  856. }
  857. //
  858. // Found, so redirect to the proper protocol.
  859. //
  860. szCHM = L"ms-its:";
  861. szCHM.append( szParent );
  862. szCHM.append( L".chm" );
  863. if(szParent.length() < szPage.length())
  864. {
  865. LPWSTR szBuf = new WCHAR[szPage.length()+1];
  866. if(szBuf)
  867. {
  868. LPWSTR szTmp;
  869. StringCchCopyW( szBuf, szPage.length()+1, szPage.c_str() );
  870. //
  871. // Convert the backslashes to slashes.
  872. //
  873. while(szTmp = wcschr( szBuf, L'\\' )) szTmp[0] = L'/';
  874. szCHM.append( L"::" );
  875. szCHM.append( &szBuf[szParent.length()] );
  876. delete [] szBuf;
  877. }
  878. }
  879. m_bstrUrlRedirected = szCHM.c_str();
  880. __MPC_EXIT_IF_METHOD_FAILS(hr, DoBind_Redirect_MSITS());
  881. break;
  882. }
  883. }
  884. }
  885. hr = S_OK;
  886. __HCP_FUNC_CLEANUP;
  887. __HCP_FUNC_EXIT(hr);
  888. }
  889. HRESULT CHCPProtocol::DoBind_Exists( /*[in] */ MPC::FileSystemObject& fso ,
  890. /*[out]*/ bool& fFound ,
  891. /*[out]*/ bool& fIsAFile )
  892. {
  893. __HCP_FUNC_ENTRY("CHCPProtocol::DoBind_Exists");
  894. HRESULT hr;
  895. if(fso.Exists())
  896. {
  897. fFound = true;
  898. fIsAFile = fso.IsFile();
  899. }
  900. else
  901. {
  902. fFound = false;
  903. fIsAFile = false;
  904. }
  905. hr = S_OK;
  906. __HCP_FUNC_EXIT(hr);
  907. }
  908. HRESULT CHCPProtocol::DoBind_Redirect_UrlMoniker()
  909. {
  910. __HCP_FUNC_ENTRY("CHCPProtocol::DoBind_Redirect_UrlMoniker");
  911. HRESULT hr;
  912. //
  913. // Create the stream used to receive downloaded data.
  914. //
  915. ::CreateStreamOnHGlobal( NULL, TRUE, &m_pstrmWrite );
  916. if(m_pstrmWrite == NULL)
  917. {
  918. __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
  919. }
  920. //
  921. // Create the downloader object.
  922. //
  923. if(SUCCEEDED(hr = m_pDownloader->CreateInstance( &m_pDownloader )))
  924. {
  925. m_pDownloader->AddRef();
  926. if(FAILED(hr = m_pDownloader->StartAsyncDownload( this, m_bstrUrlRedirected, NULL, FALSE )))
  927. {
  928. if(hr != E_PENDING) __MPC_FUNC_LEAVE;
  929. }
  930. }
  931. hr = S_OK;
  932. __HCP_FUNC_CLEANUP;
  933. __HCP_FUNC_EXIT(hr);
  934. }
  935. HRESULT CHCPProtocol::DoBind_Redirect_MSITS()
  936. {
  937. __HCP_FUNC_ENTRY("CHCPProtocol::DoBind_Redirect_MSITS");
  938. HRESULT hr;
  939. CComBSTR bstrStorageName;
  940. CComBSTR bstrFilePath;
  941. LPCWSTR szExt;
  942. WCHAR rgMime[MAX_PATH];
  943. if(MPC::MSITS::IsCHM( SAFEBSTR( m_bstrUrlRedirected ), &bstrStorageName, &bstrFilePath ) == false)
  944. {
  945. __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
  946. }
  947. //
  948. // Try to find the Mime Type for this file.
  949. //
  950. if((szExt = wcsrchr( bstrFilePath, L'.' )))
  951. {
  952. ::GetMimeFromExt( szExt, rgMime, MAX_PATH-1 );
  953. }
  954. else
  955. {
  956. rgMime[0] = 0;
  957. }
  958. //
  959. // Extract the file from the CHM.
  960. //
  961. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::MSITS::OpenAsStream( bstrStorageName, bstrFilePath, &m_pstrmRead ));
  962. //
  963. // Signal the Protocol Sink that data is available.
  964. //
  965. __MPC_EXIT_IF_METHOD_FAILS(hr, DoBind_ReturnData( /*fCloneStream*/false, szExt ? rgMime : NULL ));
  966. hr = S_OK;
  967. __HCP_FUNC_CLEANUP;
  968. __HCP_FUNC_EXIT(hr);
  969. }
  970. HRESULT CHCPProtocol::DoBind_CSS()
  971. {
  972. __HCP_FUNC_ENTRY("CHCPProtocol::DoBind_CSS");
  973. HRESULT hr;
  974. LPCWSTR szExt;
  975. WCHAR rgMime[256];
  976. //
  977. // Try to find the Mime Type for this file.
  978. //
  979. if((szExt = wcsrchr( m_bstrUrlComplete, L'.' )))
  980. {
  981. ::GetMimeFromExt( szExt, rgMime, 255 );
  982. }
  983. __MPC_EXIT_IF_METHOD_FAILS(hr, CHCPProtocolEnvironment::s_GLOBAL->GetCSS( m_pstrmRead ));
  984. //
  985. // Signal the Protocol Sink that data is available.
  986. //
  987. __MPC_EXIT_IF_METHOD_FAILS(hr, DoBind_ReturnData( /*fCloneStream*/false, szExt ? rgMime : NULL ));
  988. hr = S_OK;
  989. __HCP_FUNC_CLEANUP;
  990. __HCP_FUNC_EXIT(hr);
  991. }
  992. HRESULT CHCPProtocol::DoBind_File()
  993. {
  994. __HCP_FUNC_ENTRY("CHCPProtocol::DoBind_File");
  995. HRESULT hr;
  996. CComPtr<MPC::FileStream> pStm;
  997. LPCWSTR szFile = m_bstrUrlRedirected;
  998. LPCWSTR szExt = 0;
  999. WCHAR rgMime[256];
  1000. //
  1001. // Try to find the Mime Type for this file.
  1002. //
  1003. {
  1004. WCHAR szFullPath[MAX_PATH + 1];
  1005. LPWSTR szFilePart;
  1006. // Get the canonical file name. (BUG 542663)
  1007. DWORD dwLen = ::GetFullPathNameW(szFile, MAX_PATH, szFullPath, &szFilePart);
  1008. if (dwLen != 0 && dwLen <= MAX_PATH)
  1009. {
  1010. // Succeed, parse the file part.
  1011. if((szExt = wcsrchr( szFilePart, L'.' )))
  1012. {
  1013. ::GetMimeFromExt( szExt, rgMime, 255 );
  1014. }
  1015. }
  1016. }
  1017. //
  1018. // Create the file stream.
  1019. //
  1020. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &pStm ));
  1021. __MPC_EXIT_IF_METHOD_FAILS(hr, pStm->InitForRead ( szFile ));
  1022. __MPC_EXIT_IF_METHOD_FAILS(hr, pStm->QueryInterface( IID_IStream, (void**)&m_pstrmRead ));
  1023. //
  1024. // Signal the Protocol Sink that data is available.
  1025. //
  1026. __MPC_EXIT_IF_METHOD_FAILS(hr, DoBind_ReturnData( /*fCloneStream*/false, szExt ? rgMime : NULL ));
  1027. hr = S_OK;
  1028. __HCP_FUNC_CLEANUP;
  1029. __HCP_FUNC_EXIT(hr);
  1030. }
  1031. HRESULT CHCPProtocol::DoBind_ReturnData( /*[in]*/ bool fCloneStream ,
  1032. /*[in]*/ LPCWSTR szMimeType )
  1033. {
  1034. __HCP_FUNC_ENTRY("CHCPProtocol::DoBind_ReturnData");
  1035. HRESULT hr;
  1036. STATSTG statstg;
  1037. m_fDone = true;
  1038. if(fCloneStream)
  1039. {
  1040. LARGE_INTEGER li;
  1041. //
  1042. // Clone the stream, so that we can hand it back to the ProtSink for data reading.
  1043. //
  1044. __MPC_EXIT_IF_METHOD_FAILS(hr, m_pstrmWrite->Clone( &m_pstrmRead ));
  1045. //
  1046. // Reset stream to beginning.
  1047. //
  1048. li.LowPart = 0;
  1049. li.HighPart = 0;
  1050. __MPC_EXIT_IF_METHOD_FAILS(hr, m_pstrmRead->Seek( li, STREAM_SEEK_SET, NULL ));
  1051. }
  1052. (void)m_pstrmRead->Stat( &statstg, STATFLAG_NONAME );
  1053. m_bstrMimeType = szMimeType;
  1054. m_dwContentLength = statstg.cbSize.LowPart;
  1055. //
  1056. // Create an entry in the cache, if required.
  1057. //
  1058. if(m_bindf & BINDF_NEEDFILE)
  1059. {
  1060. (void)OpenCacheEntry();
  1061. }
  1062. if(szMimeType)
  1063. {
  1064. __MPC_EXIT_IF_METHOD_FAILS(hr, InnerReportProgress( BINDSTATUS_MIMETYPEAVAILABLE, szMimeType ));
  1065. }
  1066. if(m_hCache)
  1067. {
  1068. __MPC_EXIT_IF_METHOD_FAILS(hr, InnerReportProgress( BINDSTATUS_CACHEFILENAMEAVAILABLE, m_szCacheFileName ));
  1069. }
  1070. __MPC_EXIT_IF_METHOD_FAILS(hr, InnerReportData( BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE,
  1071. statstg.cbSize.LowPart ,
  1072. statstg.cbSize.LowPart ));
  1073. hr = S_OK;
  1074. __HCP_FUNC_CLEANUP;
  1075. __HCP_FUNC_EXIT(hr);
  1076. }
  1077. /////////////////////////////////////////////////////////////////////////////
  1078. /////////////////////////////////////////////////////////////////////////////
  1079. /////////////////////////////////////////////////////////////////////////////
  1080. //
  1081. // Implementation of the ISimpleBindStatusCallback interface.
  1082. //
  1083. STDMETHODIMP CHCPProtocol::ForwardQueryInterface( /*[in] */ REFIID riid ,
  1084. /*[out]*/ void** ppv )
  1085. {
  1086. __HCP_FUNC_ENTRY("CHCPProtocol::ForwardQueryInterface");
  1087. HRESULT hr = E_NOINTERFACE;
  1088. *ppv = NULL;
  1089. if(IsEqualIID( riid, IID_IHttpNegotiate))
  1090. {
  1091. CComQIPtr<IServiceProvider> pProv;
  1092. pProv = m_pIProtSink;
  1093. if(pProv)
  1094. {
  1095. if(SUCCEEDED(pProv->QueryService( riid, riid, ppv )))
  1096. {
  1097. __MPC_SET_ERROR_AND_EXIT(hr, S_OK);
  1098. }
  1099. }
  1100. pProv = m_pIBindInfo;
  1101. if(pProv)
  1102. {
  1103. if(SUCCEEDED(pProv->QueryService( riid, riid, ppv )))
  1104. {
  1105. __MPC_SET_ERROR_AND_EXIT(hr, S_OK);
  1106. }
  1107. }
  1108. }
  1109. __HCP_FUNC_CLEANUP;
  1110. __HCP_FUNC_EXIT(hr);
  1111. }
  1112. STDMETHODIMP CHCPProtocol::GetBindInfo( /*[out]*/ BINDINFO *pbindInfo )
  1113. {
  1114. __HCP_FUNC_ENTRY("CHCPProtocol::GetBindInfo");
  1115. HRESULT hr = ::CopyBindInfo( &m_bindinfo, pbindInfo );
  1116. __HCP_FUNC_EXIT(hr);
  1117. }
  1118. STDMETHODIMP CHCPProtocol::PreBindMoniker( /*[in]*/ IBindCtx* pBindCtx ,
  1119. /*[in]*/ IMoniker* pMoniker )
  1120. {
  1121. __HCP_FUNC_ENTRY("CHCPProtocol::PreBindMoniker");
  1122. __HCP_FUNC_EXIT(S_OK);
  1123. }
  1124. STDMETHODIMP CHCPProtocol::OnProgress( /*[in]*/ ULONG ulProgress ,
  1125. /*[in]*/ ULONG ulProgressMax,
  1126. /*[in]*/ ULONG ulStatusCode ,
  1127. /*[in]*/ LPCWSTR szStatusText )
  1128. {
  1129. __HCP_FUNC_ENTRY("CHCPProtocol::OnProgress");
  1130. HRESULT hr;
  1131. switch(ulStatusCode)
  1132. {
  1133. case BINDSTATUS_BEGINDOWNLOADDATA:
  1134. // ulProgressMax represents the total size of the download
  1135. // When talking HTTP, this is determined by the CONTENT_LENGTH header
  1136. // If this header is missing or wrong, we're missing or wrong
  1137. m_cbTotalSize = ulProgressMax;
  1138. break;
  1139. case BINDSTATUS_MIMETYPEAVAILABLE :
  1140. case BINDSTATUS_FINDINGRESOURCE :
  1141. case BINDSTATUS_CONNECTING :
  1142. case BINDSTATUS_SENDINGREQUEST :
  1143. case BINDSTATUS_CACHEFILENAMEAVAILABLE:
  1144. case BINDSTATUS_REDIRECTING :
  1145. case BINDSTATUS_USINGCACHEDCOPY :
  1146. case BINDSTATUS_CLASSIDAVAILABLE :
  1147. case BINDSTATUS_LOADINGMIMEHANDLER :
  1148. // only pass on these notifications:
  1149. __MPC_EXIT_IF_METHOD_FAILS(hr, InnerReportProgress( ulStatusCode, szStatusText ));
  1150. }
  1151. hr = S_OK;
  1152. __HCP_FUNC_CLEANUP;
  1153. __HCP_FUNC_EXIT(hr);
  1154. }
  1155. STDMETHODIMP CHCPProtocol::OnData( /*[in]*/ CHCPBindStatusCallback* pbsc ,
  1156. /*[in]*/ BYTE* pBytes ,
  1157. /*[in]*/ DWORD dwSize ,
  1158. /*[in]*/ DWORD grfBSCF ,
  1159. /*[in]*/ FORMATETC* pformatetc ,
  1160. /*[in]*/ STGMEDIUM* pstgmed )
  1161. {
  1162. __HCP_FUNC_ENTRY("CHCPProtocol::OnData");
  1163. HRESULT hr;
  1164. ULONG cbWritten;
  1165. //
  1166. // To handle an error, we just report result that we failed and terminate the download object
  1167. //
  1168. if(FAILED(hr = m_pstrmWrite->Write( pBytes, dwSize, &cbWritten )))
  1169. {
  1170. // Our own Abort handles this just nicely
  1171. Abort( hr, 0 ); __MPC_FUNC_LEAVE;
  1172. }
  1173. m_cbAvailableSize += cbWritten;
  1174. if(grfBSCF & BSCF_FIRSTDATANOTIFICATION)
  1175. {
  1176. LARGE_INTEGER li;
  1177. // We need two concurrent seek pointers to the same stream
  1178. // because we'll be writing to the stream at the end while
  1179. // we're trying to read from the beginning
  1180. __MPC_EXIT_IF_METHOD_FAILS(hr, m_pstrmWrite->Clone( &m_pstrmRead ));
  1181. // reset stream to beginning
  1182. li.LowPart = 0;
  1183. li.HighPart = 0;
  1184. __MPC_EXIT_IF_METHOD_FAILS(hr, m_pstrmRead->Seek( li, STREAM_SEEK_SET, NULL ));
  1185. }
  1186. // We've got all the data, signal complete
  1187. if(grfBSCF & BSCF_LASTDATANOTIFICATION)
  1188. {
  1189. // We need to remember if we've received LASTDATANOTIFICATION yet
  1190. m_fDone = true;
  1191. // We only need to do ReportResult if we fail somehow -
  1192. // DATAFULLYAVAILABLE is signal enough that we succeeded
  1193. // NOT NEEDED: m_pIProtSink->ReportResult(S_OK, 0, NULL);
  1194. __MPC_EXIT_IF_METHOD_FAILS(hr, InnerReportData( BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE,
  1195. m_cbAvailableSize ,
  1196. m_cbAvailableSize ));
  1197. }
  1198. else
  1199. {
  1200. // Report our progress accurately using our byte count
  1201. // of what we've read versus the total known download size
  1202. // We know the total amount to read, the total read so far, and
  1203. // the total written. The problem is that we can't know the total
  1204. // amount that will be written in the end. So we estimate at
  1205. // 1.5 * Total size and if we overrun, we just start adding some
  1206. // extra to the end
  1207. __MPC_EXIT_IF_METHOD_FAILS(hr, InnerReportData( grfBSCF, m_cbAvailableSize, m_cbTotalSize ));
  1208. }
  1209. hr = S_OK;
  1210. __HCP_FUNC_CLEANUP;
  1211. __HCP_FUNC_EXIT(hr);
  1212. }
  1213. STDMETHODIMP CHCPProtocol::OnBindingFailure( /*[in]*/ HRESULT hr ,
  1214. /*[in]*/ LPCWSTR szError )
  1215. {
  1216. __HCP_FUNC_ENTRY("CHCPProtocol::OnBindingFailure");
  1217. //
  1218. // Inform protocol-sink that we've failed to download the data for some reason.
  1219. //
  1220. __MPC_EXIT_IF_METHOD_FAILS(hr, InnerReportResult( hr, 0, szError ));
  1221. hr = S_OK;
  1222. __HCP_FUNC_CLEANUP;
  1223. __HCP_FUNC_EXIT(hr);
  1224. }