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.

1557 lines
41 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 cbMime )
  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. wcsncpy( pszMime, szMime.c_str(), cbMime );
  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. wcsncpy( pszMime, c_lookupMIME[i].szMIME, cbMime );
  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. swprintf( 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. HRESULT CHCPProtocol::DoParse( /*[in]*/ LPCWSTR szURL )
  664. {
  665. __HCP_FUNC_ENTRY("CHCPProtocol::DoParse");
  666. HRESULT hr;
  667. CComBSTR bstrURLCopy;
  668. LPCWSTR szURLCopy;
  669. LPWSTR szQuery;
  670. LPCWSTR szRedirect;
  671. bool fHCP;
  672. m_bstrUrlComplete = szURL;
  673. m_bstrUrlRedirected = (LPCOLESTR)NULL;
  674. fHCP = CHCPProtocolInfo::LookForHCP( szURL, m_fRedirected, szRedirect );
  675. m_fRedirected = false; // redirection should never happen here
  676. if(m_fRedirected)
  677. {
  678. m_bstrUrlRedirected = szRedirect;
  679. }
  680. else
  681. {
  682. const Lookup_Virtual_To_Real* ptr;
  683. int i;
  684. MPC::wstring strDir;
  685. LPOLESTR szTmp;
  686. szURLCopy = ::UnescapeFileName( bstrURLCopy, szURL ); if(!szURLCopy) __MPC_SET_ERROR_AND_EXIT(hr, E_OUTOFMEMORY);
  687. //
  688. // Remove the query part of the URL.
  689. //
  690. if(szQuery = wcschr( szURLCopy, L'?' ))
  691. {
  692. szQuery[0] = 0;
  693. }
  694. //
  695. // Do the mapping between virtual paths and real ones.
  696. //
  697. for(ptr=c_lookup, i=0; i<ARRAYSIZE(c_lookup); i++, ptr++)
  698. {
  699. if(!_wcsnicmp( szURLCopy, ptr->szPrefix, ptr->iPrefix ))
  700. {
  701. if(ptr->fCSS)
  702. {
  703. m_bstrUrlRedirected = szURL;
  704. m_fCSS = true;
  705. break;
  706. }
  707. if(!ptr->szRealSubDir)
  708. {
  709. strDir = ptr->fRelocate ? CHCPProtocolEnvironment::s_GLOBAL->HelpLocation() : HC_HELPSVC_HELPFILES_DEFAULT;
  710. strDir += L"\\";
  711. }
  712. else
  713. {
  714. strDir = ptr->fRelocate ? CHCPProtocolEnvironment::s_GLOBAL->System() : HC_HELPSET_ROOT;
  715. strDir += ptr->szRealSubDir;
  716. }
  717. MPC::SubstituteEnvVariables( strDir );
  718. m_bstrUrlRedirected = strDir.c_str();
  719. m_bstrUrlRedirected += &szURLCopy[ ptr->iPrefix ];
  720. //
  721. // Convert the slashes to backslashes.
  722. //
  723. while((szTmp = wcschr( m_bstrUrlRedirected, L'/' ))) szTmp[0] = L'\\';
  724. //
  725. // Remove any trailing slash.
  726. //
  727. while((szTmp = wcsrchr( m_bstrUrlRedirected, L'/' )) && szTmp[1] == 0) szTmp[0] = 0;
  728. while((szTmp = wcsrchr( m_bstrUrlRedirected, L'\\' )) && szTmp[1] == 0) szTmp[0] = 0;
  729. CHCPProtocolEnvironment::s_GLOBAL->ReformatURL( m_bstrUrlRedirected );
  730. if(ptr->fSkipIfMissing && MPC::FileSystemObject::IsFile( m_bstrUrlRedirected ) == false) continue;
  731. break;
  732. }
  733. }
  734. }
  735. if(!m_bstrUrlRedirected) __MPC_SET_ERROR_AND_EXIT(hr, E_OUTOFMEMORY);
  736. hr = S_OK;
  737. __HCP_FUNC_CLEANUP;
  738. __HCP_FUNC_EXIT(hr);
  739. }
  740. HRESULT CHCPProtocol::DoBind()
  741. {
  742. __HCP_FUNC_ENTRY("CHCPProtocol::DoBind");
  743. HRESULT hr;
  744. __MPC_EXIT_IF_METHOD_FAILS(hr, InnerReportProgress( BINDSTATUS_FINDINGRESOURCE, SAFEBSTR( m_bstrUrlRedirected ) ));
  745. if(m_fRedirected)
  746. {
  747. if(MPC::MSITS::IsCHM( SAFEBSTR( m_bstrUrlRedirected ) ))
  748. {
  749. __MPC_EXIT_IF_METHOD_FAILS(hr, DoBind_Redirect_MSITS());
  750. }
  751. else
  752. {
  753. __MPC_EXIT_IF_METHOD_FAILS(hr, DoBind_Redirect_UrlMoniker());
  754. }
  755. }
  756. else if(m_fCSS)
  757. {
  758. __MPC_EXIT_IF_METHOD_FAILS(hr, DoBind_CSS());
  759. }
  760. else
  761. {
  762. MPC::wstring szPage = SAFEBSTR(m_bstrUrlRedirected);
  763. MPC::FileSystemObject fso = szPage.c_str();
  764. bool fFound;
  765. bool fIsAFile;
  766. __MPC_EXIT_IF_METHOD_FAILS(hr, DoBind_Exists( fso, fFound, fIsAFile ));
  767. if(fFound && fIsAFile)
  768. {
  769. //
  770. // The file exists, so load its content.
  771. //
  772. __MPC_EXIT_IF_METHOD_FAILS(hr, DoBind_File());
  773. }
  774. else
  775. {
  776. //
  777. // The file, as is, doesn't exist, so try to find a .chm on the path.
  778. //
  779. while(1)
  780. {
  781. MPC::wstring szParent;
  782. MPC::wstring szCHM;
  783. __MPC_EXIT_IF_METHOD_FAILS(hr, fso.get_Parent( szParent ));
  784. if(szParent.length() == 0)
  785. {
  786. //
  787. // No parent, so exit with error.
  788. //
  789. __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
  790. }
  791. //
  792. // Point the FileSystemObject to its parent.
  793. //
  794. fso = szParent.c_str();
  795. __MPC_EXIT_IF_METHOD_FAILS(hr, DoBind_Exists( fso, fFound, fIsAFile ));
  796. //
  797. // Parent exists, so it cannot exist a .CHM file. Exit with error.
  798. //
  799. if(fFound)
  800. {
  801. __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
  802. }
  803. //
  804. // Add the .CHM extension and look for it.
  805. //
  806. szCHM = szParent; szCHM.append( L".chm" );
  807. fso = szCHM.c_str();
  808. __MPC_EXIT_IF_METHOD_FAILS(hr, DoBind_Exists( fso, fFound, fIsAFile ));
  809. //
  810. // No .CHM file, recurse up to the root.
  811. //
  812. if(fFound == false)
  813. {
  814. continue;
  815. }
  816. //
  817. // The .CHM is not a file, exit with error.
  818. //
  819. if(fIsAFile == false)
  820. {
  821. __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
  822. }
  823. //
  824. // Found, so redirect to the proper protocol.
  825. //
  826. szCHM = L"ms-its:";
  827. szCHM.append( szParent );
  828. szCHM.append( L".chm" );
  829. if(szParent.length() < szPage.length())
  830. {
  831. LPWSTR szBuf = new WCHAR[szPage.length()+1];
  832. if(szBuf)
  833. {
  834. LPWSTR szTmp;
  835. wcscpy( szBuf, szPage.c_str() );
  836. //
  837. // Convert the backslashes to slashes.
  838. //
  839. while(szTmp = wcschr( szBuf, L'\\' )) szTmp[0] = L'/';
  840. szCHM.append( L"::" );
  841. szCHM.append( &szBuf[szParent.length()] );
  842. delete [] szBuf;
  843. }
  844. }
  845. m_bstrUrlRedirected = szCHM.c_str();
  846. __MPC_EXIT_IF_METHOD_FAILS(hr, DoBind_Redirect_MSITS());
  847. break;
  848. }
  849. }
  850. }
  851. hr = S_OK;
  852. __HCP_FUNC_CLEANUP;
  853. __HCP_FUNC_EXIT(hr);
  854. }
  855. HRESULT CHCPProtocol::DoBind_Exists( /*[in] */ MPC::FileSystemObject& fso ,
  856. /*[out]*/ bool& fFound ,
  857. /*[out]*/ bool& fIsAFile )
  858. {
  859. __HCP_FUNC_ENTRY("CHCPProtocol::DoBind_Exists");
  860. HRESULT hr;
  861. if(fso.Exists())
  862. {
  863. fFound = true;
  864. fIsAFile = fso.IsFile();
  865. }
  866. else
  867. {
  868. fFound = false;
  869. fIsAFile = false;
  870. }
  871. hr = S_OK;
  872. __HCP_FUNC_EXIT(hr);
  873. }
  874. HRESULT CHCPProtocol::DoBind_Redirect_UrlMoniker()
  875. {
  876. __HCP_FUNC_ENTRY("CHCPProtocol::DoBind_Redirect_UrlMoniker");
  877. HRESULT hr;
  878. //
  879. // Create the stream used to receive downloaded data.
  880. //
  881. ::CreateStreamOnHGlobal( NULL, TRUE, &m_pstrmWrite );
  882. if(m_pstrmWrite == NULL)
  883. {
  884. __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
  885. }
  886. //
  887. // Create the downloader object.
  888. //
  889. if(SUCCEEDED(hr = m_pDownloader->CreateInstance( &m_pDownloader )))
  890. {
  891. m_pDownloader->AddRef();
  892. if(FAILED(hr = m_pDownloader->StartAsyncDownload( this, m_bstrUrlRedirected, NULL, FALSE )))
  893. {
  894. if(hr != E_PENDING) __MPC_FUNC_LEAVE;
  895. }
  896. }
  897. hr = S_OK;
  898. __HCP_FUNC_CLEANUP;
  899. __HCP_FUNC_EXIT(hr);
  900. }
  901. HRESULT CHCPProtocol::DoBind_Redirect_MSITS()
  902. {
  903. __HCP_FUNC_ENTRY("CHCPProtocol::DoBind_Redirect_MSITS");
  904. HRESULT hr;
  905. CComBSTR bstrStorageName;
  906. CComBSTR bstrFilePath;
  907. LPCWSTR szExt;
  908. WCHAR rgMime[MAX_PATH];
  909. if(MPC::MSITS::IsCHM( SAFEBSTR( m_bstrUrlRedirected ), &bstrStorageName, &bstrFilePath ) == false)
  910. {
  911. __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
  912. }
  913. //
  914. // Try to find the Mime Type for this file.
  915. //
  916. if((szExt = wcsrchr( bstrFilePath, L'.' )))
  917. {
  918. ::GetMimeFromExt( szExt, rgMime, MAX_PATH-1 );
  919. }
  920. else
  921. {
  922. rgMime[0] = 0;
  923. }
  924. //
  925. // Extract the file from the CHM.
  926. //
  927. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::MSITS::OpenAsStream( bstrStorageName, bstrFilePath, &m_pstrmRead ));
  928. //
  929. // Signal the Protocol Sink that data is available.
  930. //
  931. __MPC_EXIT_IF_METHOD_FAILS(hr, DoBind_ReturnData( /*fCloneStream*/false, szExt ? rgMime : NULL ));
  932. hr = S_OK;
  933. __HCP_FUNC_CLEANUP;
  934. __HCP_FUNC_EXIT(hr);
  935. }
  936. HRESULT CHCPProtocol::DoBind_CSS()
  937. {
  938. __HCP_FUNC_ENTRY("CHCPProtocol::DoBind_CSS");
  939. HRESULT hr;
  940. LPCWSTR szExt;
  941. WCHAR rgMime[256];
  942. //
  943. // Try to find the Mime Type for this file.
  944. //
  945. if((szExt = wcsrchr( m_bstrUrlComplete, L'.' )))
  946. {
  947. ::GetMimeFromExt( szExt, rgMime, 255 );
  948. }
  949. __MPC_EXIT_IF_METHOD_FAILS(hr, CHCPProtocolEnvironment::s_GLOBAL->GetCSS( m_pstrmRead ));
  950. //
  951. // Signal the Protocol Sink that data is available.
  952. //
  953. __MPC_EXIT_IF_METHOD_FAILS(hr, DoBind_ReturnData( /*fCloneStream*/false, szExt ? rgMime : NULL ));
  954. hr = S_OK;
  955. __HCP_FUNC_CLEANUP;
  956. __HCP_FUNC_EXIT(hr);
  957. }
  958. HRESULT CHCPProtocol::DoBind_File()
  959. {
  960. __HCP_FUNC_ENTRY("CHCPProtocol::DoBind_File");
  961. HRESULT hr;
  962. CComPtr<MPC::FileStream> pStm;
  963. LPCWSTR szFile = m_bstrUrlRedirected;
  964. LPCWSTR szExt;
  965. WCHAR rgMime[256];
  966. //
  967. // Try to find the Mime Type for this file.
  968. //
  969. if((szExt = wcsrchr( szFile, L'.' )))
  970. {
  971. ::GetMimeFromExt( szExt, rgMime, 255 );
  972. }
  973. //
  974. // Create the file stream.
  975. //
  976. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &pStm ));
  977. __MPC_EXIT_IF_METHOD_FAILS(hr, pStm->InitForRead ( szFile ));
  978. __MPC_EXIT_IF_METHOD_FAILS(hr, pStm->QueryInterface( IID_IStream, (void**)&m_pstrmRead ));
  979. //
  980. // Signal the Protocol Sink that data is available.
  981. //
  982. __MPC_EXIT_IF_METHOD_FAILS(hr, DoBind_ReturnData( /*fCloneStream*/false, szExt ? rgMime : NULL ));
  983. hr = S_OK;
  984. __HCP_FUNC_CLEANUP;
  985. __HCP_FUNC_EXIT(hr);
  986. }
  987. HRESULT CHCPProtocol::DoBind_ReturnData( /*[in]*/ bool fCloneStream ,
  988. /*[in]*/ LPCWSTR szMimeType )
  989. {
  990. __HCP_FUNC_ENTRY("CHCPProtocol::DoBind_ReturnData");
  991. HRESULT hr;
  992. STATSTG statstg;
  993. m_fDone = true;
  994. if(fCloneStream)
  995. {
  996. LARGE_INTEGER li;
  997. //
  998. // Clone the stream, so that we can hand it back to the ProtSink for data reading.
  999. //
  1000. __MPC_EXIT_IF_METHOD_FAILS(hr, m_pstrmWrite->Clone( &m_pstrmRead ));
  1001. //
  1002. // Reset stream to beginning.
  1003. //
  1004. li.LowPart = 0;
  1005. li.HighPart = 0;
  1006. __MPC_EXIT_IF_METHOD_FAILS(hr, m_pstrmRead->Seek( li, STREAM_SEEK_SET, NULL ));
  1007. }
  1008. (void)m_pstrmRead->Stat( &statstg, STATFLAG_NONAME );
  1009. m_bstrMimeType = szMimeType;
  1010. m_dwContentLength = statstg.cbSize.LowPart;
  1011. //
  1012. // Create an entry in the cache, if required.
  1013. //
  1014. if(m_bindf & BINDF_NEEDFILE)
  1015. {
  1016. (void)OpenCacheEntry();
  1017. }
  1018. if(szMimeType)
  1019. {
  1020. __MPC_EXIT_IF_METHOD_FAILS(hr, InnerReportProgress( BINDSTATUS_MIMETYPEAVAILABLE, szMimeType ));
  1021. }
  1022. if(m_hCache)
  1023. {
  1024. __MPC_EXIT_IF_METHOD_FAILS(hr, InnerReportProgress( BINDSTATUS_CACHEFILENAMEAVAILABLE, m_szCacheFileName ));
  1025. }
  1026. __MPC_EXIT_IF_METHOD_FAILS(hr, InnerReportData( BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE,
  1027. statstg.cbSize.LowPart ,
  1028. statstg.cbSize.LowPart ));
  1029. hr = S_OK;
  1030. __HCP_FUNC_CLEANUP;
  1031. __HCP_FUNC_EXIT(hr);
  1032. }
  1033. /////////////////////////////////////////////////////////////////////////////
  1034. /////////////////////////////////////////////////////////////////////////////
  1035. /////////////////////////////////////////////////////////////////////////////
  1036. //
  1037. // Implementation of the ISimpleBindStatusCallback interface.
  1038. //
  1039. STDMETHODIMP CHCPProtocol::ForwardQueryInterface( /*[in] */ REFIID riid ,
  1040. /*[out]*/ void** ppv )
  1041. {
  1042. __HCP_FUNC_ENTRY("CHCPProtocol::ForwardQueryInterface");
  1043. HRESULT hr = E_NOINTERFACE;
  1044. *ppv = NULL;
  1045. if(IsEqualIID( riid, IID_IHttpNegotiate))
  1046. {
  1047. CComQIPtr<IServiceProvider> pProv;
  1048. pProv = m_pIProtSink;
  1049. if(pProv)
  1050. {
  1051. if(SUCCEEDED(pProv->QueryService( riid, riid, ppv )))
  1052. {
  1053. __MPC_SET_ERROR_AND_EXIT(hr, S_OK);
  1054. }
  1055. }
  1056. pProv = m_pIBindInfo;
  1057. if(pProv)
  1058. {
  1059. if(SUCCEEDED(pProv->QueryService( riid, riid, ppv )))
  1060. {
  1061. __MPC_SET_ERROR_AND_EXIT(hr, S_OK);
  1062. }
  1063. }
  1064. }
  1065. __HCP_FUNC_CLEANUP;
  1066. __HCP_FUNC_EXIT(hr);
  1067. }
  1068. STDMETHODIMP CHCPProtocol::GetBindInfo( /*[out]*/ BINDINFO *pbindInfo )
  1069. {
  1070. __HCP_FUNC_ENTRY("CHCPProtocol::GetBindInfo");
  1071. HRESULT hr = ::CopyBindInfo( &m_bindinfo, pbindInfo );
  1072. __HCP_FUNC_EXIT(hr);
  1073. }
  1074. STDMETHODIMP CHCPProtocol::PreBindMoniker( /*[in]*/ IBindCtx* pBindCtx ,
  1075. /*[in]*/ IMoniker* pMoniker )
  1076. {
  1077. __HCP_FUNC_ENTRY("CHCPProtocol::PreBindMoniker");
  1078. __HCP_FUNC_EXIT(S_OK);
  1079. }
  1080. STDMETHODIMP CHCPProtocol::OnProgress( /*[in]*/ ULONG ulProgress ,
  1081. /*[in]*/ ULONG ulProgressMax,
  1082. /*[in]*/ ULONG ulStatusCode ,
  1083. /*[in]*/ LPCWSTR szStatusText )
  1084. {
  1085. __HCP_FUNC_ENTRY("CHCPProtocol::OnProgress");
  1086. HRESULT hr;
  1087. switch(ulStatusCode)
  1088. {
  1089. case BINDSTATUS_BEGINDOWNLOADDATA:
  1090. // ulProgressMax represents the total size of the download
  1091. // When talking HTTP, this is determined by the CONTENT_LENGTH header
  1092. // If this header is missing or wrong, we're missing or wrong
  1093. m_cbTotalSize = ulProgressMax;
  1094. break;
  1095. case BINDSTATUS_MIMETYPEAVAILABLE :
  1096. case BINDSTATUS_FINDINGRESOURCE :
  1097. case BINDSTATUS_CONNECTING :
  1098. case BINDSTATUS_SENDINGREQUEST :
  1099. case BINDSTATUS_CACHEFILENAMEAVAILABLE:
  1100. case BINDSTATUS_REDIRECTING :
  1101. case BINDSTATUS_USINGCACHEDCOPY :
  1102. case BINDSTATUS_CLASSIDAVAILABLE :
  1103. case BINDSTATUS_LOADINGMIMEHANDLER :
  1104. // only pass on these notifications:
  1105. __MPC_EXIT_IF_METHOD_FAILS(hr, InnerReportProgress( ulStatusCode, szStatusText ));
  1106. }
  1107. hr = S_OK;
  1108. __HCP_FUNC_CLEANUP;
  1109. __HCP_FUNC_EXIT(hr);
  1110. }
  1111. STDMETHODIMP CHCPProtocol::OnData( /*[in]*/ CHCPBindStatusCallback* pbsc ,
  1112. /*[in]*/ BYTE* pBytes ,
  1113. /*[in]*/ DWORD dwSize ,
  1114. /*[in]*/ DWORD grfBSCF ,
  1115. /*[in]*/ FORMATETC* pformatetc ,
  1116. /*[in]*/ STGMEDIUM* pstgmed )
  1117. {
  1118. __HCP_FUNC_ENTRY("CHCPProtocol::OnData");
  1119. HRESULT hr;
  1120. ULONG cbWritten;
  1121. //
  1122. // To handle an error, we just report result that we failed and terminate the download object
  1123. //
  1124. if(FAILED(hr = m_pstrmWrite->Write( pBytes, dwSize, &cbWritten )))
  1125. {
  1126. // Our own Abort handles this just nicely
  1127. Abort( hr, 0 ); __MPC_FUNC_LEAVE;
  1128. }
  1129. m_cbAvailableSize += cbWritten;
  1130. if(grfBSCF & BSCF_FIRSTDATANOTIFICATION)
  1131. {
  1132. LARGE_INTEGER li;
  1133. // We need two concurrent seek pointers to the same stream
  1134. // because we'll be writing to the stream at the end while
  1135. // we're trying to read from the beginning
  1136. __MPC_EXIT_IF_METHOD_FAILS(hr, m_pstrmWrite->Clone( &m_pstrmRead ));
  1137. // reset stream to beginning
  1138. li.LowPart = 0;
  1139. li.HighPart = 0;
  1140. __MPC_EXIT_IF_METHOD_FAILS(hr, m_pstrmRead->Seek( li, STREAM_SEEK_SET, NULL ));
  1141. }
  1142. // We've got all the data, signal complete
  1143. if(grfBSCF & BSCF_LASTDATANOTIFICATION)
  1144. {
  1145. // We need to remember if we've received LASTDATANOTIFICATION yet
  1146. m_fDone = true;
  1147. // We only need to do ReportResult if we fail somehow -
  1148. // DATAFULLYAVAILABLE is signal enough that we succeeded
  1149. // NOT NEEDED: m_pIProtSink->ReportResult(S_OK, 0, NULL);
  1150. __MPC_EXIT_IF_METHOD_FAILS(hr, InnerReportData( BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE,
  1151. m_cbAvailableSize ,
  1152. m_cbAvailableSize ));
  1153. }
  1154. else
  1155. {
  1156. // Report our progress accurately using our byte count
  1157. // of what we've read versus the total known download size
  1158. // We know the total amount to read, the total read so far, and
  1159. // the total written. The problem is that we can't know the total
  1160. // amount that will be written in the end. So we estimate at
  1161. // 1.5 * Total size and if we overrun, we just start adding some
  1162. // extra to the end
  1163. __MPC_EXIT_IF_METHOD_FAILS(hr, InnerReportData( grfBSCF, m_cbAvailableSize, m_cbTotalSize ));
  1164. }
  1165. hr = S_OK;
  1166. __HCP_FUNC_CLEANUP;
  1167. __HCP_FUNC_EXIT(hr);
  1168. }
  1169. STDMETHODIMP CHCPProtocol::OnBindingFailure( /*[in]*/ HRESULT hr ,
  1170. /*[in]*/ LPCWSTR szError )
  1171. {
  1172. __HCP_FUNC_ENTRY("CHCPProtocol::OnBindingFailure");
  1173. //
  1174. // Inform protocol-sink that we've failed to download the data for some reason.
  1175. //
  1176. __MPC_EXIT_IF_METHOD_FAILS(hr, InnerReportResult( hr, 0, szError ));
  1177. hr = S_OK;
  1178. __HCP_FUNC_CLEANUP;
  1179. __HCP_FUNC_EXIT(hr);
  1180. }