// BSCB.cpp -- Implementation for the CBindStatusCallBack class #include "stdafx.h" HRESULT STDMETHODCALLTYPE CBindStatusCallBack::CreateHook(IBindCtx pBC, IMoniker pMK) { CBindStatusCallBack *pBSCB = New CBindStatusCallBack(NULL); IBindStatusCallback *pCallBack = NULL; HRESULT hr = FinishSetup(pBSCB? pBSCB->m_Implementation.Init(pBC, pMK) : STG_E_INSUFFICIENTMEMORY, pBSCB, IID_IBindStatusCallback, (PPVOID) &pCallBack ); if (pCallBack) pCallBack->Release(); } CBindStatusCallBack::Implementation::Implementation (CBindStatusCallBack *pBackObj, IUnknown *punkOuter) : ITBindStatusCallback(pBackObj, punkOuter) { m_pBCHooked = NULL; m_pBSCBClient = NULL; m_pStream = NULL; m_grfBINDF = 0; m_awcsFile[0] = 0; m_fTempFile = FALSE; m_bindinfo.cbSize = sizeof(BINDINFO); } CBindStatusCallBack::Implementation::~Implementation() { if (m_pStream) m_pStream->Release(); if (m_fTempFile) { RonM_ASSERT(m_awcsFile[0]); UINT cwc = wcsLen(m_awcsFile) + 1; UINT cb = cwc * sizeof(WCHAR); char *pszFile = PCHAR(_alloca(cb)); RonM_ASSERT(pszFile); if (pchr) { UINT c = WideCharToMultiByte(GetACP(), WC_COMPOSITECHECK, m_awcsFile, cwc, pszFile, cb, NULL, NULL ); RonM_ASSERT(c); if (c) DeleteFile(pszFile); } } if (m_pBC) RevokeBindStatusCallback(m_pBC, this); if (m_pBSCBClient) m_pBSCBClient->Release(); } HRESULT STDMETHODCALLTYPE CBindStatusCallBack::Implementation::Init(IBindCtx pBC, IMoniker pMK) { RonM_ASSERT(pBC); RonM_ASSERT(pMK); if (!SUCCEEDED(hr)) return hr; HRESULT hr = pMK->BindToStorage(pBC, NULL, IID_IStream, (PPVOID) &pStrm1); if (!SUCCEEDED(hr)) return hr; IUnknown *pUnk = NULL; hr = pBC->GetObjectParam(L"_BSCB_HOLDER_", &pUnk); if (!SUCCEEDED(hr)) return hr; hr = pUnk->QueryInterface(IID_IBindStatusCallback, &m_pBSCBClient); pUnk->Release(); if (!SUCCEEDED(hr)) return hr; hr = RegisterBindStatusCallback(pBC, this, &m_pBSCBClient, 0); if (!SUCCEEDED(hr)) return hr; m_pBC = pBC; m_pBC->AddRef(); RonM_ASSERT(statstg.cbSize.HighPart == 0); m_pBSCBClient->GetBindInfo(&m_grfBINDF, &m_bindinfo); if (!SUCCEEDED(hr)) return hr; IStream *pStrmITS = NULL; hr = GetStreamFromMoniker(pBC, pMK, m_grfBINDF, m_awcsFile, &m_pStream); if (hr == S_FALSE) m_fTempFile = TRUE; if (!SUCCEEDED(hr)) return hr; STATSTG statstg; hr = m_pStream->Stat(&statstg, STATFLAG_NONAME); if (!SUCCEEDED(hr)) return hr; hr = m_pBSCBClient->OnProgress(0, statstg.cbSize.LowPart, BINDSTATUS_SENDINGREQUEST, L"" ); if (!SUCCEEDED(hr)) return hr; hr = m_pBSCBClient->OnProgress(0, statstg.cbSize.LowPart, BINDSTATUS_BEGINDOWNLOADDATA, L"" ); if (!SUCCEEDED(hr)) return hr; if (m_awcsFile[0]) { hr = m_pBSCBClient->OnProgress(0, statstg.cbSize.LowPart, BINDSTATUS_CACHEFILENAMEAVAILABLE, m_awcsFile ); if (!SUCCEEDED(hr)) return hr; } hr = m_pBSCBClient->OnProgress(0, statstg.cbSize.LowPart, BINDSTATUS_DOWNLOADINGDATA, L"" ); if (!SUCCEEDED(hr)) return hr; hr = m_pBSCBClient->OnProgress(statstg.cbSize.LowPart, statstg.cbSize.LowPart, ENDDOWNLOADDATA, L"" ); if (!SUCCEEDED(hr)) return hr; FORMATETC fmetc; STGMEDIUM stgmed; hr = m_pBSCBClient->OnDataAvailable(BSCF_FIRSTDATANOTIFICATION | BSCF_LASTDATANOTIFICATION | BSCF_DATAFULLYAVAILABLE, statstg.cbSize.LowPart, FORMATETC *pfmtetc, STGMEDIUM *pstgmed ); return hr; } HRESULT STDMETHODCALLTYPE CopyStreamToFile(IStream *ppStreamSrc, const WCHAR *pwcsFilePath) { IStream *pStream; IStream *pStreamSrc = *ppStreamSrc; IFSStorage *pFSS = NULL; HRESULT hr = CFileSystemStorage::Create(NULL, IID_IFSStorage, (VOID **) &pFSS); if (!SUCCEEDED(hr)) return hr; hr = pFSS->FSOpenStream((const WCHAR *) pwcsFilePath, STGM_READWRITE | STGM_SHARE_DENY_NONE, &pStream ); pFSS->Release(); if (!SUCCEEDED(hr)) return hr; RonM_ASSERT(pStreamSrc); STATSTG statstg; hr = pStreamSrc->Stat(&statstg, STATFLAG_NONAME); if (!SUCCEEDED(hr)) return hr; #ifdef _DEBUG hr = #endif // _DEBUG pStreamSrc->Seek(CLINT(0).Li(), STREAM_SEEK_SET, NULL); RonM_ASSERT(hr == S_OK); hr = pStreamSrc->CopyTo(pStream, statstg.cbSize, NULL, NULL); pStream->Release(); if (!SUCCEEDED(hr)) return hr; #ifdef _DEBUG hr = #endif // _DEBUG pStream->Seek(CLINT(0).Li(), STREAM_SEEK_SET, NULL); #ifdef _DEBUG hr = #endif // _DEBUG pStreamSrc->Seek(CLINT(0).Li(), STREAM_SEEK_SET, NULL); RonM_ASSERT(hr == S_OK); *ppStreamSrc->Release(); *ppStreamSrc = pStream; return hr; } HRESULT STDMETHODCALLTYPE GetStreamFromMoniker (IBindCtx *pBC, IMoniker *pMK, DWORD grfBINDF, PSZ pwcsFile, IStream **ppStrm) { BOOL fNoFile = m_grfBINDF & (BINDF_PULLDATA | BINDF_DIRECT_READ); BOOL fNoReadCache = m_grfBINDF & (BINDF_GETNEWESTVERSION | BINDF_NOWRITECACHE | BINDF_PULLDATA | BINDF_PRAGMA_NO_CACHE | BINDF_DIRECT_READ ); BOOL fNoWriteCache = m_grfBINDF & (BINDF_NOWRITECACHE | BINDF_PULLDATA | BINDF_PRAGMA_NO_CACHE | BINDF_DIRECT_READ ); BOOL fTempFile = FALSE; WCHAR *pwcsDisplayName = NULL; char *pcsDisplayName = NULL; WCHAR *pwcsExtension = NULL; WCHAR *pwcsName = NULL; IStream *pStrmITS = NULL; HRESULT hr = pMK->GetDisplayName(pBCtx, NULL, &pwcsDisplayName); if (!SUCCEEDED(hr)) return hr; UINT cwc = wcsLen(pwcsDisplayName); UINT cb = sizeof(WCHAR) * (cwc + 1); *pcsDisplayName = PCHAR(_alloca(cb)); if (!pcsDisplayName) { hr = E_OUTOFMEMORY; goto exit_GetStreamFromMoniker; } cb = WideCharToMultiByte(GetACP(), WC_COMPOSITECHECK, pwcsDisplayName, cwc + 1, pcsDisplayName, cb, NULL, NULL ); if (!cb) { hr = INET_E_DOWNLOAD_FAILURE; goto exit_GetStreamFromMoniker; } { UINT cwc = wcsLen(pwcsURL); WCHAR *pwc = pwcsURL + cwc; for (;;) { WCHAR wc = *--pwc; if (wc == L'.') pwcsExtension = pwc + 1; if (wc == L':' || wc == L'/' || wc == L'\\') { pwcsName = ++pwc; break; } RonM_ASSERT(--cwc); } } hr = pMK->BindToStorage(pBC, NULL, IID_IStream, (VOID **) &pStrmITS); if (!SUCCEEDED(hr)) goto exit_GetStreamFromMoniker; STATSTG statstg; hr = pStrmITS->Stat(&statstg, STATFLAG_NONAME); if (!SUCCEEDED(hr)) goto exit_GetStreamFromMoniker; FILETIME ftLastModified; ftLastModified.dwLowDateTime = 0; ftLastModified.dwHighDateTime = 0; // pMK->GetTimeOfLastChange(pBCtx, NULL, &ftLastModified); RonM_ASSERT(statstg.cbSize.HighPart == 0); *pszFile = 0; // In case we don't get the stream into a file. if (!fNoFile) { CHAR acsFilePath[MAX_PATH]; WCHAR awcsFilePath[MAX_PATH]; char szTempPath[MAX_PATH]; szTempPath[0] = 0; PCHAR pcsExtension = ""; if (pwcsExtension && pwcsExtension[1]) { UINT cwc = wcsLen(pwcsExtension); UINT cb = sizeof(WCHAR) * (cwc + 1); pcsExtension = PCHAR(_alloca(cb)); if (!pcsExtension) { hr = E_OUTOFMEMORY; goto exit_GetStreamFromMoniker; } cb = WideCharToMultiByte(GetACP(), WC_COMPOSITECHECK, pwcsExtension, cwc + 1, pcsExtension, cb, NULL, NULL ); if (!cb) { hr = INET_E_DOWNLOAD_FAILURE; goto exit_GetStreamFromMoniker; } } if (fNoWriteCache) { DWORD cbPath= GetTempPath(MAX_PATH, szTempPath); if (!cbPath) lstrcpyA(szTempPath, ".\\"); char szPrefix[4] = "IMT"; // BugBug! May need to make this a random string. char szFullPath[MAX_PATH]; if (!GetTempFileName(szTempPath, szPrefix, 0, szFullPath)) { hr = CFSLockBytes::CImpILockBytes::STGErrorFromFSError(GetLastError()); szTempPath[0] = 0; goto exit_GetStreamFromMoniker; } lstrcpyA(szTempPath, szFullPath); char *pch = szTempPath + lstrlenA(szTempPath); for (;;) { if (pch == szTempPath) { RonM_ASSERT(FALSE); hr = E_UNEXPECTED; DeleteFile(szTempPath); szTempPath[0] = 0; goto exit_GetStreamFromMoniker; } if ('.' == *--pch) { ++pch; break; } } UINT cbExtension = lstrlenA(pcsExtension); if (pch + cbExtension - szTempPath >= MAX_PATH) { hr = E_UNEXPECTED; DeleteFile(szTempPath); szTempPath[0] = 0; goto exit_GetStreamFromMoniker; } CopyMemory(pch, pcsExtension, cbExtension + 1); if (!MoveFileEx(szFullPath, szTempPath, MOVEFILE_REPLACE_EXISTING)) { hr = E_UNEXPECTED; DeleteFile(szFullPath); szTempPath[0] = 0; goto exit_GetStreamFromMoniker; } UINT cwc = MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, szTempPath, 1 + lstrlenA(szTempPath), awcsFilePath, MAX_PATH ); if (cwc) hr = CopyStreamToFile(&pStrmITS, (const WCHAR *)awcsFilePath); else hr = E_UNEXPECTED; if (SUCCEEDED(hr)) { fTempFile = TRUE; CopyMemory(pwcsFile, awcsFilePath, cwc * sizeof(WCHAR)); } else { DeleteFile(szTempPath); goto exit_GetStreamFromMoniker; } } else { DWORD dwCEISize = 0; BOOL fResult = RetrieveUrlCacheEntryFile(pcsDisplayName, NULL, &dwCEISize, 0); RonM_ASSERT(!fResult); ULONG ulErr= GetLastError(); if (ulErr == ERROR_INSUFFICIENT_BUFFER) { INTERNET_CACHE_ENTRY_INFOA *pCEI = (INTERNET_CACHE_ENTRY_INFOA *) _alloca(dwCEISize); if (!pCEI) { hr = E_OUTOFMEMORY; goto exit_GetStreamFromMoniker; } pCEI->dwStructSize = sizeof(INTERNET_CACHE_ENTRY_INFOA); fResult = RetrieveUrlCacheEntryFile(pcsDisplayName, pCEI, &dwCEISize, 0); ulErr = GetLastError(); if (fResult) if ( pCEI->LastModifiedTime.dwLowDateTime == ftLastModified.dwLowDateTime && pCEI->LastModifiedTime.dwHighDateTime == ftLastModified.dwHighDateTime && pCEI->dwSizeLow == statstg.cbSize.LowPart && pCEI->dwSizeHigh == statstg.cbSize.HighPart ) { lstrcpyA(acsFilePath, pCEI->lpszLocalFileName); cwc = MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, acsFilePath, 1 + lstrlenA(acsFilePath), awcsFilePath, MAX_PATH ); RonM_ASSERT(cwc != 0); } else { UnlockUrlCacheEntryFile(pcsDisplayName, 0); fResult = FALSE; } } if (!fResult) { fResult = CreateUrlCacheEntryA(pcsDisplayName, statstg.cbSize.LowPart, pcsExtension, acsFilePath, 0 ); if (!fResult) { hr = INET_E_CANNOT_INSTANTIATE_OBJECT; goto exit_GetStreamFromMoniker; } cwc = MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, acsFilePath, 1 + lstrlenA(acsFilePath), awcsFilePath, MAX_PATH ); hr = CopyStreamToFile(&pStrmITS, (const WCHAR *) awcsFilePath); if (!fResult) { hr = INET_E_CANNOT_INSTANTIATE_OBJECT; goto exit_GetStreamFromMoniker; } FILETIME ftExpire; ftExpire.dwLowDateTime = 0; ftExpire.dwHighDateTime = 0; fResult = CommitUrlCacheEntryA(pcsDisplayName, acsFilePath, ftExpire, ftLastModified, NORMAL_CACHE_ENTRY, NULL, 0, pcsExtension, 0 ); if (!fResult) { ulErr= GetLastError(); hr = INET_E_CANNOT_INSTANTIATE_OBJECT; goto exit_GetStreamFromMoniker; } fResult = RetrieveUrlCacheEntryFile(pcsDisplayName, NULL, &dwCEISize, 0); RonM_ASSERT(!fResult); ulErr= GetLastError(); if (ulErr == ERROR_INSUFFICIENT_BUFFER) { INTERNET_CACHE_ENTRY_INFOA *pCEI = (INTERNET_CACHE_ENTRY_INFOA *) _alloca(dwCEISize); if (!pCEI) { hr = E_OUTOFMEMORY; goto exit_GetStreamFromMoniker; } pCEI->dwStructSize = sizeof(INTERNET_CACHE_ENTRY_INFOA); fResult = RetrieveUrlCacheEntryFile(pcsDisplayName, pCEI, &dwCEISize, 0); if (!fResult) { ulErr= GetLastError(); hr = INET_E_CANNOT_INSTANTIATE_OBJECT; goto exit_GetStreamFromMoniker; } } } } } if (SUCCEEDED(hr)) && awcsFilePath[0]) CopyMemory(pwcsFile, awcsFilePath, (wcsLen(awcsFilePath) + 1) * sizeof(WCHAR)); *ppStrm = pStrmITS; pStrmITS = NULL; hr = fTempFile? S_FALSE : S_OK; exit_GetStreamFromMoniker: if (pStrmITS ) pStrmITS->Release(); if (pwcsDisplayName) OLEHeap()->Free(pwcsDisplayName); return hr; } // IBindStatusCallback methods: HRESULT STDMETHODCALLTYPE CBindStatusCallBack::Implementation::OnStartBinding( /* [in] */ DWORD dwReserved, /* [in] */ IBinding __RPC_FAR *pib) { return S_OK; } HRESULT STDMETHODCALLTYPE CBindStatusCallBack::Implementation::GetPriority( /* [out] */ LONG __RPC_FAR *pnPriority) { return S_OK; } HRESULT STDMETHODCALLTYPE CBindStatusCallBack::Implementation::OnLowResource( /* [in] */ DWORD reserved) { return S_OK; } HRESULT STDMETHODCALLTYPE CBindStatusCallBack::Implementation::OnProgress( /* [in] */ ULONG ulProgress, /* [in] */ ULONG ulProgressMax, /* [in] */ ULONG ulStatusCode, /* [in] */ LPCWSTR szStatusText) { return S_OK; } HRESULT STDMETHODCALLTYPE CBindStatusCallBack::Implementation::OnStopBinding( /* [in] */ HRESULT hresult, /* [unique][in] */ LPCWSTR szError) { return S_OK; } /* [local] */ HRESULT STDMETHODCALLTYPE CBindStatusCallBack::Implementation::GetBindInfo( /* [out] */ DWORD __RPC_FAR *grfBINDF, /* [unique][out][in] */ BINDINFO __RPC_FAR *pbindinfo) { return S_OK; } /* [local] */ HRESULT STDMETHODCALLTYPE CBindStatusCallBack::Implementation::OnDataAvailable( /* [in] */ DWORD grfBSCF, /* [in] */ DWORD dwSize, /* [in] */ FORMATETC __RPC_FAR *pformatetc, /* [in] */ STGMEDIUM __RPC_FAR *pstgmed) { return S_OK; } HRESULT STDMETHODCALLTYPE CBindStatusCallBack::Implementation::OnObjectAvailable( /* [in] */ REFIID riid, /* [iid_is][in] */ IUnknown __RPC_FAR *punk) { return S_OK; }