windows-nt/Source/XPSP1/NT/admin/pchealth/helpctr/service/database/offlinecache.cpp
2020-09-26 16:20:57 +08:00

737 lines
18 KiB
C++

/******************************************************************************
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<CPCHQueryResultCollection> 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<MPC::FileStream> 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<MPC::FileStream> 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);
}