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.

3033 lines
82 KiB

  1. /******************************************************************************
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. HelpSession.cpp
  5. Abstract:
  6. This file contains the implementation of the CHCPHelpSession class,
  7. which is used to store the list of visited contents.
  8. Revision History:
  9. Davide Massarenti (Dmassare) 07/29/99
  10. created
  11. ******************************************************************************/
  12. #include "stdafx.h"
  13. #include <urlhist.h>
  14. /////////////////////////////////////////////////////////////////////////////
  15. #define REMEMBER_PAGE_DELAY (3)
  16. #define NUM_OF_ENTRIES_TO_PERSIST (20)
  17. static const DWORD l_dwVersion = 0x01005348; // HS 01
  18. static const DATE l_dNewNavigationThreshold = 1.0 / (24.0 * 60.0 * 60.0); // one second.
  19. static const int l_iMaxCachedItems = 10;
  20. static const WCHAR c_szPersistFile[] = HC_ROOT_HELPCTR L"\\HelpSessionHistory.dat";
  21. static const WCHAR c_szINDEX[] = L"Index";
  22. static const LPCWSTR c_rgExclude[] =
  23. {
  24. L"hcp://system/"
  25. };
  26. static const LPCWSTR c_rgBadTitles[] =
  27. {
  28. L"ms-its:",
  29. L"hcp:" ,
  30. L"http:" ,
  31. L"https:" ,
  32. };
  33. /////////////////////////////////////////////////////////////////////////////
  34. /////////////////////////////////////////////////////////////////////////////
  35. #ifdef HSS_RPRD
  36. struct XMLHelpSessionItem : public MPC::Config::TypeConstructor
  37. {
  38. DECLARE_CONFIG_MAP(XMLHelpSessionItem);
  39. int m_iIndex;
  40. Taxonomy::HelpSet m_ths;
  41. DATE m_dLastVisited;
  42. long m_lDuration;
  43. CComBSTR m_bstrURL;
  44. CComBSTR m_bstrTitle;
  45. CComBSTR m_bstrContextID;
  46. CComBSTR m_bstrContextInfo;
  47. CComBSTR m_bstrContextURL;
  48. ////////////////////////////////////////
  49. //
  50. // MPC::Config::TypeConstructor
  51. //
  52. DEFINE_CONFIG_DEFAULTTAG();
  53. DECLARE_CONFIG_METHODS();
  54. //
  55. ////////////////////////////////////////
  56. };
  57. CFG_BEGIN_FIELDS_MAP(XMLHelpSessionItem)
  58. CFG_ATTRIBUTE( L"ID" , int , m_iIndex ),
  59. CFG_ATTRIBUTE( L"SKU" , wstring, m_ths.m_strSKU ),
  60. CFG_ATTRIBUTE( L"Language" , long , m_ths.m_lLCID ),
  61. CFG_ATTRIBUTE( L"LastVisited" , DATE , m_dLastVisited ),
  62. CFG_ATTRIBUTE( L"Duration" , long , m_lDuration ),
  63. CFG_ELEMENT ( L"URL" , BSTR , m_bstrURL ),
  64. CFG_ELEMENT ( L"Title" , BSTR , m_bstrTitle ),
  65. CFG_ATTRIBUTE( L"Context" , BSTR , m_bstrContextID ),
  66. CFG_ELEMENT ( L"ContextData" , BSTR , m_bstrContextInfo ),
  67. CFG_ELEMENT ( L"ContextTopic" , BSTR , m_bstrContextURL ),
  68. CFG_END_FIELDS_MAP()
  69. CFG_BEGIN_CHILD_MAP(XMLHelpSessionItem)
  70. CFG_END_CHILD_MAP()
  71. DEFINE_CFG_OBJECT(XMLHelpSessionItem,L"Entry")
  72. DEFINE_CONFIG_METHODS__NOCHILD(XMLHelpSessionItem)
  73. #endif
  74. /////////////////////////////////////////////////////////////////////////////
  75. /////////////////////////////////////////////////////////////////////////////
  76. static struct ContextLookup
  77. {
  78. LPCWSTR szName;
  79. HscContext iValue;
  80. bool fInternal;
  81. } const s_rgContext[] =
  82. {
  83. { L"INVALID" , HSCCONTEXT_INVALID , true },
  84. { L"STARTUP" , HSCCONTEXT_STARTUP , true },
  85. { L"HOMEPAGE" , HSCCONTEXT_HOMEPAGE , false },
  86. { L"CONTENT" , HSCCONTEXT_CONTENT , false },
  87. { L"SUBSITE" , HSCCONTEXT_SUBSITE , false },
  88. { L"SEARCH" , HSCCONTEXT_SEARCH , false },
  89. { L"INDEX" , HSCCONTEXT_INDEX , false },
  90. { L"CHANNELS" , HSCCONTEXT_CHANNELS , false },
  91. { L"FAVORITES" , HSCCONTEXT_FAVORITES , false },
  92. { L"HISTORY" , HSCCONTEXT_HISTORY , false },
  93. { L"OPTIONS" , HSCCONTEXT_OPTIONS , false },
  94. /////////////////////////////////////////////////////
  95. { L"CONTENTONLY" , HSCCONTEXT_CONTENTONLY , false },
  96. { L"FULLWINDOW" , HSCCONTEXT_FULLWINDOW , false },
  97. { L"KIOSKMODE" , HSCCONTEXT_KIOSKMODE , false },
  98. };
  99. ////////////////////////////////////////////////////////////////////////////////
  100. CPCHHelpSessionItem::State::State( /*[in]*/ CPCHHelpSessionItem* parent )
  101. {
  102. m_parent = parent; // CPCHHelpSessionItem* m_parent;
  103. m_fValid = false; // bool m_fValid;
  104. m_fDirty = false; // bool m_fDirty;
  105. m_dwLoaded = 0; // DWORD m_dwLoaded;
  106. //
  107. // MPC::CComHGLOBAL m_hgWebBrowser_CONTENTS;
  108. // MPC::CComHGLOBAL m_hgWebBrowser_HHWINDOW;
  109. // PropertyMap m_mapProperties;
  110. }
  111. ////////////////////////////////////////////////////////////////////////////////
  112. void CPCHHelpSessionItem::State::Erase( /*[in]*/ bool fUnvalidate )
  113. {
  114. m_hgWebBrowser_CONTENTS.Release();
  115. m_hgWebBrowser_HHWINDOW.Release();
  116. m_mapProperties .clear ();
  117. m_fDirty = false;
  118. if(fUnvalidate) m_fValid = false;
  119. }
  120. HRESULT CPCHHelpSessionItem::State::Load()
  121. {
  122. __HCP_FUNC_ENTRY( "CPCHHelpSessionItem::State::Load" );
  123. HRESULT hr;
  124. CComPtr<IStream> stream;
  125. if(m_parent == NULL || m_parent->GetParent() == NULL) // Already passivated.
  126. {
  127. __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
  128. }
  129. if(m_fValid)
  130. {
  131. __MPC_EXIT_IF_METHOD_FAILS(hr, m_parent->GetParent()->ItemState_GetStream( m_parent->GetIndex(), stream ));
  132. {
  133. MPC::Serializer_IStream streamReal( stream );
  134. MPC::Serializer_Buffering streamBuf ( streamReal );
  135. DWORD dwVer;
  136. Erase( /*fUnvalidate*/true );
  137. __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf >> dwVer ); if(dwVer != l_dwVersion) __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
  138. __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf >> m_hgWebBrowser_CONTENTS);
  139. __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf >> m_hgWebBrowser_HHWINDOW);
  140. __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf >> m_mapProperties );
  141. m_fValid = true;
  142. }
  143. }
  144. hr = S_OK;
  145. __HCP_FUNC_CLEANUP;
  146. __HCP_FUNC_EXIT(hr);
  147. }
  148. HRESULT CPCHHelpSessionItem::State::Save()
  149. {
  150. __HCP_FUNC_ENTRY( "CPCHHelpSessionItem::State::Save" );
  151. HRESULT hr;
  152. if(m_fDirty)
  153. {
  154. CComPtr<IStream> stream;
  155. if(m_parent == NULL || m_parent->GetParent() == NULL) // Already passivated.
  156. {
  157. __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
  158. }
  159. __MPC_EXIT_IF_METHOD_FAILS(hr, m_parent->GetParent()->ItemState_CreateStream( m_parent->GetIndex(), stream ));
  160. {
  161. MPC::Serializer_IStream streamReal( stream );
  162. MPC::Serializer_Buffering streamBuf ( streamReal );
  163. DWORD dwVer = l_dwVersion;
  164. __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf << dwVer );
  165. __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf << m_hgWebBrowser_CONTENTS);
  166. __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf << m_hgWebBrowser_HHWINDOW);
  167. __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf << m_mapProperties );
  168. __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf.Flush());
  169. }
  170. m_fDirty = false;
  171. }
  172. hr = S_OK;
  173. __HCP_FUNC_CLEANUP;
  174. __HCP_FUNC_EXIT(hr);
  175. }
  176. ////////////////////////////////////////////////////////////////////////////////
  177. HRESULT CPCHHelpSessionItem::State::AcquireState()
  178. {
  179. __HCP_FUNC_ENTRY( "CPCHHelpSessionItem::State::AcquireState" );
  180. HRESULT hr;
  181. if(m_dwLoaded++ == 0)
  182. {
  183. __MPC_EXIT_IF_METHOD_FAILS(hr, Load());
  184. }
  185. hr = S_OK;
  186. __HCP_FUNC_CLEANUP;
  187. __HCP_FUNC_EXIT(hr);
  188. }
  189. HRESULT CPCHHelpSessionItem::State::ReleaseState( /*[in]*/ bool fForce )
  190. {
  191. __HCP_FUNC_ENTRY( "CPCHHelpSessionItem::State::ReleaseState" );
  192. HRESULT hr;
  193. if(m_dwLoaded)
  194. {
  195. if(fForce || --m_dwLoaded == 0)
  196. {
  197. __MPC_EXIT_IF_METHOD_FAILS(hr, Save());
  198. Erase( /*fUnvalidate*/false ); // Just unload.
  199. }
  200. }
  201. hr = S_OK;
  202. __HCP_FUNC_CLEANUP;
  203. __HCP_FUNC_EXIT(hr);
  204. }
  205. HRESULT CPCHHelpSessionItem::State::Populate( /*[in]*/ bool fUseHH )
  206. {
  207. __HCP_FUNC_ENTRY( "CPCHHelpSessionItem::State::Populate" );
  208. HRESULT hr;
  209. CComQIPtr<IPersistHistory> pPH;
  210. CPCHHelpSession* parent2;
  211. CPCHHelpCenterExternal* parent3;
  212. if(m_parent == NULL || (parent2 = m_parent->GetParent()) == NULL || (parent3 = parent2->GetParent()) == NULL) // Already passivated.
  213. {
  214. __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
  215. }
  216. ////////////////////
  217. __MPC_EXIT_IF_METHOD_FAILS(hr, parent3->Events().FireEvent_PersistSave());
  218. ////////////////////
  219. m_hgWebBrowser_CONTENTS.Release();
  220. m_hgWebBrowser_HHWINDOW.Release();
  221. if(fUseHH == false)
  222. {
  223. CComPtr<IWebBrowser2> wb2; wb2.Attach( parent3->Contents() );
  224. pPH = wb2;
  225. if(pPH)
  226. {
  227. CComPtr<IStream> stream;
  228. __MPC_EXIT_IF_METHOD_FAILS(hr, m_hgWebBrowser_CONTENTS.NewStream( &stream ));
  229. __MPC_EXIT_IF_METHOD_FAILS(hr, pPH->SaveHistory ( stream ));
  230. m_fValid = true;
  231. m_fDirty = true;
  232. }
  233. }
  234. else
  235. {
  236. CComPtr<IWebBrowser2> wb2; wb2.Attach( parent3->HHWindow() );
  237. pPH = wb2;
  238. if(pPH)
  239. {
  240. CComPtr<IStream> stream;
  241. __MPC_EXIT_IF_METHOD_FAILS(hr, m_hgWebBrowser_HHWINDOW.NewStream( &stream ));
  242. __MPC_EXIT_IF_METHOD_FAILS(hr, pPH->SaveHistory ( stream ));
  243. m_fValid = true;
  244. m_fDirty = true;
  245. }
  246. }
  247. hr = S_OK;
  248. __HCP_FUNC_CLEANUP;
  249. __HCP_FUNC_EXIT(hr);
  250. }
  251. HRESULT CPCHHelpSessionItem::State::Restore( /*[in]*/ bool fUseHH )
  252. {
  253. __HCP_FUNC_ENTRY( "CPCHHelpSessionItem::State::Restore" );
  254. HRESULT hr;
  255. CComQIPtr<IPersistHistory> pPH;
  256. CPCHHelpSession* parent2;
  257. CPCHHelpCenterExternal* parent3;
  258. bool fAcquired = false;
  259. if(m_parent == NULL || (parent2 = m_parent->GetParent()) == NULL || (parent3 = parent2->GetParent()) == NULL) // Already passivated.
  260. {
  261. __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
  262. }
  263. __MPC_EXIT_IF_METHOD_FAILS(hr, AcquireState()); fAcquired = true;
  264. if(fUseHH == false)
  265. {
  266. if(m_hgWebBrowser_CONTENTS.Size())
  267. {
  268. {
  269. CComPtr<IMarsPanel> panel;
  270. __MPC_EXIT_IF_METHOD_FAILS(hr, parent3->GetPanel( HSCPANEL_CONTENTS, &panel, /*fEnsurePresence*/true ));
  271. }
  272. {
  273. CComPtr<IWebBrowser2> wb2; wb2.Attach( parent3->Contents() );
  274. pPH = wb2;
  275. if(pPH)
  276. {
  277. CComPtr<IStream> stream;
  278. __MPC_EXIT_IF_METHOD_FAILS(hr, m_hgWebBrowser_CONTENTS.GetAsStream( &stream, /*fClone*/true ));
  279. __MPC_EXIT_IF_METHOD_FAILS(hr, pPH->LoadHistory ( stream, NULL ));
  280. }
  281. }
  282. __MPC_EXIT_IF_METHOD_FAILS(hr, parent3->SetCorrectContentPanel( /*fShowNormal*/true, /*fShowHTMLHELP*/false, /*fNow*/false ));
  283. }
  284. }
  285. else
  286. {
  287. if(m_hgWebBrowser_HHWINDOW.Size())
  288. {
  289. {
  290. CComPtr<IMarsPanel> panel;
  291. __MPC_EXIT_IF_METHOD_FAILS(hr, parent3->GetPanel( HSCPANEL_HHWINDOW, &panel, /*fEnsurePresence*/true ));
  292. }
  293. {
  294. CComPtr<IWebBrowser2> wb2; wb2.Attach( parent3->HHWindow() );
  295. pPH = wb2;
  296. if(pPH)
  297. {
  298. CComPtr<IStream> stream;
  299. __MPC_EXIT_IF_METHOD_FAILS(hr, m_hgWebBrowser_HHWINDOW.GetAsStream( &stream, /*fClone*/true ));
  300. __MPC_EXIT_IF_METHOD_FAILS(hr, pPH->LoadHistory ( stream, NULL ));
  301. }
  302. }
  303. __MPC_EXIT_IF_METHOD_FAILS(hr, parent3->SetCorrectContentPanel( /*fShowNormal*/false, /*fShowHTMLHELP*/true, /*fNow*/false ));
  304. }
  305. }
  306. hr = S_OK;
  307. __HCP_FUNC_CLEANUP;
  308. if(fAcquired) (void)ReleaseState( /*fForce*/false );
  309. __HCP_FUNC_EXIT(hr);
  310. }
  311. HRESULT CPCHHelpSessionItem::State::Delete()
  312. {
  313. __HCP_FUNC_ENTRY( "CPCHHelpSessionItem::State::Delete" );
  314. HRESULT hr;
  315. CPCHHelpSession* parent2;
  316. if(m_parent == NULL || (parent2 = m_parent->GetParent()) == NULL) // Already passivated.
  317. {
  318. __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
  319. }
  320. Erase( /*fUnvalidate*/true );
  321. m_dwLoaded = 0;
  322. __MPC_EXIT_IF_METHOD_FAILS(hr, m_parent->GetParent()->ItemState_DeleteStream( m_parent->GetIndex() ));
  323. hr = S_OK;
  324. __HCP_FUNC_CLEANUP;
  325. __HCP_FUNC_EXIT(hr);
  326. }
  327. HRESULT CPCHHelpSessionItem::State::Clone( /*[out]*/ State& state )
  328. {
  329. __HCP_FUNC_ENTRY( "CPCHHelpSessionItem::State::Clone" );
  330. HRESULT hr;
  331. bool fAcquired = false;
  332. __MPC_EXIT_IF_METHOD_FAILS(hr, state.AcquireState()); fAcquired = true;
  333. // CPCHHelpSessionItem* m_parent;
  334. m_fValid = state.m_fValid; // bool m_fValid;
  335. m_fDirty = true; // bool m_fDirty;
  336. m_dwLoaded++; // DWORD m_dwLoaded;
  337. //
  338. m_hgWebBrowser_CONTENTS = state.m_hgWebBrowser_CONTENTS; // MPC::CComHGLOBAL m_hgWebBrowser_CONTENTS;
  339. m_hgWebBrowser_HHWINDOW = state.m_hgWebBrowser_HHWINDOW; // MPC::CComHGLOBAL m_hgWebBrowser_HHWINDOW;
  340. m_mapProperties = state.m_mapProperties; // PropertyMap m_mapProperties;
  341. hr = S_OK;
  342. __HCP_FUNC_CLEANUP;
  343. if(fAcquired) (void)state.ReleaseState( /*fForce*/false );
  344. __HCP_FUNC_EXIT(hr);
  345. }
  346. ////////////////////////////////////////////////////////////////////////////////
  347. HscContext CPCHHelpSessionItem::LookupContext( /*[in]*/ LPCWSTR szName )
  348. {
  349. const ContextLookup* ctx = s_rgContext;
  350. if(!STRINGISPRESENT(szName)) return HSCCONTEXT_HOMEPAGE;
  351. for(int i=0; i<ARRAYSIZE(s_rgContext); i++, ctx++)
  352. {
  353. if(!_wcsicmp( szName, ctx->szName ))
  354. {
  355. return ctx->fInternal ? HSCCONTEXT_INVALID : ctx->iValue;
  356. }
  357. }
  358. return HSCCONTEXT_INVALID;
  359. }
  360. LPCWSTR CPCHHelpSessionItem::LookupContext( /*[in]*/ HscContext iVal )
  361. {
  362. const ContextLookup* ctx = s_rgContext;
  363. for(int i=0; i<ARRAYSIZE(s_rgContext); i++, ctx++)
  364. {
  365. if(ctx->iValue == iVal) return ctx->szName;
  366. }
  367. return NULL;
  368. }
  369. ////////////////////////////////////////
  370. CPCHHelpSessionItem::CPCHHelpSessionItem() : m_state( this )
  371. {
  372. m_parent = NULL; // CPCHHelpSession* m_parent;
  373. // State m_state;
  374. m_fSaved = false; // bool m_fSaved;
  375. m_fInitialized = false; // bool m_fInitialized;
  376. //
  377. //////////////////////////////////////////////////////////////////////////////////
  378. //
  379. // Taxonomy::HelpSet m_ths;
  380. //
  381. // CComBSTR m_bstrURL;
  382. // CComBSTR m_bstrTitle;
  383. m_dLastVisited = 0; // DATE m_dLastVisited;
  384. m_dDuration = 0; // DATE m_dDuration;
  385. m_lNumOfHits = 0; // DWORD m_lNumOfHits;
  386. //
  387. m_iIndexPrev = NO_LINK; // int m_iIndexPrev;
  388. m_iIndex = NO_LINK; // int m_iIndex;
  389. m_iIndexNext = NO_LINK; // int m_iIndexNext;
  390. //
  391. m_lContextID = HSCCONTEXT_INVALID; // long m_lContextID; // HscContext
  392. // CComBSTR m_bstrContextInfo;
  393. // CComBSTR m_bstrContextURL;
  394. //
  395. m_fUseHH = false; // bool m_fUseHH;
  396. }
  397. void CPCHHelpSessionItem::Initialize( /*[in]*/ CPCHHelpSession* parent, /*[in]*/ bool fNew )
  398. {
  399. m_parent = parent;
  400. if(fNew)
  401. {
  402. CPCHProxy_IPCHUserSettings2* us = parent->m_parent->UserSettings();
  403. m_lContextID = parent->m_lContextID ;
  404. m_bstrContextInfo = parent->m_bstrContextInfo;
  405. m_bstrContextURL = parent->m_bstrContextURL ;
  406. if(us)
  407. {
  408. m_ths = us->THS();
  409. }
  410. }
  411. }
  412. void CPCHHelpSessionItem::Passivate()
  413. {
  414. m_state.ReleaseState( /*fForce*/true );
  415. m_parent = NULL;
  416. }
  417. ////////////////////
  418. HRESULT CPCHHelpSessionItem::Load( /*[in]*/ MPC::Serializer& streamIn )
  419. {
  420. __HCP_FUNC_ENTRY( "CPCHHelpSessionItem::Load" );
  421. HRESULT hr;
  422. //
  423. // Read its properties.
  424. //
  425. __MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_ths );
  426. __MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_bstrURL );
  427. __MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_bstrTitle );
  428. __MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_dLastVisited );
  429. __MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_dDuration );
  430. __MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_lNumOfHits );
  431. __MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_iIndexPrev );
  432. __MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_iIndex );
  433. __MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_iIndexNext );
  434. __MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_lContextID );
  435. __MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_bstrContextInfo);
  436. __MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_bstrContextURL );
  437. __MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_fUseHH );
  438. //
  439. // All the item saved to disk have a valid state.
  440. //
  441. m_state.m_fValid = true;
  442. hr = S_OK;
  443. __HCP_FUNC_CLEANUP;
  444. __HCP_FUNC_EXIT(hr);
  445. }
  446. HRESULT CPCHHelpSessionItem::Save( /*[in]*/ MPC::Serializer& streamOut ,
  447. /*[in]*/ bool fForce )
  448. {
  449. __HCP_FUNC_ENTRY( "CPCHHelpSessionItem::Save" );
  450. HRESULT hr;
  451. //
  452. // Don't save an entry if there's no IE history stream, it would be useless to reload it!
  453. //
  454. if(fForce == false && m_state.m_fValid == false)
  455. {
  456. __MPC_SET_ERROR_AND_EXIT(hr, S_OK);
  457. }
  458. //
  459. // Write its properties.
  460. //
  461. __MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_ths );
  462. __MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_bstrURL );
  463. __MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_bstrTitle );
  464. __MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_dLastVisited );
  465. __MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_dDuration );
  466. __MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_lNumOfHits );
  467. __MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_iIndexPrev );
  468. __MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_iIndex );
  469. __MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_iIndexNext );
  470. __MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_lContextID );
  471. __MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_bstrContextInfo);
  472. __MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_bstrContextURL );
  473. __MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_fUseHH );
  474. m_fSaved = true;
  475. hr = S_OK;
  476. __HCP_FUNC_CLEANUP;
  477. __HCP_FUNC_EXIT(hr);
  478. }
  479. void CPCHHelpSessionItem::HistorySelect()
  480. {
  481. if(!m_fInitialized && m_parent && m_parent->m_parent)
  482. {
  483. m_fInitialized = true;
  484. m_fUseHH = m_parent->m_parent->IsHHWindowVisible();
  485. }
  486. }
  487. HRESULT CPCHHelpSessionItem::HistoryPopulate()
  488. {
  489. HistorySelect();
  490. return m_state.Populate( m_fUseHH );
  491. }
  492. HRESULT CPCHHelpSessionItem::HistoryRestore()
  493. {
  494. return m_state.Restore( m_fUseHH );
  495. }
  496. HRESULT CPCHHelpSessionItem::HistoryDelete()
  497. {
  498. return m_state.Delete();
  499. }
  500. HRESULT CPCHHelpSessionItem::HistoryClone( /*[in]*/ bool fContext, /*[in]*/ CPCHHelpSessionItem* hsi )
  501. {
  502. __HCP_FUNC_ENTRY( "CPCHHelpSessionItem::HistoryClone" );
  503. HRESULT hr;
  504. bool fAcquired = false;
  505. if(this == hsi || !hsi) __MPC_SET_ERROR_AND_EXIT(hr, S_FALSE);
  506. __MPC_EXIT_IF_METHOD_FAILS(hr, hsi->m_state.AcquireState()); fAcquired = true;
  507. // CPCHHelpSession* m_parent;
  508. // State m_state;
  509. m_fSaved = false; // bool m_fSaved;
  510. m_fInitialized = true; // bool m_fInitialized;
  511. //
  512. ////////////////////////////////////////////////////////////////////////////////
  513. //
  514. m_ths = hsi->m_ths; // Taxonomy::HelpSet m_ths;
  515. //
  516. m_bstrURL = hsi->m_bstrURL; // CComBSTR m_bstrURL;
  517. m_bstrTitle = hsi->m_bstrTitle; // CComBSTR m_bstrTitle;
  518. // DATE m_dLastVisited;
  519. // DATE m_dDuration;
  520. m_lNumOfHits = hsi->m_lNumOfHits; // long m_lNumOfHits;
  521. //
  522. // int m_iIndexPrev;
  523. // int m_iIndex;
  524. // int m_iIndexNext;
  525. //
  526. // long m_lContextID;
  527. // CComBSTR m_bstrContextInfo;
  528. // CComBSTR m_bstrContextURL;
  529. //
  530. m_fUseHH = hsi->m_fUseHH; // bool m_fUseHH;
  531. if(fContext)
  532. {
  533. m_lContextID = hsi->m_lContextID;
  534. m_bstrContextInfo = hsi->m_bstrContextInfo;
  535. m_bstrContextURL = hsi->m_bstrContextURL;
  536. }
  537. __MPC_EXIT_IF_METHOD_FAILS(hr, m_state.Clone( hsi->m_state ));
  538. hr = S_OK;
  539. __HCP_FUNC_CLEANUP;
  540. if(fAcquired) (void)hsi->m_state.ReleaseState( /*fForce*/false );
  541. __HCP_FUNC_EXIT(hr);
  542. }
  543. /////////////////////////////////////////////////////////////////////////////
  544. HRESULT CPCHHelpSessionItem::Enter()
  545. {
  546. m_dLastVisited = MPC::GetLocalTimeEx( /*fHighPrecision*/false );
  547. return m_state.AcquireState();
  548. }
  549. HRESULT CPCHHelpSessionItem::Leave()
  550. {
  551. m_dDuration = MPC::GetLocalTimeEx( /*fHighPrecision*/false );
  552. return m_state.ReleaseState( /*fForce*/false );
  553. }
  554. bool CPCHHelpSessionItem::SeenLongEnough( DWORD dwSeconds ) const
  555. {
  556. return (m_dDuration - m_dLastVisited) * 86400 > dwSeconds;
  557. }
  558. bool CPCHHelpSessionItem::SameURL( CPCHHelpSessionItem* right ) const
  559. {
  560. return SameURL( right->m_bstrURL );
  561. }
  562. bool CPCHHelpSessionItem::SameURL( LPCWSTR right ) const
  563. {
  564. return MPC::StrICmp( m_bstrURL, right ) == 0;
  565. }
  566. bool CPCHHelpSessionItem::SameSKU( /*[in]*/ const Taxonomy::HelpSet& ths ) const
  567. {
  568. return m_ths == ths;
  569. }
  570. ////////////////////////////////////////
  571. void CPCHHelpSessionItem::put_THS( /*[in]*/ const Taxonomy::HelpSet& ths ) // Internal Method.
  572. {
  573. m_ths = ths;
  574. }
  575. STDMETHODIMP CPCHHelpSessionItem::get_SKU( /*[out, retval]*/ BSTR *pVal )
  576. {
  577. return MPC::GetBSTR( m_ths.GetSKU(), pVal );
  578. }
  579. STDMETHODIMP CPCHHelpSessionItem::get_Language( /*[out, retval]*/ long *pVal )
  580. {
  581. if(!pVal) return E_POINTER;
  582. *pVal = m_ths.GetLanguage();
  583. return S_OK;
  584. }
  585. STDMETHODIMP CPCHHelpSessionItem::get_URL( /*[out, retval]*/ BSTR *pVal )
  586. {
  587. return MPC::GetBSTR( m_bstrURL, pVal );
  588. }
  589. HRESULT CPCHHelpSessionItem::put_URL( /*[in]*/ BSTR newVal ) // Internal Method.
  590. {
  591. return MPC::PutBSTR( m_bstrURL, newVal );
  592. }
  593. STDMETHODIMP CPCHHelpSessionItem::get_Title( /*[out, retval]*/ BSTR *pVal )
  594. {
  595. return MPC::GetBSTR( m_bstrTitle, pVal );
  596. }
  597. HRESULT CPCHHelpSessionItem::put_Title( /*[in]*/ BSTR newVal ) // Internal Method.
  598. {
  599. return MPC::PutBSTR( m_bstrTitle, newVal );
  600. }
  601. STDMETHODIMP CPCHHelpSessionItem::get_LastVisited( /*[out, retval]*/ DATE *pVal )
  602. {
  603. if(pVal == NULL) return E_POINTER;
  604. *pVal = m_dLastVisited;
  605. return S_OK;
  606. }
  607. STDMETHODIMP CPCHHelpSessionItem::get_Duration( /*[out, retval]*/ DATE *pVal )
  608. {
  609. if(pVal == NULL) return E_POINTER;
  610. *pVal = m_dDuration;
  611. return S_OK;
  612. }
  613. STDMETHODIMP CPCHHelpSessionItem::get_NumOfHits( /*[out, retval]*/ long *pVal )
  614. {
  615. if(pVal == NULL) return E_POINTER;
  616. *pVal = m_lNumOfHits;
  617. return S_OK;
  618. }
  619. STDMETHODIMP CPCHHelpSessionItem::get_Property( /*[in]*/ BSTR bstrName, /*[out, retval]*/ VARIANT *pVal )
  620. {
  621. __HCP_FUNC_ENTRY( "CPCHHelpSessionItem::get_Property" );
  622. HRESULT hr;
  623. State::PropertyIter it;
  624. bool fAcquired = false;
  625. __MPC_PARAMCHECK_BEGIN(hr)
  626. __MPC_PARAMCHECK_STRING_NOT_EMPTY(bstrName);
  627. __MPC_PARAMCHECK_NOTNULL(pVal);
  628. __MPC_PARAMCHECK_END();
  629. __MPC_EXIT_IF_METHOD_FAILS(hr, m_state.AcquireState()); fAcquired = true;
  630. ::VariantClear( pVal );
  631. it = m_state.m_mapProperties.find( bstrName );
  632. if(it != m_state.m_mapProperties.end())
  633. {
  634. pVal->vt = VT_BSTR;
  635. pVal->bstrVal = ::SysAllocString( it->second.c_str() );
  636. }
  637. hr = S_OK;
  638. __HCP_FUNC_CLEANUP;
  639. if(fAcquired) (void)m_state.ReleaseState( /*fForce*/false );
  640. __HCP_FUNC_EXIT(hr);
  641. }
  642. STDMETHODIMP CPCHHelpSessionItem::put_Property( /*[in]*/ BSTR bstrName, /*[in]*/ VARIANT pVal )
  643. {
  644. __HCP_FUNC_ENTRY( "CPCHHelpSessionItem::put_Property" );
  645. HRESULT hr;
  646. MPC::wstring strName;
  647. CComVariant v;
  648. bool fAcquired = false;
  649. __MPC_PARAMCHECK_BEGIN(hr)
  650. __MPC_PARAMCHECK_STRING_NOT_EMPTY(bstrName);
  651. __MPC_PARAMCHECK_END();
  652. __MPC_EXIT_IF_METHOD_FAILS(hr, m_state.AcquireState()); fAcquired = true;
  653. strName = bstrName;
  654. (void)::VariantChangeType( &v, &pVal, 0, VT_BSTR );
  655. if(v.vt == VT_BSTR && v.bstrVal && v.bstrVal[0])
  656. {
  657. m_state.m_mapProperties[ strName ] = v.bstrVal;
  658. }
  659. else
  660. {
  661. m_state.m_mapProperties.erase( strName );
  662. }
  663. m_state.m_fDirty = true;
  664. hr = S_OK;
  665. __HCP_FUNC_CLEANUP;
  666. if(fAcquired) (void)m_state.ReleaseState( /*fForce*/false );
  667. __HCP_FUNC_EXIT(hr);
  668. }
  669. STDMETHODIMP CPCHHelpSessionItem::get_ContextName( /*[out, retval]*/ BSTR *pVal )
  670. {
  671. return MPC::GetBSTR( LookupContext( GetContextID() ), pVal );
  672. }
  673. STDMETHODIMP CPCHHelpSessionItem::get_ContextInfo( /*[out, retval]*/ BSTR *pVal )
  674. {
  675. return MPC::GetBSTR( GetContextInfo(), pVal );
  676. }
  677. STDMETHODIMP CPCHHelpSessionItem::get_ContextURL( /*[out, retval]*/ BSTR *pVal )
  678. {
  679. return MPC::GetBSTR( GetContextURL(), pVal );
  680. }
  681. ////////////////////////////////////////
  682. STDMETHODIMP CPCHHelpSessionItem::CheckProperty( /*[in]*/ BSTR bstrName, /*[out, retval]*/ VARIANT_BOOL *pVal )
  683. {
  684. __HCP_FUNC_ENTRY( "CPCHHelpSessionItem::CheckProperty" );
  685. HRESULT hr;
  686. State::PropertyIter it;
  687. bool fAcquired = false;
  688. __MPC_PARAMCHECK_BEGIN(hr)
  689. __MPC_PARAMCHECK_STRING_NOT_EMPTY(bstrName);
  690. __MPC_PARAMCHECK_POINTER_AND_SET(pVal,VARIANT_FALSE);
  691. __MPC_PARAMCHECK_END();
  692. __MPC_EXIT_IF_METHOD_FAILS(hr, m_state.AcquireState()); fAcquired = true;
  693. it = m_state.m_mapProperties.find( bstrName );
  694. if(it != m_state.m_mapProperties.end())
  695. {
  696. *pVal = VARIANT_TRUE;
  697. }
  698. hr = S_OK;
  699. __HCP_FUNC_CLEANUP;
  700. if(fAcquired) (void)m_state.ReleaseState( /*fForce*/false );
  701. __HCP_FUNC_EXIT(hr);
  702. }
  703. ////////////////////////////////////////
  704. CPCHHelpSessionItem* CPCHHelpSessionItem::Previous() { return (m_parent && m_iIndexPrev != NO_LINK) ? m_parent->FindPage( m_iIndexPrev ) : NULL; }
  705. CPCHHelpSessionItem* CPCHHelpSessionItem::Next () { return (m_parent && m_iIndexNext != NO_LINK) ? m_parent->FindPage( m_iIndexNext ) : NULL; }
  706. ////////////////////////////////////////
  707. HRESULT CPCHHelpSessionItem::ExtractTitle()
  708. {
  709. __HCP_FUNC_ENTRY( "CPCHHelpSessionItem::ExtractTitle" );
  710. HRESULT hr;
  711. if(m_parent)
  712. {
  713. CPCHHelpCenterExternal* ext = m_parent->GetParent();
  714. HistorySelect();
  715. if(!STRINGISPRESENT(m_bstrTitle))
  716. {
  717. __MPC_EXIT_IF_METHOD_FAILS(hr, m_parent->LookupTitle( m_bstrURL, m_bstrTitle, /*fUseIECache*/false ));
  718. }
  719. if(!STRINGISPRESENT(m_bstrTitle) && ext)
  720. {
  721. CComPtr<IWebBrowser2> wb2; wb2.Attach( m_fUseHH ? ext->HHWindow() : ext->Contents() );
  722. CComPtr<IHTMLDocument2> doc;
  723. if(SUCCEEDED(MPC::HTML::IDispatch_To_IHTMLDocument2( doc, wb2 )))
  724. {
  725. (void)doc->get_title( &m_bstrTitle );
  726. }
  727. }
  728. if(!STRINGISPRESENT(m_bstrTitle))
  729. {
  730. __MPC_EXIT_IF_METHOD_FAILS(hr, m_parent->LookupTitle( m_bstrURL, m_bstrTitle, /*fUseIECache*/true ));
  731. }
  732. if(STRINGISPRESENT(m_bstrTitle))
  733. {
  734. for(int i=0; i<ARRAYSIZE(c_rgBadTitles); i++)
  735. {
  736. LPCWSTR szPtr = c_rgBadTitles[i];
  737. if(!_wcsnicmp( m_bstrTitle, szPtr, wcslen( szPtr ) ))
  738. {
  739. m_bstrTitle.Empty();
  740. break;
  741. }
  742. }
  743. }
  744. if(STRINGISPRESENT(m_bstrTitle))
  745. {
  746. DebugLog( L"%%%%%%%%%%%%%%%%%%%% TITLE %s - %s\n", m_bstrURL, m_bstrTitle );
  747. }
  748. }
  749. hr = S_OK;
  750. __HCP_FUNC_CLEANUP;
  751. __HCP_FUNC_EXIT(hr);
  752. }
  753. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  754. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  755. //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  756. #ifdef DEBUG
  757. static const WCHAR c_rgHelpSessionLog[] = L"%TEMP%\\helpsession_debug.txt";
  758. void CPCHHelpSession::DEBUG_DumpState_HG( /*[in]*/ MPC::FileLog& log ,
  759. /*[in]*/ MPC::CComHGLOBAL& hg )
  760. {
  761. CComPtr<IStream> stream;
  762. if(SUCCEEDED(hg.GetAsStream( &stream, /*fClone*/false )))
  763. {
  764. BYTE rgBuf[32];
  765. ULONG lRead;
  766. while(SUCCEEDED(stream->Read( rgBuf, sizeof(rgBuf), &lRead )) && lRead)
  767. {
  768. WCHAR rgHex[2*sizeof(rgBuf)+1];
  769. WCHAR rgTxt[ sizeof(rgBuf)+1];
  770. BYTE* pIn = rgBuf;
  771. WCHAR* szOutHex = rgHex;
  772. WCHAR* szOutTxt = rgTxt;
  773. while(lRead-- > 0)
  774. {
  775. BYTE c = *pIn++;
  776. *szOutHex++ = MPC::NumToHex( c >> 4 );
  777. *szOutHex++ = MPC::NumToHex( c );
  778. *szOutTxt++ = isprint( c ) ? c : '.';
  779. }
  780. szOutHex[0] = 0;
  781. szOutTxt[0] = 0;
  782. log.LogRecord( L" %-64s %s\n", rgHex, rgTxt );
  783. }
  784. log.LogRecord( L"\n" );
  785. }
  786. }
  787. void CPCHHelpSession::DEBUG_DumpState_BLOB( /*[in]*/ MPC::FileLog& log ,
  788. /*[in]*/ CPCHHelpSessionItem* hsi )
  789. {
  790. if(SUCCEEDED(hsi->m_state.AcquireState()))
  791. {
  792. if(hsi->m_state.m_hgWebBrowser_CONTENTS.Size())
  793. {
  794. log.LogRecord( L" m_hgWebBrowser_CONTENTS:\n" );
  795. DEBUG_DumpState_HG( log, hsi->m_state.m_hgWebBrowser_CONTENTS );
  796. }
  797. if(hsi->m_state.m_hgWebBrowser_HHWINDOW.Size())
  798. {
  799. log.LogRecord( L" m_hgWebBrowser_HHWINDOW:\n" );
  800. DEBUG_DumpState_HG( log, hsi->m_state.m_hgWebBrowser_HHWINDOW );
  801. }
  802. hsi->m_state.ReleaseState( /*fForce*/false );
  803. }
  804. }
  805. void CPCHHelpSession::DEBUG_DumpState( /*[in]*/ LPCWSTR szText, /*[in]*/ bool fHeader, /*[in]*/ bool fCurrent, /*[in]*/ bool fAll, /*[in]*/ bool fState )
  806. {
  807. static int iCount = 0;
  808. IterConst it;
  809. MPC::FileLog log;
  810. {
  811. MPC::wstring strLog( c_rgHelpSessionLog ); MPC::SubstituteEnvVariables( strLog );
  812. log.SetLocation( strLog.c_str() );
  813. }
  814. log.LogRecord( L"################################################################################ %d %s\n\n", ++iCount, SAFEWSTR( szText ) );
  815. if(fHeader)
  816. {
  817. log.LogRecord( L" m_dwTravelling : %d\n" , m_dwTravelling );
  818. log.LogRecord( L" m_fAlreadySaved : %s\n" , m_fAlreadySaved ? L"true" : L"false" );
  819. log.LogRecord( L" m_fAlreadyCreated : %s\n" , m_fAlreadyCreated ? L"true" : L"false" );
  820. log.LogRecord( L" m_fOverwrite : %s\n" , m_fOverwrite ? L"true" : L"false" );
  821. log.LogRecord( L" m_dwIgnore : %d\n" , m_dwIgnore );
  822. log.LogRecord( L" m_dwNoEvents : %d\n" , m_dwNoEvents );
  823. log.LogRecord( L" m_iLastIndex : %d\n\n", m_iLastIndex );
  824. log.LogRecord( L" ########################################\n\n" );
  825. }
  826. if(fCurrent)
  827. {
  828. if(m_hsiCurrentPage)
  829. {
  830. log.LogRecord( L" Current URL : %s\n" , SAFEBSTR( m_hsiCurrentPage->m_bstrURL ) );
  831. log.LogRecord( L" Current iIndexPrev: %d\n" , m_hsiCurrentPage->m_iIndexPrev );
  832. log.LogRecord( L" Current iIndex : %d\n" , m_hsiCurrentPage->m_iIndex );
  833. log.LogRecord( L" Current iIndexNext: %d\n\n", m_hsiCurrentPage->m_iIndexNext );
  834. log.LogRecord( L" Current m_lContextID : %s\n" , CPCHHelpSessionItem::LookupContext( (HscContext)m_hsiCurrentPage->m_lContextID ) );
  835. log.LogRecord( L" Current m_bstrContextInfo: %s\n" , SAFEBSTR ( m_hsiCurrentPage->m_bstrContextInfo ) );
  836. log.LogRecord( L" Current m_bstrContextURL : %s\n\n", SAFEBSTR ( m_hsiCurrentPage->m_bstrContextURL ) );
  837. if(fState)
  838. {
  839. DEBUG_DumpState_BLOB( log, m_hsiCurrentPage );
  840. }
  841. log.LogRecord( L" ########################################\n\n" );
  842. }
  843. }
  844. if(fAll)
  845. {
  846. for(it = m_lstVisitedPages.begin(); it != m_lstVisitedPages.end(); it++)
  847. {
  848. CPCHHelpSessionItem* hsi = *it;
  849. log.LogRecord( L" URL : %s\n" , SAFEBSTR( hsi->m_bstrURL ) );
  850. log.LogRecord( L" iIndexPrev: %d\n" , hsi->m_iIndexPrev );
  851. log.LogRecord( L" iIndex : %d\n" , hsi->m_iIndex );
  852. log.LogRecord( L" iIndexNext: %d\n" , hsi->m_iIndexNext );
  853. log.LogRecord( L" bstrTitle : %s\n\n", SAFEBSTR( hsi->m_bstrTitle ) );
  854. log.LogRecord( L" lContextID : %s\n" , CPCHHelpSessionItem::LookupContext( (HscContext)hsi->m_lContextID ) );
  855. log.LogRecord( L" bstrContextInfo: %s\n" , SAFEBSTR ( hsi->m_bstrContextInfo ) );
  856. log.LogRecord( L" bstrContextURL : %s\n\n", SAFEBSTR ( hsi->m_bstrContextURL ) );
  857. if(fState)
  858. {
  859. DEBUG_DumpState_BLOB( log, hsi );
  860. }
  861. }
  862. }
  863. log.LogRecord( L"\n\n" );
  864. }
  865. void CPCHHelpSession::DEBUG_DumpSavedPages()
  866. {
  867. IterConst it;
  868. MPC::FileLog log;
  869. {
  870. MPC::wstring strLog( c_rgHelpSessionLog ); MPC::SubstituteEnvVariables( strLog );
  871. log.SetLocation( strLog.c_str() );
  872. }
  873. for(int pass=0; pass<2; pass++)
  874. {
  875. log.LogRecord( L"################################################################################ %sSAVED PAGES\n\n", pass == 0 ? L"" : L"NON-" );
  876. for(it = m_lstVisitedPages.begin(); it != m_lstVisitedPages.end(); it++)
  877. {
  878. CPCHHelpSessionItem* hsi = *it;
  879. if(hsi->m_fSaved == (pass == 0))
  880. {
  881. long lDuration = 86400.0 * ( hsi->m_dDuration - hsi->m_dLastVisited ); // Number of milliseconds for the page.
  882. log.LogRecord( L" lDuration : %ld\n" , lDuration );
  883. log.LogRecord( L" URL : %s\n" , SAFEBSTR ( hsi->m_bstrURL ) );
  884. log.LogRecord( L" bstrTitle : %s\n" , SAFEBSTR ( hsi->m_bstrTitle ) );
  885. log.LogRecord( L" lContextID : %s\n" , CPCHHelpSessionItem::LookupContext( (HscContext)hsi->m_lContextID ) );
  886. log.LogRecord( L" bstrContextInfo: %s\n" , SAFEBSTR ( hsi->m_bstrContextInfo ) );
  887. log.LogRecord( L" bstrContextURL : %s\n\n", SAFEBSTR ( hsi->m_bstrContextURL ) );
  888. }
  889. }
  890. log.LogRecord( L"\n\n" );
  891. }
  892. }
  893. #endif
  894. ////////////////////////////////////////////////////////////////////////////////
  895. //
  896. // ITSS.DLL is broken under IA64....
  897. //
  898. #ifdef _IA64_
  899. #define HELPSESSION_STORAGETOUSE false
  900. #else
  901. #define HELPSESSION_STORAGETOUSE true
  902. #endif
  903. CPCHHelpSession::CPCHHelpSession() : m_disk( STGM_READWRITE, /*fITSS*/HELPSESSION_STORAGETOUSE )
  904. {
  905. __HCP_FUNC_ENTRY( "CPCHHelpSession::CPCHHelpSession" );
  906. m_parent = NULL; // CPCHHelpCenterExternal* m_parent;
  907. //
  908. // MPC::wstring m_szBackupFile;
  909. // MPC::StorageObject m_disk;
  910. m_dStartOfSession = MPC::GetLocalTime(); // DATE m_dStartOfSession;
  911. //
  912. // CComPtr<IUrlHistoryStg> m_pIHistory;
  913. //
  914. // MPC::WStringUCList m_lstIgnore;
  915. // TitleMap m_mapTitles;
  916. // List m_lstVisitedPages;
  917. // List m_lstCachedVisitedPages;
  918. // CComPtr<CPCHHelpSessionItem> m_hsiCurrentPage;
  919. m_dwTravelling = 0; // DWORD m_dwTravelling;
  920. m_fAlreadySaved = false; // bool m_fAlreadySaved;
  921. m_fAlreadyCreated = false; // bool m_fAlreadyCreated;
  922. m_fOverwrite = false; // bool m_fOverwrite;
  923. m_dwIgnore = 0; // DWORD m_dwIgnore;
  924. m_dwNoEvents = 0; // DWORD m_dwNoEvents;
  925. m_dLastNavigation = 0.0; // DATE m_dLastNavigation;
  926. m_iLastIndex = 0; // int m_iLastIndex;
  927. //
  928. m_lContextID = HSCCONTEXT_INVALID; // long m_lContextID;
  929. // CComBSTR m_bstrContextInfo;
  930. // CComBSTR m_bstrContextURL;
  931. //
  932. m_fPossibleBack = false; // bool m_fPossibleBack;
  933. m_dwPossibleBack = 0; // DWORD m_dwPossibleBack;
  934. }
  935. CPCHHelpSession::~CPCHHelpSession()
  936. {
  937. Passivate();
  938. }
  939. HRESULT CPCHHelpSession::Initialize( /*[in]*/ CPCHHelpCenterExternal* parent )
  940. {
  941. __HCP_FUNC_ENTRY( "CPCHHelpSession::Initialize" );
  942. HRESULT hr;
  943. MPC::wstring szFile;
  944. HANDLE hFile = INVALID_HANDLE_VALUE;
  945. m_parent = parent;
  946. //
  947. // Copy live file onto temporary one or create a new archive.
  948. //
  949. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::GetUserWritablePath( szFile, c_szPersistFile ));
  950. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::MakeDir ( szFile ));
  951. if(parent == NULL) // No parent, point to the user file and recreate it.
  952. {
  953. m_disk = szFile.c_str();
  954. __MPC_EXIT_IF_METHOD_FAILS(hr, m_disk.Create());
  955. }
  956. else
  957. {
  958. #ifdef DEBUG
  959. {
  960. MPC::wstring strLog( c_rgHelpSessionLog ); MPC::SubstituteEnvVariables( strLog );
  961. MPC::DeleteFile( strLog );
  962. }
  963. #endif
  964. try
  965. {
  966. //
  967. // Prepare temporary file.
  968. //
  969. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::GetTemporaryFileName( m_szBackupFile )); m_disk = m_szBackupFile.c_str();
  970. if(MPC::FileSystemObject::IsFile( szFile.c_str() ))
  971. {
  972. if(SUCCEEDED(hr = MPC::CopyFile( szFile, m_szBackupFile )))
  973. {
  974. hr = m_disk.Exists();
  975. }
  976. }
  977. else
  978. {
  979. hr = E_FAIL;
  980. }
  981. if(FAILED(hr))
  982. {
  983. __MPC_EXIT_IF_METHOD_FAILS(hr, m_disk.Create());
  984. }
  985. if(FAILED(Load()))
  986. {
  987. (void)Erase();
  988. }
  989. }
  990. catch(...)
  991. {
  992. //
  993. // If the file is corrupted, ITSS will crash. Delete the file and exit.
  994. //
  995. MPC::DeleteFile( szFile, /*fForce*/true, /*fDelayed*/true );
  996. ::ExitProcess(0);
  997. }
  998. }
  999. hr = S_OK;
  1000. __HCP_FUNC_CLEANUP;
  1001. __HCP_FUNC_EXIT(hr);
  1002. }
  1003. void CPCHHelpSession::Passivate()
  1004. {
  1005. (void)Erase();
  1006. m_parent = NULL;
  1007. m_disk.Release();
  1008. (void)MPC::RemoveTemporaryFile( m_szBackupFile );
  1009. }
  1010. ////////////////////
  1011. HRESULT CPCHHelpSession::Persist()
  1012. {
  1013. __HCP_FUNC_ENTRY( "CPCHHelpSession::Persist" );
  1014. HRESULT hr;
  1015. //
  1016. // Before shutdown, update the time information for the current entry.
  1017. //
  1018. __MPC_EXIT_IF_METHOD_FAILS(hr, LeaveCurrentPage());
  1019. (void)Save();
  1020. hr = S_OK;
  1021. __HCP_FUNC_CLEANUP;
  1022. __HCP_FUNC_EXIT(hr);
  1023. }
  1024. ////////////////////
  1025. HRESULT CPCHHelpSession::Load()
  1026. {
  1027. __HCP_FUNC_ENTRY( "CPCHHelpSession::Load" );
  1028. HRESULT hr;
  1029. MPC::StorageObject* child;
  1030. __MPC_EXIT_IF_METHOD_FAILS(hr, ItemState_GetIndexObject( /*fCreate*/false, child ));
  1031. if(child)
  1032. {
  1033. CComPtr<IStream> stream;
  1034. __MPC_EXIT_IF_METHOD_FAILS(hr, child->GetStream( stream ));
  1035. if(stream)
  1036. {
  1037. CComPtr<CPCHHelpSessionItem> hsi;
  1038. MPC::Serializer_IStream streamReal( stream );
  1039. MPC::Serializer_Buffering streamBuf ( streamReal );
  1040. DWORD dwVer;
  1041. __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf >> dwVer ); if(dwVer != l_dwVersion) __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
  1042. __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf >> m_iLastIndex);
  1043. while(1)
  1044. {
  1045. __MPC_EXIT_IF_METHOD_FAILS(hr, AllocateItem( /*fNew*/false, /*fLink*/false, /*fNewIndex*/false, hsi ));
  1046. if(FAILED(hsi->Load( streamBuf ))) break;
  1047. m_lstVisitedPages.push_back( hsi.Detach() );
  1048. }
  1049. }
  1050. }
  1051. //
  1052. // Cleanup broken links.
  1053. //
  1054. {
  1055. CPCHHelpSessionItem* hsi;
  1056. CPCHHelpSessionItem* hsiLast = NULL;
  1057. IterConst it;
  1058. //
  1059. // First of all, reset broken Forward and Backward pointers.
  1060. //
  1061. for(it = m_lstVisitedPages.begin(); it != m_lstVisitedPages.end(); it++)
  1062. {
  1063. hsi = *it;
  1064. if(FindPage( hsi->m_iIndexPrev ) == NULL) hsi->m_iIndexPrev = CPCHHelpSessionItem::NO_LINK;
  1065. if(FindPage( hsi->m_iIndexNext ) == NULL) hsi->m_iIndexNext = CPCHHelpSessionItem::NO_LINK;
  1066. }
  1067. //
  1068. // Then, link in some wayFirst of all, reset broken Forward and Backward pointers.
  1069. //
  1070. // REMEMBER, the list is actually a reverse list, so the "Previous" element will follow in the list.
  1071. //
  1072. for(it = m_lstVisitedPages.begin(); it != m_lstVisitedPages.end(); it++)
  1073. {
  1074. hsi = *it;
  1075. //
  1076. // We saw an item not linked, so let's link it!
  1077. //
  1078. if(hsiLast)
  1079. {
  1080. hsiLast->m_iIndexPrev = hsi->m_iIndex; hsiLast = NULL;
  1081. }
  1082. //
  1083. // Oh, unlinked item, remember pointer, probably we can link it to the next one ("previous" actually, see above).
  1084. //
  1085. if(hsi->m_iIndexPrev == CPCHHelpSessionItem::NO_LINK)
  1086. {
  1087. hsiLast = hsi;
  1088. }
  1089. }
  1090. }
  1091. hr = S_OK;
  1092. __HCP_FUNC_CLEANUP;
  1093. __HCP_FUNC_EXIT(hr);
  1094. }
  1095. HRESULT CPCHHelpSession::Save()
  1096. {
  1097. __HCP_FUNC_ENTRY( "CPCHHelpSession::Save" );
  1098. HRESULT hr;
  1099. MPC::StorageObject* child;
  1100. int iCount = NUM_OF_ENTRIES_TO_PERSIST;
  1101. List lstObject;
  1102. IterConst it;
  1103. //
  1104. // Initialize flags for deletion of unused slots.
  1105. //
  1106. for(it = m_lstVisitedPages.begin(); it != m_lstVisitedPages.end(); it++)
  1107. {
  1108. CPCHHelpSessionItem* hsi = *it;
  1109. hsi->m_state.ReleaseState( /*fForce*/true );
  1110. hsi->m_fSaved = false;
  1111. }
  1112. #ifdef HSS_RPRD
  1113. //
  1114. // If the registry value is set, create a new XML file for the current session.
  1115. //
  1116. {
  1117. DWORD dwDumpSession = 0;
  1118. bool fFound;
  1119. (void)MPC::RegKey_Value_Read( dwDumpSession, fFound, HC_REGISTRY_HELPCTR, L"DumpHelpSession", HKEY_LOCAL_MACHINE );
  1120. if(dwDumpSession)
  1121. {
  1122. (void)DumpSession();
  1123. }
  1124. }
  1125. #endif
  1126. //
  1127. // Get the list of items to return.
  1128. //
  1129. __MPC_EXIT_IF_METHOD_FAILS(hr, FilterPages( HS_READ, lstObject ));
  1130. __MPC_EXIT_IF_METHOD_FAILS(hr, ItemState_GetIndexObject( /*fCreate*/true, child ));
  1131. if(child)
  1132. {
  1133. CComPtr<IStream> stream;
  1134. __MPC_EXIT_IF_METHOD_FAILS(hr, child->GetStream( stream ));
  1135. if(stream)
  1136. {
  1137. MPC::Serializer_IStream streamReal( stream );
  1138. MPC::Serializer_Buffering streamBuf ( streamReal );
  1139. __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf << l_dwVersion );
  1140. __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf << m_iLastIndex);
  1141. for(it = lstObject.begin(); it != lstObject.end() && iCount > 0; it++)
  1142. {
  1143. CPCHHelpSessionItem* hsi = *it;
  1144. //
  1145. // Don't save entries without a title.
  1146. //
  1147. if(hsi->m_bstrTitle.Length() == 0) continue;
  1148. //
  1149. // Don't save entries from the exclude list.
  1150. //
  1151. for(int i=0; i<ARRAYSIZE(c_rgExclude); i++)
  1152. {
  1153. LPCWSTR szURL = hsi->GetURL();
  1154. if(szURL && !_wcsnicmp( szURL, c_rgExclude[i], wcslen( c_rgExclude[i] ) )) break;
  1155. }
  1156. if(i != ARRAYSIZE(c_rgExclude)) continue;
  1157. __MPC_EXIT_IF_METHOD_FAILS(hr, hsi->Save( streamBuf ));
  1158. iCount--;
  1159. }
  1160. __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf.Flush());
  1161. }
  1162. }
  1163. //
  1164. // Create a new instance of the HelpSession and copy all of valid entries into it.
  1165. //
  1166. {
  1167. CComPtr<CPCHHelpSession> hsCopy;
  1168. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &hsCopy ));
  1169. __MPC_EXIT_IF_METHOD_FAILS(hr, hsCopy->Initialize( NULL ));
  1170. __MPC_EXIT_IF_METHOD_FAILS(hr, Clone( *hsCopy ));
  1171. }
  1172. DEBUG_DumpSavedPages();
  1173. hr = S_OK;
  1174. __HCP_FUNC_CLEANUP;
  1175. __HCP_FUNC_EXIT(hr);
  1176. }
  1177. static HRESULT local_CopyStream( /*[in]*/ MPC::StorageObject* childSrc ,
  1178. /*[in]*/ MPC::StorageObject* childDst )
  1179. {
  1180. __HCP_FUNC_ENTRY( "local_CopyStream" );
  1181. HRESULT hr;
  1182. if(childSrc && childDst)
  1183. {
  1184. CComPtr<IStream> streamSrc;
  1185. CComPtr<IStream> streamDst;
  1186. __MPC_EXIT_IF_METHOD_FAILS(hr, childSrc->Rewind ());
  1187. __MPC_EXIT_IF_METHOD_FAILS(hr, childDst->Rewind ());
  1188. __MPC_EXIT_IF_METHOD_FAILS(hr, childDst->Truncate());
  1189. __MPC_EXIT_IF_METHOD_FAILS(hr, childSrc->GetStream( streamSrc ));
  1190. __MPC_EXIT_IF_METHOD_FAILS(hr, childDst->GetStream( streamDst ));
  1191. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::BaseStream::TransferData( streamSrc, streamDst ));
  1192. }
  1193. hr = S_OK;
  1194. __HCP_FUNC_CLEANUP;
  1195. __HCP_FUNC_EXIT(hr);
  1196. }
  1197. HRESULT CPCHHelpSession::Clone( /*[in]*/ CPCHHelpSession& hsCopy )
  1198. {
  1199. __HCP_FUNC_ENTRY( "CPCHHelpSession::Clone" );
  1200. HRESULT hr;
  1201. MPC::StorageObject* childSrc;
  1202. MPC::StorageObject* childDst;
  1203. MPC::wstring szFile;
  1204. IterConst it;
  1205. __MPC_EXIT_IF_METHOD_FAILS(hr, ItemState_GetIndexObject( /*fCreate*/false, childSrc ));
  1206. __MPC_EXIT_IF_METHOD_FAILS(hr, hsCopy.ItemState_GetIndexObject( /*fCreate*/true , childDst ));
  1207. __MPC_EXIT_IF_METHOD_FAILS(hr, local_CopyStream ( childSrc, childDst ));
  1208. //
  1209. // Purge unused slots.
  1210. //
  1211. for(it = m_lstVisitedPages.begin(); it != m_lstVisitedPages.end(); it++)
  1212. {
  1213. CPCHHelpSessionItem* hsi = *it;
  1214. if(hsi->m_fSaved)
  1215. {
  1216. __MPC_EXIT_IF_METHOD_FAILS(hr, ItemState_GetStorageObject( hsi->GetIndex(), /*fCreate*/false, childSrc ));
  1217. __MPC_EXIT_IF_METHOD_FAILS(hr, hsCopy.ItemState_GetStorageObject( hsi->GetIndex(), /*fCreate*/true , childDst ));
  1218. __MPC_EXIT_IF_METHOD_FAILS(hr, local_CopyStream ( childSrc, childDst ));
  1219. }
  1220. }
  1221. hr = S_OK;
  1222. __HCP_FUNC_CLEANUP;
  1223. __HCP_FUNC_EXIT(hr);
  1224. }
  1225. ////////////////////////////////////////
  1226. #ifdef HSS_RPRD
  1227. HRESULT CPCHHelpSession::DumpSession()
  1228. {
  1229. __HCP_FUNC_ENTRY( "CPCHHelpSession::DumpSession" );
  1230. HRESULT hr;
  1231. MPC::XmlUtil xml;
  1232. CComPtr<IXMLDOMNode> xdn;
  1233. bool fGot = false;
  1234. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.New( L"TravelLog" ));
  1235. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetRoot( &xdn ));
  1236. for(IterConst it = m_lstVisitedPages.begin(); it != m_lstVisitedPages.end(); it++)
  1237. {
  1238. CPCHHelpSessionItem* hsi = *it;
  1239. XMLHelpSessionItem dmp;
  1240. if(m_dStartOfSession > hsi->m_dLastVisited) continue;
  1241. dmp.m_ths = hsi->m_ths;
  1242. dmp.m_iIndex = hsi->m_iIndex;
  1243. dmp.m_dLastVisited = hsi->m_dLastVisited;
  1244. dmp.m_lDuration = 86400.0 * ( hsi->m_dDuration - hsi->m_dLastVisited ); // Number of milliseconds for the page.
  1245. dmp.m_bstrURL = hsi->m_bstrURL;
  1246. dmp.m_bstrTitle = hsi->m_bstrTitle;
  1247. dmp.m_bstrContextID = CPCHHelpSessionItem::LookupContext( (HscContext)hsi->m_lContextID );
  1248. dmp.m_bstrContextInfo = hsi->m_bstrContextInfo;
  1249. dmp.m_bstrContextURL = hsi->m_bstrContextURL;
  1250. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::Config::SaveSubNode( &dmp, xdn ));
  1251. fGot = true;
  1252. }
  1253. if(fGot)
  1254. {
  1255. SYSTEMTIME st;
  1256. WCHAR rgTime[512];
  1257. MPC::wstring strFile;
  1258. //
  1259. // Append current time.
  1260. //
  1261. // <FileName>__<Year>_<Month>_<Day>_<hour>-<minute>-<second>
  1262. //
  1263. ::GetLocalTime( &st );
  1264. swprintf( rgTime, L"__%04u-%02u-%02u_%02u-%02u-%02u.xml", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond );
  1265. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::GetUserWritablePath( strFile, HC_ROOT_HELPCTR L"\\RPRD" )); strFile.append( rgTime );
  1266. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::MakeDir( strFile ));
  1267. __MPC_EXIT_IF_METHOD_FAILS(hr, xml.Save ( strFile.c_str() ));
  1268. }
  1269. hr = S_OK;
  1270. __HCP_FUNC_CLEANUP;
  1271. __HCP_FUNC_EXIT(hr);
  1272. }
  1273. #endif
  1274. ////////////////////////////////////////
  1275. HRESULT CPCHHelpSession::ItemState_GetIndexObject( /*[in]*/ bool fCreate ,
  1276. /*[out]*/ MPC::StorageObject*& child )
  1277. {
  1278. return m_disk.GetChild( c_szINDEX, child, STGM_READWRITE, fCreate ? STGTY_STREAM : 0 );
  1279. }
  1280. HRESULT CPCHHelpSession::ItemState_GetStorageObject( /*[in]*/ int iIndex ,
  1281. /*[in]*/ bool fCreate ,
  1282. /*[out]*/ MPC::StorageObject*& child )
  1283. {
  1284. WCHAR rgName[64]; swprintf( rgName, L"STATE_%d", iIndex );
  1285. return m_disk.GetChild( rgName, child, STGM_READWRITE, fCreate ? STGTY_STREAM : 0 );
  1286. }
  1287. HRESULT CPCHHelpSession::ItemState_CreateStream( /*[in]*/ int iIndex ,
  1288. /*[out]*/ CComPtr<IStream>& stream )
  1289. {
  1290. __HCP_FUNC_ENTRY( "CPCHHelpSession::ItemState_CreateStream" );
  1291. HRESULT hr;
  1292. MPC::StorageObject* child;
  1293. __MPC_EXIT_IF_METHOD_FAILS(hr, ItemState_GetStorageObject( iIndex, /*fCreate*/true, child ));
  1294. if(child)
  1295. {
  1296. __MPC_EXIT_IF_METHOD_FAILS(hr, child->GetStream( stream ));
  1297. }
  1298. if(!stream)
  1299. {
  1300. __MPC_SET_ERROR_AND_EXIT(hr, STG_E_FILENOTFOUND);
  1301. }
  1302. hr = S_OK;
  1303. __HCP_FUNC_CLEANUP;
  1304. __HCP_FUNC_EXIT(hr);
  1305. }
  1306. HRESULT CPCHHelpSession::ItemState_GetStream( /*[in]*/ int iIndex ,
  1307. /*[out]*/ CComPtr<IStream>& stream )
  1308. {
  1309. __HCP_FUNC_ENTRY( "CPCHHelpSession::ItemState_GetStream" );
  1310. HRESULT hr;
  1311. MPC::StorageObject* child;
  1312. __MPC_EXIT_IF_METHOD_FAILS(hr, ItemState_GetStorageObject( iIndex, /*fCreate*/false, child ));
  1313. if(child)
  1314. {
  1315. __MPC_EXIT_IF_METHOD_FAILS(hr, child->GetStream( stream ));
  1316. }
  1317. if(!stream)
  1318. {
  1319. __MPC_SET_ERROR_AND_EXIT(hr, STG_E_FILENOTFOUND);
  1320. }
  1321. hr = S_OK;
  1322. __HCP_FUNC_CLEANUP;
  1323. __HCP_FUNC_EXIT(hr);
  1324. }
  1325. HRESULT CPCHHelpSession::ItemState_DeleteStream( /*[in]*/ int iIndex )
  1326. {
  1327. __HCP_FUNC_ENTRY( "CPCHHelpSession::ItemState_DeleteStream" );
  1328. HRESULT hr;
  1329. MPC::StorageObject* child;
  1330. __MPC_EXIT_IF_METHOD_FAILS(hr, ItemState_GetStorageObject( iIndex, /*fCreate*/false, child ));
  1331. if(child)
  1332. {
  1333. __MPC_EXIT_IF_METHOD_FAILS(hr, child->Delete());
  1334. }
  1335. hr = S_OK;
  1336. __HCP_FUNC_CLEANUP;
  1337. __HCP_FUNC_EXIT(hr);
  1338. }
  1339. /////////////////////////////////////////////////////////////////////////////
  1340. CPCHHelpSessionItem* CPCHHelpSession::FindPage( /*[in]*/ BSTR bstrURL )
  1341. {
  1342. IterConst it;
  1343. //
  1344. // First of all, look if the page is already present.
  1345. //
  1346. for(it = m_lstVisitedPages.begin(); it != m_lstVisitedPages.end(); it++)
  1347. {
  1348. if((*it)->SameURL( bstrURL))
  1349. {
  1350. return *it;
  1351. }
  1352. }
  1353. return NULL;
  1354. }
  1355. CPCHHelpSessionItem* CPCHHelpSession::FindPage( /*[in]*/ IPCHHelpSessionItem* pHSI )
  1356. {
  1357. IterConst it;
  1358. //
  1359. // First of all, look if the page is already present.
  1360. //
  1361. for(it = m_lstVisitedPages.begin(); it != m_lstVisitedPages.end(); it++)
  1362. {
  1363. if((*it) == pHSI)
  1364. {
  1365. return *it;
  1366. }
  1367. }
  1368. return NULL;
  1369. }
  1370. CPCHHelpSessionItem* CPCHHelpSession::FindPage( /*[in]*/ int iIndex )
  1371. {
  1372. IterConst it;
  1373. //
  1374. // First of all, look if the page is already present.
  1375. //
  1376. for(it = m_lstVisitedPages.begin(); it != m_lstVisitedPages.end(); it++)
  1377. {
  1378. if((*it)->m_iIndex == iIndex)
  1379. {
  1380. return *it;
  1381. }
  1382. }
  1383. return NULL;
  1384. }
  1385. HRESULT CPCHHelpSession::Erase()
  1386. {
  1387. __HCP_FUNC_ENTRY( "CPCHHelpSession::Erase" );
  1388. //
  1389. // Release all the items.
  1390. //
  1391. MPC::ReleaseAll( m_lstVisitedPages );
  1392. MPC::ReleaseAll( m_lstCachedVisitedPages );
  1393. m_hsiCurrentPage.Release();
  1394. ResetTitles();
  1395. __HCP_FUNC_EXIT(S_OK);
  1396. }
  1397. ////////////////////////////////////////
  1398. HRESULT CPCHHelpSession::ResetTitles()
  1399. {
  1400. __HCP_FUNC_ENTRY( "CPCHHelpSession::ResetTitles" );
  1401. HRESULT hr;
  1402. MPC::SmartLock<_ThreadModel> lock( this );
  1403. m_mapTitles.clear();
  1404. hr = S_OK;
  1405. __HCP_FUNC_EXIT(hr);
  1406. }
  1407. HRESULT CPCHHelpSession::RecordTitle( /*[in]*/ BSTR bstrURL ,
  1408. /*[in]*/ BSTR bstrTitle ,
  1409. /*[in]*/ bool fStrong )
  1410. {
  1411. __HCP_FUNC_ENTRY( "CPCHHelpSession::RecordTitle" );
  1412. HRESULT hr;
  1413. MPC::SmartLock<_ThreadModel> lock( this );
  1414. //
  1415. // The binding is not strong, so check if there's already a title for the url.
  1416. //
  1417. if(!STRINGISPRESENT(bstrTitle))
  1418. {
  1419. //
  1420. // If there's already a previous page with the same URL, use its title.
  1421. //
  1422. CPCHHelpSessionItem* hsi = FindPage( bstrURL );
  1423. if(hsi && hsi->m_bstrTitle.Length())
  1424. {
  1425. bstrTitle = hsi->m_bstrTitle;
  1426. }
  1427. }
  1428. if(STRINGISPRESENT(bstrTitle))
  1429. {
  1430. TitleEntry& entry = m_mapTitles[ SAFEBSTR( bstrURL ) ];
  1431. //
  1432. // Only update the title if the new one is more "powerful".
  1433. //
  1434. if(entry.m_fStrong == false || fStrong)
  1435. {
  1436. entry.m_szTitle = bstrTitle;
  1437. entry.m_fStrong = fStrong;
  1438. }
  1439. }
  1440. hr = S_OK;
  1441. __HCP_FUNC_EXIT(hr);
  1442. }
  1443. HRESULT CPCHHelpSession::LookupTitle( /*[in ]*/ BSTR bstrURL ,
  1444. /*[out]*/ CComBSTR& bstrTitle ,
  1445. /*[in ]*/ bool fUseIECache )
  1446. {
  1447. __HCP_FUNC_ENTRY( "CPCHHelpSession::LookupTitle" );
  1448. HRESULT hr;
  1449. MPC::SmartLock<_ThreadModel> lock( this );
  1450. if(fUseIECache)
  1451. {
  1452. if(!m_pIHistory)
  1453. {
  1454. __MPC_EXIT_IF_METHOD_FAILS(hr, ::CoCreateInstance( CLSID_CUrlHistory, NULL, CLSCTX_INPROC_SERVER, IID_IUrlHistoryStg, (LPVOID*)&m_pIHistory ));
  1455. }
  1456. if(m_pIHistory)
  1457. {
  1458. STATURL stat;
  1459. if(SUCCEEDED(m_pIHistory->QueryUrl( bstrURL, 0, &stat )))
  1460. {
  1461. bstrTitle = stat.pwcsTitle;
  1462. }
  1463. }
  1464. }
  1465. else
  1466. {
  1467. TitleIter it;
  1468. it = m_mapTitles.find( MPC::wstring( SAFEWSTR( bstrURL ) ) );
  1469. if(it != m_mapTitles.end())
  1470. {
  1471. bstrTitle = it->second.m_szTitle.c_str();
  1472. }
  1473. }
  1474. hr = S_OK;
  1475. __HCP_FUNC_CLEANUP;
  1476. __HCP_FUNC_EXIT(hr);
  1477. }
  1478. ////////////////////////////////////////
  1479. HRESULT CPCHHelpSession::FilterPages( /*[in]*/ HS_MODE hsMode ,
  1480. /*[out]*/ List& lstObject )
  1481. {
  1482. __HCP_FUNC_ENTRY( "CPCHHelpSession::FilterPages" );
  1483. HRESULT hr;
  1484. List lstAlreadySeen;
  1485. IterConst it;
  1486. for(it = m_lstVisitedPages.begin(); it != m_lstVisitedPages.end(); it++)
  1487. {
  1488. CPCHHelpSessionItem* hsi = *it;
  1489. if(hsMode == HS_READ)
  1490. {
  1491. IterConst itRead;
  1492. if(hsi->SeenLongEnough( REMEMBER_PAGE_DELAY ) != true) continue;
  1493. //
  1494. // Make sure there aren't duplicate entries.
  1495. //
  1496. for(itRead = lstAlreadySeen.begin(); itRead != lstAlreadySeen.end(); itRead++)
  1497. {
  1498. if(hsi->SameURL( *itRead )) break;
  1499. }
  1500. if(itRead != lstAlreadySeen.end())
  1501. {
  1502. continue;
  1503. }
  1504. //
  1505. // Add the new URL to the list of seen URLs.
  1506. //
  1507. lstAlreadySeen.push_back( hsi );
  1508. }
  1509. lstObject.push_back( hsi );
  1510. }
  1511. hr = S_OK;
  1512. __HCP_FUNC_EXIT(hr);
  1513. }
  1514. /////////////////////////////////////////////////////////////////////////////
  1515. HRESULT CPCHHelpSession::AllocateItem( /*[in ]*/ bool fNew ,
  1516. /*[in ]*/ bool fLink ,
  1517. /*[in ]*/ bool fNewIndex ,
  1518. /*[out]*/ CComPtr<CPCHHelpSessionItem>& hsi )
  1519. {
  1520. __HCP_FUNC_ENTRY( "CPCHHelpSession::AllocateItem" );
  1521. HRESULT hr;
  1522. CPCHHelpSessionItem* hsiPrev = m_hsiCurrentPage;
  1523. //
  1524. // If we are flagged to recycle the current item, let's do so.
  1525. //
  1526. if(fNew && fLink && m_fOverwrite)
  1527. {
  1528. m_fOverwrite = false;
  1529. if(hsiPrev)
  1530. {
  1531. hsi = hsiPrev;
  1532. __MPC_SET_ERROR_AND_EXIT(hr, S_OK);
  1533. }
  1534. }
  1535. //
  1536. // Create a new item and link it to the system.
  1537. //
  1538. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &hsi )); hsi->Initialize( this, /*fNew*/fNew );
  1539. //
  1540. // Build the chain of predecessor-successor.
  1541. //
  1542. if(fNewIndex)
  1543. {
  1544. hsi->m_iIndex = m_iLastIndex++;
  1545. }
  1546. if(fLink && hsiPrev && hsi->m_ths == hsiPrev->m_ths)
  1547. {
  1548. hsiPrev->m_iIndexNext = hsi ->m_iIndex;
  1549. hsi ->m_iIndexPrev = hsiPrev->m_iIndex;
  1550. }
  1551. hr = S_OK;
  1552. __HCP_FUNC_CLEANUP;
  1553. __HCP_FUNC_EXIT(hr);
  1554. }
  1555. HRESULT CPCHHelpSession::SetCurrentItem( /*[in]*/ bool fLink, /*[in]*/ CPCHHelpSessionItem* hsi )
  1556. {
  1557. __HCP_FUNC_ENTRY( "CPCHHelpSession::SetCurrentItem" );
  1558. HRESULT hr;
  1559. if(hsi != m_hsiCurrentPage)
  1560. {
  1561. //
  1562. // When navigating to a new page, "Leave" the previous one and "Enter" the new one.
  1563. //
  1564. __MPC_EXIT_IF_METHOD_FAILS(hr, LeaveCurrentPage());
  1565. m_hsiCurrentPage = hsi; __MPC_EXIT_IF_METHOD_FAILS(hr, m_hsiCurrentPage->Enter());
  1566. if(fLink)
  1567. {
  1568. m_lstVisitedPages.push_front( hsi ); hsi->AddRef();
  1569. }
  1570. __MPC_EXIT_IF_METHOD_FAILS(hr, AppendToCached( hsi ));
  1571. }
  1572. hr = S_OK;
  1573. __HCP_FUNC_CLEANUP;
  1574. __HCP_FUNC_EXIT(hr);
  1575. }
  1576. HRESULT CPCHHelpSession::AppendToCached( /*[in]*/ CPCHHelpSessionItem* hsi )
  1577. {
  1578. __HCP_FUNC_ENTRY( "CPCHHelpSession::AppendToCached" );
  1579. HRESULT hr;
  1580. if(hsi)
  1581. {
  1582. IterConst it;
  1583. IterConst itOldest;
  1584. bool fGot = false;
  1585. CPCHHelpSessionItem* hsiOldest = NULL;
  1586. for(it = m_lstCachedVisitedPages.begin(); it != m_lstCachedVisitedPages.end(); it++)
  1587. {
  1588. CPCHHelpSessionItem* hsiObj = *it;
  1589. if(hsiObj == hsi) { fGot = true; break; }
  1590. if(!hsiOldest || hsiOldest->m_dLastVisited > hsiObj->m_dLastVisited)
  1591. {
  1592. itOldest = it;
  1593. hsiOldest = hsiObj;
  1594. }
  1595. }
  1596. if(fGot == false)
  1597. {
  1598. if(m_lstCachedVisitedPages.size() > l_iMaxCachedItems && hsiOldest)
  1599. {
  1600. __MPC_EXIT_IF_METHOD_FAILS(hr, hsiOldest->m_state.ReleaseState( /*fForce*/false ));
  1601. m_lstCachedVisitedPages.erase( itOldest ); hsiOldest->Release();
  1602. }
  1603. __MPC_EXIT_IF_METHOD_FAILS(hr, hsi->m_state.AcquireState());
  1604. m_lstCachedVisitedPages.push_front( hsi ); hsi->AddRef();
  1605. }
  1606. }
  1607. hr = S_OK;
  1608. __HCP_FUNC_CLEANUP;
  1609. __HCP_FUNC_EXIT(hr);
  1610. }
  1611. HRESULT CPCHHelpSession::RegisterContextSwitch( /*[in ]*/ HscContext iVal ,
  1612. /*[in ]*/ BSTR bstrInfo ,
  1613. /*[in ]*/ BSTR bstrURL ,
  1614. /*[out]*/ CPCHHelpSessionItem* *pVal )
  1615. {
  1616. __HCP_FUNC_ENTRY( "CPCHHelpSession::RegisterContextSwitch" );
  1617. HRESULT hr;
  1618. if(pVal)
  1619. {
  1620. CComPtr<CPCHHelpSessionItem> hsi;
  1621. __MPC_EXIT_IF_METHOD_FAILS(hr, AllocateItem( /*fNew*/true, /*fLink*/false, /*fNewIndex*/false, hsi ));
  1622. hsi->m_lContextID = iVal;
  1623. hsi->m_bstrContextInfo = bstrInfo;
  1624. hsi->m_bstrContextURL = bstrURL;
  1625. *pVal = hsi.Detach();
  1626. }
  1627. else
  1628. {
  1629. m_lContextID = iVal;
  1630. m_bstrContextInfo = bstrInfo;
  1631. m_bstrContextURL = bstrURL;
  1632. }
  1633. hr = S_OK;
  1634. __HCP_FUNC_CLEANUP;
  1635. __HCP_FUNC_EXIT(hr);
  1636. }
  1637. HRESULT CPCHHelpSession::RecordNavigationInAdvance( /*[in]*/ BSTR bstrURL )
  1638. {
  1639. __HCP_FUNC_ENTRY( "CPCHHelpSession::RecordNavigationInAdvance" );
  1640. HRESULT hr;
  1641. CComPtr<CPCHHelpSessionItem> hsi;
  1642. __MPC_EXIT_IF_METHOD_FAILS(hr, AllocateItem( /*fNew*/true, /*fLink*/true, /*fNewIndex*/true, hsi ));
  1643. __MPC_EXIT_IF_METHOD_FAILS(hr, hsi->put_URL ( bstrURL ));
  1644. __MPC_EXIT_IF_METHOD_FAILS(hr, hsi->put_Title( NULL ));
  1645. __MPC_EXIT_IF_METHOD_FAILS(hr, SetCurrentItem( /*fLink*/true, hsi ));
  1646. m_fAlreadyCreated = true;
  1647. hr = S_OK;
  1648. __HCP_FUNC_CLEANUP;
  1649. __HCP_FUNC_EXIT(hr);
  1650. }
  1651. HRESULT CPCHHelpSession::DuplicateNavigation()
  1652. {
  1653. __HCP_FUNC_ENTRY( "CPCHHelpSession::DuplicateNavigation" );
  1654. HRESULT hr;
  1655. CComPtr<CPCHHelpSessionItem> hsi;
  1656. bool fAcquired = false;
  1657. __MPC_EXIT_IF_METHOD_FAILS(hr, AllocateItem( /*fNew*/true, /*fLink*/true, /*fNewIndex*/true, hsi ));
  1658. if(m_hsiCurrentPage)
  1659. {
  1660. __MPC_EXIT_IF_METHOD_FAILS(hr, hsi->HistoryClone( /*fContext*/false, m_hsiCurrentPage )); fAcquired = true;
  1661. }
  1662. __MPC_EXIT_IF_METHOD_FAILS(hr, SetCurrentItem( /*fLink*/true, hsi ));
  1663. m_fAlreadyCreated = true;
  1664. hr = S_OK;
  1665. __HCP_FUNC_CLEANUP;
  1666. if(fAcquired && hsi) (void)hsi->m_state.ReleaseState( /*fForce*/false );
  1667. __HCP_FUNC_EXIT(hr);
  1668. }
  1669. HRESULT CPCHHelpSession::CancelNavigation()
  1670. {
  1671. __HCP_FUNC_ENTRY( "CPCHHelpSession::CancelNavigation" );
  1672. HRESULT hr;
  1673. if(m_fAlreadyCreated) // The navigation has been cancelled but an entry was already created. Recycle it.
  1674. {
  1675. m_fOverwrite = true;
  1676. }
  1677. hr = S_OK;
  1678. __HCP_FUNC_EXIT(hr);
  1679. }
  1680. ////////////////////////////////////////////////////////////////////////////////
  1681. void CPCHHelpSession::SetThreshold()
  1682. {
  1683. m_dLastNavigation = MPC::GetSystemTimeEx( /*fHighPrecision*/false );
  1684. }
  1685. void CPCHHelpSession::CancelThreshold()
  1686. {
  1687. m_dLastNavigation = 0.0;
  1688. }
  1689. bool CPCHHelpSession::HasThresholdExpired()
  1690. {
  1691. DATE dStart = MPC::GetSystemTimeEx( /*fHighPrecision*/false );
  1692. #ifdef DEBUG
  1693. if(m_dLastNavigation)
  1694. {
  1695. DebugLog( L"Threshold: %g\n", (dStart - m_dLastNavigation) * 86400 );
  1696. }
  1697. #endif
  1698. if(m_dLastNavigation && (dStart - m_dLastNavigation) < l_dNewNavigationThreshold) return false;
  1699. return true;
  1700. }
  1701. bool CPCHHelpSession::IsUrlToIgnore( /*[in]*/ LPCWSTR szURL, /*[in]*/ bool fRemove )
  1702. {
  1703. if(szURL)
  1704. {
  1705. MPC::WStringUCIter it;
  1706. MPC::wstringUC str( szURL );
  1707. for(it = m_lstIgnore.begin(); it != m_lstIgnore.end(); it++)
  1708. {
  1709. if(str == *it)
  1710. {
  1711. if(fRemove) m_lstIgnore.erase( it );
  1712. return true;
  1713. }
  1714. }
  1715. }
  1716. return false;
  1717. }
  1718. HRESULT CPCHHelpSession::IgnoreUrl( /*[in]*/ LPCWSTR szURL )
  1719. {
  1720. __HCP_FUNC_ENTRY( "CPCHHelpSession::IgnoreUrl" );
  1721. HRESULT hr;
  1722. m_lstIgnore.push_back( szURL );
  1723. hr = S_OK;
  1724. __HCP_FUNC_EXIT(hr);
  1725. }
  1726. HRESULT CPCHHelpSession::StartNavigation( /*[in]*/ BSTR bstrURL ,
  1727. /*[in]*/ HscPanel idPanel )
  1728. {
  1729. __HCP_FUNC_ENTRY( "CPCHHelpSession::StartNavigation" );
  1730. HRESULT hr;
  1731. if(IsUrlToIgnore( bstrURL, /*fRemove*/false ))
  1732. {
  1733. DebugLog( L"StartNavigation: IsUrlToIgnore %s\n", bstrURL );
  1734. __MPC_SET_ERROR_AND_EXIT(hr, S_FALSE);
  1735. }
  1736. //
  1737. // For now, we just consider content navigations.
  1738. //
  1739. if(idPanel != HSCPANEL_CONTENTS &&
  1740. idPanel != HSCPANEL_HHWINDOW )
  1741. {
  1742. DebugLog( L"StartNavigation: Wrong panel %d\n", (int)idPanel );
  1743. __MPC_SET_ERROR_AND_EXIT(hr, S_FALSE);
  1744. }
  1745. #ifdef DEBUG
  1746. {
  1747. WCHAR rgBuf[1024]; _snwprintf( rgBuf, MAXSTRLEN(rgBuf), L"StartNavigation: start %s", SAFEWSTR( bstrURL ) );
  1748. DEBUG_DumpState( rgBuf, /*fHeader*/true, /*fCurrent*/false, /*fAll*/false, /*fState*/false );
  1749. }
  1750. #endif
  1751. //
  1752. // When we navigate away from the Homepage, let's change the context....
  1753. //
  1754. {
  1755. static const CComBSTR c_bstrURL_Home( L"hcp://system/HomePage.htm" );
  1756. if(m_lContextID == HSCCONTEXT_HOMEPAGE && MPC::StrICmp( bstrURL, c_bstrURL_Home ) != 0)
  1757. {
  1758. m_lContextID = HSCCONTEXT_FULLWINDOW;
  1759. }
  1760. }
  1761. //
  1762. // Check recursion.
  1763. //
  1764. if(m_dwTravelling++)
  1765. {
  1766. DebugLog( L"StartNavigation: Travelling %d\n", (int)m_dwTravelling );
  1767. SetThreshold();
  1768. __MPC_SET_ERROR_AND_EXIT(hr, S_OK);
  1769. }
  1770. //
  1771. // If it hasn't passed enough time, ignore navigation!
  1772. //
  1773. if(HasThresholdExpired() == false)
  1774. {
  1775. if(m_dwIgnore == 0) // But only if we are not inside another controlled navigation!
  1776. {
  1777. m_dwIgnore++;
  1778. m_dwNoEvents++;
  1779. DebugLog( L"StartNavigation: Threshold Expired\n" );
  1780. }
  1781. }
  1782. SetThreshold();
  1783. //
  1784. // Flag set, so we don't create a new node.
  1785. //
  1786. if(m_dwIgnore)
  1787. {
  1788. DebugLog( L"StartNavigation: Ignore Start %d\n", (int)m_dwIgnore );
  1789. __MPC_SET_ERROR_AND_EXIT(hr, S_OK);
  1790. }
  1791. if(m_fAlreadyCreated == false || m_hsiCurrentPage == NULL)
  1792. {
  1793. CComPtr<CPCHHelpSessionItem> hsi;
  1794. DebugLog( L"%%%%%%%%%%%%%%%%%%%% NEW ENTRY %s\n", SAFEBSTR( bstrURL ) );
  1795. __MPC_EXIT_IF_METHOD_FAILS(hr, AllocateItem( /*fNew*/true, /*fLink*/true, /*fNewIndex*/true, hsi ));
  1796. __MPC_EXIT_IF_METHOD_FAILS(hr, SetCurrentItem( /*fLink*/true, hsi ));
  1797. }
  1798. else
  1799. {
  1800. DebugLog( L"StartNavigation: Recycle entry\n" );
  1801. }
  1802. if(m_hsiCurrentPage)
  1803. {
  1804. m_hsiCurrentPage->m_fInitialized = true;
  1805. m_hsiCurrentPage->m_fUseHH = (idPanel == HSCPANEL_HHWINDOW);
  1806. m_fAlreadyCreated = false;
  1807. __MPC_EXIT_IF_METHOD_FAILS(hr, m_hsiCurrentPage->put_URL ( bstrURL ));
  1808. __MPC_EXIT_IF_METHOD_FAILS(hr, m_hsiCurrentPage->put_Title( NULL ));
  1809. }
  1810. DEBUG_DumpState( L"StartNavigation: end", /*fHeader*/true, /*fCurrent*/true, /*fAll*/false, /*fState*/false );
  1811. hr = S_OK;
  1812. __HCP_FUNC_CLEANUP;
  1813. __HCP_FUNC_EXIT(hr);
  1814. }
  1815. HRESULT CPCHHelpSession::CompleteNavigation( /*[in]*/ HscPanel idPanel )
  1816. {
  1817. __HCP_FUNC_ENTRY( "CPCHHelpSession::CompleteNavigation" );
  1818. HRESULT hr;
  1819. //
  1820. // For now, we just consider content navigations.
  1821. //
  1822. if(idPanel != HSCPANEL_CONTENTS &&
  1823. idPanel != HSCPANEL_HHWINDOW )
  1824. {
  1825. __MPC_SET_ERROR_AND_EXIT(hr, S_FALSE);
  1826. }
  1827. DEBUG_DumpState( L"CompleteNavigation", /*fHeader*/true, /*fCurrent*/true, /*fAll*/false, /*fState*/false );
  1828. //
  1829. // Handle startup scenario: we cannot rely on BeforeNavigate to occur.
  1830. //
  1831. if(!IsTravelling())
  1832. {
  1833. //
  1834. // Sometime, frequently on startup, the web browser embedded in HTMLHELP doesn't fire the BeforeNavigate event, so we are stuck with previous CPCHHelpSessionItem.
  1835. //
  1836. if(idPanel == HSCPANEL_HHWINDOW)
  1837. {
  1838. m_fAlreadyCreated = false;
  1839. }
  1840. __MPC_SET_ERROR_AND_EXIT(hr, S_OK); // Spurious notification.
  1841. }
  1842. SetThreshold();
  1843. m_fAlreadyCreated = false;
  1844. //
  1845. // Check recursion.
  1846. //
  1847. if(--m_dwTravelling)
  1848. {
  1849. if(m_dwIgnore ) m_dwIgnore--;
  1850. if(m_dwNoEvents) m_dwNoEvents--;
  1851. __MPC_SET_ERROR_AND_EXIT(hr, S_OK);
  1852. }
  1853. if(m_dwIgnore)
  1854. {
  1855. m_dwIgnore--;
  1856. }
  1857. if(m_dwNoEvents == 0)
  1858. {
  1859. __MPC_EXIT_IF_METHOD_FAILS(hr, m_parent->Events().FireEvent_PersistLoad ( ));
  1860. __MPC_EXIT_IF_METHOD_FAILS(hr, m_parent->Events().FireEvent_NavigateComplete( m_hsiCurrentPage->GetURL(), idPanel ));
  1861. __MPC_EXIT_IF_METHOD_FAILS(hr, m_parent->Events().FireEvent_TravelDone ( ));
  1862. }
  1863. else
  1864. {
  1865. m_dwNoEvents--;
  1866. }
  1867. //
  1868. // Look up the title in the map, in the IE cache or in the document.
  1869. //
  1870. if(m_hsiCurrentPage)
  1871. {
  1872. m_hsiCurrentPage->ExtractTitle();
  1873. }
  1874. DEBUG_DumpState( L"CompleteNavigation: end", /*fHeader*/true, /*fCurrent*/true, /*fAll*/true, /*fState*/false );
  1875. __MPC_EXIT_IF_METHOD_FAILS(hr, m_parent->EnsurePlace());
  1876. hr = S_OK;
  1877. __HCP_FUNC_CLEANUP;
  1878. __HCP_FUNC_EXIT(hr);
  1879. }
  1880. HRESULT CPCHHelpSession::ForceHistoryPopulate()
  1881. {
  1882. return LeaveCurrentPage( /*fSaveHistory*/true, /*fClearPage*/false );
  1883. }
  1884. /////////////////////////////////////////////////////////////////////////////
  1885. HRESULT CPCHHelpSession::LeaveCurrentPage( /*[in]*/ bool fSaveHistory, /*[in]*/ bool fClearPage )
  1886. {
  1887. __HCP_FUNC_ENTRY( "CPCHHelpSession::LeaveCurrentPage" );
  1888. HRESULT hr;
  1889. CComPtr<CPCHHelpSessionItem> hsi = m_hsiCurrentPage;
  1890. if(hsi)
  1891. {
  1892. hsi->ExtractTitle();
  1893. if(fSaveHistory && m_fAlreadySaved == false)
  1894. {
  1895. __MPC_EXIT_IF_METHOD_FAILS(hr, hsi->HistoryPopulate());
  1896. m_fAlreadySaved = true;
  1897. DEBUG_DumpState( L"Populate", /*fHeader*/false, /*fCurrent*/true, /*fAll*/false, /*fState*/true );
  1898. }
  1899. //
  1900. // Update the time spent on this page.
  1901. //
  1902. if(fClearPage)
  1903. {
  1904. hsi->Leave();
  1905. m_hsiCurrentPage.Release();
  1906. m_fAlreadySaved = false;
  1907. }
  1908. }
  1909. hr = S_OK;
  1910. __HCP_FUNC_CLEANUP;
  1911. __HCP_FUNC_EXIT(hr);
  1912. }
  1913. HRESULT CPCHHelpSession::FindTravelLog( /*[in]*/ long lLength, /*[out]*/ CPCHHelpSessionItem*& hsi )
  1914. {
  1915. __HCP_FUNC_ENTRY( "CPCHHelpSession::FindTravelLog" );
  1916. HRESULT hr;
  1917. hsi = m_hsiCurrentPage;
  1918. while(hsi && lLength)
  1919. {
  1920. if(lLength > 0)
  1921. {
  1922. lLength--;
  1923. hsi = FindPage( hsi->m_iIndexNext );
  1924. }
  1925. else
  1926. {
  1927. lLength++;
  1928. hsi = FindPage( hsi->m_iIndexPrev );
  1929. }
  1930. }
  1931. if(hsi == NULL)
  1932. {
  1933. __MPC_SET_ERROR_AND_EXIT(hr, E_INVALIDARG);
  1934. }
  1935. // DebugLog( L"Next %s\n", SAFEBSTR( hsi->GetURL() ) );
  1936. hr = S_OK;
  1937. __HCP_FUNC_CLEANUP;
  1938. __HCP_FUNC_EXIT(hr);
  1939. }
  1940. HRESULT CPCHHelpSession::Travel( /*[in]*/ CPCHHelpSessionItem* hsi )
  1941. {
  1942. __HCP_FUNC_ENTRY( "CPCHHelpSession::Travel" );
  1943. HRESULT hr;
  1944. HRESULT hr2;
  1945. VARIANT_BOOL Cancel;
  1946. m_fPossibleBack = false;
  1947. #ifdef DEBUG
  1948. {
  1949. WCHAR rgBuf[1024]; _snwprintf( rgBuf, MAXSTRLEN(rgBuf), L"Travel %d", hsi->m_iIndex );
  1950. DEBUG_DumpState( rgBuf, /*fHeader*/true, /*fCurrent*/false, /*fAll*/false, /*fState*/false );
  1951. }
  1952. #endif
  1953. //
  1954. // Sorry, already navigating, abort...
  1955. //
  1956. if(IsTravelling())
  1957. {
  1958. __MPC_SET_ERROR_AND_EXIT(hr, S_OK);
  1959. }
  1960. ////////////////////////////////////////////////////////////////////////////////
  1961. //
  1962. // Check if someone has something to say about the navigaiton.
  1963. //
  1964. m_dwTravelling++; // Fake counter, so scripts can check "IsNavigating" and find out this is an history navigation.
  1965. hr2 = m_parent->Events().FireEvent_BeforeNavigate( hsi->GetURL(), NULL, HSCPANEL_CONTENTS, &Cancel );
  1966. m_dwTravelling--; // Restore real counter.
  1967. if(SUCCEEDED(hr2))
  1968. {
  1969. if(Cancel == VARIANT_TRUE)
  1970. {
  1971. __MPC_SET_ERROR_AND_EXIT(hr, S_OK);
  1972. }
  1973. }
  1974. ////////////////////////////////////////////////////////////////////////////////
  1975. //
  1976. // Update the state information for the page.
  1977. //
  1978. __MPC_EXIT_IF_METHOD_FAILS(hr, SetCurrentItem( /*fLink*/false, hsi ));
  1979. //
  1980. // Set the new page as the current one (but don't generate a new history element!)
  1981. //
  1982. m_dwIgnore++;
  1983. DEBUG_DumpState( L"Restore", /*fHeader*/true, /*fCurrent*/true, /*fAll*/false, /*fState*/true );
  1984. __MPC_EXIT_IF_METHOD_FAILS(hr, m_parent->ChangeContext( (HscContext)hsi->m_lContextID, hsi->m_bstrContextInfo, hsi->m_bstrContextURL, /*fAlsoContent*/false ));
  1985. SetThreshold();
  1986. __MPC_EXIT_IF_METHOD_FAILS(hr, hsi->HistoryRestore());
  1987. DEBUG_DumpState( L"Travel: end", /*fHeader*/true, /*fCurrent*/true, /*fAll*/true, /*fState*/false );
  1988. hr = S_OK;
  1989. __HCP_FUNC_CLEANUP;
  1990. __HCP_FUNC_EXIT(hr);
  1991. }
  1992. HRESULT CPCHHelpSession::Travel( /*[in]*/ long lLength )
  1993. {
  1994. __HCP_FUNC_ENTRY( "CPCHHelpSession::Travel" );
  1995. HRESULT hr;
  1996. CPCHHelpSessionItem* hsi;
  1997. __MPC_EXIT_IF_METHOD_FAILS(hr, FindTravelLog( lLength, hsi ));
  1998. __MPC_EXIT_IF_METHOD_FAILS(hr, Travel ( hsi ));
  1999. hr = S_OK;
  2000. __HCP_FUNC_CLEANUP;
  2001. __HCP_FUNC_EXIT(hr);
  2002. }
  2003. void CPCHHelpSession::PossibleBack()
  2004. {
  2005. m_fPossibleBack = true;
  2006. m_dwPossibleBack = ::GetTickCount();
  2007. }
  2008. bool CPCHHelpSession::IsPossibleBack()
  2009. {
  2010. //
  2011. // Since we don't have a way to block VK_BACK in all the cases, we need to look for the sequence VK_BACK -> Navigation.
  2012. // If the two events come within 100millisec, it's a Back navigation, not backspace.
  2013. //
  2014. if(m_fPossibleBack)
  2015. {
  2016. if(m_dwPossibleBack + 100 > ::GetTickCount())
  2017. {
  2018. return true;
  2019. }
  2020. }
  2021. return false;
  2022. }
  2023. /////////////////////////////////////////////////////////////////////////////
  2024. // IPCHHelpSession Methods.
  2025. /////////////////////////////////////////////////////////////////////////////
  2026. STDMETHODIMP CPCHHelpSession::get_CurrentContext( /*[out, retval]*/ IPCHHelpSessionItem* *ppHSI )
  2027. {
  2028. if(ppHSI == NULL) return E_POINTER;
  2029. *ppHSI = NULL;
  2030. return m_hsiCurrentPage ? m_hsiCurrentPage->QueryInterface( IID_IPCHHelpSessionItem, (void**)ppHSI ) : S_OK;
  2031. }
  2032. STDMETHODIMP CPCHHelpSession::VisitedHelpPages( /*[in]*/ HS_MODE hsMode ,
  2033. /*[out, retval]*/ IPCHCollection* *ppC )
  2034. {
  2035. __HCP_FUNC_ENTRY( "CPCHHelpSession::VisitedHelpPages" );
  2036. HRESULT hr;
  2037. List lstObject;
  2038. IterConst it;
  2039. CComPtr<CPCHCollection> pColl;
  2040. __MPC_PARAMCHECK_BEGIN(hr)
  2041. __MPC_PARAMCHECK_POINTER_AND_SET(ppC,NULL);
  2042. __MPC_PARAMCHECK_END();
  2043. //
  2044. // Create the Enumerator and fill it with jobs.
  2045. //
  2046. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &pColl ));
  2047. //
  2048. // Get the list of items to return.
  2049. //
  2050. __MPC_EXIT_IF_METHOD_FAILS(hr, FilterPages( hsMode, lstObject ));
  2051. //
  2052. // Fill the collection with results.
  2053. //
  2054. {
  2055. const Taxonomy::HelpSet& ths = m_parent->UserSettings()->THS();
  2056. for(it = lstObject.begin(); it != lstObject.end(); it++)
  2057. {
  2058. CPCHHelpSessionItem* hsi = *it;
  2059. if(hsi->SameSKU( ths ))
  2060. {
  2061. __MPC_EXIT_IF_METHOD_FAILS(hr, pColl->AddItem( hsi ));
  2062. }
  2063. }
  2064. }
  2065. __MPC_EXIT_IF_METHOD_FAILS(hr, pColl->QueryInterface( IID_IPCHCollection, (void**)ppC ));
  2066. hr = S_OK;
  2067. __HCP_FUNC_CLEANUP;
  2068. __HCP_FUNC_EXIT(hr);
  2069. }
  2070. STDMETHODIMP CPCHHelpSession::SetTitle( /*[in]*/ BSTR bstrURL ,
  2071. /*[in]*/ BSTR bstrTitle )
  2072. {
  2073. __HCP_FUNC_ENTRY( "CPCHHelpSession::SetTitle" );
  2074. HRESULT hr;
  2075. __MPC_PARAMCHECK_BEGIN(hr)
  2076. __MPC_PARAMCHECK_STRING_NOT_EMPTY(bstrURL);
  2077. __MPC_PARAMCHECK_NOTNULL(bstrTitle);
  2078. __MPC_PARAMCHECK_END();
  2079. __MPC_EXIT_IF_METHOD_FAILS(hr, RecordTitle( bstrURL, bstrTitle, /*fStrong*/true ) );
  2080. hr = S_OK;
  2081. __HCP_FUNC_CLEANUP;
  2082. __HCP_FUNC_EXIT(hr);
  2083. }
  2084. /////////////////////////////////////////////////////////////////////////////
  2085. STDMETHODIMP CPCHHelpSession::ForceNavigation( /*[in]*/ BSTR bstrURL )
  2086. {
  2087. __HCP_FUNC_ENTRY( "CPCHHelpSession::ForceNavigation" );
  2088. HRESULT hr;
  2089. __MPC_EXIT_IF_METHOD_FAILS(hr, StartNavigation ( bstrURL, HSCPANEL_CONTENTS ));
  2090. __MPC_EXIT_IF_METHOD_FAILS(hr, CompleteNavigation( HSCPANEL_CONTENTS ));
  2091. hr = S_OK;
  2092. __HCP_FUNC_CLEANUP;
  2093. __HCP_FUNC_EXIT(hr);
  2094. }
  2095. STDMETHODIMP CPCHHelpSession::IgnoreNavigation()
  2096. {
  2097. __HCP_FUNC_ENTRY( "CPCHHelpSession::IgnoreNavigation" );
  2098. HRESULT hr;
  2099. //
  2100. // Save the current state of the browser.
  2101. //
  2102. __MPC_EXIT_IF_METHOD_FAILS(hr, LeaveCurrentPage( /*fSaveHistory*/true, /*fClearPage*/false ));
  2103. m_dwIgnore++;
  2104. m_dwNoEvents++;
  2105. hr = S_OK;
  2106. __HCP_FUNC_CLEANUP;
  2107. __HCP_FUNC_EXIT(hr);
  2108. }
  2109. STDMETHODIMP CPCHHelpSession::EraseNavigation()
  2110. {
  2111. m_fOverwrite = true;
  2112. return S_OK;
  2113. }
  2114. STDMETHODIMP CPCHHelpSession::IsNavigating( /*[out, retval]*/ VARIANT_BOOL *pVal )
  2115. {
  2116. __HCP_FUNC_ENTRY( "CPCHHelpSession::IsNavigating" );
  2117. HRESULT hr;
  2118. *pVal = IsTravelling() ? VARIANT_TRUE : VARIANT_FALSE;
  2119. hr = S_OK;
  2120. __HCP_FUNC_EXIT(hr);
  2121. }
  2122. /////////////////////////////////////////////////////////////////////////////
  2123. STDMETHODIMP CPCHHelpSession::Back( /*[in]*/ long lLength )
  2124. {
  2125. __HCP_FUNC_ENTRY( "CPCHHelpSession::Back" );
  2126. __HCP_FUNC_EXIT( Travel( -lLength ) );
  2127. }
  2128. STDMETHODIMP CPCHHelpSession::Forward( /*[in]*/ long lLength )
  2129. {
  2130. __HCP_FUNC_ENTRY( "CPCHHelpSession::Forward" );
  2131. __HCP_FUNC_EXIT( Travel( lLength ) );
  2132. }
  2133. STDMETHODIMP CPCHHelpSession::IsValid( /*[in]*/ long lLength ,
  2134. /*[out, retval]*/ VARIANT_BOOL *pVal )
  2135. {
  2136. __HCP_FUNC_ENTRY( "CPCHHelpSession::IsValid" );
  2137. HRESULT hr;
  2138. CPCHHelpSessionItem* hsi;
  2139. *pVal = (SUCCEEDED(FindTravelLog( lLength, hsi )) ? VARIANT_TRUE : VARIANT_FALSE);
  2140. hr = S_OK;
  2141. __HCP_FUNC_EXIT(hr);
  2142. }
  2143. STDMETHODIMP CPCHHelpSession::Navigate( /*[in]*/ IPCHHelpSessionItem* pHSI )
  2144. {
  2145. __HCP_FUNC_ENTRY( "CPCHHelpSession::Navigate" );
  2146. HRESULT hr;
  2147. CPCHHelpSessionItem* hsiSrc;
  2148. CComPtr<CPCHHelpSessionItem> hsi;
  2149. bool fAcquired = false;
  2150. __MPC_PARAMCHECK_BEGIN(hr)
  2151. __MPC_PARAMCHECK_NOTNULL(pHSI);
  2152. __MPC_PARAMCHECK_END();
  2153. hsiSrc = FindPage( pHSI );
  2154. if(hsiSrc == NULL)
  2155. {
  2156. __MPC_SET_ERROR_AND_EXIT(hr, E_INVALIDARG);
  2157. }
  2158. __MPC_EXIT_IF_METHOD_FAILS(hr, AllocateItem ( /*fNew */true, /*fLink*/true, /*fNewIndex*/true, hsi ));
  2159. __MPC_EXIT_IF_METHOD_FAILS(hr, hsi->HistoryClone( /*fContext*/true, hsiSrc )); fAcquired = true;
  2160. __MPC_EXIT_IF_METHOD_FAILS(hr, Travel( hsi ));
  2161. hr = S_OK;
  2162. __HCP_FUNC_CLEANUP;
  2163. if(fAcquired && hsi) (void)hsi->m_state.ReleaseState( /*fForce*/false );
  2164. __HCP_FUNC_EXIT(hr);
  2165. }
  2166. STDMETHODIMP CPCHHelpSession::ChangeContext( /*[in]*/ BSTR bstrName, /*[in,optional]*/ VARIANT vInfo, /*[in,optional]*/ VARIANT vURL )
  2167. {
  2168. __HCP_FUNC_ENTRY( "CPCHHelpSession::ChangeContext" );
  2169. HRESULT hr;
  2170. HscContext lContextID = CPCHHelpSessionItem::LookupContext( bstrName );
  2171. CComBSTR bstrContextInfo;
  2172. CComBSTR bstrContextURL;
  2173. if(lContextID == HSCCONTEXT_INVALID || m_parent == NULL)
  2174. {
  2175. __MPC_SET_ERROR_AND_EXIT(hr, E_INVALIDARG);
  2176. }
  2177. CancelThreshold();
  2178. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::PutBSTR( bstrContextInfo, &vInfo ));
  2179. __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::PutBSTR( bstrContextURL , &vURL ));
  2180. __MPC_EXIT_IF_METHOD_FAILS(hr, m_parent->ChangeContext( lContextID, bstrContextInfo, bstrContextURL ));
  2181. hr = S_OK;
  2182. __HCP_FUNC_CLEANUP;
  2183. __HCP_FUNC_EXIT(hr);
  2184. }