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.

627 lines
18 KiB

  1. // BSCB.cpp -- Implementation for the CBindStatusCallBack class
  2. #include "stdafx.h"
  3. HRESULT STDMETHODCALLTYPE CBindStatusCallBack::CreateHook(IBindCtx pBC, IMoniker pMK)
  4. {
  5. CBindStatusCallBack *pBSCB = New CBindStatusCallBack(NULL);
  6. IBindStatusCallback *pCallBack = NULL;
  7. HRESULT hr = FinishSetup(pBSCB? pBSCB->m_Implementation.Init(pBC, pMK)
  8. : STG_E_INSUFFICIENTMEMORY,
  9. pBSCB, IID_IBindStatusCallback, (PPVOID) &pCallBack
  10. );
  11. if (pCallBack) pCallBack->Release();
  12. }
  13. CBindStatusCallBack::Implementation::Implementation
  14. (CBindStatusCallBack *pBackObj, IUnknown *punkOuter)
  15. : ITBindStatusCallback(pBackObj, punkOuter)
  16. {
  17. m_pBCHooked = NULL;
  18. m_pBSCBClient = NULL;
  19. m_pStream = NULL;
  20. m_grfBINDF = 0;
  21. m_awcsFile[0] = 0;
  22. m_fTempFile = FALSE;
  23. m_bindinfo.cbSize = sizeof(BINDINFO);
  24. }
  25. CBindStatusCallBack::Implementation::~Implementation()
  26. {
  27. if (m_pStream) m_pStream->Release();
  28. if (m_fTempFile)
  29. {
  30. RonM_ASSERT(m_awcsFile[0]);
  31. UINT cwc = wcsLen(m_awcsFile) + 1;
  32. UINT cb = cwc * sizeof(WCHAR);
  33. char *pszFile = PCHAR(_alloca(cb));
  34. RonM_ASSERT(pszFile);
  35. if (pchr)
  36. {
  37. UINT c = WideCharToMultiByte(GetACP(), WC_COMPOSITECHECK, m_awcsFile, cwc,
  38. pszFile, cb, NULL, NULL
  39. );
  40. RonM_ASSERT(c);
  41. if (c) DeleteFile(pszFile);
  42. }
  43. }
  44. if (m_pBC)
  45. RevokeBindStatusCallback(m_pBC, this);
  46. if (m_pBSCBClient) m_pBSCBClient->Release();
  47. }
  48. HRESULT STDMETHODCALLTYPE CBindStatusCallBack::Implementation::Init(IBindCtx pBC, IMoniker pMK)
  49. {
  50. RonM_ASSERT(pBC);
  51. RonM_ASSERT(pMK);
  52. if (!SUCCEEDED(hr)) return hr;
  53. HRESULT hr = pMK->BindToStorage(pBC, NULL, IID_IStream, (PPVOID) &pStrm1);
  54. if (!SUCCEEDED(hr)) return hr;
  55. IUnknown *pUnk = NULL;
  56. hr = pBC->GetObjectParam(L"_BSCB_HOLDER_", &pUnk);
  57. if (!SUCCEEDED(hr)) return hr;
  58. hr = pUnk->QueryInterface(IID_IBindStatusCallback, &m_pBSCBClient);
  59. pUnk->Release();
  60. if (!SUCCEEDED(hr)) return hr;
  61. hr = RegisterBindStatusCallback(pBC, this, &m_pBSCBClient, 0);
  62. if (!SUCCEEDED(hr)) return hr;
  63. m_pBC = pBC;
  64. m_pBC->AddRef();
  65. RonM_ASSERT(statstg.cbSize.HighPart == 0);
  66. m_pBSCBClient->GetBindInfo(&m_grfBINDF, &m_bindinfo);
  67. if (!SUCCEEDED(hr)) return hr;
  68. IStream *pStrmITS = NULL;
  69. hr = GetStreamFromMoniker(pBC, pMK, m_grfBINDF, m_awcsFile, &m_pStream);
  70. if (hr == S_FALSE) m_fTempFile = TRUE;
  71. if (!SUCCEEDED(hr)) return hr;
  72. STATSTG statstg;
  73. hr = m_pStream->Stat(&statstg, STATFLAG_NONAME);
  74. if (!SUCCEEDED(hr)) return hr;
  75. hr = m_pBSCBClient->OnProgress(0, statstg.cbSize.LowPart,
  76. BINDSTATUS_SENDINGREQUEST, L""
  77. );
  78. if (!SUCCEEDED(hr)) return hr;
  79. hr = m_pBSCBClient->OnProgress(0, statstg.cbSize.LowPart,
  80. BINDSTATUS_BEGINDOWNLOADDATA, L""
  81. );
  82. if (!SUCCEEDED(hr)) return hr;
  83. if (m_awcsFile[0])
  84. {
  85. hr = m_pBSCBClient->OnProgress(0, statstg.cbSize.LowPart,
  86. BINDSTATUS_CACHEFILENAMEAVAILABLE, m_awcsFile
  87. );
  88. if (!SUCCEEDED(hr)) return hr;
  89. }
  90. hr = m_pBSCBClient->OnProgress(0, statstg.cbSize.LowPart,
  91. BINDSTATUS_DOWNLOADINGDATA, L""
  92. );
  93. if (!SUCCEEDED(hr)) return hr;
  94. hr = m_pBSCBClient->OnProgress(statstg.cbSize.LowPart, statstg.cbSize.LowPart,
  95. ENDDOWNLOADDATA, L""
  96. );
  97. if (!SUCCEEDED(hr)) return hr;
  98. FORMATETC fmetc;
  99. STGMEDIUM stgmed;
  100. hr = m_pBSCBClient->OnDataAvailable(BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION
  101. | BSCF_DATAFULLYAVAILABLE,
  102. statstg.cbSize.LowPart,
  103. FORMATETC *pfmtetc,
  104. STGMEDIUM *pstgmed
  105. );
  106. return hr;
  107. }
  108. HRESULT STDMETHODCALLTYPE CopyStreamToFile(IStream *ppStreamSrc, const WCHAR *pwcsFilePath)
  109. {
  110. IStream *pStream;
  111. IStream *pStreamSrc = *ppStreamSrc;
  112. IFSStorage *pFSS = NULL;
  113. HRESULT hr = CFileSystemStorage::Create(NULL, IID_IFSStorage, (VOID **) &pFSS);
  114. if (!SUCCEEDED(hr)) return hr;
  115. hr = pFSS->FSOpenStream((const WCHAR *) pwcsFilePath,
  116. STGM_READWRITE | STGM_SHARE_DENY_NONE,
  117. &pStream
  118. );
  119. pFSS->Release();
  120. if (!SUCCEEDED(hr)) return hr;
  121. RonM_ASSERT(pStreamSrc);
  122. STATSTG statstg;
  123. hr = pStreamSrc->Stat(&statstg, STATFLAG_NONAME);
  124. if (!SUCCEEDED(hr)) return hr;
  125. #ifdef _DEBUG
  126. hr =
  127. #endif // _DEBUG
  128. pStreamSrc->Seek(CLINT(0).Li(), STREAM_SEEK_SET, NULL);
  129. RonM_ASSERT(hr == S_OK);
  130. hr = pStreamSrc->CopyTo(pStream, statstg.cbSize, NULL, NULL);
  131. pStream->Release();
  132. if (!SUCCEEDED(hr)) return hr;
  133. #ifdef _DEBUG
  134. hr =
  135. #endif // _DEBUG
  136. pStream->Seek(CLINT(0).Li(), STREAM_SEEK_SET, NULL);
  137. #ifdef _DEBUG
  138. hr =
  139. #endif // _DEBUG
  140. pStreamSrc->Seek(CLINT(0).Li(), STREAM_SEEK_SET, NULL);
  141. RonM_ASSERT(hr == S_OK);
  142. *ppStreamSrc->Release();
  143. *ppStreamSrc = pStream;
  144. return hr;
  145. }
  146. HRESULT STDMETHODCALLTYPE GetStreamFromMoniker
  147. (IBindCtx *pBC, IMoniker *pMK, DWORD grfBINDF, PSZ pwcsFile, IStream **ppStrm)
  148. {
  149. BOOL fNoFile = m_grfBINDF & (BINDF_PULLDATA | BINDF_DIRECT_READ);
  150. BOOL fNoReadCache = m_grfBINDF & (BINDF_GETNEWESTVERSION | BINDF_NOWRITECACHE
  151. | BINDF_PULLDATA
  152. | BINDF_PRAGMA_NO_CACHE
  153. | BINDF_DIRECT_READ
  154. );
  155. BOOL fNoWriteCache = m_grfBINDF & (BINDF_NOWRITECACHE | BINDF_PULLDATA
  156. | BINDF_PRAGMA_NO_CACHE
  157. | BINDF_DIRECT_READ
  158. );
  159. BOOL fTempFile = FALSE;
  160. WCHAR *pwcsDisplayName = NULL;
  161. char *pcsDisplayName = NULL;
  162. WCHAR *pwcsExtension = NULL;
  163. WCHAR *pwcsName = NULL;
  164. IStream *pStrmITS = NULL;
  165. HRESULT hr = pMK->GetDisplayName(pBCtx, NULL, &pwcsDisplayName);
  166. if (!SUCCEEDED(hr)) return hr;
  167. UINT cwc = wcsLen(pwcsDisplayName);
  168. UINT cb = sizeof(WCHAR) * (cwc + 1);
  169. *pcsDisplayName = PCHAR(_alloca(cb));
  170. if (!pcsDisplayName)
  171. {
  172. hr = E_OUTOFMEMORY;
  173. goto exit_GetStreamFromMoniker;
  174. }
  175. cb = WideCharToMultiByte(GetACP(), WC_COMPOSITECHECK, pwcsDisplayName, cwc + 1,
  176. pcsDisplayName, cb, NULL, NULL
  177. );
  178. if (!cb)
  179. {
  180. hr = INET_E_DOWNLOAD_FAILURE;
  181. goto exit_GetStreamFromMoniker;
  182. }
  183. {
  184. UINT cwc = wcsLen(pwcsURL);
  185. WCHAR *pwc = pwcsURL + cwc;
  186. for (;;)
  187. {
  188. WCHAR wc = *--pwc;
  189. if (wc == L'.')
  190. pwcsExtension = pwc + 1;
  191. if (wc == L':' || wc == L'/' || wc == L'\\')
  192. {
  193. pwcsName = ++pwc;
  194. break;
  195. }
  196. RonM_ASSERT(--cwc);
  197. }
  198. }
  199. hr = pMK->BindToStorage(pBC, NULL, IID_IStream, (VOID **) &pStrmITS);
  200. if (!SUCCEEDED(hr)) goto exit_GetStreamFromMoniker;
  201. STATSTG statstg;
  202. hr = pStrmITS->Stat(&statstg, STATFLAG_NONAME);
  203. if (!SUCCEEDED(hr)) goto exit_GetStreamFromMoniker;
  204. FILETIME ftLastModified;
  205. ftLastModified.dwLowDateTime = 0;
  206. ftLastModified.dwHighDateTime = 0;
  207. // pMK->GetTimeOfLastChange(pBCtx, NULL, &ftLastModified);
  208. RonM_ASSERT(statstg.cbSize.HighPart == 0);
  209. *pszFile = 0; // In case we don't get the stream into a file.
  210. if (!fNoFile)
  211. {
  212. CHAR acsFilePath[MAX_PATH];
  213. WCHAR awcsFilePath[MAX_PATH];
  214. char szTempPath[MAX_PATH];
  215. szTempPath[0] = 0;
  216. PCHAR pcsExtension = "";
  217. if (pwcsExtension && pwcsExtension[1])
  218. {
  219. UINT cwc = wcsLen(pwcsExtension);
  220. UINT cb = sizeof(WCHAR) * (cwc + 1);
  221. pcsExtension = PCHAR(_alloca(cb));
  222. if (!pcsExtension)
  223. {
  224. hr = E_OUTOFMEMORY;
  225. goto exit_GetStreamFromMoniker;
  226. }
  227. cb = WideCharToMultiByte(GetACP(), WC_COMPOSITECHECK, pwcsExtension, cwc + 1,
  228. pcsExtension, cb, NULL, NULL
  229. );
  230. if (!cb)
  231. {
  232. hr = INET_E_DOWNLOAD_FAILURE;
  233. goto exit_GetStreamFromMoniker;
  234. }
  235. }
  236. if (fNoWriteCache)
  237. {
  238. DWORD cbPath= GetTempPath(MAX_PATH, szTempPath);
  239. if (!cbPath)
  240. lstrcpyA(szTempPath, ".\\");
  241. char szPrefix[4] = "IMT"; // BugBug! May need to make this a random string.
  242. char szFullPath[MAX_PATH];
  243. if (!GetTempFileName(szTempPath, szPrefix, 0, szFullPath))
  244. {
  245. hr = CFSLockBytes::CImpILockBytes::STGErrorFromFSError(GetLastError());
  246. szTempPath[0] = 0;
  247. goto exit_GetStreamFromMoniker;
  248. }
  249. lstrcpyA(szTempPath, szFullPath);
  250. char *pch = szTempPath + lstrlenA(szTempPath);
  251. for (;;)
  252. {
  253. if (pch == szTempPath)
  254. {
  255. RonM_ASSERT(FALSE);
  256. hr = E_UNEXPECTED;
  257. DeleteFile(szTempPath);
  258. szTempPath[0] = 0;
  259. goto exit_GetStreamFromMoniker;
  260. }
  261. if ('.' == *--pch)
  262. {
  263. ++pch;
  264. break;
  265. }
  266. }
  267. UINT cbExtension = lstrlenA(pcsExtension);
  268. if (pch + cbExtension - szTempPath >= MAX_PATH)
  269. {
  270. hr = E_UNEXPECTED;
  271. DeleteFile(szTempPath);
  272. szTempPath[0] = 0;
  273. goto exit_GetStreamFromMoniker;
  274. }
  275. CopyMemory(pch, pcsExtension, cbExtension + 1);
  276. if (!MoveFileEx(szFullPath, szTempPath, MOVEFILE_REPLACE_EXISTING))
  277. {
  278. hr = E_UNEXPECTED;
  279. DeleteFile(szFullPath);
  280. szTempPath[0] = 0;
  281. goto exit_GetStreamFromMoniker;
  282. }
  283. UINT cwc = MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, szTempPath,
  284. 1 + lstrlenA(szTempPath), awcsFilePath, MAX_PATH
  285. );
  286. if (cwc)
  287. hr = CopyStreamToFile(&pStrmITS, (const WCHAR *)awcsFilePath);
  288. else hr = E_UNEXPECTED;
  289. if (SUCCEEDED(hr))
  290. {
  291. fTempFile = TRUE;
  292. CopyMemory(pwcsFile, awcsFilePath, cwc * sizeof(WCHAR));
  293. }
  294. else
  295. {
  296. DeleteFile(szTempPath);
  297. goto exit_GetStreamFromMoniker;
  298. }
  299. }
  300. else
  301. {
  302. DWORD dwCEISize = 0;
  303. BOOL fResult = RetrieveUrlCacheEntryFile(pcsDisplayName, NULL, &dwCEISize, 0);
  304. RonM_ASSERT(!fResult);
  305. ULONG ulErr= GetLastError();
  306. if (ulErr == ERROR_INSUFFICIENT_BUFFER)
  307. {
  308. INTERNET_CACHE_ENTRY_INFOA *pCEI = (INTERNET_CACHE_ENTRY_INFOA *) _alloca(dwCEISize);
  309. if (!pCEI)
  310. {
  311. hr = E_OUTOFMEMORY;
  312. goto exit_GetStreamFromMoniker;
  313. }
  314. pCEI->dwStructSize = sizeof(INTERNET_CACHE_ENTRY_INFOA);
  315. fResult = RetrieveUrlCacheEntryFile(pcsDisplayName, pCEI, &dwCEISize, 0);
  316. ulErr = GetLastError();
  317. if (fResult)
  318. if ( pCEI->LastModifiedTime.dwLowDateTime == ftLastModified.dwLowDateTime
  319. && pCEI->LastModifiedTime.dwHighDateTime == ftLastModified.dwHighDateTime
  320. && pCEI->dwSizeLow == statstg.cbSize.LowPart
  321. && pCEI->dwSizeHigh == statstg.cbSize.HighPart
  322. )
  323. {
  324. lstrcpyA(acsFilePath, pCEI->lpszLocalFileName);
  325. cwc = MultiByteToWideChar(GetACP(), MB_PRECOMPOSED,
  326. acsFilePath, 1 + lstrlenA(acsFilePath),
  327. awcsFilePath, MAX_PATH
  328. );
  329. RonM_ASSERT(cwc != 0);
  330. }
  331. else
  332. {
  333. UnlockUrlCacheEntryFile(pcsDisplayName, 0);
  334. fResult = FALSE;
  335. }
  336. }
  337. if (!fResult)
  338. {
  339. fResult = CreateUrlCacheEntryA(pcsDisplayName, statstg.cbSize.LowPart,
  340. pcsExtension, acsFilePath, 0
  341. );
  342. if (!fResult)
  343. {
  344. hr = INET_E_CANNOT_INSTANTIATE_OBJECT;
  345. goto exit_GetStreamFromMoniker;
  346. }
  347. cwc = MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, acsFilePath,
  348. 1 + lstrlenA(acsFilePath), awcsFilePath, MAX_PATH
  349. );
  350. hr = CopyStreamToFile(&pStrmITS, (const WCHAR *) awcsFilePath);
  351. if (!fResult)
  352. {
  353. hr = INET_E_CANNOT_INSTANTIATE_OBJECT;
  354. goto exit_GetStreamFromMoniker;
  355. }
  356. FILETIME ftExpire;
  357. ftExpire.dwLowDateTime = 0;
  358. ftExpire.dwHighDateTime = 0;
  359. fResult = CommitUrlCacheEntryA(pcsDisplayName, acsFilePath, ftExpire,
  360. ftLastModified, NORMAL_CACHE_ENTRY, NULL,
  361. 0, pcsExtension, 0
  362. );
  363. if (!fResult)
  364. {
  365. ulErr= GetLastError();
  366. hr = INET_E_CANNOT_INSTANTIATE_OBJECT;
  367. goto exit_GetStreamFromMoniker;
  368. }
  369. fResult = RetrieveUrlCacheEntryFile(pcsDisplayName, NULL, &dwCEISize, 0);
  370. RonM_ASSERT(!fResult);
  371. ulErr= GetLastError();
  372. if (ulErr == ERROR_INSUFFICIENT_BUFFER)
  373. {
  374. INTERNET_CACHE_ENTRY_INFOA *pCEI = (INTERNET_CACHE_ENTRY_INFOA *) _alloca(dwCEISize);
  375. if (!pCEI)
  376. {
  377. hr = E_OUTOFMEMORY;
  378. goto exit_GetStreamFromMoniker;
  379. }
  380. pCEI->dwStructSize = sizeof(INTERNET_CACHE_ENTRY_INFOA);
  381. fResult = RetrieveUrlCacheEntryFile(pcsDisplayName, pCEI, &dwCEISize, 0);
  382. if (!fResult)
  383. {
  384. ulErr= GetLastError();
  385. hr = INET_E_CANNOT_INSTANTIATE_OBJECT;
  386. goto exit_GetStreamFromMoniker;
  387. }
  388. }
  389. }
  390. }
  391. }
  392. if (SUCCEEDED(hr)) && awcsFilePath[0])
  393. CopyMemory(pwcsFile, awcsFilePath, (wcsLen(awcsFilePath) + 1) * sizeof(WCHAR));
  394. *ppStrm = pStrmITS; pStrmITS = NULL;
  395. hr = fTempFile? S_FALSE : S_OK;
  396. exit_GetStreamFromMoniker:
  397. if (pStrmITS ) pStrmITS->Release();
  398. if (pwcsDisplayName) OLEHeap()->Free(pwcsDisplayName);
  399. return hr;
  400. }
  401. // IBindStatusCallback methods:
  402. HRESULT STDMETHODCALLTYPE CBindStatusCallBack::Implementation::OnStartBinding(
  403. /* [in] */ DWORD dwReserved,
  404. /* [in] */ IBinding __RPC_FAR *pib)
  405. {
  406. return S_OK;
  407. }
  408. HRESULT STDMETHODCALLTYPE CBindStatusCallBack::Implementation::GetPriority(
  409. /* [out] */ LONG __RPC_FAR *pnPriority)
  410. {
  411. return S_OK;
  412. }
  413. HRESULT STDMETHODCALLTYPE CBindStatusCallBack::Implementation::OnLowResource(
  414. /* [in] */ DWORD reserved)
  415. {
  416. return S_OK;
  417. }
  418. HRESULT STDMETHODCALLTYPE CBindStatusCallBack::Implementation::OnProgress(
  419. /* [in] */ ULONG ulProgress,
  420. /* [in] */ ULONG ulProgressMax,
  421. /* [in] */ ULONG ulStatusCode,
  422. /* [in] */ LPCWSTR szStatusText)
  423. {
  424. return S_OK;
  425. }
  426. HRESULT STDMETHODCALLTYPE CBindStatusCallBack::Implementation::OnStopBinding(
  427. /* [in] */ HRESULT hresult,
  428. /* [unique][in] */ LPCWSTR szError)
  429. {
  430. return S_OK;
  431. }
  432. /* [local] */ HRESULT STDMETHODCALLTYPE CBindStatusCallBack::Implementation::GetBindInfo(
  433. /* [out] */ DWORD __RPC_FAR *grfBINDF,
  434. /* [unique][out][in] */ BINDINFO __RPC_FAR *pbindinfo)
  435. {
  436. return S_OK;
  437. }
  438. /* [local] */ HRESULT STDMETHODCALLTYPE CBindStatusCallBack::Implementation::OnDataAvailable(
  439. /* [in] */ DWORD grfBSCF,
  440. /* [in] */ DWORD dwSize,
  441. /* [in] */ FORMATETC __RPC_FAR *pformatetc,
  442. /* [in] */ STGMEDIUM __RPC_FAR *pstgmed)
  443. {
  444. return S_OK;
  445. }
  446. HRESULT STDMETHODCALLTYPE CBindStatusCallBack::Implementation::OnObjectAvailable(
  447. /* [in] */ REFIID riid,
  448. /* [iid_is][in] */ IUnknown __RPC_FAR *punk)
  449. {
  450. return S_OK;
  451. }