// Moniker.cpp -- Implementation for the CStorageMoniker class #include "stdafx.h" HRESULT CStorageMoniker::CreateStorageMoniker (IUnknown *punkOuter, IBindCtx __RPC_FAR *pbc, LPOLESTR pszDisplayName, ULONG __RPC_FAR *pchEaten, IMoniker __RPC_FAR *__RPC_FAR *ppmkOut ) { CStorageMoniker *pstmk = New CStorageMoniker(punkOuter); return FinishSetup(pstmk? pstmk->m_ImpIStorageMoniker.InitCreateStorageMoniker (pbc, pszDisplayName, pchEaten) : STG_E_INSUFFICIENTMEMORY, pstmk, IID_IMoniker, (PPVOID) ppmkOut ); } CStorageMoniker::CImpIStorageMoniker::CImpIStorageMoniker (CStorageMoniker *pBackObj, IUnknown *punkOuter) : IITMoniker(pBackObj, punkOuter) { m_pStorageRoot = NULL; m_awszStorageFile[0] = 0; m_awszStoragePath[0] = 0; #ifdef IE30Hack m_acsTempFile [0] = 0; m_pcsDisplayName = NULL; #endif // IE30Hack } CStorageMoniker::CImpIStorageMoniker::~CImpIStorageMoniker(void) { if (m_pStorageRoot) m_pStorageRoot->Release(); #ifdef IE30Hack if (m_pcsDisplayName) { UnlockUrlCacheEntryFile(m_pcsDisplayName, 0); delete [] m_pcsDisplayName; } if (m_acsTempFile[0]) DeleteFile(m_acsTempFile); #endif // IE30Hack } HRESULT CStorageMoniker::CImpIStorageMoniker::InitCreateStorageMoniker (IBindCtx __RPC_FAR *pbc, LPOLESTR pszDisplayName, ULONG __RPC_FAR *pchEaten ) { DWORD cwc = wcsLen(pszDisplayName) + 1; DWORD cb = cwc * sizeof(WCHAR); PWCHAR pwcsCopy = PWCHAR(_alloca(cwc * sizeof(WCHAR))); if (!pwcsCopy) return E_OUTOFMEMORY; memCpy(pwcsCopy, pszDisplayName, cb); PWCHAR pwcsExternal = NULL; PWCHAR pwcsInternal = NULL; PWCHAR pwcsProtocol = NULL; HRESULT hr = DisectUrl(pwcsCopy, &pwcsProtocol, &pwcsExternal, &pwcsInternal); if (!SUCCEEDED(hr)) return (hr == INET_E_DEFAULT_ACTION)? INET_E_INVALID_URL : hr; wcsCpy(m_awszStorageFile, pwcsExternal); wcsCpy(m_awszStoragePath, pwcsInternal); cwc = wcsLen(m_awszStoragePath); if (m_awszStoragePath[cwc-1] == L'/') m_awszStoragePath[cwc-1] = 0; *pchEaten = cwc - 1; return NO_ERROR; } // IPersist methods HRESULT STDMETHODCALLTYPE CStorageMoniker::CImpIStorageMoniker::GetClassID( /* [out] */ CLSID __RPC_FAR *pClassID) { *pClassID = CLSID_ITStorage; return NOERROR; } // IPersistStream methods HRESULT STDMETHODCALLTYPE CStorageMoniker::CImpIStorageMoniker::IsDirty( void) { RonM_ASSERT(FALSE); // To catch unexpected uses of this interface... return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE CStorageMoniker::CImpIStorageMoniker::Load( /* [unique][in] */ IStream __RPC_FAR *pStm) { RonM_ASSERT(FALSE); // To catch unexpected uses of this interface... return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE CStorageMoniker::CImpIStorageMoniker::Save( /* [unique][in] */ IStream __RPC_FAR *pStm, /* [in] */ BOOL fClearDirty) { RonM_ASSERT(FALSE); // To catch unexpected uses of this interface... return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE CStorageMoniker::CImpIStorageMoniker::GetSizeMax( /* [out] */ ULARGE_INTEGER __RPC_FAR *pcbSize) { RonM_ASSERT(FALSE); // To catch unexpected uses of this interface... return E_NOTIMPL; } // IMoniker methods /* [local] */ HRESULT STDMETHODCALLTYPE CStorageMoniker::CImpIStorageMoniker::BindToObject( /* [unique][in] */ IBindCtx __RPC_FAR *pbc, /* [unique][in] */ IMoniker __RPC_FAR *pmkToLeft, /* [in] */ REFIID riidResult, /* [out] */ void __RPC_FAR *__RPC_FAR *ppvResult) { RonM_ASSERT(FALSE); // To catch unexpected uses of this interface... return E_NOTIMPL; } #pragma data_seg(".text", "CODE") static const char txtTomeMapKey [] = ITSS_MAP; static const char txtTomeFinderKey[] = ITSS_FINDER; #pragma data_seg() HRESULT STDMETHODCALLTYPE FileExists(WCHAR *pwszStorageFile, const CHAR *pcsFullPath) { if (GetFileAttributes(pcsFullPath) == (DWORD) -1) return STG_E_FILENOTFOUND; // File exists! Now we need to convert the path to Unicode and store it. WCHAR awcsPath[MAX_PATH]; UINT cwc = MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, pcsFullPath, -1, awcsPath, MAX_PATH ); if (cwc == 0 || cwc > MAX_PATH) return STG_E_FILENOTFOUND; wcsCpy(pwszStorageFile, awcsPath); return S_OK; } char * __stdcall FindMBCSExtension(char *pcsFileName) { char *pchLastPeriod = NULL; for (;; pcsFileName = DBCS_SYSTEM()? CharNext(pcsFileName) : pcsFileName + 1) { char ch = *pcsFileName; if (!ch) break; if (ch != '.') continue; pchLastPeriod = pcsFileName; } return pchLastPeriod; } HRESULT STDMETHODCALLTYPE FindRootStorageFile(WCHAR * pwszStorageFile) { char csRoot [MAX_PATH * 2]; // * 2 for DBCS locales char csBuffer[MAX_PATH * 2]; UINT cb = WideCharToMultiByte(CP_USER_DEFAULT(), WC_COMPOSITECHECK | WC_SEPCHARS, pwszStorageFile, 1 + wcsLen(pwszStorageFile), csRoot, sizeof(csRoot), NULL, NULL ); if (cb == 0) return STG_E_INVALIDNAME; LPSTR pcsFileName = NULL; UINT cbFull = GetFullPathName(csRoot, sizeof(csBuffer), csBuffer, &pcsFileName); if (!cbFull || !pcsFileName) return STG_E_INVALIDNAME; HRESULT hr = FileExists(pwszStorageFile, (const char *) csBuffer); if (hr == S_OK) return hr; HKEY hkey; DWORD type; DWORD cbPath = MAX_PATH; LONG result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, txtTomeMapKey, 0, KEY_READ, &hkey); if (result == ERROR_SUCCESS) { result = RegQueryValueEx(hkey, (const char *) pcsFileName, 0, &type, (PBYTE) csRoot, &cbPath ); RegCloseKey(hkey); } if (result == ERROR_SUCCESS) { hr = FileExists(pwszStorageFile, (const char *) csRoot); if (hr == S_OK) return hr; } result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, txtTomeFinderKey, 0, KEY_READ, &hkey); if (result == ERROR_SUCCESS) { result = RegQueryValueEx(hkey, (const char *) pcsFileName, 0, &type, (PBYTE) csRoot, &cbPath ); if (result != ERROR_SUCCESS) { char *pcsFileExtension = FindMBCSExtension(pcsFileName); if (pcsFileExtension) result = RegQueryValueEx(hkey, pcsFileExtension, 0, &type, (PBYTE) csRoot, &cbPath ); } RegCloseKey(hkey); } hr = STG_E_FILENOTFOUND; if (result == ERROR_SUCCESS) { CLSID clsid; WCHAR wcsFileName[MAX_PATH]; UINT cwc = MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, csRoot, -1, wcsFileName, MAX_PATH ); if (cwc != 0) { HRESULT hr2 = CLSIDFromString(wcsFileName, &clsid); if (hr2 == S_OK) { IITFileFinder *pFileFinder = NULL; cwc = MultiByteToWideChar(GetACP(), MB_PRECOMPOSED, pcsFileName, -1, wcsFileName, MAX_PATH ); if (cwc != 0) { hr2 = CoCreateInstance(clsid, NULL, CLSCTX_INPROC_SERVER, IID_IITFileFinder, (void **) &pFileFinder ); if (hr2 == S_OK) __try { WCHAR *pwcsFullPath = NULL; BOOL fRecord = FALSE; hr2 = pFileFinder->FindThisFile((const WCHAR *) wcsFileName, &pwcsFullPath, &fRecord); // REMOVE THIS OutputDebugString("Moniker.cpp Find This File\n"); OutputDebugStringW(wcsFileName); OutputDebugString("\n"); // REMOVE THIS pFileFinder->Release(); pFileFinder = NULL; if (hr2 == S_OK) { RonM_ASSERT(pwcsFullPath); cb = WideCharToMultiByte(CP_USER_DEFAULT(), WC_COMPOSITECHECK | WC_SEPCHARS, pwcsFullPath, 1 + wcsLen(pwcsFullPath), csRoot, sizeof(csRoot), NULL, NULL ); OLEHeap()->Free(pwcsFullPath); hr = (cb == 0)? STG_E_FILENOTFOUND : FileExists(pwszStorageFile, (const char *) csRoot); if (hr == S_OK && fRecord) { result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, txtTomeMapKey, 0, KEY_READ, &hkey); if (result == ERROR_SUCCESS) { result = RegSetValueEx(hkey, (const char *) pcsFileName, 0, REG_SZ, (PBYTE) csRoot, lstrlen(csRoot) ); RegCloseKey(hkey); } } } } __except (TRUE) { if (pFileFinder) pFileFinder->Release(); }; } } } } return hr; } HRESULT STDMETHODCALLTYPE CStorageMoniker::CImpIStorageMoniker::OpenRootStorage (DWORD grfMode) { PWCHAR pwc = wcsChr((const WCHAR *) m_awszStorageFile, L':'); if (pwc && pwc[1] == L':') // Ignore a "::" separator pwc = NULL; // Here we're special casing non-protocol references to a file. // We recognize those situations by looking for a protocol prefix. // Protocol prefixes have the form : // where is always longer than one character. if (!pwc || (pwc - m_awszStorageFile == 1)) { HRESULT hr = FindRootStorageFile(m_awszStorageFile); if (hr != S_OK) return hr; return CITFileSystem::OpenITFileSystem(NULL, (const WCHAR *) m_awszStorageFile, grfMode, (IStorageITEx **)&m_pStorageRoot ); } ILockBytes * plkbRoot = NULL; HRESULT hr = CStrmLockBytes::OpenUrlStream((const WCHAR *) m_awszStorageFile, &plkbRoot ); if (hr == S_OK) hr = CITFileSystem::OpenITFSOnLockBytes(NULL, plkbRoot, grfMode, (IStorageITEx **)&m_pStorageRoot ); if (plkbRoot) plkbRoot->Release(); return hr; } const PWCHAR apwcsDefaultPages[5] = { L"/default.htm", L"/default.html", L"/index.htm", L"/index.html", NULL }; /* [local] */ HRESULT STDMETHODCALLTYPE CStorageMoniker::CImpIStorageMoniker::BindToStorage( /* [unique][in] */ IBindCtx __RPC_FAR *pbc, /* [unique][in] */ IMoniker __RPC_FAR *pmkToLeft, /* [in] */ REFIID riid, /* [out] */ void __RPC_FAR *__RPC_FAR *ppvObj) { HRESULT hr = NOERROR; BIND_OPTS bo; bo.cbStruct = sizeof(bo); hr = pbc->GetBindOptions(&bo); // Streams and storages are always opened read-only with share deny-none // in the context of a URL. bo.grfMode &= ~(STGM_WRITE | STGM_READWRITE); bo.grfMode &= ~(STGM_SHARE_DENY_NONE | STGM_SHARE_DENY_READ | STGM_SHARE_DENY_WRITE | STGM_SHARE_EXCLUSIVE ); bo.grfMode |= STGM_SHARE_DENY_NONE; if (hr != S_OK) return hr; if (!m_pStorageRoot) { hr = OpenRootStorage(bo.grfMode); if (hr != S_OK) return hr; } if (riid == IID_IStorage) hr = m_pStorageRoot->OpenStorage(m_awszStoragePath, NULL, bo.grfMode, NULL, 0, (IStorage **) ppvObj ); else if (riid == IID_IStream) { hr = m_pStorageRoot->OpenStream(m_awszStoragePath, NULL, bo.grfMode, 0, (IStream **) ppvObj ); if (!SUCCEEDED(hr)) { const PWCHAR *ppwcsDefPages = apwcsDefaultPages; for (;;) { const PWCHAR pwcsDefPage = *ppwcsDefPages++; if (!pwcsDefPage) break; WCHAR awszDefault[MAX_PATH]; wcsCpy(awszDefault, m_awszStoragePath); UINT cwc= wcsLen(m_awszStoragePath) + wcsLen(pwcsDefPage); if (cwc < MAX_PATH) { wcsCat(awszDefault, pwcsDefPage); hr = m_pStorageRoot->OpenStream(awszDefault, NULL, bo.grfMode, 0, (IStream **) ppvObj ); if (SUCCEEDED(hr)) { wcsCpy(m_awszStoragePath, awszDefault); break; } } } } } else return E_NOINTERFACE; #ifdef IE30Hack // The following code is a slimey hack to work around a defect in the IE 3.0x // URLMon code. The problem is that IE 3.0 treats the trailing part of our URL // as if it were a file name, and that makes many things break. // // The code below crawls up the stack and follows several pointers to locate the // incorrect file name and fix it to point to a file which a copy of the stream // we've just opened. if (SUCCEEDED(hr) && !IS_IE4()) // Running in IE 3.0x ??? { PWCHAR pwcsDisplayName = NULL; // We use a try/except bracket to recover from crawl failures. __try { // First we compute stack frame pointers for BindToStorage // and the next higher frame. DWORD *pdwFrame = ((DWORD *) &pbc) - 3; DWORD *pdwFrameNext = (DWORD *) *pdwFrame; DWORD *pdwCINet; // We're looking for a pointer to a CINetStream object. That pointer // is located at different places in the retail and debug builds // of URLMon. if (pdwFrameNext - pdwFrame > 0x1b6) pdwCINet = (DWORD *) pdwFrameNext[5]; // Debug build else pdwCINet = (DWORD *) pdwFrame [8]; // Retail build // From there we can get the pointer to the transaction object. PBYTE pbTransData = (PBYTE) pdwCINet[0x8de]; // Then the transaction object contains the erroneous // file paths. PWCHAR pwcsFilePath = (PWCHAR) (pbTransData + 0xC ); PCHAR pcsFilePath = ( PCHAR) (pbTransData + 0x284); hr = GetDisplayName(pbc, NULL, &pwcsDisplayName); if ( SUCCEEDED(hr) && !wcsicmp_0x0409((const WCHAR *) pwcsDisplayName + 14, (const WCHAR *)pwcsFilePath) ) { #ifdef _DEBUG HRESULT hr2 = #endif // _DEBUG StreamToIEFile((IStream *) *ppvObj, pwcsDisplayName, m_pcsDisplayName, pcsFilePath, pwcsFilePath, m_acsTempFile, (IMoniker *) this, FALSE, FALSE ); RonM_ASSERT(SUCCEEDED(hr2)); } } __except (EXCEPTION_EXECUTE_HANDLER) { } if (pwcsDisplayName) OLEHeap()->Free(pwcsDisplayName); } #endif // IE30Hack return hr; } HRESULT STDMETHODCALLTYPE CStorageMoniker::CImpIStorageMoniker::Reduce( /* [unique][in] */ IBindCtx __RPC_FAR *pbc, /* [in] */ DWORD dwReduceHowFar, /* [unique][out][in] */ IMoniker __RPC_FAR *__RPC_FAR *ppmkToLeft, /* [out] */ IMoniker __RPC_FAR *__RPC_FAR *ppmkReduced) { RonM_ASSERT(FALSE); // To catch unexpected uses of this interface... return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE CStorageMoniker::CImpIStorageMoniker::ComposeWith( /* [unique][in] */ IMoniker __RPC_FAR *pmkRight, /* [in] */ BOOL fOnlyIfNotGeneric, /* [out] */ IMoniker __RPC_FAR *__RPC_FAR *ppmkComposite) { RonM_ASSERT(FALSE); // To catch unexpected uses of this interface... return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE CStorageMoniker::CImpIStorageMoniker::Enum( /* [in] */ BOOL fForward, /* [out] */ IEnumMoniker __RPC_FAR *__RPC_FAR *ppenumMoniker) { RonM_ASSERT(FALSE); // To catch unexpected uses of this interface... return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE CStorageMoniker::CImpIStorageMoniker::IsEqual( /* [unique][in] */ IMoniker __RPC_FAR *pmkOtherMoniker) { RonM_ASSERT(FALSE); // To catch unexpected uses of this interface... return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE CStorageMoniker::CImpIStorageMoniker::Hash( /* [out] */ DWORD __RPC_FAR *pdwHash) { RonM_ASSERT(FALSE); // To catch unexpected uses of this interface... return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE CStorageMoniker::CImpIStorageMoniker::IsRunning( /* [unique][in] */ IBindCtx __RPC_FAR *pbc, /* [unique][in] */ IMoniker __RPC_FAR *pmkToLeft, /* [unique][in] */ IMoniker __RPC_FAR *pmkNewlyRunning) { RonM_ASSERT(FALSE); // To catch unexpected uses of this interface... return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE CStorageMoniker::CImpIStorageMoniker::GetTimeOfLastChange( /* [unique][in] */ IBindCtx __RPC_FAR *pbc, /* [unique][in] */ IMoniker __RPC_FAR *pmkToLeft, /* [out] */ FILETIME __RPC_FAR *pFileTime) { STATSTG statstg; HRESULT hr = m_pStorageRoot->Stat(&statstg, STATFLAG_NONAME); if (!SUCCEEDED(hr)) return hr; if (pFileTime) *pFileTime = statstg.mtime; return NO_ERROR; } HRESULT STDMETHODCALLTYPE CStorageMoniker::CImpIStorageMoniker::Inverse( /* [out] */ IMoniker __RPC_FAR *__RPC_FAR *ppmk) { RonM_ASSERT(FALSE); // To catch unexpected uses of this interface... return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE CStorageMoniker::CImpIStorageMoniker::CommonPrefixWith( /* [unique][in] */ IMoniker __RPC_FAR *pmkOther, /* [out] */ IMoniker __RPC_FAR *__RPC_FAR *ppmkPrefix) { RonM_ASSERT(FALSE); // To catch unexpected uses of this interface... return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE CStorageMoniker::CImpIStorageMoniker::RelativePathTo( /* [unique][in] */ IMoniker __RPC_FAR *pmkOther, /* [out] */ IMoniker __RPC_FAR *__RPC_FAR *ppmkRelPath) { RonM_ASSERT(FALSE); // To catch unexpected uses of this interface... return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE CStorageMoniker::CImpIStorageMoniker::GetDisplayName( /* [unique][in] */ IBindCtx __RPC_FAR *pbc, /* [unique][in] */ IMoniker __RPC_FAR *pmkToLeft, /* [out] */ LPOLESTR __RPC_FAR *ppszDisplayName) { UINT cwcExternalPath = wcsLen(m_awszStorageFile); UINT cwcInternalPath = wcsLen(m_awszStoragePath); UINT cwcDisplayName = (IS_IE4()? 9 : 16) + cwcExternalPath + cwcInternalPath; PWCHAR pwcsDisplayName = PWCHAR(OLEHeap()->Alloc(sizeof(WCHAR) * (cwcDisplayName + 1))); if (!pwcsDisplayName) return E_OUTOFMEMORY; wcsCpy(pwcsDisplayName, IS_IE4()? L"ms-its:" :L"mk:@msitstore:"); wcsCat(pwcsDisplayName, m_awszStorageFile); wcsCat(pwcsDisplayName, L"::"); wcsCat(pwcsDisplayName, m_awszStoragePath); *ppszDisplayName = pwcsDisplayName; return NO_ERROR; } HRESULT STDMETHODCALLTYPE CStorageMoniker::CImpIStorageMoniker::ParseDisplayName( /* [unique][in] */ IBindCtx __RPC_FAR *pbc, /* [unique][in] */ IMoniker __RPC_FAR *pmkToLeft, /* [in] */ LPOLESTR pszDisplayName, /* [out] */ ULONG __RPC_FAR *pchEaten, /* [out] */ IMoniker __RPC_FAR *__RPC_FAR *ppmkOut) { RonM_ASSERT(FALSE); // To catch unexpected uses of this interface... return E_NOTIMPL; } HRESULT STDMETHODCALLTYPE CStorageMoniker::CImpIStorageMoniker::IsSystemMoniker( /* [out] */ DWORD __RPC_FAR *pdwMksys) { return MKSYS_NONE; }