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.

546 lines
12 KiB

  1. /******************************************************************************
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. Favorites.cpp
  5. Abstract:
  6. This file contains the implementation of the CPCHFavorites class,
  7. which is used to store the list of favorite contents.
  8. Revision History:
  9. Davide Massarenti (Dmassare) 05/10/2000
  10. created
  11. ******************************************************************************/
  12. #include "stdafx.h"
  13. /////////////////////////////////////////////////////////////////////////////
  14. const WCHAR c_szPersistFile[] = HC_ROOT_HELPCTR L"\\Favorites.stream";
  15. static const DWORD l_dwVersion = 0x01564146; // FAV 01
  16. /////////////////////////////////////////////////////////////////////////////
  17. HRESULT CPCHFavorites::Entry::Init()
  18. {
  19. __HCP_FUNC_ENTRY( "CPCHFavorites::Entry::Init" );
  20. HRESULT hr;
  21. if(m_Data == NULL)
  22. {
  23. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &m_Data ));
  24. }
  25. hr = S_OK;
  26. __HCP_FUNC_CLEANUP;
  27. __HCP_FUNC_EXIT(hr);
  28. }
  29. HRESULT CPCHFavorites::Entry::Load( /*[in]*/ MPC::Serializer& streamIn )
  30. {
  31. __HCP_FUNC_ENTRY( "CPCHFavorites::Entry::Load" );
  32. HRESULT hr;
  33. __MPC_PARAMCHECK_BEGIN(hr)
  34. __MPC_PARAMCHECK_NOTNULL(m_Data);
  35. __MPC_PARAMCHECK_END();
  36. __MPC_EXIT_IF_METHOD_FAILS(hr, m_Data->Load( streamIn ));
  37. hr = S_OK;
  38. __HCP_FUNC_CLEANUP;
  39. __HCP_FUNC_EXIT(hr);
  40. }
  41. HRESULT CPCHFavorites::Entry::Save( /*[in]*/ MPC::Serializer& streamOut )
  42. {
  43. __HCP_FUNC_ENTRY( "CPCHFavorites::Entry::Save" );
  44. HRESULT hr;
  45. if(m_Data)
  46. {
  47. __MPC_EXIT_IF_METHOD_FAILS(hr, m_Data->Save( streamOut, true ));
  48. }
  49. hr = S_OK;
  50. __HCP_FUNC_CLEANUP;
  51. __HCP_FUNC_EXIT(hr);
  52. }
  53. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  54. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  55. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  56. CPCHFavorites::CPCHFavorites()
  57. {
  58. __HCP_FUNC_ENTRY( "CPCHFavorites::CPCHFavorites" );
  59. // List m_lstFavorites;
  60. m_fLoaded = false; // bool m_fLoaded;
  61. }
  62. CPCHFavorites::~CPCHFavorites()
  63. {
  64. __HCP_FUNC_ENTRY( "CPCHFavorites::~CPCHFavorites" );
  65. }
  66. ////////////////////
  67. CPCHFavorites* CPCHFavorites::s_GLOBAL( NULL );
  68. HRESULT CPCHFavorites::InitializeSystem()
  69. {
  70. if(s_GLOBAL) return S_OK;
  71. return MPC::CreateInstance( &CPCHFavorites::s_GLOBAL );
  72. }
  73. void CPCHFavorites::FinalizeSystem()
  74. {
  75. if(s_GLOBAL)
  76. {
  77. s_GLOBAL->Release(); s_GLOBAL = NULL;
  78. }
  79. }
  80. ////////////////////////////////////////////////////////////////////////////////
  81. HRESULT CPCHFavorites::FindEntry( /*[in]*/ IPCHHelpSessionItem* pItem, /*[out]*/ Iter& it )
  82. {
  83. __HCP_FUNC_ENTRY( "CPCHFavorites::FindEntry" );
  84. HRESULT hr;
  85. //
  86. // First of all, look if the page is already present.
  87. //
  88. for(it = m_lstFavorites.begin(); it != m_lstFavorites.end(); it++)
  89. {
  90. if(it->m_Data == pItem)
  91. {
  92. __MPC_SET_ERROR_AND_EXIT(hr, S_OK);
  93. }
  94. }
  95. hr = HRESULT_FROM_WIN32( ERROR_NOT_FOUND );
  96. __HCP_FUNC_CLEANUP;
  97. __HCP_FUNC_EXIT(hr);
  98. }
  99. ////////////////////////////////////////////////////////////////////////////////
  100. HRESULT CPCHFavorites::Erase()
  101. {
  102. __HCP_FUNC_ENTRY( "CPCHFavorites::Erase" );
  103. HRESULT hr;
  104. MPC::SmartLock<_ThreadModel> lock(this);
  105. CPCHFavorites_Parent::Erase();
  106. m_lstFavorites.clear();
  107. m_fLoaded = false;
  108. hr = S_OK;
  109. __HCP_FUNC_EXIT(hr);
  110. }
  111. HRESULT CPCHFavorites::Load()
  112. {
  113. __HCP_FUNC_ENTRY( "CPCHFavorites::Load" );
  114. HRESULT hr;
  115. MPC::SmartLock<_ThreadModel> lock(this);
  116. HANDLE hFile = INVALID_HANDLE_VALUE;
  117. if(m_fLoaded == false)
  118. {
  119. MPC::wstring szFile;
  120. //
  121. // Open file and read it.
  122. //
  123. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::GetUserWritablePath( szFile, c_szPersistFile ));
  124. __MPC_EXIT_IF_INVALID_HANDLE(hr, hFile, ::CreateFileW( szFile.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL ));
  125. {
  126. MPC::Serializer_File streamReal( hFile );
  127. MPC::Serializer_Buffering streamBuf ( streamReal );
  128. DWORD dwVer;
  129. __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf >> dwVer); if(dwVer != l_dwVersion) __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
  130. while(1)
  131. {
  132. Iter it = m_lstFavorites.insert( m_lstFavorites.end() );
  133. __MPC_EXIT_IF_METHOD_FAILS(hr, it->Init());
  134. if(FAILED(it->Load( streamBuf )))
  135. {
  136. m_lstFavorites.erase( it );
  137. break;
  138. }
  139. }
  140. }
  141. }
  142. hr = S_OK;
  143. __HCP_FUNC_CLEANUP;
  144. if(FAILED(hr)) Erase();
  145. if(hFile != INVALID_HANDLE_VALUE) ::CloseHandle( hFile );
  146. m_fLoaded = true; // Anyway, flag the object as loaded.
  147. __HCP_FUNC_EXIT(S_OK); // Never fail.
  148. }
  149. HRESULT CPCHFavorites::Save()
  150. {
  151. __HCP_FUNC_ENTRY( "CPCHFavorites::Save" );
  152. HRESULT hr;
  153. MPC::SmartLock<_ThreadModel> lock(this);
  154. HANDLE hFile = INVALID_HANDLE_VALUE;
  155. if(m_fLoaded)
  156. {
  157. MPC::wstring szFile;
  158. Iter it;
  159. //
  160. // Create the new file.
  161. //
  162. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::GetUserWritablePath( szFile, c_szPersistFile ));
  163. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::MakeDir ( szFile ));
  164. __MPC_EXIT_IF_INVALID_HANDLE(hr, hFile, ::CreateFileW( szFile.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL ));
  165. {
  166. MPC::Serializer_File streamReal( hFile );
  167. MPC::Serializer_Buffering streamBuf ( streamReal );
  168. __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf << l_dwVersion);
  169. for(it = m_lstFavorites.begin(); it != m_lstFavorites.end(); it++)
  170. {
  171. __MPC_EXIT_IF_METHOD_FAILS(hr, it->Save( streamBuf ));
  172. }
  173. __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf.Flush());
  174. }
  175. __MPC_EXIT_IF_METHOD_FAILS(hr, Synchronize( false ));
  176. __MPC_EXIT_IF_METHOD_FAILS(hr, CPCHHelpCenterExternal::s_GLOBAL->Events().FireEvent_FavoritesUpdate());
  177. }
  178. hr = S_OK;
  179. __HCP_FUNC_CLEANUP;
  180. if(hFile != INVALID_HANDLE_VALUE)
  181. {
  182. ::FlushFileBuffers( hFile );
  183. ::CloseHandle ( hFile );
  184. }
  185. __HCP_FUNC_EXIT(hr);
  186. }
  187. /////////////////////////////////////////////////////////////////////////////
  188. HRESULT CPCHFavorites::Synchronize( /*[in]*/ bool fForce )
  189. {
  190. __HCP_FUNC_ENTRY( "CPCHFavorites::Synchronize" );
  191. HRESULT hr;
  192. MPC::SmartLock<_ThreadModel> lock(this);
  193. if(fForce) Erase();
  194. __MPC_EXIT_IF_METHOD_FAILS(hr, Load());
  195. if(m_fLoaded)
  196. {
  197. Iter it;
  198. const Taxonomy::HelpSet& ths = CPCHHelpCenterExternal::s_GLOBAL->UserSettings()->THS();
  199. //
  200. // We actually have two lists, the real one, m_lstFavorites, and the enumerator's one, m_coll.
  201. // So, whenever the real one changes, we need to rebuild the one held by the enumerator.
  202. //
  203. CPCHFavorites_Parent::Erase();
  204. for(it = m_lstFavorites.begin(); it != m_lstFavorites.end(); it++)
  205. {
  206. CPCHHelpSessionItem* data = it->m_Data;
  207. if(data->SameSKU( ths ))
  208. {
  209. __MPC_EXIT_IF_METHOD_FAILS(hr, AddItem( data ));
  210. }
  211. }
  212. }
  213. hr = S_OK;
  214. __HCP_FUNC_CLEANUP;
  215. __HCP_FUNC_EXIT(hr);
  216. }
  217. /////////////////////////////////////////////////////////////////////////////
  218. STDMETHODIMP CPCHFavorites::IsDuplicate( /*[in]*/ BSTR bstrURL ,
  219. /*[out, retval]*/ VARIANT_BOOL *pfDup )
  220. {
  221. __HCP_FUNC_ENTRY( "CPCHFavorites::IsDuplicate" );
  222. HRESULT hr;
  223. MPC::SmartLock<_ThreadModel> lock(this);
  224. const Taxonomy::HelpSet& ths = CPCHHelpCenterExternal::s_GLOBAL->UserSettings()->THS();
  225. Iter it;
  226. __MPC_PARAMCHECK_BEGIN(hr)
  227. __MPC_PARAMCHECK_POINTER_AND_SET(pfDup,VARIANT_FALSE);
  228. __MPC_PARAMCHECK_END();
  229. __MPC_EXIT_IF_METHOD_FAILS(hr, Load());
  230. for(it = m_lstFavorites.begin(); it != m_lstFavorites.end(); it++)
  231. {
  232. CPCHHelpSessionItem* data = it->m_Data;
  233. if(data->SameSKU( ths ) &&
  234. data->SameURL( bstrURL ) )
  235. {
  236. *pfDup = VARIANT_TRUE;
  237. break;
  238. }
  239. }
  240. hr = S_OK;
  241. __HCP_FUNC_CLEANUP;
  242. __HCP_FUNC_EXIT(hr);
  243. }
  244. STDMETHODIMP CPCHFavorites::Add( /*[in]*/ BSTR bstrURL ,
  245. /*[in,optional]*/ VARIANT vTitle ,
  246. /*[out, retval]*/ IPCHHelpSessionItem* *ppItem )
  247. {
  248. __HCP_FUNC_ENTRY( "CPCHFavorites::Add" );
  249. HRESULT hr;
  250. MPC::SmartLock<_ThreadModel> lock(this);
  251. CPCHProxy_IPCHUserSettings2* us = CPCHHelpCenterExternal::s_GLOBAL->UserSettings();
  252. CPCHHelpSessionItem* data;
  253. CComBSTR bstrTitleInfer;
  254. BSTR bstrTitle;
  255. Iter it;
  256. __MPC_PARAMCHECK_BEGIN(hr)
  257. __MPC_PARAMCHECK_STRING_NOT_EMPTY(bstrURL);
  258. __MPC_PARAMCHECK_END();
  259. __MPC_EXIT_IF_METHOD_FAILS(hr, Load());
  260. if(vTitle.vt == VT_BSTR)
  261. {
  262. bstrTitle = vTitle.bstrVal;
  263. }
  264. else
  265. {
  266. __MPC_EXIT_IF_METHOD_FAILS(hr, CPCHHelpCenterExternal::s_GLOBAL->HelpSession()->LookupTitle( bstrURL, bstrTitleInfer, /*fUseCache*/false ));
  267. bstrTitle = bstrTitleInfer;
  268. }
  269. if(bstrTitle == NULL || bstrTitle[0] == 0) bstrTitle = bstrURL; // We need some sort of title.
  270. it = m_lstFavorites.insert( m_lstFavorites.end() );
  271. __MPC_EXIT_IF_METHOD_FAILS(hr, it->Init());
  272. data = it->m_Data;
  273. data->put_THS( us->THS() );
  274. __MPC_EXIT_IF_METHOD_FAILS(hr, data->put_URL ( bstrURL ));
  275. __MPC_EXIT_IF_METHOD_FAILS(hr, data->put_Title( bstrTitle ));
  276. __MPC_EXIT_IF_METHOD_FAILS(hr, Save());
  277. hr = S_OK;
  278. __HCP_FUNC_CLEANUP;
  279. __HCP_FUNC_EXIT(hr);
  280. }
  281. STDMETHODIMP CPCHFavorites::Rename( /*[in]*/ BSTR bstrTitle ,
  282. /*[in]*/ IPCHHelpSessionItem* pItem )
  283. {
  284. __HCP_FUNC_ENTRY( "CPCHFavorites::Rename" );
  285. HRESULT hr;
  286. MPC::SmartLock<_ThreadModel> lock(this);
  287. Iter it;
  288. __MPC_PARAMCHECK_BEGIN(hr)
  289. __MPC_PARAMCHECK_STRING_NOT_EMPTY(bstrTitle);
  290. __MPC_PARAMCHECK_END();
  291. __MPC_EXIT_IF_METHOD_FAILS(hr, Load());
  292. __MPC_EXIT_IF_METHOD_FAILS(hr, FindEntry( pItem, it ));
  293. __MPC_EXIT_IF_METHOD_FAILS(hr, it->m_Data->put_Title( bstrTitle ));
  294. __MPC_EXIT_IF_METHOD_FAILS(hr, Save());
  295. hr = S_OK;
  296. __HCP_FUNC_CLEANUP;
  297. __HCP_FUNC_EXIT(hr);
  298. }
  299. STDMETHODIMP CPCHFavorites::Move( /*[in]*/ IPCHHelpSessionItem* pInsertBefore ,
  300. /*[in]*/ IPCHHelpSessionItem* pItem )
  301. {
  302. __HCP_FUNC_ENTRY( "CPCHFavorites::Move" );
  303. HRESULT hr;
  304. MPC::SmartLock<_ThreadModel> lock(this);
  305. CPCHHelpSessionItem* data = NULL;
  306. Iter itBefore;
  307. Iter itOld;
  308. Iter itNew;
  309. __MPC_EXIT_IF_METHOD_FAILS(hr, Load());
  310. //
  311. // If an element is passed, then we insert before it, otherwise we insert at the end.
  312. //
  313. if(pInsertBefore)
  314. {
  315. __MPC_EXIT_IF_METHOD_FAILS(hr, FindEntry( pInsertBefore, itBefore ));
  316. }
  317. else
  318. {
  319. itBefore = m_lstFavorites.end();
  320. }
  321. __MPC_EXIT_IF_METHOD_FAILS(hr, FindEntry( pItem, itOld ));
  322. //
  323. // Trying to move the element on itself.
  324. //
  325. if(itOld == itBefore)
  326. {
  327. __MPC_SET_ERROR_AND_EXIT(hr, E_INVALIDARG);
  328. }
  329. //
  330. // Save pointer to data, erase old item, create a new one and restore pointer.
  331. //
  332. data = itOld->m_Data; data->AddRef();
  333. m_lstFavorites.erase ( itOld );
  334. itNew = m_lstFavorites.insert( itBefore );
  335. itNew->m_Data = data; data = NULL;
  336. __MPC_EXIT_IF_METHOD_FAILS(hr, Save());
  337. hr = S_OK;
  338. __HCP_FUNC_CLEANUP;
  339. MPC::Release( data );
  340. __HCP_FUNC_EXIT(hr);
  341. }
  342. STDMETHODIMP CPCHFavorites::Delete( /*[in]*/ IPCHHelpSessionItem* pItem )
  343. {
  344. __HCP_FUNC_ENTRY( "CPCHFavorites::Delete" );
  345. HRESULT hr;
  346. MPC::SmartLock<_ThreadModel> lock(this);
  347. Iter it;
  348. __MPC_EXIT_IF_METHOD_FAILS(hr, Load());
  349. __MPC_EXIT_IF_METHOD_FAILS(hr, FindEntry( pItem, it ));
  350. m_lstFavorites.erase( it );
  351. __MPC_EXIT_IF_METHOD_FAILS(hr, Synchronize( false ));
  352. __MPC_EXIT_IF_METHOD_FAILS(hr, Save());
  353. hr = S_OK;
  354. __HCP_FUNC_CLEANUP;
  355. __HCP_FUNC_EXIT(hr);
  356. }