/****************************************************************************** Copyright (c) 1999-2000 Microsoft Corporation Module Name: OfflineCache.cpp Abstract: Handles caching of database lookups. Revision History: Davide Massarenti (Dmassare) 07/17/2000 created ******************************************************************************/ #include "stdafx.h" //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// HRESULT OfflineCache::operator>>( /*[in]*/ MPC::Serializer& stream, /*[out]*/ OfflineCache::Query& val ) { __HCP_FUNC_ENTRY( "OfflineCache::OfflineCache::operator>> OfflineCache::Query" ); HRESULT hr; __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> val.m_strID ); __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> val.m_iType ); __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> val.m_iSequence); __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> val.m_fNull ); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } HRESULT OfflineCache::operator<<( /*[in]*/ MPC::Serializer& stream, /*[in] */ const OfflineCache::Query& val ) { __HCP_FUNC_ENTRY( "OfflineCache::operator<< OfflineCache::Query" ); HRESULT hr; __MPC_EXIT_IF_METHOD_FAILS(hr, stream << val.m_strID ); __MPC_EXIT_IF_METHOD_FAILS(hr, stream << val.m_iType ); __MPC_EXIT_IF_METHOD_FAILS(hr, stream << val.m_iSequence); __MPC_EXIT_IF_METHOD_FAILS(hr, stream << val.m_fNull ); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } OfflineCache::Query::Query() { // MPC::wstring m_strID; m_iType = ET_INVALID; // int m_iType; m_iSequence = 0; // int m_iSequence; m_fNull = true; // bool m_fNull; } HRESULT OfflineCache::Query::InitFile( /*[in ]*/ const MPC::wstring& strDir , /*[out]*/ MPC::wstring& strFile ) { __HCP_FUNC_ENTRY( "OfflineCache::Query::InitFile" ); HRESULT hr; WCHAR rgBuf[64]; swprintf( rgBuf, L"\\%08x.query", m_iSequence ); strFile = strDir; strFile += rgBuf; hr = S_OK; __HCP_FUNC_EXIT(hr); } HRESULT OfflineCache::Query::Retrieve( /*[in]*/ const MPC::wstring& strDir , /*[in]*/ CPCHQueryResultCollection* *pColl ) { __HCP_FUNC_ENTRY( "OfflineCache::Query::Retrieve" ); HRESULT hr; CComPtr coll; __MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_POINTER_AND_SET(pColl, NULL); __MPC_PARAMCHECK_END(); __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &coll )); if(m_fNull == false) { MPC::wstring strFile; CComPtr stream; __MPC_EXIT_IF_METHOD_FAILS(hr, InitFile ( strDir , strFile )); __MPC_EXIT_IF_METHOD_FAILS(hr, SVC::SafeLoad( strFile, stream )); // // Create the collection from the IStream. // { MPC::Serializer_IStream streamGen ( stream ); MPC::Serializer_Buffering streamGen2( streamGen ); __MPC_EXIT_IF_METHOD_FAILS(hr, coll->Load( streamGen2 )); } } *pColl = coll.Detach(); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// HRESULT OfflineCache::operator>>( /*[in] */ MPC::Serializer& stream , /*[out]*/ OfflineCache::SetOfHelpTopics& val ) { __HCP_FUNC_ENTRY( "OfflineCache::operator>> OfflineCache::SetOfHelpTopics" ); HRESULT hr; __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> val.m_inst ); __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> val.m_lstQueries); __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> val.m_iLastSeq ); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } HRESULT OfflineCache::operator<<( /*[in]*/ MPC::Serializer& stream , /*[in]*/ const OfflineCache::SetOfHelpTopics& val ) { __HCP_FUNC_ENTRY( "OfflineCache::operator<< OfflineCache::SetOfHelpTopics" ); HRESULT hr; __MPC_EXIT_IF_METHOD_FAILS(hr, stream << val.m_inst ); __MPC_EXIT_IF_METHOD_FAILS(hr, stream << val.m_lstQueries); __MPC_EXIT_IF_METHOD_FAILS(hr, stream << val.m_iLastSeq ); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } OfflineCache::SetOfHelpTopics::SetOfHelpTopics() { m_parent = NULL; // Root* m_parent; // // Taxonomy::Instance m_inst; // QueryList m_lstQueries; m_iLastSeq = 0; // int m_iLastSeq; } //////////////////// HRESULT OfflineCache::SetOfHelpTopics::InitDir( /*[in]*/ MPC::wstring& strDir ) { __HCP_FUNC_ENTRY( "OfflineCache::SetOfHelpTopics::InitDir" ); HRESULT hr; WCHAR rgDir[MAX_PATH]; _snwprintf( rgDir, MAXSTRLEN(rgDir), L"%s\\%s#%04lx", HC_ROOT_HELPSVC_OFFLINECACHE, m_inst.m_ths.GetSKU(), m_inst.m_ths.GetLanguage() ); __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::SubstituteEnvVariables( strDir = rgDir )); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } HRESULT OfflineCache::SetOfHelpTopics::Find( /*[in] */ LPCWSTR& szID , /*[in] */ int iType , /*[out]*/ QueryIter& it ) { __HCP_FUNC_ENTRY( "OfflineCache::SetOfHelpTopics::Find" ); HRESULT hr; if(szID == NULL) szID = L""; for(it = m_lstQueries.begin(); it != m_lstQueries.end(); it++) { if(!MPC::StrICmp( it->m_strID , szID ) && it->m_iType == iType ) { break; } } hr = S_OK; __HCP_FUNC_EXIT(hr); } void OfflineCache::SetOfHelpTopics::ConnectToParent( /*[in]*/ Root* parent ) { m_parent = parent; } //////////////////////////////////////// HRESULT OfflineCache::SetOfHelpTopics::Retrieve( /*[in]*/ LPCWSTR szID , /*[in]*/ int iType , /*[in]*/ CPCHQueryResultCollection* *pColl ) { __HCP_FUNC_ENTRY( "OfflineCache::SetOfHelpTopics::Retrieve" ); HRESULT hr; QueryIter it; __MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_POINTER_AND_SET(pColl, NULL); __MPC_PARAMCHECK_END(); __MPC_EXIT_IF_METHOD_FAILS(hr, Find( szID, iType, it )); if(it == m_lstQueries.end()) { __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_FILE_NOT_FOUND); } // // Load from the registry. // { MPC::wstring strDir; __MPC_EXIT_IF_METHOD_FAILS(hr, InitDir( strDir )); __MPC_EXIT_IF_METHOD_FAILS(hr, it->Retrieve( strDir, pColl )); } hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// OfflineCache::Handle::Handle() { m_main = NULL; // Root* m_main; m_sht = NULL; // SetOfHelpTopics* m_sht; } OfflineCache::Handle::~Handle() { Release(); } void OfflineCache::Handle::Attach( /*[in]*/ Root* main, /*[in]*/ SetOfHelpTopics* sht ) { Release(); m_main = main; if(main) main->Lock(); m_sht = sht; } void OfflineCache::Handle::Release() { if(m_main) m_main->Unlock(); m_main = NULL; m_sht = NULL; } //////////////////////////////////////////////////////////////////////////////// //////////////////////////////////////////////////////////////////////////////// HRESULT OfflineCache::operator>>( /*[in] */ MPC::Serializer& stream , /*[out]*/ OfflineCache::Root& val ) { __HCP_FUNC_ENTRY( "OfflineCache::operator>> OfflineCache::Root" ); HRESULT hr; __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> val.m_fReady ); __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> val.m_instMachine); __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> val.m_lstSKUs ); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } HRESULT OfflineCache::operator<<( /*[in]*/ MPC::Serializer& stream , /*[in]*/ const OfflineCache::Root& val ) { __HCP_FUNC_ENTRY( "OfflineCache::operator<< OfflineCache::Root" ); HRESULT hr; __MPC_EXIT_IF_METHOD_FAILS(hr, stream << val.m_fReady ); __MPC_EXIT_IF_METHOD_FAILS(hr, stream << val.m_instMachine); __MPC_EXIT_IF_METHOD_FAILS(hr, stream << val.m_lstSKUs ); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } OfflineCache::Root::Root( /*[in]*/ bool fMaster ) : m_nmSharedLock( L"GLOBAL\\PCH_OFFLINECACHE", /*fCloseOnRelease*/true ) { // MPC::NamedMutex m_nmSharedLock; // m_fReady = false; // bool m_fReady; // Taxonomy::Instance m_instMachine; // SKUList m_lstSKUs; // m_fMaster = fMaster; // bool m_fMaster; m_fLoaded = false; // bool m_fLoaded; m_fDirty = false; // bool m_fDirty; m_dwDisableSave = 0; // DWORD m_dwDisableSave; m_hChangeNotification = INVALID_HANDLE_VALUE; // HANDLE m_hChangeNotification; } OfflineCache::Root::~Root() { (void)Clean(); } //////////////////// OfflineCache::Root* OfflineCache::Root::s_GLOBAL( NULL ); HRESULT OfflineCache::Root::InitializeSystem( /*[in]*/ bool fMaster ) { if(s_GLOBAL == NULL) { s_GLOBAL = new OfflineCache::Root( fMaster ); } return s_GLOBAL ? S_OK : E_OUTOFMEMORY; } void OfflineCache::Root::FinalizeSystem() { if(s_GLOBAL) { delete s_GLOBAL; s_GLOBAL = NULL; } } //////////////////// void OfflineCache::Root::Lock() { super::Lock(); (void)m_nmSharedLock.Acquire( 500 ); } void OfflineCache::Root::Unlock() { (void)m_nmSharedLock.Release(); super::Unlock(); } //////////////////// HRESULT OfflineCache::Root::GetIndexFile( /*[in]*/ MPC::wstring& strIndex ) { __HCP_FUNC_ENTRY( "OfflineCache::Root::GetIndexFile" ); HRESULT hr; strIndex.reserve( MAX_PATH ); strIndex = HC_ROOT_HELPSVC_OFFLINECACHE; strIndex += L"\\index.dat"; __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::SubstituteEnvVariables( strIndex )); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } HRESULT OfflineCache::Root::Load() { __HCP_FUNC_ENTRY( "OfflineCache::Root::Load" ); HRESULT hr; // // If the content of the offline cache directory has changed, reload everything. // if(m_hChangeNotification != INVALID_HANDLE_VALUE) { if(::WaitForSingleObject( m_hChangeNotification, 0 ) != WAIT_TIMEOUT) { ::FindNextChangeNotification( m_hChangeNotification ); Clean(); } } // // Not already loaded, try to load, but without failing. // if(m_fLoaded == false) { MPC::wstring strIndex; CComPtr stream; if(SUCCEEDED(GetIndexFile ( strIndex )) && SUCCEEDED(SVC::SafeLoad( strIndex, stream )) ) { MPC::Serializer_IStream streamGen ( stream ); MPC::Serializer_Buffering streamGen2( streamGen ); DWORD dwVer; if(SUCCEEDED(streamGen2 >> dwVer) && dwVer == s_dwVersion) { if(SUCCEEDED(streamGen2 >> *this)) { for(SKUIter it = m_lstSKUs.begin(); it != m_lstSKUs.end(); it++) { it->ConnectToParent( this ); } if(m_fMaster == false && m_fReady) { __MPC_EXIT_IF_METHOD_FAILS(hr, Taxonomy::HelpSet::SetMachineInfo( m_instMachine )); } } else { Clean(); } } // // Setup change notification, if we are a slave. // if(m_fMaster == false) { static const DWORD s_dwNotify = FILE_NOTIFY_CHANGE_FILE_NAME | FILE_NOTIFY_CHANGE_DIR_NAME | FILE_NOTIFY_CHANGE_ATTRIBUTES | FILE_NOTIFY_CHANGE_SIZE | FILE_NOTIFY_CHANGE_LAST_WRITE | FILE_NOTIFY_CHANGE_CREATION; m_hChangeNotification = ::FindFirstChangeNotificationW( strIndex.c_str(), TRUE, s_dwNotify ); } } m_fLoaded = true; m_fDirty = false; } hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } HRESULT OfflineCache::Root::Clean() { __HCP_FUNC_ENTRY( "OfflineCache::Root::Clean" ); HRESULT hr; m_fLoaded = false; m_fDirty = false; m_fReady = false; m_lstSKUs.clear(); if(m_hChangeNotification != INVALID_HANDLE_VALUE) { ::FindCloseChangeNotification( m_hChangeNotification ); m_hChangeNotification = INVALID_HANDLE_VALUE; } hr = S_OK; __HCP_FUNC_EXIT(hr); } //////////////////// HRESULT OfflineCache::Root::Find( /*[in ]*/ const Taxonomy::HelpSet& ths , /*[out]*/ SKUIter& it ) { __HCP_FUNC_ENTRY( "OfflineCache::Root::Find" ); HRESULT hr; __MPC_EXIT_IF_METHOD_FAILS(hr, Load()); for(it = m_lstSKUs.begin(); it != m_lstSKUs.end(); it++) { if(it->m_inst.m_ths == ths) { break; } } hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } //////////////////////////////////////// HRESULT OfflineCache::Root::Locate( /*[in] */ const Taxonomy::HelpSet& ths , /*[out]*/ Handle& handle ) { __HCP_FUNC_ENTRY( "OfflineCache::Root::Locate" ); HRESULT hr; MPC::SmartLock<_ThreadModel> lock( this ); SKUIter it; handle.Release(); __MPC_EXIT_IF_METHOD_FAILS(hr, Find( ths, it )); if(it == m_lstSKUs.end()) { __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_FILE_NOT_FOUND); } handle.Attach( this, &(*it) ); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } //////////////////////////////////////// HRESULT OfflineCache::Root::SetMachineInfo( /*[in]*/ const Taxonomy::Instance& inst ) { __HCP_FUNC_ENTRY( "OfflineCache::Root::SetMachineInfo" ); HRESULT hr; MPC::SmartLock<_ThreadModel> lock( this ); if(m_fMaster) { Taxonomy::HelpSet ths; __MPC_EXIT_IF_METHOD_FAILS(hr, Load()); m_instMachine = inst; m_fDirty = true; } hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } //////////////////// bool OfflineCache::Root::IsReady() { __HCP_FUNC_ENTRY( "OfflineCache::Root::IsReady" ); HRESULT hr; MPC::SmartLock<_ThreadModel> lock( this ); __MPC_EXIT_IF_METHOD_FAILS(hr, Load()); __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(m_fReady); } //////////////////////////////////////// HRESULT OfflineCache::Root::FindMatch( /*[in]*/ LPCWSTR szSKU , /*[in]*/ LPCWSTR szLanguage , /*[out]*/ Taxonomy::HelpSet& ths ) { __HCP_FUNC_ENTRY( "OfflineCache::Root::FindMatch" ); HRESULT hr; MPC::SmartLock<_ThreadModel> lock( this ); SKUIter it; __MPC_EXIT_IF_METHOD_FAILS(hr, Load()); for(it = m_lstSKUs.begin(); it != m_lstSKUs.end(); it++) { SetOfHelpTopics& sht = *it; if(STRINGISPRESENT(szSKU)) { if(!_wcsicmp( szSKU, L"All" )) { ; } else if(!_wcsicmp( szSKU, L"Server" )) { if(sht.m_inst.m_fServer == false) continue; } else if(!_wcsicmp( szSKU, L"Desktop" )) { if(sht.m_inst.m_fDesktop == false) continue; } else if(!_wcsicmp( szSKU, L"Embedded" )) { if(sht.m_inst.m_fEmbedded == false) continue; } else { if(_wcsicmp( szSKU, sht.m_inst.m_ths.GetSKU() ) != 0) continue; } } if(STRINGISPRESENT(szLanguage)) { if(!_wcsicmp( szLanguage, L"All" )) { ; } else if(!_wcsicmp( szLanguage, L"MUI" )) { if(sht.m_inst.m_fMUI == false || GetUserDefaultUILanguage() != sht.m_inst.m_ths.GetLanguage()) { continue; } } else { if(_wtol( szLanguage ) != sht.m_inst.m_ths.GetLanguage()) continue; } } ths = sht.m_inst.m_ths; break; } if(it == m_lstSKUs.end()) { __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_FILE_NOT_FOUND); } hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); }