Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

736 lines
18 KiB

  1. /******************************************************************************
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. OfflineCache.cpp
  5. Abstract:
  6. Handles caching of database lookups.
  7. Revision History:
  8. Davide Massarenti (Dmassare) 07/17/2000
  9. created
  10. ******************************************************************************/
  11. #include "stdafx.h"
  12. ////////////////////////////////////////////////////////////////////////////////
  13. ////////////////////////////////////////////////////////////////////////////////
  14. HRESULT OfflineCache::operator>>( /*[in]*/ MPC::Serializer& stream, /*[out]*/ OfflineCache::Query& val )
  15. {
  16. __HCP_FUNC_ENTRY( "OfflineCache::OfflineCache::operator>> OfflineCache::Query" );
  17. HRESULT hr;
  18. __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> val.m_strID );
  19. __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> val.m_iType );
  20. __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> val.m_iSequence);
  21. __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> val.m_fNull );
  22. hr = S_OK;
  23. __HCP_FUNC_CLEANUP;
  24. __HCP_FUNC_EXIT(hr);
  25. }
  26. HRESULT OfflineCache::operator<<( /*[in]*/ MPC::Serializer& stream, /*[in] */ const OfflineCache::Query& val )
  27. {
  28. __HCP_FUNC_ENTRY( "OfflineCache::operator<< OfflineCache::Query" );
  29. HRESULT hr;
  30. __MPC_EXIT_IF_METHOD_FAILS(hr, stream << val.m_strID );
  31. __MPC_EXIT_IF_METHOD_FAILS(hr, stream << val.m_iType );
  32. __MPC_EXIT_IF_METHOD_FAILS(hr, stream << val.m_iSequence);
  33. __MPC_EXIT_IF_METHOD_FAILS(hr, stream << val.m_fNull );
  34. hr = S_OK;
  35. __HCP_FUNC_CLEANUP;
  36. __HCP_FUNC_EXIT(hr);
  37. }
  38. OfflineCache::Query::Query()
  39. {
  40. // MPC::wstring m_strID;
  41. m_iType = ET_INVALID; // int m_iType;
  42. m_iSequence = 0; // int m_iSequence;
  43. m_fNull = true; // bool m_fNull;
  44. }
  45. HRESULT OfflineCache::Query::InitFile( /*[in ]*/ const MPC::wstring& strDir ,
  46. /*[out]*/ MPC::wstring& strFile )
  47. {
  48. __HCP_FUNC_ENTRY( "OfflineCache::Query::InitFile" );
  49. HRESULT hr;
  50. WCHAR rgBuf[64]; swprintf( rgBuf, L"\\%08x.query", m_iSequence );
  51. strFile = strDir;
  52. strFile += rgBuf;
  53. hr = S_OK;
  54. __HCP_FUNC_EXIT(hr);
  55. }
  56. HRESULT OfflineCache::Query::Retrieve( /*[in]*/ const MPC::wstring& strDir ,
  57. /*[in]*/ CPCHQueryResultCollection* *pColl )
  58. {
  59. __HCP_FUNC_ENTRY( "OfflineCache::Query::Retrieve" );
  60. HRESULT hr;
  61. CComPtr<CPCHQueryResultCollection> coll;
  62. __MPC_PARAMCHECK_BEGIN(hr)
  63. __MPC_PARAMCHECK_POINTER_AND_SET(pColl, NULL);
  64. __MPC_PARAMCHECK_END();
  65. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &coll ));
  66. if(m_fNull == false)
  67. {
  68. MPC::wstring strFile;
  69. CComPtr<MPC::FileStream> stream;
  70. __MPC_EXIT_IF_METHOD_FAILS(hr, InitFile ( strDir , strFile ));
  71. __MPC_EXIT_IF_METHOD_FAILS(hr, SVC::SafeLoad( strFile, stream ));
  72. //
  73. // Create the collection from the IStream.
  74. //
  75. {
  76. MPC::Serializer_IStream streamGen ( stream );
  77. MPC::Serializer_Buffering streamGen2( streamGen );
  78. __MPC_EXIT_IF_METHOD_FAILS(hr, coll->Load( streamGen2 ));
  79. }
  80. }
  81. *pColl = coll.Detach();
  82. hr = S_OK;
  83. __HCP_FUNC_CLEANUP;
  84. __HCP_FUNC_EXIT(hr);
  85. }
  86. ////////////////////////////////////////////////////////////////////////////////
  87. ////////////////////////////////////////////////////////////////////////////////
  88. HRESULT OfflineCache::operator>>( /*[in] */ MPC::Serializer& stream ,
  89. /*[out]*/ OfflineCache::SetOfHelpTopics& val )
  90. {
  91. __HCP_FUNC_ENTRY( "OfflineCache::operator>> OfflineCache::SetOfHelpTopics" );
  92. HRESULT hr;
  93. __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> val.m_inst );
  94. __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> val.m_lstQueries);
  95. __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> val.m_iLastSeq );
  96. hr = S_OK;
  97. __HCP_FUNC_CLEANUP;
  98. __HCP_FUNC_EXIT(hr);
  99. }
  100. HRESULT OfflineCache::operator<<( /*[in]*/ MPC::Serializer& stream ,
  101. /*[in]*/ const OfflineCache::SetOfHelpTopics& val )
  102. {
  103. __HCP_FUNC_ENTRY( "OfflineCache::operator<< OfflineCache::SetOfHelpTopics" );
  104. HRESULT hr;
  105. __MPC_EXIT_IF_METHOD_FAILS(hr, stream << val.m_inst );
  106. __MPC_EXIT_IF_METHOD_FAILS(hr, stream << val.m_lstQueries);
  107. __MPC_EXIT_IF_METHOD_FAILS(hr, stream << val.m_iLastSeq );
  108. hr = S_OK;
  109. __HCP_FUNC_CLEANUP;
  110. __HCP_FUNC_EXIT(hr);
  111. }
  112. OfflineCache::SetOfHelpTopics::SetOfHelpTopics()
  113. {
  114. m_parent = NULL; // Root* m_parent;
  115. //
  116. // Taxonomy::Instance m_inst;
  117. // QueryList m_lstQueries;
  118. m_iLastSeq = 0; // int m_iLastSeq;
  119. }
  120. ////////////////////
  121. HRESULT OfflineCache::SetOfHelpTopics::InitDir( /*[in]*/ MPC::wstring& strDir )
  122. {
  123. __HCP_FUNC_ENTRY( "OfflineCache::SetOfHelpTopics::InitDir" );
  124. HRESULT hr;
  125. WCHAR rgDir[MAX_PATH];
  126. _snwprintf( rgDir, MAXSTRLEN(rgDir), L"%s\\%s#%04lx", HC_ROOT_HELPSVC_OFFLINECACHE, m_inst.m_ths.GetSKU(), m_inst.m_ths.GetLanguage() );
  127. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::SubstituteEnvVariables( strDir = rgDir ));
  128. hr = S_OK;
  129. __HCP_FUNC_CLEANUP;
  130. __HCP_FUNC_EXIT(hr);
  131. }
  132. HRESULT OfflineCache::SetOfHelpTopics::Find( /*[in] */ LPCWSTR& szID ,
  133. /*[in] */ int iType ,
  134. /*[out]*/ QueryIter& it )
  135. {
  136. __HCP_FUNC_ENTRY( "OfflineCache::SetOfHelpTopics::Find" );
  137. HRESULT hr;
  138. if(szID == NULL) szID = L"";
  139. for(it = m_lstQueries.begin(); it != m_lstQueries.end(); it++)
  140. {
  141. if(!MPC::StrICmp( it->m_strID , szID ) &&
  142. it->m_iType == iType )
  143. {
  144. break;
  145. }
  146. }
  147. hr = S_OK;
  148. __HCP_FUNC_EXIT(hr);
  149. }
  150. void OfflineCache::SetOfHelpTopics::ConnectToParent( /*[in]*/ Root* parent )
  151. {
  152. m_parent = parent;
  153. }
  154. ////////////////////////////////////////
  155. HRESULT OfflineCache::SetOfHelpTopics::Retrieve( /*[in]*/ LPCWSTR szID ,
  156. /*[in]*/ int iType ,
  157. /*[in]*/ CPCHQueryResultCollection* *pColl )
  158. {
  159. __HCP_FUNC_ENTRY( "OfflineCache::SetOfHelpTopics::Retrieve" );
  160. HRESULT hr;
  161. QueryIter it;
  162. __MPC_PARAMCHECK_BEGIN(hr)
  163. __MPC_PARAMCHECK_POINTER_AND_SET(pColl, NULL);
  164. __MPC_PARAMCHECK_END();
  165. __MPC_EXIT_IF_METHOD_FAILS(hr, Find( szID, iType, it ));
  166. if(it == m_lstQueries.end())
  167. {
  168. __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_FILE_NOT_FOUND);
  169. }
  170. //
  171. // Load from the registry.
  172. //
  173. {
  174. MPC::wstring strDir;
  175. __MPC_EXIT_IF_METHOD_FAILS(hr, InitDir( strDir ));
  176. __MPC_EXIT_IF_METHOD_FAILS(hr, it->Retrieve( strDir, pColl ));
  177. }
  178. hr = S_OK;
  179. __HCP_FUNC_CLEANUP;
  180. __HCP_FUNC_EXIT(hr);
  181. }
  182. ////////////////////////////////////////////////////////////////////////////////
  183. ////////////////////////////////////////////////////////////////////////////////
  184. OfflineCache::Handle::Handle()
  185. {
  186. m_main = NULL; // Root* m_main;
  187. m_sht = NULL; // SetOfHelpTopics* m_sht;
  188. }
  189. OfflineCache::Handle::~Handle()
  190. {
  191. Release();
  192. }
  193. void OfflineCache::Handle::Attach( /*[in]*/ Root* main, /*[in]*/ SetOfHelpTopics* sht )
  194. {
  195. Release();
  196. m_main = main; if(main) main->Lock();
  197. m_sht = sht;
  198. }
  199. void OfflineCache::Handle::Release()
  200. {
  201. if(m_main) m_main->Unlock();
  202. m_main = NULL;
  203. m_sht = NULL;
  204. }
  205. ////////////////////////////////////////////////////////////////////////////////
  206. ////////////////////////////////////////////////////////////////////////////////
  207. HRESULT OfflineCache::operator>>( /*[in] */ MPC::Serializer& stream ,
  208. /*[out]*/ OfflineCache::Root& val )
  209. {
  210. __HCP_FUNC_ENTRY( "OfflineCache::operator>> OfflineCache::Root" );
  211. HRESULT hr;
  212. __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> val.m_fReady );
  213. __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> val.m_instMachine);
  214. __MPC_EXIT_IF_METHOD_FAILS(hr, stream >> val.m_lstSKUs );
  215. hr = S_OK;
  216. __HCP_FUNC_CLEANUP;
  217. __HCP_FUNC_EXIT(hr);
  218. }
  219. HRESULT OfflineCache::operator<<( /*[in]*/ MPC::Serializer& stream ,
  220. /*[in]*/ const OfflineCache::Root& val )
  221. {
  222. __HCP_FUNC_ENTRY( "OfflineCache::operator<< OfflineCache::Root" );
  223. HRESULT hr;
  224. __MPC_EXIT_IF_METHOD_FAILS(hr, stream << val.m_fReady );
  225. __MPC_EXIT_IF_METHOD_FAILS(hr, stream << val.m_instMachine);
  226. __MPC_EXIT_IF_METHOD_FAILS(hr, stream << val.m_lstSKUs );
  227. hr = S_OK;
  228. __HCP_FUNC_CLEANUP;
  229. __HCP_FUNC_EXIT(hr);
  230. }
  231. OfflineCache::Root::Root( /*[in]*/ bool fMaster ) : m_nmSharedLock( L"GLOBAL\\PCH_OFFLINECACHE", /*fCloseOnRelease*/true )
  232. {
  233. // MPC::NamedMutex m_nmSharedLock;
  234. //
  235. m_fReady = false; // bool m_fReady;
  236. // Taxonomy::Instance m_instMachine;
  237. // SKUList m_lstSKUs;
  238. //
  239. m_fMaster = fMaster; // bool m_fMaster;
  240. m_fLoaded = false; // bool m_fLoaded;
  241. m_fDirty = false; // bool m_fDirty;
  242. m_dwDisableSave = 0; // DWORD m_dwDisableSave;
  243. m_hChangeNotification = INVALID_HANDLE_VALUE; // HANDLE m_hChangeNotification;
  244. }
  245. OfflineCache::Root::~Root()
  246. {
  247. (void)Clean();
  248. }
  249. ////////////////////
  250. OfflineCache::Root* OfflineCache::Root::s_GLOBAL( NULL );
  251. HRESULT OfflineCache::Root::InitializeSystem( /*[in]*/ bool fMaster )
  252. {
  253. if(s_GLOBAL == NULL)
  254. {
  255. s_GLOBAL = new OfflineCache::Root( fMaster );
  256. }
  257. return s_GLOBAL ? S_OK : E_OUTOFMEMORY;
  258. }
  259. void OfflineCache::Root::FinalizeSystem()
  260. {
  261. if(s_GLOBAL)
  262. {
  263. delete s_GLOBAL; s_GLOBAL = NULL;
  264. }
  265. }
  266. ////////////////////
  267. void OfflineCache::Root::Lock()
  268. {
  269. super::Lock();
  270. (void)m_nmSharedLock.Acquire( 500 );
  271. }
  272. void OfflineCache::Root::Unlock()
  273. {
  274. (void)m_nmSharedLock.Release();
  275. super::Unlock();
  276. }
  277. ////////////////////
  278. HRESULT OfflineCache::Root::GetIndexFile( /*[in]*/ MPC::wstring& strIndex )
  279. {
  280. __HCP_FUNC_ENTRY( "OfflineCache::Root::GetIndexFile" );
  281. HRESULT hr;
  282. strIndex.reserve( MAX_PATH );
  283. strIndex = HC_ROOT_HELPSVC_OFFLINECACHE;
  284. strIndex += L"\\index.dat";
  285. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::SubstituteEnvVariables( strIndex ));
  286. hr = S_OK;
  287. __HCP_FUNC_CLEANUP;
  288. __HCP_FUNC_EXIT(hr);
  289. }
  290. HRESULT OfflineCache::Root::Load()
  291. {
  292. __HCP_FUNC_ENTRY( "OfflineCache::Root::Load" );
  293. HRESULT hr;
  294. //
  295. // If the content of the offline cache directory has changed, reload everything.
  296. //
  297. if(m_hChangeNotification != INVALID_HANDLE_VALUE)
  298. {
  299. if(::WaitForSingleObject( m_hChangeNotification, 0 ) != WAIT_TIMEOUT)
  300. {
  301. ::FindNextChangeNotification( m_hChangeNotification );
  302. Clean();
  303. }
  304. }
  305. //
  306. // Not already loaded, try to load, but without failing.
  307. //
  308. if(m_fLoaded == false)
  309. {
  310. MPC::wstring strIndex;
  311. CComPtr<MPC::FileStream> stream;
  312. if(SUCCEEDED(GetIndexFile ( strIndex )) &&
  313. SUCCEEDED(SVC::SafeLoad( strIndex, stream )) )
  314. {
  315. MPC::Serializer_IStream streamGen ( stream );
  316. MPC::Serializer_Buffering streamGen2( streamGen );
  317. DWORD dwVer;
  318. if(SUCCEEDED(streamGen2 >> dwVer) && dwVer == s_dwVersion)
  319. {
  320. if(SUCCEEDED(streamGen2 >> *this))
  321. {
  322. for(SKUIter it = m_lstSKUs.begin(); it != m_lstSKUs.end(); it++)
  323. {
  324. it->ConnectToParent( this );
  325. }
  326. if(m_fMaster == false && m_fReady)
  327. {
  328. __MPC_EXIT_IF_METHOD_FAILS(hr, Taxonomy::HelpSet::SetMachineInfo( m_instMachine ));
  329. }
  330. }
  331. else
  332. {
  333. Clean();
  334. }
  335. }
  336. //
  337. // Setup change notification, if we are a slave.
  338. //
  339. if(m_fMaster == false)
  340. {
  341. static const DWORD s_dwNotify = FILE_NOTIFY_CHANGE_FILE_NAME |
  342. FILE_NOTIFY_CHANGE_DIR_NAME |
  343. FILE_NOTIFY_CHANGE_ATTRIBUTES |
  344. FILE_NOTIFY_CHANGE_SIZE |
  345. FILE_NOTIFY_CHANGE_LAST_WRITE |
  346. FILE_NOTIFY_CHANGE_CREATION;
  347. m_hChangeNotification = ::FindFirstChangeNotificationW( strIndex.c_str(), TRUE, s_dwNotify );
  348. }
  349. }
  350. m_fLoaded = true;
  351. m_fDirty = false;
  352. }
  353. hr = S_OK;
  354. __HCP_FUNC_CLEANUP;
  355. __HCP_FUNC_EXIT(hr);
  356. }
  357. HRESULT OfflineCache::Root::Clean()
  358. {
  359. __HCP_FUNC_ENTRY( "OfflineCache::Root::Clean" );
  360. HRESULT hr;
  361. m_fLoaded = false;
  362. m_fDirty = false;
  363. m_fReady = false;
  364. m_lstSKUs.clear();
  365. if(m_hChangeNotification != INVALID_HANDLE_VALUE)
  366. {
  367. ::FindCloseChangeNotification( m_hChangeNotification );
  368. m_hChangeNotification = INVALID_HANDLE_VALUE;
  369. }
  370. hr = S_OK;
  371. __HCP_FUNC_EXIT(hr);
  372. }
  373. ////////////////////
  374. HRESULT OfflineCache::Root::Find( /*[in ]*/ const Taxonomy::HelpSet& ths ,
  375. /*[out]*/ SKUIter& it )
  376. {
  377. __HCP_FUNC_ENTRY( "OfflineCache::Root::Find" );
  378. HRESULT hr;
  379. __MPC_EXIT_IF_METHOD_FAILS(hr, Load());
  380. for(it = m_lstSKUs.begin(); it != m_lstSKUs.end(); it++)
  381. {
  382. if(it->m_inst.m_ths == ths)
  383. {
  384. break;
  385. }
  386. }
  387. hr = S_OK;
  388. __HCP_FUNC_CLEANUP;
  389. __HCP_FUNC_EXIT(hr);
  390. }
  391. ////////////////////////////////////////
  392. HRESULT OfflineCache::Root::Locate( /*[in] */ const Taxonomy::HelpSet& ths ,
  393. /*[out]*/ Handle& handle )
  394. {
  395. __HCP_FUNC_ENTRY( "OfflineCache::Root::Locate" );
  396. HRESULT hr;
  397. MPC::SmartLock<_ThreadModel> lock( this );
  398. SKUIter it;
  399. handle.Release();
  400. __MPC_EXIT_IF_METHOD_FAILS(hr, Find( ths, it ));
  401. if(it == m_lstSKUs.end())
  402. {
  403. __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_FILE_NOT_FOUND);
  404. }
  405. handle.Attach( this, &(*it) );
  406. hr = S_OK;
  407. __HCP_FUNC_CLEANUP;
  408. __HCP_FUNC_EXIT(hr);
  409. }
  410. ////////////////////////////////////////
  411. HRESULT OfflineCache::Root::SetMachineInfo( /*[in]*/ const Taxonomy::Instance& inst )
  412. {
  413. __HCP_FUNC_ENTRY( "OfflineCache::Root::SetMachineInfo" );
  414. HRESULT hr;
  415. MPC::SmartLock<_ThreadModel> lock( this );
  416. if(m_fMaster)
  417. {
  418. Taxonomy::HelpSet ths;
  419. __MPC_EXIT_IF_METHOD_FAILS(hr, Load());
  420. m_instMachine = inst;
  421. m_fDirty = true;
  422. }
  423. hr = S_OK;
  424. __HCP_FUNC_CLEANUP;
  425. __HCP_FUNC_EXIT(hr);
  426. }
  427. ////////////////////
  428. bool OfflineCache::Root::IsReady()
  429. {
  430. __HCP_FUNC_ENTRY( "OfflineCache::Root::IsReady" );
  431. HRESULT hr;
  432. MPC::SmartLock<_ThreadModel> lock( this );
  433. __MPC_EXIT_IF_METHOD_FAILS(hr, Load());
  434. __HCP_FUNC_CLEANUP;
  435. __HCP_FUNC_EXIT(m_fReady);
  436. }
  437. ////////////////////////////////////////
  438. HRESULT OfflineCache::Root::FindMatch( /*[in]*/ LPCWSTR szSKU ,
  439. /*[in]*/ LPCWSTR szLanguage ,
  440. /*[out]*/ Taxonomy::HelpSet& ths )
  441. {
  442. __HCP_FUNC_ENTRY( "OfflineCache::Root::FindMatch" );
  443. HRESULT hr;
  444. MPC::SmartLock<_ThreadModel> lock( this );
  445. SKUIter it;
  446. __MPC_EXIT_IF_METHOD_FAILS(hr, Load());
  447. for(it = m_lstSKUs.begin(); it != m_lstSKUs.end(); it++)
  448. {
  449. SetOfHelpTopics& sht = *it;
  450. if(STRINGISPRESENT(szSKU))
  451. {
  452. if(!_wcsicmp( szSKU, L"All" ))
  453. {
  454. ;
  455. }
  456. else if(!_wcsicmp( szSKU, L"Server" ))
  457. {
  458. if(sht.m_inst.m_fServer == false) continue;
  459. }
  460. else if(!_wcsicmp( szSKU, L"Desktop" ))
  461. {
  462. if(sht.m_inst.m_fDesktop == false) continue;
  463. }
  464. else if(!_wcsicmp( szSKU, L"Embedded" ))
  465. {
  466. if(sht.m_inst.m_fEmbedded == false) continue;
  467. }
  468. else
  469. {
  470. if(_wcsicmp( szSKU, sht.m_inst.m_ths.GetSKU() ) != 0) continue;
  471. }
  472. }
  473. if(STRINGISPRESENT(szLanguage))
  474. {
  475. if(!_wcsicmp( szLanguage, L"All" ))
  476. {
  477. ;
  478. }
  479. else if(!_wcsicmp( szLanguage, L"MUI" ))
  480. {
  481. if(sht.m_inst.m_fMUI == false || GetUserDefaultUILanguage() != sht.m_inst.m_ths.GetLanguage())
  482. {
  483. continue;
  484. }
  485. }
  486. else
  487. {
  488. if(_wtol( szLanguage ) != sht.m_inst.m_ths.GetLanguage()) continue;
  489. }
  490. }
  491. ths = sht.m_inst.m_ths;
  492. break;
  493. }
  494. if(it == m_lstSKUs.end())
  495. {
  496. __MPC_SET_WIN32_ERROR_AND_EXIT(hr, ERROR_FILE_NOT_FOUND);
  497. }
  498. hr = S_OK;
  499. __HCP_FUNC_CLEANUP;
  500. __HCP_FUNC_EXIT(hr);
  501. }