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.

1432 lines
38 KiB

  1. // Protocol.cpp -- Implementation for class CIOITnetProtocol
  2. #include "StdAfx.h"
  3. // Creation:
  4. HRESULT CIOITnetProtocol::Create
  5. (IUnknown *punkOuter, REFIID riid, PPVOID ppv)
  6. {
  7. CIOITnetProtocol *pNP = New CIOITnetProtocol(punkOuter);
  8. return FinishSetup(pNP? pNP->m_ImpIOITnetProtocol.Init()
  9. : STG_E_INSUFFICIENTMEMORY,
  10. pNP, riid, (PPVOID) ppv
  11. );
  12. }
  13. // Constructor and Destructor:
  14. CIOITnetProtocol::CImpIOITnetProtocol::CImpIOITnetProtocol
  15. (CIOITnetProtocol *pBackObj, IUnknown *pUnkOuter)
  16. : IOITnetProtocol(pBackObj, pUnkOuter) ,
  17. IOITnetProtocolInfo(pBackObj, pUnkOuter)
  18. {
  19. m_grfSTI = 0;
  20. m_grfBINDF = 0;
  21. m_szTempPath[0] = 0;
  22. ZeroMemory(&m_BindInfo, sizeof(m_BindInfo));
  23. m_pwcsURL = NULL;
  24. m_pcsDisplayName = NULL;
  25. m_pOIProtSink = NULL;
  26. m_pOIBindInfo = NULL;
  27. m_pStream = NULL;
  28. }
  29. CIOITnetProtocol::CImpIOITnetProtocol::~CImpIOITnetProtocol(void)
  30. {
  31. if (m_pcsDisplayName)
  32. {
  33. UnlockUrlCacheEntryFile(m_pcsDisplayName, 0);
  34. delete [] m_pcsDisplayName;
  35. }
  36. if (m_pwcsURL)
  37. delete [] m_pwcsURL;
  38. if (m_pOIProtSink)
  39. m_pOIProtSink->Release();
  40. if (m_pOIBindInfo)
  41. m_pOIBindInfo->Release();
  42. if (m_pStream)
  43. m_pStream->Release();
  44. if (m_szTempPath[0])
  45. DeleteFile(m_szTempPath);
  46. }
  47. // Initialing routine:
  48. HRESULT CIOITnetProtocol::CImpIOITnetProtocol::Init()
  49. {
  50. return NO_ERROR;
  51. }
  52. // IOITnetProtocolRoot interfaces:
  53. void STDMETHODCALLTYPE MapSurrogateCharacters
  54. (PWCHAR pwcsBuffer)
  55. {
  56. PWCHAR pwcsDest = pwcsBuffer;
  57. for (;;)
  58. {
  59. WCHAR wc = *pwcsBuffer++;
  60. *pwcsDest++ = wc;
  61. if (!wc) break;
  62. if (wc == L'%' && pwcsBuffer[0] && pwcsBuffer[1])
  63. {
  64. WCHAR wcSurrogate = 0;
  65. WCHAR wcFirst = pwcsBuffer[0];
  66. WCHAR wcSecond = pwcsBuffer[1];
  67. if (wcFirst >= L'0' && wcFirst <= L'9')
  68. wcSurrogate = wcFirst - L'0';
  69. else
  70. if (wcFirst >= L'A' && wcFirst <= L'F')
  71. wcSurrogate = 10 + wcFirst - L'A';
  72. else
  73. if (wcFirst >= L'a' && wcFirst <= L'f')
  74. wcSurrogate = 10 + wcFirst - L'a';
  75. else continue;
  76. wcSurrogate <<= 4;
  77. if (wcSecond >= L'0' && wcSecond <= L'9')
  78. wcSurrogate |= wcSecond - L'0';
  79. else
  80. if (wcSecond >= L'A' && wcSecond <= L'F')
  81. wcSurrogate |= 10 + wcSecond - L'A';
  82. else
  83. if (wcSecond >= L'a' && wcSecond <= L'f')
  84. wcSurrogate |= 10 + wcSecond - L'a';
  85. else continue;
  86. pwcsDest[-1] = wcSurrogate;
  87. pwcsBuffer += 2;
  88. }
  89. }
  90. }
  91. HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::Start
  92. (
  93. /* [in] */ LPCWSTR szUrl,
  94. /* [in] */ IOInetProtocolSink __RPC_FAR *pOIProtSink,
  95. /* [in] */ IOInetBindInfo __RPC_FAR *pOIBindInfo,
  96. /* [in] */ DWORD grfSTI,
  97. /* [in] */ DWORD dwReserved
  98. )
  99. {
  100. DWORD cwc = wcsLen(szUrl);
  101. PWCHAR pwcsBuffer = PWCHAR(_alloca((cwc + 1) * sizeof(WCHAR)));
  102. if (!pwcsBuffer) return E_OUTOFMEMORY;
  103. CopyMemory(pwcsBuffer, szUrl, sizeof(WCHAR) * (cwc + 1));
  104. PWCHAR pwcsExternalPath = NULL;
  105. PWCHAR pwcsInternalPath = NULL;
  106. HRESULT hr = DisectUrl(pwcsBuffer, NULL, &pwcsExternalPath, &pwcsInternalPath);
  107. if (!SUCCEEDED(hr))
  108. {
  109. if (hr != INET_E_DEFAULT_ACTION && (grfSTI & PI_PARSE_URL)) return S_FALSE;
  110. else return hr;
  111. }
  112. hr = AssembleUrl(NULL, 0, &cwc, L"ms-its", pwcsExternalPath, pwcsInternalPath);
  113. RonM_ASSERT(hr == E_OUTOFMEMORY);
  114. m_pwcsURL = New WCHAR[cwc];
  115. if (!m_pwcsURL)
  116. return E_OUTOFMEMORY;
  117. DWORD cwcRequired = 0;
  118. hr = AssembleUrl(m_pwcsURL, cwc, &cwcRequired, L"ms-its", pwcsExternalPath, pwcsInternalPath);
  119. RonM_ASSERT(hr == S_OK);
  120. m_pOIProtSink = pOIProtSink;
  121. m_pOIBindInfo = pOIBindInfo;
  122. m_grfSTI = grfSTI;
  123. m_pOIProtSink->AddRef();
  124. m_pOIBindInfo->AddRef();
  125. m_BindInfo.cbSize = sizeof(BINDINFO);
  126. hr = GetBindInfo(&m_grfBINDF, &m_BindInfo);
  127. if (!SUCCEEDED(hr)) return hr;
  128. if (grfSTI & PI_PARSE_URL)
  129. return ParseAndBind(FALSE);
  130. if (!(grfSTI & PI_FORCE_ASYNC))
  131. return ParseAndBind(TRUE);
  132. PROTOCOLDATA protdata;
  133. protdata.grfFlags = PI_FORCE_ASYNC;
  134. protdata.dwState = ITS_BIND_DATA;
  135. protdata.pData = NULL;
  136. protdata.cbData = 0;
  137. Switch(&protdata);
  138. return E_PENDING;
  139. }
  140. HRESULT STDMETHODCALLTYPE CopyStreamToFile(const WCHAR *pwcsFilePath, IStream *pStreamSrc)
  141. {
  142. IStream *pStream;
  143. IFSStorage *pFSS = NULL;
  144. HRESULT hr = CFileSystemStorage::Create(NULL, IID_IFSStorage, (VOID **) &pFSS);
  145. if (!SUCCEEDED(hr)) return hr;
  146. hr = pFSS->FSOpenStream((const WCHAR *) pwcsFilePath,
  147. STGM_READWRITE | STGM_SHARE_DENY_NONE,
  148. &pStream
  149. );
  150. pFSS->Release();
  151. if (!SUCCEEDED(hr)) return hr;
  152. RonM_ASSERT(pStreamSrc);
  153. STATSTG statstg;
  154. hr = pStreamSrc->Stat(&statstg, STATFLAG_NONAME);
  155. if (!SUCCEEDED(hr)) return hr;
  156. #ifdef _DEBUG
  157. hr =
  158. #endif // _DEBUG
  159. pStreamSrc->Seek(CLINT(0).Li(), STREAM_SEEK_SET, NULL);
  160. RonM_ASSERT(hr == S_OK);
  161. hr = pStreamSrc->CopyTo(pStream, statstg.cbSize, NULL, NULL);
  162. pStream->Release();
  163. if (!SUCCEEDED(hr)) return hr;
  164. #ifdef _DEBUG
  165. hr =
  166. #endif // _DEBUG
  167. pStreamSrc->Seek(CLINT(0).Li(), STREAM_SEEK_SET, NULL);
  168. RonM_ASSERT(hr == S_OK);
  169. return hr;
  170. }
  171. HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::ParseAndBind(BOOL fBind)
  172. {
  173. WCHAR *pwcsURL = m_pwcsURL;
  174. WCHAR *pwcsURLActual = NULL;
  175. BOOL fNoFile = (m_grfBINDF & BINDF_NEEDFILE) == 0; // FALSE;
  176. BOOL fNoReadCache = m_grfBINDF & (BINDF_GETNEWESTVERSION | BINDF_NOWRITECACHE
  177. | BINDF_PRAGMA_NO_CACHE
  178. | BINDF_DIRECT_READ
  179. );
  180. BOOL fNoWriteCache = m_grfBINDF & (BINDF_NOWRITECACHE | BINDF_PRAGMA_NO_CACHE
  181. | BINDF_DIRECT_READ
  182. );
  183. IBindCtx *pBCtx = NULL;
  184. IMoniker *pMK = NULL;
  185. PWCHAR pwcsExtension = NULL;
  186. PWCHAR pwcsMimeType = NULL;
  187. PWCHAR pwcsStreamName = NULL;
  188. ULONG chEaten = 0;
  189. DWORD cbSample = 0;
  190. HRESULT hr = CreateBindCtx(0, &pBCtx);
  191. if (!SUCCEEDED(hr)) goto exit_ParseAndBind;
  192. hr = CStorageMoniker::CreateStorageMoniker(NULL, pBCtx, pwcsURL, &chEaten, &pMK);
  193. if (!fBind)
  194. {
  195. if (hr != S_OK)
  196. hr = S_FALSE;
  197. goto exit_ParseAndBind;
  198. }
  199. if (!SUCCEEDED(hr)) goto exit_ParseAndBind;
  200. hr = pMK->BindToStorage(pBCtx, NULL, IID_IStream, (VOID **) &m_pStream);
  201. if (!SUCCEEDED(hr)) goto exit_ParseAndBind;
  202. hr = pMK->GetDisplayName(NULL, NULL, &pwcsURLActual);
  203. RonM_ASSERT(hr == S_OK);
  204. {
  205. UINT cwc = wcsLen(pwcsURLActual);
  206. WCHAR *pwc = pwcsURLActual + cwc;
  207. for (;;)
  208. {
  209. WCHAR wc = *--pwc;
  210. if (!pwcsExtension && wc == L'.')
  211. pwcsExtension = pwc + 1;
  212. if (wc == L':' || wc == L'/' || wc == L'\\')
  213. {
  214. pwc++;
  215. break;
  216. }
  217. RonM_ASSERT(--cwc);
  218. }
  219. pwcsStreamName = pwc;
  220. ReportProgress(BINDSTATUS_SENDINGREQUEST, (const WCHAR *) pwc);
  221. }
  222. STATSTG statstg;
  223. hr = m_pStream->Stat(&statstg, STATFLAG_NONAME);
  224. if (!SUCCEEDED(hr)) goto exit_ParseAndBind;
  225. RonM_ASSERT(statstg.cbSize.HighPart == 0);
  226. BYTE abSample[CB_SAMPLE];
  227. if (pwcsExtension && pwcsExtension[0])
  228. {
  229. UINT cwc = wcsLen(pwcsExtension-1);
  230. UINT cb = sizeof(WCHAR) * (cwc + 1);
  231. char *pcsExtension = PCHAR(_alloca(cb));
  232. if (!pcsExtension)
  233. {
  234. hr = E_OUTOFMEMORY;
  235. goto exit_ParseAndBind;
  236. }
  237. cb = WideCharToMultiByte(GetACP(), WC_COMPOSITECHECK, pwcsExtension-1, cwc + 1,
  238. pcsExtension, cb, NULL, NULL
  239. );
  240. if (!cb)
  241. {
  242. hr = E_FAIL;
  243. goto exit_ParseAndBind;
  244. }
  245. HKEY hkeyMime;
  246. if (RegOpenKeyEx(HKEY_CLASSES_ROOT, pcsExtension, 0, KEY_QUERY_VALUE, &hkeyMime)
  247. == ERROR_SUCCESS
  248. )
  249. {
  250. cb = CB_SAMPLE;
  251. if (RegQueryValueEx(hkeyMime, "Content Type", NULL, NULL, abSample, (DWORD *) &cb)
  252. == ERROR_SUCCESS
  253. && cb > 0
  254. )
  255. {
  256. PWCHAR pwc = (PWCHAR) (OLEHeap()->Alloc(cb * sizeof(WCHAR)));
  257. if (pwc)
  258. {
  259. UINT cwc = MultiByteToWideChar
  260. (GetACP(), MB_PRECOMPOSED, (const char *) abSample,
  261. cb, pwc, cb
  262. );
  263. if (cwc) pwcsMimeType = pwc;
  264. else OLEHeap()->Free(pwc);
  265. }
  266. }
  267. RegCloseKey(hkeyMime);
  268. }
  269. }
  270. if (!pwcsMimeType)
  271. {
  272. DWORD cbRead;
  273. cbSample = statstg.cbSize.LowPart < CB_SAMPLE? statstg.cbSize.LowPart : CB_SAMPLE;
  274. hr = m_pStream->Read(abSample, cbSample, &cbRead);
  275. if (!SUCCEEDED(hr)) goto exit_ParseAndBind;
  276. if (cbRead != cbSample)
  277. {
  278. hr = E_FAIL;
  279. goto exit_ParseAndBind;
  280. }
  281. m_pStream->Seek(CLINT(0).Li(), STREAM_SEEK_SET, NULL);
  282. hr = pFindMimeFromData(NULL, pwcsStreamName, abSample, cbSample, NULL, 0, &pwcsMimeType, 0);
  283. if (!SUCCEEDED(hr)) goto exit_ParseAndBind;
  284. }
  285. if (pwcsMimeType)
  286. {
  287. // The test below is a hack to get around a bug in UrlMon.
  288. // UrlMon incorrectly tells us we need to copy HTML files into the cache.
  289. if (!wcsicmp_0x0409(pwcsMimeType, L"text/html")) fNoFile = TRUE;
  290. ReportProgress(BINDSTATUS_MIMETYPEAVAILABLE, pwcsMimeType);
  291. }
  292. if (!fNoFile)
  293. {
  294. CHAR acsFilePath[MAX_PATH];
  295. WCHAR awcsFilePath[MAX_PATH];
  296. hr = StreamToIEFile(m_pStream, m_pwcsURL, m_pcsDisplayName,
  297. acsFilePath, awcsFilePath, m_szTempPath,
  298. pMK, fNoWriteCache, fNoReadCache
  299. );
  300. if (!SUCCEEDED(hr))
  301. goto exit_ParseAndBind;
  302. hr = ReportProgress(BINDSTATUS_CACHEFILENAMEAVAILABLE, awcsFilePath);
  303. if (!SUCCEEDED(hr)) goto exit_ParseAndBind;
  304. }
  305. hr = ReportData(BSCF_FIRSTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE,
  306. statstg.cbSize.LowPart, statstg.cbSize.LowPart
  307. );
  308. // The call to ReportData may indirectly call the Terminate method. So we have
  309. // to be very careful about references to m_pOIProtSink afterwards.
  310. if (SUCCEEDED(hr) && m_pOIProtSink)
  311. hr = ReportProgress(BSCF_LASTDATANOTIFICATION, NULL);
  312. if (SUCCEEDED(hr) && m_pOIProtSink)
  313. ReportResult(hr, 0, 0);
  314. exit_ParseAndBind:
  315. if (pwcsURLActual)
  316. OLEHeap()->Free(pwcsURLActual);
  317. if (pMK)
  318. pMK->Release();
  319. if (pBCtx)
  320. pBCtx->Release();
  321. if (hr != NO_ERROR)
  322. ReportResult(hr, 0, 0);
  323. return hr;
  324. }
  325. HRESULT STDMETHODCALLTYPE StreamToIEFile
  326. (IStream *pStreamSrc, PWCHAR pwcsDisplayName, PCHAR &pcsDisplayName,
  327. PCHAR pcsFileName, PWCHAR pwcsFileName, PCHAR pcsTempFile,
  328. IMoniker *pmk, BOOL fNoWriteCache, BOOL fNoReadCache
  329. )
  330. {
  331. HRESULT hr = NO_ERROR;
  332. PWCHAR pwcsExtension = NULL;
  333. PWCHAR pwc = NULL;
  334. PCHAR pcsExtension = "";
  335. STATSTG statstg;
  336. hr = pStreamSrc->Stat(&statstg, STATFLAG_NONAME);
  337. if (!SUCCEEDED(hr)) goto exit_StreamToIEFile;
  338. RonM_ASSERT(statstg.cbSize.HighPart == 0);
  339. FILETIME ftLastModified;
  340. ftLastModified.dwLowDateTime = 0;
  341. ftLastModified.dwHighDateTime = 0;
  342. // pmk->GetTimeOfLastChange(pBCtx, NULL, &ftLastModified);
  343. pwc = pwcsDisplayName + wcsLen(pwcsDisplayName);
  344. for (;;)
  345. {
  346. WCHAR wc = *--pwc;
  347. if (!pwcsExtension && wc == L'.')
  348. pwcsExtension = pwc + 1;
  349. if (wc == L':' || wc == L'/' || wc == L'\\')
  350. {
  351. pwc++;
  352. break;
  353. }
  354. RonM_ASSERT(pwc > pwcsDisplayName);
  355. }
  356. if (pwcsExtension && pwcsExtension[0])
  357. {
  358. UINT cwc = wcsLen(pwcsExtension);
  359. UINT cb = sizeof(WCHAR) * (cwc + 1);
  360. pcsExtension = PCHAR(_alloca(cb));
  361. if (!pcsExtension)
  362. {
  363. hr = E_OUTOFMEMORY;
  364. goto exit_StreamToIEFile;
  365. }
  366. cb = WideCharToMultiByte(GetACP(), WC_COMPOSITECHECK, pwcsExtension, cwc + 1,
  367. pcsExtension, cb, NULL, NULL
  368. );
  369. if (!cb)
  370. {
  371. hr = E_FAIL;
  372. goto exit_StreamToIEFile;
  373. }
  374. }
  375. if (fNoWriteCache)
  376. {
  377. DWORD cbPath= GetTempPath(MAX_PATH, pcsTempFile);
  378. if (!cbPath)
  379. lstrcpyA(pcsTempFile, ".\\");
  380. char szPrefix[4] = "IMT"; // BugBug! May need to make this a random string.
  381. char szFullPath[MAX_PATH];
  382. if (!GetTempFileName(pcsTempFile, szPrefix, 0, szFullPath))
  383. {
  384. hr = CFSLockBytes::CImpILockBytes::STGErrorFromFSError(GetLastError());
  385. pcsTempFile[0] = 0;
  386. goto exit_StreamToIEFile;
  387. }
  388. lstrcpyA(pcsTempFile, szFullPath);
  389. char *pch = pcsTempFile + lstrlenA(pcsTempFile);
  390. for (;;)
  391. {
  392. if (pch == pcsTempFile)
  393. {
  394. RonM_ASSERT(FALSE);
  395. hr = E_UNEXPECTED;
  396. DeleteFile(pcsTempFile);
  397. pcsTempFile[0] = 0;
  398. goto exit_StreamToIEFile;
  399. }
  400. if ('.' == *--pch)
  401. {
  402. ++pch;
  403. break;
  404. }
  405. }
  406. UINT cbExtension = lstrlenA(pcsExtension);
  407. if (pch + cbExtension - pcsTempFile >= MAX_PATH)
  408. {
  409. hr = E_UNEXPECTED;
  410. DeleteFile(pcsTempFile);
  411. pcsTempFile[0] = 0;
  412. goto exit_StreamToIEFile;
  413. }
  414. CopyMemory(pch, pcsExtension, cbExtension + 1);
  415. if (!MoveFileEx(szFullPath, pcsTempFile, MOVEFILE_REPLACE_EXISTING))
  416. {
  417. hr = E_UNEXPECTED;
  418. DeleteFile(szFullPath);
  419. pcsTempFile[0] = 0;
  420. goto exit_StreamToIEFile;
  421. }
  422. UINT cwc = MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, pcsTempFile,
  423. 1 + lstrlenA(pcsTempFile), pwcsFileName, MAX_PATH
  424. );
  425. if (cwc == 0)
  426. {
  427. hr = E_FAIL;
  428. DeleteFile(pcsTempFile);
  429. pcsTempFile [0] = 0;
  430. pwcsFileName[0] = 0;
  431. goto exit_StreamToIEFile;
  432. }
  433. hr = CopyStreamToFile((const WCHAR *)pwcsFileName, pStreamSrc);
  434. if (!SUCCEEDED(hr))
  435. {
  436. DeleteFile(pcsTempFile);
  437. pcsTempFile[0] = 0;
  438. pwcsFileName[0] = 0;
  439. goto exit_StreamToIEFile;
  440. }
  441. lstrcpyA(pcsFileName, pcsTempFile);
  442. }
  443. else
  444. {
  445. UINT cwc = wcsLen(pwcsDisplayName);
  446. UINT cb = sizeof(WCHAR) * (cwc + 1);
  447. pcsDisplayName = New char[cb];
  448. if (!pcsDisplayName)
  449. {
  450. hr = E_OUTOFMEMORY;
  451. goto exit_StreamToIEFile;
  452. }
  453. cb = WideCharToMultiByte(GetACP(), WC_COMPOSITECHECK, pwcsDisplayName, cwc + 1,
  454. pcsDisplayName, cb, NULL, NULL
  455. );
  456. if (!cb)
  457. {
  458. hr = INET_E_DOWNLOAD_FAILURE;
  459. delete [] pcsDisplayName; pcsDisplayName = NULL;
  460. goto exit_StreamToIEFile;
  461. }
  462. BOOL fResult = FALSE;
  463. DWORD dwCEISize = 0;
  464. ULONG ulErr = 0;
  465. if (!fNoReadCache)
  466. {
  467. RonM_ASSERT(dwCEISize == 0);
  468. fResult = RetrieveUrlCacheEntryFile(pcsDisplayName, NULL, &dwCEISize, 0);
  469. RonM_ASSERT(!fResult);
  470. ulErr= GetLastError();
  471. if (ulErr == ERROR_INSUFFICIENT_BUFFER)
  472. {
  473. dwCEISize += 4; // To work around a bug in the RetrieveUrlCacheEntryFile;
  474. // It sometimes gives an incorrect size immediately after
  475. // data has been copied to the cache.
  476. INTERNET_CACHE_ENTRY_INFOA *pCEI = (INTERNET_CACHE_ENTRY_INFOA *) _alloca(dwCEISize);
  477. if (!pCEI)
  478. {
  479. hr = E_OUTOFMEMORY;
  480. goto exit_StreamToIEFile;
  481. }
  482. pCEI->dwStructSize = sizeof(INTERNET_CACHE_ENTRY_INFOA);
  483. fResult = RetrieveUrlCacheEntryFile(pcsDisplayName, pCEI, &dwCEISize, 0);
  484. ulErr = GetLastError();
  485. if (fResult)
  486. if ( pCEI->LastModifiedTime.dwLowDateTime == ftLastModified.dwLowDateTime
  487. && pCEI->LastModifiedTime.dwHighDateTime == ftLastModified.dwHighDateTime
  488. && pCEI->dwSizeLow == statstg.cbSize.LowPart
  489. && pCEI->dwSizeHigh == statstg.cbSize.HighPart
  490. )
  491. {
  492. lstrcpyA(pcsFileName, pCEI->lpszLocalFileName);
  493. cwc = MultiByteToWideChar(GetACP(), MB_PRECOMPOSED,
  494. pcsFileName, 1 + lstrlenA(pcsFileName),
  495. pwcsFileName, MAX_PATH
  496. );
  497. RonM_ASSERT(cwc != 0);
  498. }
  499. else
  500. {
  501. UnlockUrlCacheEntryFile(pcsDisplayName, 0);
  502. fResult = FALSE;
  503. }
  504. }
  505. }
  506. if (!fResult)
  507. {
  508. fResult = CreateUrlCacheEntryA(pcsDisplayName, statstg.cbSize.LowPart,
  509. pcsExtension, pcsFileName, 0
  510. );
  511. if (!fResult)
  512. {
  513. hr = INET_E_CANNOT_INSTANTIATE_OBJECT;
  514. delete [] pcsDisplayName; pcsDisplayName = NULL;
  515. goto exit_StreamToIEFile;
  516. }
  517. cwc = MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, pcsFileName,
  518. 1 + lstrlenA(pcsFileName), pwcsFileName, MAX_PATH
  519. );
  520. hr = CopyStreamToFile((const WCHAR *) pwcsFileName, pStreamSrc);
  521. if (!fResult)
  522. {
  523. hr = INET_E_CANNOT_INSTANTIATE_OBJECT;
  524. delete [] pcsDisplayName; pcsDisplayName = NULL;
  525. pcsFileName[0] = 0;
  526. pwcsFileName[0] = 0;
  527. goto exit_StreamToIEFile;
  528. }
  529. FILETIME ftExpire;
  530. ftExpire.dwLowDateTime = 0;
  531. ftExpire.dwHighDateTime = 0;
  532. fResult = CommitUrlCacheEntryA(pcsDisplayName, pcsFileName, ftExpire,
  533. ftLastModified, NORMAL_CACHE_ENTRY, NULL,
  534. 0, pcsExtension, 0
  535. );
  536. if (!fResult)
  537. {
  538. ulErr= GetLastError();
  539. hr = INET_E_CANNOT_INSTANTIATE_OBJECT;
  540. delete [] pcsDisplayName; pcsDisplayName = NULL;
  541. pcsFileName[0] = 0;
  542. pwcsFileName[0] = 0;
  543. goto exit_StreamToIEFile;
  544. }
  545. dwCEISize = 0;
  546. fResult = RetrieveUrlCacheEntryFile(pcsDisplayName, NULL, &dwCEISize, 0);
  547. RonM_ASSERT(!fResult);
  548. ulErr= GetLastError();
  549. if (ulErr == ERROR_INSUFFICIENT_BUFFER)
  550. {
  551. dwCEISize += 4; // To work around a bug in the RetrieveUrlCacheEntryFile;
  552. // It sometimes gives an incorrect size immediately after
  553. // data has been copied to the cache.
  554. INTERNET_CACHE_ENTRY_INFOA *pCEI = (INTERNET_CACHE_ENTRY_INFOA *) _alloca(dwCEISize);
  555. if (!pCEI)
  556. {
  557. hr = E_OUTOFMEMORY;
  558. delete [] pcsDisplayName; pcsDisplayName = NULL;
  559. pcsFileName[0] = 0;
  560. pwcsFileName[0] = 0;
  561. goto exit_StreamToIEFile;
  562. }
  563. pCEI->dwStructSize = sizeof(INTERNET_CACHE_ENTRY_INFOA);
  564. fResult = RetrieveUrlCacheEntryFile(pcsDisplayName, pCEI, &dwCEISize, 0);
  565. if (!fResult)
  566. {
  567. ulErr= GetLastError();
  568. RonM_ASSERT(FALSE);
  569. hr = INET_E_CANNOT_INSTANTIATE_OBJECT;
  570. delete [] pcsDisplayName; pcsDisplayName = NULL;
  571. pcsFileName[0] = 0;
  572. pwcsFileName[0] = 0;
  573. goto exit_StreamToIEFile;
  574. }
  575. }
  576. }
  577. }
  578. return NO_ERROR;
  579. exit_StreamToIEFile:
  580. return hr;
  581. }
  582. HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::Continue
  583. (/* [in] */ PROTOCOLDATA __RPC_FAR *pProtocolData)
  584. {
  585. switch (pProtocolData->dwState)
  586. {
  587. case ITS_BIND_DATA:
  588. return ParseAndBind(TRUE);
  589. default:
  590. RonM_ASSERT(FALSE);
  591. return INET_E_INVALID_REQUEST;
  592. }
  593. }
  594. HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::Abort
  595. (
  596. /* [in] */ HRESULT hrReason,
  597. /* [in] */ DWORD dwOptions
  598. )
  599. {
  600. return ReportResult(E_ABORT, 0, 0);
  601. }
  602. HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::Terminate
  603. (/* [in] */ DWORD dwOptions)
  604. {
  605. if (m_pwcsURL)
  606. {
  607. delete [] m_pwcsURL; m_pwcsURL = NULL;
  608. }
  609. if (m_pOIProtSink)
  610. {
  611. m_pOIProtSink->Release(); m_pOIProtSink = NULL;
  612. }
  613. if (m_pOIBindInfo)
  614. {
  615. m_pOIBindInfo->Release(); m_pOIBindInfo = NULL;
  616. }
  617. return NO_ERROR;
  618. }
  619. HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::Suspend(void)
  620. {
  621. return NO_ERROR;
  622. }
  623. HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::Resume(void)
  624. {
  625. return NO_ERROR;
  626. }
  627. // IOITnetProtocol interfaces:
  628. HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::Read
  629. (
  630. /* [length_is][size_is][out] */ void __RPC_FAR *pv,
  631. /* [in] */ ULONG cb,
  632. /* [out] */ ULONG __RPC_FAR *pcbRead
  633. )
  634. {
  635. if (m_pStream)
  636. return m_pStream->Read(pv, cb, pcbRead);
  637. else return INET_E_DATA_NOT_AVAILABLE;
  638. }
  639. HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::Seek
  640. (
  641. /* [in] */ LARGE_INTEGER dlibMove,
  642. /* [in] */ DWORD dwOrigin,
  643. /* [out] */ ULARGE_INTEGER __RPC_FAR *plibNewPosition
  644. )
  645. {
  646. if (m_pStream)
  647. return m_pStream->Seek(dlibMove, dwOrigin, plibNewPosition);
  648. else return INET_E_DATA_NOT_AVAILABLE;
  649. }
  650. HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::LockRequest
  651. (/* [in] */ DWORD dwOptions)
  652. {
  653. return NO_ERROR;
  654. }
  655. HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::UnlockRequest(void)
  656. {
  657. return NO_ERROR;
  658. }
  659. HRESULT STDMETHODCALLTYPE DisectUrl
  660. (PWCHAR pwcsUrlBuffer, PWCHAR *ppwcProtocolName,
  661. PWCHAR *ppwcExternalPath,
  662. PWCHAR *ppwcInternalPath
  663. )
  664. {
  665. PWCHAR pwcProtocolName = NULL,
  666. pwcExternalPath = NULL,
  667. pwcInternalPath = NULL;
  668. MapSurrogateCharacters(pwcsUrlBuffer);
  669. PWCHAR pwc = wcsChr((const WCHAR *) pwcsUrlBuffer, L':');
  670. if (!pwc)
  671. return URL_E_INVALID_SYNTAX;
  672. *pwc++ = 0;
  673. pwcProtocolName = pwcsUrlBuffer;
  674. if ( L'@' == *pwcProtocolName
  675. && !wcsicmp_0x0409((const WCHAR *) (pwcProtocolName+1), L"msitstore")
  676. )
  677. {
  678. pwcProtocolName = L"mk:@msitstore";
  679. }
  680. else if (!wcsicmp_0x0409((const WCHAR *)pwcProtocolName, L"mk"))
  681. {
  682. // This URL begins with "mk:". We handle entries which
  683. // begin with "mk:@MSITStore:"
  684. // We treat the @<classid> as part of the protocol name.
  685. // So we must first put the colon separator back.
  686. pwc[-1] = L':';
  687. if (L'@' != *pwc) return URL_E_INVALID_SYNTAX;
  688. PWCHAR pwcClassName = pwc + 1;
  689. pwc = wcsChr((const WCHAR *) pwcClassName, L':');
  690. if (!pwc) return URL_E_INVALID_SYNTAX;
  691. *pwc++ = 0;
  692. if (wcsicmp_0x0409((const WCHAR *)pwcClassName, L"msitstore"))
  693. return INET_E_DEFAULT_ACTION;
  694. }
  695. else if (!wcsicmp_0x0409((const WCHAR *)pwcsUrlBuffer, L"its"))
  696. {
  697. }
  698. else if (!wcsicmp_0x0409((const WCHAR *)pwcsUrlBuffer, L"ms-its"))
  699. {
  700. }
  701. else return INET_E_DEFAULT_ACTION;
  702. pwcExternalPath = pwc;
  703. pwc += wcsLen(pwc);
  704. for (; pwc > pwcExternalPath; )
  705. {
  706. WCHAR wc = *--pwc;
  707. if (wc == L':')
  708. if (pwc > pwcExternalPath && L':' == *--pwc)
  709. {
  710. *pwc = 0;
  711. pwc += 2;
  712. break;
  713. }
  714. }
  715. if (pwc == pwcExternalPath)
  716. pwc += wcsLen(pwc);
  717. if (!*pwcExternalPath || wcsLen(pwcExternalPath) >= MAX_PATH) return URL_E_INVALID_SYNTAX;
  718. pwcInternalPath = pwc;
  719. for (;*pwc; pwc++);
  720. if (pwcInternalPath == pwc)
  721. pwcInternalPath = L"/";
  722. if (wcsLen(pwcInternalPath) >= MAX_PATH) return URL_E_INVALID_SYNTAX;
  723. if (ppwcProtocolName) *ppwcProtocolName = pwcProtocolName;
  724. if (ppwcExternalPath) *ppwcExternalPath = pwcExternalPath;
  725. if (ppwcInternalPath) *ppwcInternalPath = pwcInternalPath;
  726. return NO_ERROR;
  727. }
  728. HRESULT STDMETHODCALLTYPE AssembleUrl
  729. (PWCHAR pwcsResult, DWORD cwcBuffer, DWORD *pcwcRequired,
  730. PWCHAR pwcsProtocolName, PWCHAR pwcsExternalPath, PWCHAR pwcsInternalPath
  731. )
  732. {
  733. UINT cwc = wcsLen(pwcsProtocolName) + wcsLen(pwcsExternalPath)
  734. + wcsLen(pwcsInternalPath)
  735. + 4;
  736. *pcwcRequired = cwc;
  737. if (cwc > cwcBuffer)
  738. return E_OUTOFMEMORY;
  739. wcsCpy(pwcsResult, pwcsProtocolName);
  740. wcsCat(pwcsResult, L":");
  741. wcsCat(pwcsResult, pwcsExternalPath);
  742. wcsCat(pwcsResult, L"::");
  743. wcsCat(pwcsResult, pwcsInternalPath);
  744. return NO_ERROR;
  745. }
  746. HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::ParseUrl
  747. (
  748. /* [in] */ LPCWSTR pwzUrl,
  749. /* [in] */ PARSEACTION ParseAction,
  750. /* [in] */ DWORD dwParseFlags,
  751. /* [out] */ LPWSTR pwzResult,
  752. /* [in] */ DWORD cchResult,
  753. /* [out] */ DWORD __RPC_FAR *pcchResult,
  754. /* [in] */ DWORD dwReserved
  755. )
  756. {
  757. switch (ParseAction)
  758. {
  759. case PARSE_CANONICALIZE:
  760. case PARSE_SECURITY_URL:
  761. {
  762. // First we make a working copy of the URL.
  763. UINT cwc = wcsLen(pwzUrl);
  764. UINT cb = sizeof(WCHAR) * (cwc + 1);
  765. PWCHAR pwcsUrl = PWCHAR(_alloca(cb));
  766. if (!pwcsUrl)
  767. return E_OUTOFMEMORY;
  768. CopyMemory(pwcsUrl, pwzUrl, cb);
  769. PWCHAR pwcProtocolName = NULL,
  770. pwcExternalPath = NULL,
  771. pwcInternalPath = NULL;
  772. BOOL fLocalFilePath = FALSE;
  773. HRESULT hr = DisectUrl(pwcsUrl, &pwcProtocolName, &pwcExternalPath, &pwcInternalPath);
  774. if (!SUCCEEDED(hr)) return hr;
  775. // Here we copy the external path string to a buffer because
  776. // it may be a partial local path which needs to be mapped into
  777. // a full path.
  778. WCHAR awcsExternalPath[MAX_PATH];
  779. RonM_ASSERT(wcsLen(pwcExternalPath) < MAX_PATH);
  780. wcsCpy(awcsExternalPath, pwcExternalPath);
  781. PWCHAR pwc = wcsChr((const WCHAR *) awcsExternalPath, L':');
  782. if (pwc && pwc[1] == L':') // Ignore a "::" separator
  783. pwc = NULL;
  784. // Here we're special casing non-protocol references to a file.
  785. // We recognize those situations by looking for a protocol prefix.
  786. // Protocol prefixes have the form <Protocol Name> :
  787. // where <Protocol Name> is always longer than one character.
  788. if (!pwc || (pwc - awcsExternalPath == 1))
  789. {
  790. fLocalFilePath = TRUE;
  791. if (FindRootStorageFile(awcsExternalPath) == S_OK)
  792. pwcExternalPath = awcsExternalPath;
  793. }
  794. if (ParseAction == PARSE_SECURITY_URL)
  795. {
  796. UINT cwcExt = 1 + wcsLen(pwcExternalPath);
  797. if (fLocalFilePath)
  798. {
  799. // It's a local file. Got to prefix the result with
  800. // "File://".
  801. RonM_ASSERT(7 == wcsLen(L"File://"));
  802. *pcchResult = cwcExt + 7;
  803. if (cchResult < (cwcExt + 7))
  804. return E_OUTOFMEMORY;
  805. CopyMemory(pwzResult, L"File://", 7 * sizeof(WCHAR));
  806. pwzResult += 7;
  807. }
  808. else
  809. {
  810. *pcchResult = cwcExt;
  811. if (cwcExt > cchResult)
  812. return E_OUTOFMEMORY;
  813. }
  814. CopyMemory(pwzResult, pwcExternalPath, cwcExt * sizeof(WCHAR));
  815. return NO_ERROR;
  816. }
  817. cwc = wcsLen(pwcInternalPath);
  818. BOOL fStorage = pwcInternalPath[cwc-1] == L'/' || pwcInternalPath[cwc-1] == L'\\';
  819. WCHAR awcsInternalPath[MAX_PATH];
  820. hr = ResolvePath(awcsInternalPath, L"/", (const WCHAR *) pwcInternalPath, fStorage);
  821. if (!SUCCEEDED(hr)) return hr;
  822. hr = AssembleUrl(pwzResult, cchResult, pcchResult,
  823. pwcProtocolName, pwcExternalPath, awcsInternalPath
  824. );
  825. return hr;
  826. }
  827. case PARSE_FRIENDLY:
  828. case PARSE_ROOTDOCUMENT:
  829. case PARSE_DOCUMENT:
  830. case PARSE_ANCHOR:
  831. case PARSE_ENCODE:
  832. case PARSE_DECODE:
  833. case PARSE_PATH_FROM_URL:
  834. case PARSE_URL_FROM_PATH:
  835. case PARSE_LOCATION:
  836. case PARSE_MIME:
  837. case PARSE_SECURITY_DOMAIN:
  838. default:
  839. return INET_E_DEFAULT_ACTION;
  840. }
  841. }
  842. HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::CombineUrl
  843. (
  844. /* [in] */ LPCWSTR pwzBaseUrl,
  845. /* [in] */ LPCWSTR pwzRelativeUrl,
  846. /* [in] */ DWORD dwCombineFlags,
  847. /* [out] */ LPWSTR pwzResult,
  848. /* [in] */ DWORD cchResult,
  849. /* [out] */ DWORD __RPC_FAR *pcchResult,
  850. /* [in] */ DWORD dwReserved
  851. )
  852. {
  853. // First we make a working copy of the URL.
  854. UINT cwc = wcsLen(pwzBaseUrl);
  855. UINT cb = sizeof(WCHAR) * (cwc + 1);
  856. PWCHAR pwcsUrl = PWCHAR(_alloca(cb));
  857. if (!pwcsUrl)
  858. return E_OUTOFMEMORY;
  859. CopyMemory(pwcsUrl, pwzBaseUrl, cb);
  860. PWCHAR pwcProtocolName = NULL,
  861. pwcExternalPath = NULL,
  862. pwcInternalPath = NULL;
  863. HRESULT hr = DisectUrl(pwcsUrl, &pwcProtocolName, &pwcExternalPath, &pwcInternalPath);
  864. if (!SUCCEEDED(hr)) return hr;
  865. WCHAR awcsInternalPath[MAX_PATH];
  866. if (*pwzRelativeUrl == L'#')
  867. {
  868. // Special case for intra page relative URLs.
  869. // BugBug! How many other special case do we need to add to match
  870. // the behavior of file:// and html:// ??
  871. if (wcsLen(pwcInternalPath) + wcsLen(pwzRelativeUrl) >= MAX_PATH)
  872. return INET_E_INVALID_URL;
  873. wcsCpy(awcsInternalPath, pwcInternalPath);
  874. wcsCat(awcsInternalPath, pwzRelativeUrl);
  875. }
  876. else
  877. {
  878. // Here we assume that the relative url is a stream path suffix.
  879. // Since we'll be combining with pwzRelativeUrl we must first
  880. // truncate the internal path at the last storage name separator.
  881. PWCHAR pwc = pwcInternalPath + wcsLen(pwcInternalPath);
  882. for (;;)
  883. {
  884. WCHAR wc = *--pwc;
  885. if (wc == L'/' || wc == L'\\') break;
  886. }
  887. *++pwc = 0;
  888. cwc = wcsLen(pwzRelativeUrl);
  889. if (!cwc) return URL_E_INVALID_SYNTAX;
  890. WCHAR wc = pwzRelativeUrl[cwc - 1];
  891. hr = ResolvePath(awcsInternalPath, (const WCHAR *) pwcInternalPath,
  892. (const WCHAR *) pwzRelativeUrl,
  893. (wc == L'/' || wc == L'\\')
  894. );
  895. if (!SUCCEEDED(hr)) return hr;
  896. }
  897. hr = AssembleUrl(pwzResult, cchResult, pcchResult,
  898. pwcProtocolName, pwcExternalPath, awcsInternalPath
  899. );
  900. return hr;
  901. }
  902. HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::CompareUrl
  903. (
  904. /* [in] */ LPCWSTR pwzUrl1,
  905. /* [in] */ LPCWSTR pwzUrl2,
  906. /* [in] */ DWORD dwCompareFlags
  907. )
  908. {
  909. DWORD cwc1 = wcsLen(pwzUrl1);
  910. PWCHAR pwcsBuffer1 = PWCHAR(_alloca((cwc1 + 1) * sizeof(WCHAR)));
  911. if (!pwcsBuffer1) return E_OUTOFMEMORY;
  912. CopyMemory(pwcsBuffer1, pwzUrl1, sizeof(WCHAR) * (cwc1 + 1));
  913. PWCHAR pwcsExternalPath1 = NULL;
  914. PWCHAR pwcsInternalPath1 = NULL;
  915. HRESULT hr = DisectUrl(pwcsBuffer1, NULL, &pwcsExternalPath1, &pwcsInternalPath1);
  916. if (!SUCCEEDED(hr))
  917. return hr;
  918. WCHAR awcsExternalPath1[MAX_PATH];
  919. if (wcsLen(pwcsExternalPath1) < MAX_PATH)
  920. {
  921. wcsCpy(awcsExternalPath1, pwcsExternalPath1);
  922. PWCHAR pwc = wcsChr((const WCHAR *) awcsExternalPath1, L':');
  923. if (pwc && pwc[1] == L':') // Ignore a "::" separator
  924. pwc = NULL;
  925. // Here we're special casing non-protocol references to a file.
  926. // We recognize those situations by looking for a protocol prefix.
  927. // Protocol prefixes have the form <Protocol Name> :
  928. // where <Protocol Name> is always longer than one character.
  929. if (!pwc || (pwc - awcsExternalPath1 == 1))
  930. {
  931. if (FindRootStorageFile(awcsExternalPath1) == S_OK)
  932. pwcsExternalPath1 = awcsExternalPath1;
  933. }
  934. }
  935. DWORD cwc2 = wcsLen(pwzUrl2);
  936. PWCHAR pwcsBuffer2 = PWCHAR(_alloca((cwc2 + 1) * sizeof(WCHAR)));
  937. if (!pwcsBuffer2) return E_OUTOFMEMORY;
  938. CopyMemory(pwcsBuffer2, pwzUrl2, sizeof(WCHAR) * (cwc2 + 1));
  939. PWCHAR pwcsExternalPath2 = NULL;
  940. PWCHAR pwcsInternalPath2 = NULL;
  941. hr = DisectUrl(pwcsBuffer2, NULL, &pwcsExternalPath2, &pwcsInternalPath2);
  942. if (!SUCCEEDED(hr))
  943. return hr;
  944. WCHAR awcsExternalPath2[MAX_PATH];
  945. if (wcsLen(pwcsExternalPath2) < MAX_PATH)
  946. {
  947. wcsCpy(awcsExternalPath2, pwcsExternalPath2);
  948. PWCHAR pwc = wcsChr((const WCHAR *) awcsExternalPath2, L':');
  949. if (pwc && pwc[1] == L':') // Ignore a "::" separator
  950. pwc = NULL;
  951. // Here we're special casing non-protocol references to a file.
  952. // We recognize those situations by looking for a protocol prefix.
  953. // Protocol prefixes have the form <Protocol Name> :
  954. // where <Protocol Name> is always longer than one character.
  955. if (!pwc || (pwc - awcsExternalPath2 == 1))
  956. {
  957. if (FindRootStorageFile(awcsExternalPath2) == S_OK)
  958. pwcsExternalPath2 = awcsExternalPath2;
  959. }
  960. }
  961. if (wcsicmp_0x0409((const WCHAR *) pwcsExternalPath1, (const WCHAR *) pwcsExternalPath2))
  962. return S_FALSE;
  963. if (wcsicmp_0x0409((const WCHAR *) pwcsInternalPath1, (const WCHAR *) pwcsInternalPath2))
  964. return S_FALSE;
  965. return S_OK;
  966. }
  967. HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::QueryInfo
  968. (
  969. /* [in] */ LPCWSTR pwzUrl,
  970. /* [in] */ QUERYOPTION QueryOption,
  971. /* [in] */ DWORD dwQueryFlags,
  972. /* [size_is][out][in] */ LPVOID pBuffer,
  973. /* [in] */ DWORD cbBuffer,
  974. /* [out][in] */ DWORD __RPC_FAR *pcbBuf,
  975. /* [in] */ DWORD dwReserved
  976. )
  977. {
  978. switch (QueryOption)
  979. {
  980. case QUERY_CAN_NAVIGATE: // What does this really mean?
  981. if (pcbBuf) *pcbBuf = sizeof(DWORD);
  982. if (cbBuffer < sizeof(DWORD)) return E_FAIL;
  983. *(DWORD *) pBuffer = TRUE;
  984. return NO_ERROR;
  985. case QUERY_EXPIRATION_DATE:
  986. case QUERY_TIME_OF_LAST_CHANGE:
  987. // case QUERY_CONTEXT_ENCODING:
  988. case QUERY_REFRESH:
  989. case QUERY_RECOMBINE:
  990. default:
  991. // RonM_ASSERT(FALSE);
  992. return E_NOTIMPL;
  993. }
  994. }
  995. #ifdef PROFILING
  996. // These wrapper functions are defined for the profiling version
  997. // of the code so that we can measure how much time is consumed
  998. // by callbacks into URLMON.
  999. HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::Switch
  1000. (PROTOCOLDATA __RPC_FAR *pProtocolData)
  1001. {
  1002. return m_pOIProtSink->Switch(pProtocolData);
  1003. }
  1004. HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::ReportProgress
  1005. (ULONG ulStatusCode, LPCWSTR szStatusText)
  1006. {
  1007. return m_pOIProtSink->ReportProgress(ulStatusCode, szStatusText);
  1008. }
  1009. HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::ReportData
  1010. (DWORD grfBSCF, ULONG ulProgress, ULONG ulProgressMax)
  1011. {
  1012. return m_pOIProtSink->ReportData(grfBSCF, ulProgress, ulProgressMax);
  1013. }
  1014. HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::ReportResult
  1015. (HRESULT hrResult, DWORD dwError, LPCWSTR szResult)
  1016. {
  1017. return m_pOIProtSink->ReportResult(hrResult, dwError, szResult);
  1018. }
  1019. HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::GetBindInfo
  1020. (DWORD __RPC_FAR *grfBINDF,
  1021. BINDINFO __RPC_FAR *pbindinfo
  1022. )
  1023. {
  1024. return m_pOIBindInfo->GetBindInfo(grfBINDF, pbindinfo);
  1025. }
  1026. HRESULT STDMETHODCALLTYPE CIOITnetProtocol::CImpIOITnetProtocol::GetBindString
  1027. (ULONG ulStringType, LPOLESTR __RPC_FAR *ppwzStr,
  1028. ULONG cEl, ULONG __RPC_FAR *pcElFetched
  1029. )
  1030. {
  1031. return m_pOIBindInfo->GetBindString(ulStringType, ppwzStr, cEl, pcElFetched);
  1032. }
  1033. #endif // PROFILING