737 lines
18 KiB
C++
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);
|
|
}
|