3034 lines
82 KiB
C++
3034 lines
82 KiB
C++
/******************************************************************************
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
HelpSession.cpp
|
|
|
|
Abstract:
|
|
This file contains the implementation of the CHCPHelpSession class,
|
|
which is used to store the list of visited contents.
|
|
|
|
Revision History:
|
|
Davide Massarenti (Dmassare) 07/29/99
|
|
created
|
|
|
|
******************************************************************************/
|
|
|
|
#include "stdafx.h"
|
|
|
|
#include <urlhist.h>
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#define REMEMBER_PAGE_DELAY (3)
|
|
#define NUM_OF_ENTRIES_TO_PERSIST (20)
|
|
|
|
static const DWORD l_dwVersion = 0x01005348; // HS 01
|
|
|
|
|
|
static const DATE l_dNewNavigationThreshold = 1.0 / (24.0 * 60.0 * 60.0); // one second.
|
|
static const int l_iMaxCachedItems = 10;
|
|
|
|
|
|
static const WCHAR c_szPersistFile[] = HC_ROOT_HELPCTR L"\\HelpSessionHistory.dat";
|
|
|
|
static const WCHAR c_szINDEX[] = L"Index";
|
|
|
|
|
|
static const LPCWSTR c_rgExclude[] =
|
|
{
|
|
L"hcp://system/"
|
|
};
|
|
|
|
static const LPCWSTR c_rgBadTitles[] =
|
|
{
|
|
L"ms-its:",
|
|
L"hcp:" ,
|
|
L"http:" ,
|
|
L"https:" ,
|
|
};
|
|
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef HSS_RPRD
|
|
|
|
struct XMLHelpSessionItem : public MPC::Config::TypeConstructor
|
|
{
|
|
DECLARE_CONFIG_MAP(XMLHelpSessionItem);
|
|
|
|
int m_iIndex;
|
|
Taxonomy::HelpSet m_ths;
|
|
DATE m_dLastVisited;
|
|
long m_lDuration;
|
|
|
|
CComBSTR m_bstrURL;
|
|
CComBSTR m_bstrTitle;
|
|
|
|
CComBSTR m_bstrContextID;
|
|
CComBSTR m_bstrContextInfo;
|
|
CComBSTR m_bstrContextURL;
|
|
|
|
////////////////////////////////////////
|
|
//
|
|
// MPC::Config::TypeConstructor
|
|
//
|
|
DEFINE_CONFIG_DEFAULTTAG();
|
|
DECLARE_CONFIG_METHODS();
|
|
//
|
|
////////////////////////////////////////
|
|
};
|
|
|
|
CFG_BEGIN_FIELDS_MAP(XMLHelpSessionItem)
|
|
CFG_ATTRIBUTE( L"ID" , int , m_iIndex ),
|
|
CFG_ATTRIBUTE( L"SKU" , wstring, m_ths.m_strSKU ),
|
|
CFG_ATTRIBUTE( L"Language" , long , m_ths.m_lLCID ),
|
|
CFG_ATTRIBUTE( L"LastVisited" , DATE , m_dLastVisited ),
|
|
CFG_ATTRIBUTE( L"Duration" , long , m_lDuration ),
|
|
|
|
CFG_ELEMENT ( L"URL" , BSTR , m_bstrURL ),
|
|
CFG_ELEMENT ( L"Title" , BSTR , m_bstrTitle ),
|
|
CFG_ATTRIBUTE( L"Context" , BSTR , m_bstrContextID ),
|
|
CFG_ELEMENT ( L"ContextData" , BSTR , m_bstrContextInfo ),
|
|
CFG_ELEMENT ( L"ContextTopic" , BSTR , m_bstrContextURL ),
|
|
CFG_END_FIELDS_MAP()
|
|
|
|
CFG_BEGIN_CHILD_MAP(XMLHelpSessionItem)
|
|
CFG_END_CHILD_MAP()
|
|
|
|
DEFINE_CFG_OBJECT(XMLHelpSessionItem,L"Entry")
|
|
|
|
DEFINE_CONFIG_METHODS__NOCHILD(XMLHelpSessionItem)
|
|
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
static struct ContextLookup
|
|
{
|
|
LPCWSTR szName;
|
|
HscContext iValue;
|
|
bool fInternal;
|
|
} const s_rgContext[] =
|
|
{
|
|
{ L"INVALID" , HSCCONTEXT_INVALID , true },
|
|
{ L"STARTUP" , HSCCONTEXT_STARTUP , true },
|
|
{ L"HOMEPAGE" , HSCCONTEXT_HOMEPAGE , false },
|
|
{ L"CONTENT" , HSCCONTEXT_CONTENT , false },
|
|
{ L"SUBSITE" , HSCCONTEXT_SUBSITE , false },
|
|
{ L"SEARCH" , HSCCONTEXT_SEARCH , false },
|
|
{ L"INDEX" , HSCCONTEXT_INDEX , false },
|
|
{ L"CHANNELS" , HSCCONTEXT_CHANNELS , false },
|
|
{ L"FAVORITES" , HSCCONTEXT_FAVORITES , false },
|
|
{ L"HISTORY" , HSCCONTEXT_HISTORY , false },
|
|
{ L"OPTIONS" , HSCCONTEXT_OPTIONS , false },
|
|
/////////////////////////////////////////////////////
|
|
{ L"CONTENTONLY" , HSCCONTEXT_CONTENTONLY , false },
|
|
{ L"FULLWINDOW" , HSCCONTEXT_FULLWINDOW , false },
|
|
{ L"KIOSKMODE" , HSCCONTEXT_KIOSKMODE , false },
|
|
};
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
CPCHHelpSessionItem::State::State( /*[in]*/ CPCHHelpSessionItem* parent )
|
|
{
|
|
m_parent = parent; // CPCHHelpSessionItem* m_parent;
|
|
m_fValid = false; // bool m_fValid;
|
|
m_fDirty = false; // bool m_fDirty;
|
|
m_dwLoaded = 0; // DWORD m_dwLoaded;
|
|
//
|
|
// MPC::CComHGLOBAL m_hgWebBrowser_CONTENTS;
|
|
// MPC::CComHGLOBAL m_hgWebBrowser_HHWINDOW;
|
|
// PropertyMap m_mapProperties;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void CPCHHelpSessionItem::State::Erase( /*[in]*/ bool fUnvalidate )
|
|
{
|
|
m_hgWebBrowser_CONTENTS.Release();
|
|
m_hgWebBrowser_HHWINDOW.Release();
|
|
m_mapProperties .clear ();
|
|
|
|
m_fDirty = false;
|
|
|
|
if(fUnvalidate) m_fValid = false;
|
|
}
|
|
|
|
HRESULT CPCHHelpSessionItem::State::Load()
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSessionItem::State::Load" );
|
|
|
|
HRESULT hr;
|
|
CComPtr<IStream> stream;
|
|
|
|
if(m_parent == NULL || m_parent->GetParent() == NULL) // Already passivated.
|
|
{
|
|
__MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
|
|
}
|
|
|
|
|
|
if(m_fValid)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_parent->GetParent()->ItemState_GetStream( m_parent->GetIndex(), stream ));
|
|
|
|
{
|
|
MPC::Serializer_IStream streamReal( stream );
|
|
MPC::Serializer_Buffering streamBuf ( streamReal );
|
|
DWORD dwVer;
|
|
|
|
Erase( /*fUnvalidate*/true );
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf >> dwVer ); if(dwVer != l_dwVersion) __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf >> m_hgWebBrowser_CONTENTS);
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf >> m_hgWebBrowser_HHWINDOW);
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf >> m_mapProperties );
|
|
|
|
m_fValid = true;
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CPCHHelpSessionItem::State::Save()
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSessionItem::State::Save" );
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
if(m_fDirty)
|
|
{
|
|
CComPtr<IStream> stream;
|
|
|
|
if(m_parent == NULL || m_parent->GetParent() == NULL) // Already passivated.
|
|
{
|
|
__MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
|
|
}
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_parent->GetParent()->ItemState_CreateStream( m_parent->GetIndex(), stream ));
|
|
|
|
{
|
|
MPC::Serializer_IStream streamReal( stream );
|
|
MPC::Serializer_Buffering streamBuf ( streamReal );
|
|
DWORD dwVer = l_dwVersion;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf << dwVer );
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf << m_hgWebBrowser_CONTENTS);
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf << m_hgWebBrowser_HHWINDOW);
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf << m_mapProperties );
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf.Flush());
|
|
}
|
|
|
|
m_fDirty = false;
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT CPCHHelpSessionItem::State::AcquireState()
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSessionItem::State::AcquireState" );
|
|
|
|
HRESULT hr;
|
|
|
|
if(m_dwLoaded++ == 0)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, Load());
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CPCHHelpSessionItem::State::ReleaseState( /*[in]*/ bool fForce )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSessionItem::State::ReleaseState" );
|
|
|
|
HRESULT hr;
|
|
|
|
if(m_dwLoaded)
|
|
{
|
|
if(fForce || --m_dwLoaded == 0)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, Save());
|
|
|
|
Erase( /*fUnvalidate*/false ); // Just unload.
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
|
|
HRESULT CPCHHelpSessionItem::State::Populate( /*[in]*/ bool fUseHH )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSessionItem::State::Populate" );
|
|
|
|
HRESULT hr;
|
|
CComQIPtr<IPersistHistory> pPH;
|
|
CPCHHelpSession* parent2;
|
|
CPCHHelpCenterExternal* parent3;
|
|
|
|
|
|
if(m_parent == NULL || (parent2 = m_parent->GetParent()) == NULL || (parent3 = parent2->GetParent()) == NULL) // Already passivated.
|
|
{
|
|
__MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
|
|
}
|
|
|
|
////////////////////
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, parent3->Events().FireEvent_PersistSave());
|
|
|
|
////////////////////
|
|
|
|
m_hgWebBrowser_CONTENTS.Release();
|
|
m_hgWebBrowser_HHWINDOW.Release();
|
|
|
|
if(fUseHH == false)
|
|
{
|
|
CComPtr<IWebBrowser2> wb2; wb2.Attach( parent3->Contents() );
|
|
|
|
pPH = wb2;
|
|
if(pPH)
|
|
{
|
|
CComPtr<IStream> stream;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_hgWebBrowser_CONTENTS.NewStream( &stream ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, pPH->SaveHistory ( stream ));
|
|
|
|
m_fValid = true;
|
|
m_fDirty = true;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
CComPtr<IWebBrowser2> wb2; wb2.Attach( parent3->HHWindow() );
|
|
|
|
pPH = wb2;
|
|
if(pPH)
|
|
{
|
|
CComPtr<IStream> stream;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_hgWebBrowser_HHWINDOW.NewStream( &stream ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, pPH->SaveHistory ( stream ));
|
|
|
|
m_fValid = true;
|
|
m_fDirty = true;
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CPCHHelpSessionItem::State::Restore( /*[in]*/ bool fUseHH )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSessionItem::State::Restore" );
|
|
|
|
HRESULT hr;
|
|
CComQIPtr<IPersistHistory> pPH;
|
|
CPCHHelpSession* parent2;
|
|
CPCHHelpCenterExternal* parent3;
|
|
bool fAcquired = false;
|
|
|
|
|
|
if(m_parent == NULL || (parent2 = m_parent->GetParent()) == NULL || (parent3 = parent2->GetParent()) == NULL) // Already passivated.
|
|
{
|
|
__MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
|
|
}
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, AcquireState()); fAcquired = true;
|
|
|
|
if(fUseHH == false)
|
|
{
|
|
if(m_hgWebBrowser_CONTENTS.Size())
|
|
{
|
|
{
|
|
CComPtr<IMarsPanel> panel;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, parent3->GetPanel( HSCPANEL_CONTENTS, &panel, /*fEnsurePresence*/true ));
|
|
}
|
|
|
|
{
|
|
CComPtr<IWebBrowser2> wb2; wb2.Attach( parent3->Contents() );
|
|
|
|
pPH = wb2;
|
|
if(pPH)
|
|
{
|
|
CComPtr<IStream> stream;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_hgWebBrowser_CONTENTS.GetAsStream( &stream, /*fClone*/true ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, pPH->LoadHistory ( stream, NULL ));
|
|
}
|
|
}
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, parent3->SetCorrectContentPanel( /*fShowNormal*/true, /*fShowHTMLHELP*/false, /*fNow*/false ));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if(m_hgWebBrowser_HHWINDOW.Size())
|
|
{
|
|
{
|
|
CComPtr<IMarsPanel> panel;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, parent3->GetPanel( HSCPANEL_HHWINDOW, &panel, /*fEnsurePresence*/true ));
|
|
}
|
|
|
|
{
|
|
CComPtr<IWebBrowser2> wb2; wb2.Attach( parent3->HHWindow() );
|
|
|
|
pPH = wb2;
|
|
if(pPH)
|
|
{
|
|
CComPtr<IStream> stream;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_hgWebBrowser_HHWINDOW.GetAsStream( &stream, /*fClone*/true ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, pPH->LoadHistory ( stream, NULL ));
|
|
}
|
|
}
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, parent3->SetCorrectContentPanel( /*fShowNormal*/false, /*fShowHTMLHELP*/true, /*fNow*/false ));
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
if(fAcquired) (void)ReleaseState( /*fForce*/false );
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CPCHHelpSessionItem::State::Delete()
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSessionItem::State::Delete" );
|
|
|
|
HRESULT hr;
|
|
CPCHHelpSession* parent2;
|
|
|
|
if(m_parent == NULL || (parent2 = m_parent->GetParent()) == NULL) // Already passivated.
|
|
{
|
|
__MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
|
|
}
|
|
|
|
|
|
Erase( /*fUnvalidate*/true );
|
|
m_dwLoaded = 0;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_parent->GetParent()->ItemState_DeleteStream( m_parent->GetIndex() ));
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CPCHHelpSessionItem::State::Clone( /*[out]*/ State& state )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSessionItem::State::Clone" );
|
|
|
|
HRESULT hr;
|
|
bool fAcquired = false;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, state.AcquireState()); fAcquired = true;
|
|
|
|
// CPCHHelpSessionItem* m_parent;
|
|
m_fValid = state.m_fValid; // bool m_fValid;
|
|
m_fDirty = true; // bool m_fDirty;
|
|
m_dwLoaded++; // DWORD m_dwLoaded;
|
|
//
|
|
m_hgWebBrowser_CONTENTS = state.m_hgWebBrowser_CONTENTS; // MPC::CComHGLOBAL m_hgWebBrowser_CONTENTS;
|
|
m_hgWebBrowser_HHWINDOW = state.m_hgWebBrowser_HHWINDOW; // MPC::CComHGLOBAL m_hgWebBrowser_HHWINDOW;
|
|
m_mapProperties = state.m_mapProperties; // PropertyMap m_mapProperties;
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
if(fAcquired) (void)state.ReleaseState( /*fForce*/false );
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
HscContext CPCHHelpSessionItem::LookupContext( /*[in]*/ LPCWSTR szName )
|
|
{
|
|
const ContextLookup* ctx = s_rgContext;
|
|
|
|
if(!STRINGISPRESENT(szName)) return HSCCONTEXT_HOMEPAGE;
|
|
|
|
for(int i=0; i<ARRAYSIZE(s_rgContext); i++, ctx++)
|
|
{
|
|
if(!_wcsicmp( szName, ctx->szName ))
|
|
{
|
|
return ctx->fInternal ? HSCCONTEXT_INVALID : ctx->iValue;
|
|
}
|
|
}
|
|
|
|
return HSCCONTEXT_INVALID;
|
|
}
|
|
|
|
LPCWSTR CPCHHelpSessionItem::LookupContext( /*[in]*/ HscContext iVal )
|
|
{
|
|
const ContextLookup* ctx = s_rgContext;
|
|
|
|
for(int i=0; i<ARRAYSIZE(s_rgContext); i++, ctx++)
|
|
{
|
|
if(ctx->iValue == iVal) return ctx->szName;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
|
|
CPCHHelpSessionItem::CPCHHelpSessionItem() : m_state( this )
|
|
{
|
|
m_parent = NULL; // CPCHHelpSession* m_parent;
|
|
// State m_state;
|
|
m_fSaved = false; // bool m_fSaved;
|
|
m_fInitialized = false; // bool m_fInitialized;
|
|
//
|
|
//////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
// Taxonomy::HelpSet m_ths;
|
|
//
|
|
// CComBSTR m_bstrURL;
|
|
// CComBSTR m_bstrTitle;
|
|
m_dLastVisited = 0; // DATE m_dLastVisited;
|
|
m_dDuration = 0; // DATE m_dDuration;
|
|
m_lNumOfHits = 0; // DWORD m_lNumOfHits;
|
|
//
|
|
m_iIndexPrev = NO_LINK; // int m_iIndexPrev;
|
|
m_iIndex = NO_LINK; // int m_iIndex;
|
|
m_iIndexNext = NO_LINK; // int m_iIndexNext;
|
|
//
|
|
m_lContextID = HSCCONTEXT_INVALID; // long m_lContextID; // HscContext
|
|
// CComBSTR m_bstrContextInfo;
|
|
// CComBSTR m_bstrContextURL;
|
|
//
|
|
m_fUseHH = false; // bool m_fUseHH;
|
|
}
|
|
|
|
void CPCHHelpSessionItem::Initialize( /*[in]*/ CPCHHelpSession* parent, /*[in]*/ bool fNew )
|
|
{
|
|
m_parent = parent;
|
|
|
|
if(fNew)
|
|
{
|
|
CPCHProxy_IPCHUserSettings2* us = parent->m_parent->UserSettings();
|
|
|
|
m_lContextID = parent->m_lContextID ;
|
|
m_bstrContextInfo = parent->m_bstrContextInfo;
|
|
m_bstrContextURL = parent->m_bstrContextURL ;
|
|
|
|
if(us)
|
|
{
|
|
m_ths = us->THS();
|
|
}
|
|
}
|
|
}
|
|
|
|
void CPCHHelpSessionItem::Passivate()
|
|
{
|
|
m_state.ReleaseState( /*fForce*/true );
|
|
|
|
m_parent = NULL;
|
|
}
|
|
|
|
////////////////////
|
|
|
|
HRESULT CPCHHelpSessionItem::Load( /*[in]*/ MPC::Serializer& streamIn )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSessionItem::Load" );
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
//
|
|
// Read its properties.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_ths );
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_bstrURL );
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_bstrTitle );
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_dLastVisited );
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_dDuration );
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_lNumOfHits );
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_iIndexPrev );
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_iIndex );
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_iIndexNext );
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_lContextID );
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_bstrContextInfo);
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_bstrContextURL );
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamIn >> m_fUseHH );
|
|
|
|
//
|
|
// All the item saved to disk have a valid state.
|
|
//
|
|
m_state.m_fValid = true;
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CPCHHelpSessionItem::Save( /*[in]*/ MPC::Serializer& streamOut ,
|
|
/*[in]*/ bool fForce )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSessionItem::Save" );
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
//
|
|
// Don't save an entry if there's no IE history stream, it would be useless to reload it!
|
|
//
|
|
if(fForce == false && m_state.m_fValid == false)
|
|
{
|
|
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
|
}
|
|
|
|
//
|
|
// Write its properties.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_ths );
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_bstrURL );
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_bstrTitle );
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_dLastVisited );
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_dDuration );
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_lNumOfHits );
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_iIndexPrev );
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_iIndex );
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_iIndexNext );
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_lContextID );
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_bstrContextInfo);
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_bstrContextURL );
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamOut << m_fUseHH );
|
|
|
|
m_fSaved = true;
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
|
|
void CPCHHelpSessionItem::HistorySelect()
|
|
{
|
|
if(!m_fInitialized && m_parent && m_parent->m_parent)
|
|
{
|
|
m_fInitialized = true;
|
|
m_fUseHH = m_parent->m_parent->IsHHWindowVisible();
|
|
}
|
|
}
|
|
|
|
HRESULT CPCHHelpSessionItem::HistoryPopulate()
|
|
{
|
|
HistorySelect();
|
|
|
|
return m_state.Populate( m_fUseHH );
|
|
}
|
|
|
|
HRESULT CPCHHelpSessionItem::HistoryRestore()
|
|
{
|
|
return m_state.Restore( m_fUseHH );
|
|
}
|
|
|
|
HRESULT CPCHHelpSessionItem::HistoryDelete()
|
|
{
|
|
return m_state.Delete();
|
|
}
|
|
|
|
HRESULT CPCHHelpSessionItem::HistoryClone( /*[in]*/ bool fContext, /*[in]*/ CPCHHelpSessionItem* hsi )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSessionItem::HistoryClone" );
|
|
|
|
HRESULT hr;
|
|
bool fAcquired = false;
|
|
|
|
|
|
if(this == hsi || !hsi) __MPC_SET_ERROR_AND_EXIT(hr, S_FALSE);
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, hsi->m_state.AcquireState()); fAcquired = true;
|
|
|
|
|
|
// CPCHHelpSession* m_parent;
|
|
// State m_state;
|
|
m_fSaved = false; // bool m_fSaved;
|
|
m_fInitialized = true; // bool m_fInitialized;
|
|
//
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
//
|
|
m_ths = hsi->m_ths; // Taxonomy::HelpSet m_ths;
|
|
//
|
|
m_bstrURL = hsi->m_bstrURL; // CComBSTR m_bstrURL;
|
|
m_bstrTitle = hsi->m_bstrTitle; // CComBSTR m_bstrTitle;
|
|
// DATE m_dLastVisited;
|
|
// DATE m_dDuration;
|
|
m_lNumOfHits = hsi->m_lNumOfHits; // long m_lNumOfHits;
|
|
//
|
|
// int m_iIndexPrev;
|
|
// int m_iIndex;
|
|
// int m_iIndexNext;
|
|
//
|
|
// long m_lContextID;
|
|
// CComBSTR m_bstrContextInfo;
|
|
// CComBSTR m_bstrContextURL;
|
|
//
|
|
m_fUseHH = hsi->m_fUseHH; // bool m_fUseHH;
|
|
|
|
if(fContext)
|
|
{
|
|
m_lContextID = hsi->m_lContextID;
|
|
m_bstrContextInfo = hsi->m_bstrContextInfo;
|
|
m_bstrContextURL = hsi->m_bstrContextURL;
|
|
}
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_state.Clone( hsi->m_state ));
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
if(fAcquired) (void)hsi->m_state.ReleaseState( /*fForce*/false );
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT CPCHHelpSessionItem::Enter()
|
|
{
|
|
m_dLastVisited = MPC::GetLocalTimeEx( /*fHighPrecision*/false );
|
|
|
|
return m_state.AcquireState();
|
|
}
|
|
|
|
HRESULT CPCHHelpSessionItem::Leave()
|
|
{
|
|
m_dDuration = MPC::GetLocalTimeEx( /*fHighPrecision*/false );
|
|
|
|
return m_state.ReleaseState( /*fForce*/false );
|
|
}
|
|
|
|
bool CPCHHelpSessionItem::SeenLongEnough( DWORD dwSeconds ) const
|
|
{
|
|
return (m_dDuration - m_dLastVisited) * 86400 > dwSeconds;
|
|
}
|
|
|
|
bool CPCHHelpSessionItem::SameURL( CPCHHelpSessionItem* right ) const
|
|
{
|
|
return SameURL( right->m_bstrURL );
|
|
}
|
|
|
|
bool CPCHHelpSessionItem::SameURL( LPCWSTR right ) const
|
|
{
|
|
return MPC::StrICmp( m_bstrURL, right ) == 0;
|
|
}
|
|
|
|
bool CPCHHelpSessionItem::SameSKU( /*[in]*/ const Taxonomy::HelpSet& ths ) const
|
|
{
|
|
return m_ths == ths;
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
|
|
void CPCHHelpSessionItem::put_THS( /*[in]*/ const Taxonomy::HelpSet& ths ) // Internal Method.
|
|
{
|
|
m_ths = ths;
|
|
}
|
|
|
|
STDMETHODIMP CPCHHelpSessionItem::get_SKU( /*[out, retval]*/ BSTR *pVal )
|
|
{
|
|
return MPC::GetBSTR( m_ths.GetSKU(), pVal );
|
|
}
|
|
|
|
|
|
STDMETHODIMP CPCHHelpSessionItem::get_Language( /*[out, retval]*/ long *pVal )
|
|
{
|
|
if(!pVal) return E_POINTER;
|
|
|
|
*pVal = m_ths.GetLanguage();
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CPCHHelpSessionItem::get_URL( /*[out, retval]*/ BSTR *pVal )
|
|
{
|
|
return MPC::GetBSTR( m_bstrURL, pVal );
|
|
}
|
|
|
|
HRESULT CPCHHelpSessionItem::put_URL( /*[in]*/ BSTR newVal ) // Internal Method.
|
|
{
|
|
return MPC::PutBSTR( m_bstrURL, newVal );
|
|
}
|
|
|
|
|
|
STDMETHODIMP CPCHHelpSessionItem::get_Title( /*[out, retval]*/ BSTR *pVal )
|
|
{
|
|
return MPC::GetBSTR( m_bstrTitle, pVal );
|
|
}
|
|
|
|
HRESULT CPCHHelpSessionItem::put_Title( /*[in]*/ BSTR newVal ) // Internal Method.
|
|
{
|
|
return MPC::PutBSTR( m_bstrTitle, newVal );
|
|
}
|
|
|
|
|
|
STDMETHODIMP CPCHHelpSessionItem::get_LastVisited( /*[out, retval]*/ DATE *pVal )
|
|
{
|
|
if(pVal == NULL) return E_POINTER;
|
|
|
|
*pVal = m_dLastVisited;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CPCHHelpSessionItem::get_Duration( /*[out, retval]*/ DATE *pVal )
|
|
{
|
|
if(pVal == NULL) return E_POINTER;
|
|
|
|
*pVal = m_dDuration;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CPCHHelpSessionItem::get_NumOfHits( /*[out, retval]*/ long *pVal )
|
|
{
|
|
if(pVal == NULL) return E_POINTER;
|
|
|
|
*pVal = m_lNumOfHits;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
STDMETHODIMP CPCHHelpSessionItem::get_Property( /*[in]*/ BSTR bstrName, /*[out, retval]*/ VARIANT *pVal )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSessionItem::get_Property" );
|
|
|
|
HRESULT hr;
|
|
State::PropertyIter it;
|
|
bool fAcquired = false;
|
|
|
|
__MPC_PARAMCHECK_BEGIN(hr)
|
|
__MPC_PARAMCHECK_STRING_NOT_EMPTY(bstrName);
|
|
__MPC_PARAMCHECK_NOTNULL(pVal);
|
|
__MPC_PARAMCHECK_END();
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_state.AcquireState()); fAcquired = true;
|
|
|
|
::VariantClear( pVal );
|
|
|
|
it = m_state.m_mapProperties.find( bstrName );
|
|
if(it != m_state.m_mapProperties.end())
|
|
{
|
|
pVal->vt = VT_BSTR;
|
|
pVal->bstrVal = ::SysAllocString( it->second.c_str() );
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
if(fAcquired) (void)m_state.ReleaseState( /*fForce*/false );
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
STDMETHODIMP CPCHHelpSessionItem::put_Property( /*[in]*/ BSTR bstrName, /*[in]*/ VARIANT pVal )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSessionItem::put_Property" );
|
|
|
|
HRESULT hr;
|
|
MPC::wstring strName;
|
|
CComVariant v;
|
|
bool fAcquired = false;
|
|
|
|
__MPC_PARAMCHECK_BEGIN(hr)
|
|
__MPC_PARAMCHECK_STRING_NOT_EMPTY(bstrName);
|
|
__MPC_PARAMCHECK_END();
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_state.AcquireState()); fAcquired = true;
|
|
|
|
strName = bstrName;
|
|
|
|
|
|
(void)::VariantChangeType( &v, &pVal, 0, VT_BSTR );
|
|
if(v.vt == VT_BSTR && v.bstrVal && v.bstrVal[0])
|
|
{
|
|
m_state.m_mapProperties[ strName ] = v.bstrVal;
|
|
}
|
|
else
|
|
{
|
|
m_state.m_mapProperties.erase( strName );
|
|
}
|
|
|
|
m_state.m_fDirty = true;
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
if(fAcquired) (void)m_state.ReleaseState( /*fForce*/false );
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
|
|
STDMETHODIMP CPCHHelpSessionItem::get_ContextName( /*[out, retval]*/ BSTR *pVal )
|
|
{
|
|
return MPC::GetBSTR( LookupContext( GetContextID() ), pVal );
|
|
}
|
|
|
|
STDMETHODIMP CPCHHelpSessionItem::get_ContextInfo( /*[out, retval]*/ BSTR *pVal )
|
|
{
|
|
return MPC::GetBSTR( GetContextInfo(), pVal );
|
|
}
|
|
|
|
STDMETHODIMP CPCHHelpSessionItem::get_ContextURL( /*[out, retval]*/ BSTR *pVal )
|
|
{
|
|
return MPC::GetBSTR( GetContextURL(), pVal );
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
|
|
STDMETHODIMP CPCHHelpSessionItem::CheckProperty( /*[in]*/ BSTR bstrName, /*[out, retval]*/ VARIANT_BOOL *pVal )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSessionItem::CheckProperty" );
|
|
|
|
HRESULT hr;
|
|
State::PropertyIter it;
|
|
bool fAcquired = false;
|
|
|
|
__MPC_PARAMCHECK_BEGIN(hr)
|
|
__MPC_PARAMCHECK_STRING_NOT_EMPTY(bstrName);
|
|
__MPC_PARAMCHECK_POINTER_AND_SET(pVal,VARIANT_FALSE);
|
|
__MPC_PARAMCHECK_END();
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_state.AcquireState()); fAcquired = true;
|
|
|
|
it = m_state.m_mapProperties.find( bstrName );
|
|
if(it != m_state.m_mapProperties.end())
|
|
{
|
|
*pVal = VARIANT_TRUE;
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
if(fAcquired) (void)m_state.ReleaseState( /*fForce*/false );
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
|
|
CPCHHelpSessionItem* CPCHHelpSessionItem::Previous() { return (m_parent && m_iIndexPrev != NO_LINK) ? m_parent->FindPage( m_iIndexPrev ) : NULL; }
|
|
CPCHHelpSessionItem* CPCHHelpSessionItem::Next () { return (m_parent && m_iIndexNext != NO_LINK) ? m_parent->FindPage( m_iIndexNext ) : NULL; }
|
|
|
|
////////////////////////////////////////
|
|
|
|
HRESULT CPCHHelpSessionItem::ExtractTitle()
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSessionItem::ExtractTitle" );
|
|
|
|
HRESULT hr;
|
|
|
|
if(m_parent)
|
|
{
|
|
CPCHHelpCenterExternal* ext = m_parent->GetParent();
|
|
|
|
HistorySelect();
|
|
|
|
if(!STRINGISPRESENT(m_bstrTitle))
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_parent->LookupTitle( m_bstrURL, m_bstrTitle, /*fUseIECache*/false ));
|
|
}
|
|
|
|
if(!STRINGISPRESENT(m_bstrTitle) && ext)
|
|
{
|
|
CComPtr<IWebBrowser2> wb2; wb2.Attach( m_fUseHH ? ext->HHWindow() : ext->Contents() );
|
|
CComPtr<IHTMLDocument2> doc;
|
|
|
|
if(SUCCEEDED(MPC::HTML::IDispatch_To_IHTMLDocument2( doc, wb2 )))
|
|
{
|
|
(void)doc->get_title( &m_bstrTitle );
|
|
}
|
|
}
|
|
|
|
if(!STRINGISPRESENT(m_bstrTitle))
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_parent->LookupTitle( m_bstrURL, m_bstrTitle, /*fUseIECache*/true ));
|
|
}
|
|
|
|
if(STRINGISPRESENT(m_bstrTitle))
|
|
{
|
|
for(int i=0; i<ARRAYSIZE(c_rgBadTitles); i++)
|
|
{
|
|
LPCWSTR szPtr = c_rgBadTitles[i];
|
|
|
|
if(!_wcsnicmp( m_bstrTitle, szPtr, wcslen( szPtr ) ))
|
|
{
|
|
m_bstrTitle.Empty();
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(STRINGISPRESENT(m_bstrTitle))
|
|
{
|
|
DebugLog( L"%%%%%%%%%%%%%%%%%%%% TITLE %s - %s\n", m_bstrURL, m_bstrTitle );
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
#ifdef DEBUG
|
|
|
|
static const WCHAR c_rgHelpSessionLog[] = L"%TEMP%\\helpsession_debug.txt";
|
|
|
|
void CPCHHelpSession::DEBUG_DumpState_HG( /*[in]*/ MPC::FileLog& log ,
|
|
/*[in]*/ MPC::CComHGLOBAL& hg )
|
|
{
|
|
CComPtr<IStream> stream;
|
|
|
|
if(SUCCEEDED(hg.GetAsStream( &stream, /*fClone*/false )))
|
|
{
|
|
BYTE rgBuf[32];
|
|
ULONG lRead;
|
|
|
|
while(SUCCEEDED(stream->Read( rgBuf, sizeof(rgBuf), &lRead )) && lRead)
|
|
{
|
|
WCHAR rgHex[2*sizeof(rgBuf)+1];
|
|
WCHAR rgTxt[ sizeof(rgBuf)+1];
|
|
BYTE* pIn = rgBuf;
|
|
WCHAR* szOutHex = rgHex;
|
|
WCHAR* szOutTxt = rgTxt;
|
|
|
|
while(lRead-- > 0)
|
|
{
|
|
BYTE c = *pIn++;
|
|
|
|
*szOutHex++ = MPC::NumToHex( c >> 4 );
|
|
*szOutHex++ = MPC::NumToHex( c );
|
|
|
|
*szOutTxt++ = isprint( c ) ? c : '.';
|
|
}
|
|
szOutHex[0] = 0;
|
|
szOutTxt[0] = 0;
|
|
|
|
log.LogRecord( L" %-64s %s\n", rgHex, rgTxt );
|
|
}
|
|
log.LogRecord( L"\n" );
|
|
}
|
|
}
|
|
|
|
void CPCHHelpSession::DEBUG_DumpState_BLOB( /*[in]*/ MPC::FileLog& log ,
|
|
/*[in]*/ CPCHHelpSessionItem* hsi )
|
|
{
|
|
if(SUCCEEDED(hsi->m_state.AcquireState()))
|
|
{
|
|
if(hsi->m_state.m_hgWebBrowser_CONTENTS.Size())
|
|
{
|
|
log.LogRecord( L" m_hgWebBrowser_CONTENTS:\n" );
|
|
DEBUG_DumpState_HG( log, hsi->m_state.m_hgWebBrowser_CONTENTS );
|
|
}
|
|
|
|
if(hsi->m_state.m_hgWebBrowser_HHWINDOW.Size())
|
|
{
|
|
log.LogRecord( L" m_hgWebBrowser_HHWINDOW:\n" );
|
|
DEBUG_DumpState_HG( log, hsi->m_state.m_hgWebBrowser_HHWINDOW );
|
|
}
|
|
|
|
hsi->m_state.ReleaseState( /*fForce*/false );
|
|
}
|
|
}
|
|
|
|
void CPCHHelpSession::DEBUG_DumpState( /*[in]*/ LPCWSTR szText, /*[in]*/ bool fHeader, /*[in]*/ bool fCurrent, /*[in]*/ bool fAll, /*[in]*/ bool fState )
|
|
{
|
|
static int iCount = 0;
|
|
IterConst it;
|
|
MPC::FileLog log;
|
|
|
|
{
|
|
MPC::wstring strLog( c_rgHelpSessionLog ); MPC::SubstituteEnvVariables( strLog );
|
|
|
|
log.SetLocation( strLog.c_str() );
|
|
}
|
|
|
|
log.LogRecord( L"################################################################################ %d %s\n\n", ++iCount, SAFEWSTR( szText ) );
|
|
|
|
if(fHeader)
|
|
{
|
|
log.LogRecord( L" m_dwTravelling : %d\n" , m_dwTravelling );
|
|
log.LogRecord( L" m_fAlreadySaved : %s\n" , m_fAlreadySaved ? L"true" : L"false" );
|
|
log.LogRecord( L" m_fAlreadyCreated : %s\n" , m_fAlreadyCreated ? L"true" : L"false" );
|
|
log.LogRecord( L" m_fOverwrite : %s\n" , m_fOverwrite ? L"true" : L"false" );
|
|
log.LogRecord( L" m_dwIgnore : %d\n" , m_dwIgnore );
|
|
log.LogRecord( L" m_dwNoEvents : %d\n" , m_dwNoEvents );
|
|
log.LogRecord( L" m_iLastIndex : %d\n\n", m_iLastIndex );
|
|
|
|
log.LogRecord( L" ########################################\n\n" );
|
|
}
|
|
|
|
if(fCurrent)
|
|
{
|
|
if(m_hsiCurrentPage)
|
|
{
|
|
log.LogRecord( L" Current URL : %s\n" , SAFEBSTR( m_hsiCurrentPage->m_bstrURL ) );
|
|
log.LogRecord( L" Current iIndexPrev: %d\n" , m_hsiCurrentPage->m_iIndexPrev );
|
|
log.LogRecord( L" Current iIndex : %d\n" , m_hsiCurrentPage->m_iIndex );
|
|
log.LogRecord( L" Current iIndexNext: %d\n\n", m_hsiCurrentPage->m_iIndexNext );
|
|
|
|
log.LogRecord( L" Current m_lContextID : %s\n" , CPCHHelpSessionItem::LookupContext( (HscContext)m_hsiCurrentPage->m_lContextID ) );
|
|
log.LogRecord( L" Current m_bstrContextInfo: %s\n" , SAFEBSTR ( m_hsiCurrentPage->m_bstrContextInfo ) );
|
|
log.LogRecord( L" Current m_bstrContextURL : %s\n\n", SAFEBSTR ( m_hsiCurrentPage->m_bstrContextURL ) );
|
|
|
|
if(fState)
|
|
{
|
|
DEBUG_DumpState_BLOB( log, m_hsiCurrentPage );
|
|
}
|
|
|
|
log.LogRecord( L" ########################################\n\n" );
|
|
|
|
}
|
|
}
|
|
|
|
if(fAll)
|
|
{
|
|
for(it = m_lstVisitedPages.begin(); it != m_lstVisitedPages.end(); it++)
|
|
{
|
|
CPCHHelpSessionItem* hsi = *it;
|
|
|
|
log.LogRecord( L" URL : %s\n" , SAFEBSTR( hsi->m_bstrURL ) );
|
|
log.LogRecord( L" iIndexPrev: %d\n" , hsi->m_iIndexPrev );
|
|
log.LogRecord( L" iIndex : %d\n" , hsi->m_iIndex );
|
|
log.LogRecord( L" iIndexNext: %d\n" , hsi->m_iIndexNext );
|
|
log.LogRecord( L" bstrTitle : %s\n\n", SAFEBSTR( hsi->m_bstrTitle ) );
|
|
|
|
log.LogRecord( L" lContextID : %s\n" , CPCHHelpSessionItem::LookupContext( (HscContext)hsi->m_lContextID ) );
|
|
log.LogRecord( L" bstrContextInfo: %s\n" , SAFEBSTR ( hsi->m_bstrContextInfo ) );
|
|
log.LogRecord( L" bstrContextURL : %s\n\n", SAFEBSTR ( hsi->m_bstrContextURL ) );
|
|
|
|
if(fState)
|
|
{
|
|
DEBUG_DumpState_BLOB( log, hsi );
|
|
}
|
|
}
|
|
}
|
|
|
|
log.LogRecord( L"\n\n" );
|
|
}
|
|
|
|
void CPCHHelpSession::DEBUG_DumpSavedPages()
|
|
{
|
|
IterConst it;
|
|
MPC::FileLog log;
|
|
|
|
{
|
|
MPC::wstring strLog( c_rgHelpSessionLog ); MPC::SubstituteEnvVariables( strLog );
|
|
|
|
log.SetLocation( strLog.c_str() );
|
|
}
|
|
|
|
for(int pass=0; pass<2; pass++)
|
|
{
|
|
log.LogRecord( L"################################################################################ %sSAVED PAGES\n\n", pass == 0 ? L"" : L"NON-" );
|
|
|
|
for(it = m_lstVisitedPages.begin(); it != m_lstVisitedPages.end(); it++)
|
|
{
|
|
CPCHHelpSessionItem* hsi = *it;
|
|
|
|
if(hsi->m_fSaved == (pass == 0))
|
|
{
|
|
long lDuration = 86400.0 * ( hsi->m_dDuration - hsi->m_dLastVisited ); // Number of milliseconds for the page.
|
|
|
|
log.LogRecord( L" lDuration : %ld\n" , lDuration );
|
|
log.LogRecord( L" URL : %s\n" , SAFEBSTR ( hsi->m_bstrURL ) );
|
|
log.LogRecord( L" bstrTitle : %s\n" , SAFEBSTR ( hsi->m_bstrTitle ) );
|
|
log.LogRecord( L" lContextID : %s\n" , CPCHHelpSessionItem::LookupContext( (HscContext)hsi->m_lContextID ) );
|
|
log.LogRecord( L" bstrContextInfo: %s\n" , SAFEBSTR ( hsi->m_bstrContextInfo ) );
|
|
log.LogRecord( L" bstrContextURL : %s\n\n", SAFEBSTR ( hsi->m_bstrContextURL ) );
|
|
}
|
|
}
|
|
|
|
log.LogRecord( L"\n\n" );
|
|
}
|
|
}
|
|
#endif
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// ITSS.DLL is broken under IA64....
|
|
//
|
|
#ifdef _IA64_
|
|
#define HELPSESSION_STORAGETOUSE false
|
|
#else
|
|
#define HELPSESSION_STORAGETOUSE true
|
|
#endif
|
|
|
|
CPCHHelpSession::CPCHHelpSession() : m_disk( STGM_READWRITE, /*fITSS*/HELPSESSION_STORAGETOUSE )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::CPCHHelpSession" );
|
|
|
|
m_parent = NULL; // CPCHHelpCenterExternal* m_parent;
|
|
//
|
|
// MPC::wstring m_szBackupFile;
|
|
// MPC::StorageObject m_disk;
|
|
m_dStartOfSession = MPC::GetLocalTime(); // DATE m_dStartOfSession;
|
|
//
|
|
// CComPtr<IUrlHistoryStg> m_pIHistory;
|
|
//
|
|
// MPC::WStringUCList m_lstIgnore;
|
|
// TitleMap m_mapTitles;
|
|
// List m_lstVisitedPages;
|
|
// List m_lstCachedVisitedPages;
|
|
// CComPtr<CPCHHelpSessionItem> m_hsiCurrentPage;
|
|
m_dwTravelling = 0; // DWORD m_dwTravelling;
|
|
m_fAlreadySaved = false; // bool m_fAlreadySaved;
|
|
m_fAlreadyCreated = false; // bool m_fAlreadyCreated;
|
|
m_fOverwrite = false; // bool m_fOverwrite;
|
|
m_dwIgnore = 0; // DWORD m_dwIgnore;
|
|
m_dwNoEvents = 0; // DWORD m_dwNoEvents;
|
|
m_dLastNavigation = 0.0; // DATE m_dLastNavigation;
|
|
m_iLastIndex = 0; // int m_iLastIndex;
|
|
//
|
|
m_lContextID = HSCCONTEXT_INVALID; // long m_lContextID;
|
|
// CComBSTR m_bstrContextInfo;
|
|
// CComBSTR m_bstrContextURL;
|
|
//
|
|
m_fPossibleBack = false; // bool m_fPossibleBack;
|
|
m_dwPossibleBack = 0; // DWORD m_dwPossibleBack;
|
|
}
|
|
|
|
CPCHHelpSession::~CPCHHelpSession()
|
|
{
|
|
Passivate();
|
|
}
|
|
|
|
HRESULT CPCHHelpSession::Initialize( /*[in]*/ CPCHHelpCenterExternal* parent )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::Initialize" );
|
|
|
|
HRESULT hr;
|
|
MPC::wstring szFile;
|
|
HANDLE hFile = INVALID_HANDLE_VALUE;
|
|
|
|
|
|
m_parent = parent;
|
|
|
|
|
|
//
|
|
// Copy live file onto temporary one or create a new archive.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::GetUserWritablePath( szFile, c_szPersistFile ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::MakeDir ( szFile ));
|
|
|
|
|
|
if(parent == NULL) // No parent, point to the user file and recreate it.
|
|
{
|
|
m_disk = szFile.c_str();
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_disk.Create());
|
|
}
|
|
else
|
|
{
|
|
#ifdef DEBUG
|
|
{
|
|
MPC::wstring strLog( c_rgHelpSessionLog ); MPC::SubstituteEnvVariables( strLog );
|
|
|
|
MPC::DeleteFile( strLog );
|
|
}
|
|
#endif
|
|
|
|
try
|
|
{
|
|
//
|
|
// Prepare temporary file.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::GetTemporaryFileName( m_szBackupFile )); m_disk = m_szBackupFile.c_str();
|
|
|
|
if(MPC::FileSystemObject::IsFile( szFile.c_str() ))
|
|
{
|
|
if(SUCCEEDED(hr = MPC::CopyFile( szFile, m_szBackupFile )))
|
|
{
|
|
hr = m_disk.Exists();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
hr = E_FAIL;
|
|
}
|
|
|
|
if(FAILED(hr))
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_disk.Create());
|
|
}
|
|
|
|
|
|
if(FAILED(Load()))
|
|
{
|
|
(void)Erase();
|
|
}
|
|
}
|
|
catch(...)
|
|
{
|
|
//
|
|
// If the file is corrupted, ITSS will crash. Delete the file and exit.
|
|
//
|
|
MPC::DeleteFile( szFile, /*fForce*/true, /*fDelayed*/true );
|
|
|
|
::ExitProcess(0);
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
void CPCHHelpSession::Passivate()
|
|
{
|
|
(void)Erase();
|
|
|
|
m_parent = NULL;
|
|
|
|
m_disk.Release();
|
|
|
|
(void)MPC::RemoveTemporaryFile( m_szBackupFile );
|
|
}
|
|
|
|
////////////////////
|
|
|
|
HRESULT CPCHHelpSession::Persist()
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::Persist" );
|
|
|
|
HRESULT hr;
|
|
|
|
//
|
|
// Before shutdown, update the time information for the current entry.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, LeaveCurrentPage());
|
|
|
|
(void)Save();
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
////////////////////
|
|
|
|
HRESULT CPCHHelpSession::Load()
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::Load" );
|
|
|
|
HRESULT hr;
|
|
MPC::StorageObject* child;
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, ItemState_GetIndexObject( /*fCreate*/false, child ));
|
|
if(child)
|
|
{
|
|
CComPtr<IStream> stream;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, child->GetStream( stream ));
|
|
if(stream)
|
|
{
|
|
CComPtr<CPCHHelpSessionItem> hsi;
|
|
MPC::Serializer_IStream streamReal( stream );
|
|
MPC::Serializer_Buffering streamBuf ( streamReal );
|
|
DWORD dwVer;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf >> dwVer ); if(dwVer != l_dwVersion) __MPC_SET_ERROR_AND_EXIT(hr, E_FAIL);
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf >> m_iLastIndex);
|
|
|
|
while(1)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, AllocateItem( /*fNew*/false, /*fLink*/false, /*fNewIndex*/false, hsi ));
|
|
|
|
if(FAILED(hsi->Load( streamBuf ))) break;
|
|
|
|
m_lstVisitedPages.push_back( hsi.Detach() );
|
|
}
|
|
}
|
|
}
|
|
|
|
//
|
|
// Cleanup broken links.
|
|
//
|
|
{
|
|
CPCHHelpSessionItem* hsi;
|
|
CPCHHelpSessionItem* hsiLast = NULL;
|
|
IterConst it;
|
|
|
|
//
|
|
// First of all, reset broken Forward and Backward pointers.
|
|
//
|
|
for(it = m_lstVisitedPages.begin(); it != m_lstVisitedPages.end(); it++)
|
|
{
|
|
hsi = *it;
|
|
|
|
if(FindPage( hsi->m_iIndexPrev ) == NULL) hsi->m_iIndexPrev = CPCHHelpSessionItem::NO_LINK;
|
|
if(FindPage( hsi->m_iIndexNext ) == NULL) hsi->m_iIndexNext = CPCHHelpSessionItem::NO_LINK;
|
|
}
|
|
|
|
//
|
|
// Then, link in some wayFirst of all, reset broken Forward and Backward pointers.
|
|
//
|
|
// REMEMBER, the list is actually a reverse list, so the "Previous" element will follow in the list.
|
|
//
|
|
for(it = m_lstVisitedPages.begin(); it != m_lstVisitedPages.end(); it++)
|
|
{
|
|
hsi = *it;
|
|
|
|
//
|
|
// We saw an item not linked, so let's link it!
|
|
//
|
|
if(hsiLast)
|
|
{
|
|
hsiLast->m_iIndexPrev = hsi->m_iIndex; hsiLast = NULL;
|
|
}
|
|
|
|
//
|
|
// Oh, unlinked item, remember pointer, probably we can link it to the next one ("previous" actually, see above).
|
|
//
|
|
if(hsi->m_iIndexPrev == CPCHHelpSessionItem::NO_LINK)
|
|
{
|
|
hsiLast = hsi;
|
|
}
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CPCHHelpSession::Save()
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::Save" );
|
|
|
|
HRESULT hr;
|
|
MPC::StorageObject* child;
|
|
int iCount = NUM_OF_ENTRIES_TO_PERSIST;
|
|
List lstObject;
|
|
IterConst it;
|
|
|
|
|
|
//
|
|
// Initialize flags for deletion of unused slots.
|
|
//
|
|
for(it = m_lstVisitedPages.begin(); it != m_lstVisitedPages.end(); it++)
|
|
{
|
|
CPCHHelpSessionItem* hsi = *it;
|
|
|
|
hsi->m_state.ReleaseState( /*fForce*/true );
|
|
hsi->m_fSaved = false;
|
|
}
|
|
|
|
|
|
#ifdef HSS_RPRD
|
|
//
|
|
// If the registry value is set, create a new XML file for the current session.
|
|
//
|
|
{
|
|
DWORD dwDumpSession = 0;
|
|
bool fFound;
|
|
|
|
(void)MPC::RegKey_Value_Read( dwDumpSession, fFound, HC_REGISTRY_HELPCTR, L"DumpHelpSession", HKEY_LOCAL_MACHINE );
|
|
|
|
if(dwDumpSession)
|
|
{
|
|
(void)DumpSession();
|
|
}
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Get the list of items to return.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, FilterPages( HS_READ, lstObject ));
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, ItemState_GetIndexObject( /*fCreate*/true, child ));
|
|
if(child)
|
|
{
|
|
CComPtr<IStream> stream;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, child->GetStream( stream ));
|
|
if(stream)
|
|
{
|
|
MPC::Serializer_IStream streamReal( stream );
|
|
MPC::Serializer_Buffering streamBuf ( streamReal );
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf << l_dwVersion );
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf << m_iLastIndex);
|
|
|
|
for(it = lstObject.begin(); it != lstObject.end() && iCount > 0; it++)
|
|
{
|
|
CPCHHelpSessionItem* hsi = *it;
|
|
|
|
//
|
|
// Don't save entries without a title.
|
|
//
|
|
if(hsi->m_bstrTitle.Length() == 0) continue;
|
|
|
|
//
|
|
// Don't save entries from the exclude list.
|
|
//
|
|
for(int i=0; i<ARRAYSIZE(c_rgExclude); i++)
|
|
{
|
|
LPCWSTR szURL = hsi->GetURL();
|
|
|
|
if(szURL && !_wcsnicmp( szURL, c_rgExclude[i], wcslen( c_rgExclude[i] ) )) break;
|
|
}
|
|
if(i != ARRAYSIZE(c_rgExclude)) continue;
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, hsi->Save( streamBuf ));
|
|
iCount--;
|
|
}
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf.Flush());
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create a new instance of the HelpSession and copy all of valid entries into it.
|
|
//
|
|
{
|
|
CComPtr<CPCHHelpSession> hsCopy;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &hsCopy ));
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, hsCopy->Initialize( NULL ));
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, Clone( *hsCopy ));
|
|
}
|
|
|
|
DEBUG_DumpSavedPages();
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
static HRESULT local_CopyStream( /*[in]*/ MPC::StorageObject* childSrc ,
|
|
/*[in]*/ MPC::StorageObject* childDst )
|
|
{
|
|
__HCP_FUNC_ENTRY( "local_CopyStream" );
|
|
|
|
HRESULT hr;
|
|
|
|
if(childSrc && childDst)
|
|
{
|
|
CComPtr<IStream> streamSrc;
|
|
CComPtr<IStream> streamDst;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, childSrc->Rewind ());
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, childDst->Rewind ());
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, childDst->Truncate());
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, childSrc->GetStream( streamSrc ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, childDst->GetStream( streamDst ));
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::BaseStream::TransferData( streamSrc, streamDst ));
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CPCHHelpSession::Clone( /*[in]*/ CPCHHelpSession& hsCopy )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::Clone" );
|
|
|
|
HRESULT hr;
|
|
MPC::StorageObject* childSrc;
|
|
MPC::StorageObject* childDst;
|
|
MPC::wstring szFile;
|
|
IterConst it;
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, ItemState_GetIndexObject( /*fCreate*/false, childSrc ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, hsCopy.ItemState_GetIndexObject( /*fCreate*/true , childDst ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, local_CopyStream ( childSrc, childDst ));
|
|
|
|
//
|
|
// Purge unused slots.
|
|
//
|
|
for(it = m_lstVisitedPages.begin(); it != m_lstVisitedPages.end(); it++)
|
|
{
|
|
CPCHHelpSessionItem* hsi = *it;
|
|
|
|
if(hsi->m_fSaved)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, ItemState_GetStorageObject( hsi->GetIndex(), /*fCreate*/false, childSrc ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, hsCopy.ItemState_GetStorageObject( hsi->GetIndex(), /*fCreate*/true , childDst ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, local_CopyStream ( childSrc, childDst ));
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
|
|
#ifdef HSS_RPRD
|
|
|
|
HRESULT CPCHHelpSession::DumpSession()
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::DumpSession" );
|
|
|
|
HRESULT hr;
|
|
MPC::XmlUtil xml;
|
|
CComPtr<IXMLDOMNode> xdn;
|
|
bool fGot = false;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.New( L"TravelLog" ));
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.GetRoot( &xdn ));
|
|
|
|
for(IterConst it = m_lstVisitedPages.begin(); it != m_lstVisitedPages.end(); it++)
|
|
{
|
|
CPCHHelpSessionItem* hsi = *it;
|
|
XMLHelpSessionItem dmp;
|
|
|
|
if(m_dStartOfSession > hsi->m_dLastVisited) continue;
|
|
|
|
dmp.m_ths = hsi->m_ths;
|
|
dmp.m_iIndex = hsi->m_iIndex;
|
|
dmp.m_dLastVisited = hsi->m_dLastVisited;
|
|
dmp.m_lDuration = 86400.0 * ( hsi->m_dDuration - hsi->m_dLastVisited ); // Number of milliseconds for the page.
|
|
|
|
dmp.m_bstrURL = hsi->m_bstrURL;
|
|
dmp.m_bstrTitle = hsi->m_bstrTitle;
|
|
|
|
dmp.m_bstrContextID = CPCHHelpSessionItem::LookupContext( (HscContext)hsi->m_lContextID );
|
|
dmp.m_bstrContextInfo = hsi->m_bstrContextInfo;
|
|
dmp.m_bstrContextURL = hsi->m_bstrContextURL;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::Config::SaveSubNode( &dmp, xdn ));
|
|
|
|
fGot = true;
|
|
}
|
|
|
|
if(fGot)
|
|
{
|
|
SYSTEMTIME st;
|
|
WCHAR rgTime[512];
|
|
MPC::wstring strFile;
|
|
|
|
//
|
|
// Append current time.
|
|
//
|
|
// <FileName>__<Year>_<Month>_<Day>_<hour>-<minute>-<second>
|
|
//
|
|
::GetLocalTime( &st );
|
|
swprintf( rgTime, L"__%04u-%02u-%02u_%02u-%02u-%02u.xml", st.wYear, st.wMonth, st.wDay, st.wHour, st.wMinute, st.wSecond );
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::GetUserWritablePath( strFile, HC_ROOT_HELPCTR L"\\RPRD" )); strFile.append( rgTime );
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::MakeDir( strFile ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, xml.Save ( strFile.c_str() ));
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
#endif
|
|
|
|
////////////////////////////////////////
|
|
|
|
HRESULT CPCHHelpSession::ItemState_GetIndexObject( /*[in]*/ bool fCreate ,
|
|
/*[out]*/ MPC::StorageObject*& child )
|
|
{
|
|
return m_disk.GetChild( c_szINDEX, child, STGM_READWRITE, fCreate ? STGTY_STREAM : 0 );
|
|
}
|
|
|
|
HRESULT CPCHHelpSession::ItemState_GetStorageObject( /*[in]*/ int iIndex ,
|
|
/*[in]*/ bool fCreate ,
|
|
/*[out]*/ MPC::StorageObject*& child )
|
|
{
|
|
WCHAR rgName[64]; swprintf( rgName, L"STATE_%d", iIndex );
|
|
|
|
return m_disk.GetChild( rgName, child, STGM_READWRITE, fCreate ? STGTY_STREAM : 0 );
|
|
}
|
|
|
|
HRESULT CPCHHelpSession::ItemState_CreateStream( /*[in]*/ int iIndex ,
|
|
/*[out]*/ CComPtr<IStream>& stream )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::ItemState_CreateStream" );
|
|
|
|
HRESULT hr;
|
|
MPC::StorageObject* child;
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, ItemState_GetStorageObject( iIndex, /*fCreate*/true, child ));
|
|
if(child)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, child->GetStream( stream ));
|
|
}
|
|
|
|
if(!stream)
|
|
{
|
|
__MPC_SET_ERROR_AND_EXIT(hr, STG_E_FILENOTFOUND);
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CPCHHelpSession::ItemState_GetStream( /*[in]*/ int iIndex ,
|
|
/*[out]*/ CComPtr<IStream>& stream )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::ItemState_GetStream" );
|
|
|
|
HRESULT hr;
|
|
MPC::StorageObject* child;
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, ItemState_GetStorageObject( iIndex, /*fCreate*/false, child ));
|
|
if(child)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, child->GetStream( stream ));
|
|
}
|
|
|
|
if(!stream)
|
|
{
|
|
__MPC_SET_ERROR_AND_EXIT(hr, STG_E_FILENOTFOUND);
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CPCHHelpSession::ItemState_DeleteStream( /*[in]*/ int iIndex )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::ItemState_DeleteStream" );
|
|
|
|
HRESULT hr;
|
|
MPC::StorageObject* child;
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, ItemState_GetStorageObject( iIndex, /*fCreate*/false, child ));
|
|
if(child)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, child->Delete());
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
CPCHHelpSessionItem* CPCHHelpSession::FindPage( /*[in]*/ BSTR bstrURL )
|
|
{
|
|
IterConst it;
|
|
|
|
//
|
|
// First of all, look if the page is already present.
|
|
//
|
|
for(it = m_lstVisitedPages.begin(); it != m_lstVisitedPages.end(); it++)
|
|
{
|
|
if((*it)->SameURL( bstrURL))
|
|
{
|
|
return *it;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
CPCHHelpSessionItem* CPCHHelpSession::FindPage( /*[in]*/ IPCHHelpSessionItem* pHSI )
|
|
{
|
|
IterConst it;
|
|
|
|
//
|
|
// First of all, look if the page is already present.
|
|
//
|
|
for(it = m_lstVisitedPages.begin(); it != m_lstVisitedPages.end(); it++)
|
|
{
|
|
if((*it) == pHSI)
|
|
{
|
|
return *it;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
CPCHHelpSessionItem* CPCHHelpSession::FindPage( /*[in]*/ int iIndex )
|
|
{
|
|
IterConst it;
|
|
|
|
//
|
|
// First of all, look if the page is already present.
|
|
//
|
|
for(it = m_lstVisitedPages.begin(); it != m_lstVisitedPages.end(); it++)
|
|
{
|
|
if((*it)->m_iIndex == iIndex)
|
|
{
|
|
return *it;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
HRESULT CPCHHelpSession::Erase()
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::Erase" );
|
|
|
|
//
|
|
// Release all the items.
|
|
//
|
|
MPC::ReleaseAll( m_lstVisitedPages );
|
|
MPC::ReleaseAll( m_lstCachedVisitedPages );
|
|
m_hsiCurrentPage.Release();
|
|
|
|
ResetTitles();
|
|
|
|
|
|
__HCP_FUNC_EXIT(S_OK);
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
|
|
HRESULT CPCHHelpSession::ResetTitles()
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::ResetTitles" );
|
|
|
|
HRESULT hr;
|
|
MPC::SmartLock<_ThreadModel> lock( this );
|
|
|
|
|
|
m_mapTitles.clear();
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CPCHHelpSession::RecordTitle( /*[in]*/ BSTR bstrURL ,
|
|
/*[in]*/ BSTR bstrTitle ,
|
|
/*[in]*/ bool fStrong )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::RecordTitle" );
|
|
|
|
HRESULT hr;
|
|
MPC::SmartLock<_ThreadModel> lock( this );
|
|
|
|
|
|
//
|
|
// The binding is not strong, so check if there's already a title for the url.
|
|
//
|
|
if(!STRINGISPRESENT(bstrTitle))
|
|
{
|
|
//
|
|
// If there's already a previous page with the same URL, use its title.
|
|
//
|
|
CPCHHelpSessionItem* hsi = FindPage( bstrURL );
|
|
|
|
if(hsi && hsi->m_bstrTitle.Length())
|
|
{
|
|
bstrTitle = hsi->m_bstrTitle;
|
|
}
|
|
}
|
|
|
|
if(STRINGISPRESENT(bstrTitle))
|
|
{
|
|
TitleEntry& entry = m_mapTitles[ SAFEBSTR( bstrURL ) ];
|
|
|
|
//
|
|
// Only update the title if the new one is more "powerful".
|
|
//
|
|
if(entry.m_fStrong == false || fStrong)
|
|
{
|
|
entry.m_szTitle = bstrTitle;
|
|
entry.m_fStrong = fStrong;
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CPCHHelpSession::LookupTitle( /*[in ]*/ BSTR bstrURL ,
|
|
/*[out]*/ CComBSTR& bstrTitle ,
|
|
/*[in ]*/ bool fUseIECache )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::LookupTitle" );
|
|
|
|
HRESULT hr;
|
|
MPC::SmartLock<_ThreadModel> lock( this );
|
|
|
|
if(fUseIECache)
|
|
{
|
|
if(!m_pIHistory)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, ::CoCreateInstance( CLSID_CUrlHistory, NULL, CLSCTX_INPROC_SERVER, IID_IUrlHistoryStg, (LPVOID*)&m_pIHistory ));
|
|
}
|
|
|
|
if(m_pIHistory)
|
|
{
|
|
STATURL stat;
|
|
|
|
if(SUCCEEDED(m_pIHistory->QueryUrl( bstrURL, 0, &stat )))
|
|
{
|
|
bstrTitle = stat.pwcsTitle;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
TitleIter it;
|
|
|
|
|
|
it = m_mapTitles.find( MPC::wstring( SAFEWSTR( bstrURL ) ) );
|
|
if(it != m_mapTitles.end())
|
|
{
|
|
bstrTitle = it->second.m_szTitle.c_str();
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
////////////////////////////////////////
|
|
|
|
HRESULT CPCHHelpSession::FilterPages( /*[in]*/ HS_MODE hsMode ,
|
|
/*[out]*/ List& lstObject )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::FilterPages" );
|
|
|
|
HRESULT hr;
|
|
List lstAlreadySeen;
|
|
IterConst it;
|
|
|
|
|
|
for(it = m_lstVisitedPages.begin(); it != m_lstVisitedPages.end(); it++)
|
|
{
|
|
CPCHHelpSessionItem* hsi = *it;
|
|
|
|
if(hsMode == HS_READ)
|
|
{
|
|
IterConst itRead;
|
|
|
|
if(hsi->SeenLongEnough( REMEMBER_PAGE_DELAY ) != true) continue;
|
|
|
|
//
|
|
// Make sure there aren't duplicate entries.
|
|
//
|
|
for(itRead = lstAlreadySeen.begin(); itRead != lstAlreadySeen.end(); itRead++)
|
|
{
|
|
if(hsi->SameURL( *itRead )) break;
|
|
}
|
|
if(itRead != lstAlreadySeen.end())
|
|
{
|
|
continue;
|
|
}
|
|
|
|
|
|
//
|
|
// Add the new URL to the list of seen URLs.
|
|
//
|
|
lstAlreadySeen.push_back( hsi );
|
|
}
|
|
|
|
lstObject.push_back( hsi );
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT CPCHHelpSession::AllocateItem( /*[in ]*/ bool fNew ,
|
|
/*[in ]*/ bool fLink ,
|
|
/*[in ]*/ bool fNewIndex ,
|
|
/*[out]*/ CComPtr<CPCHHelpSessionItem>& hsi )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::AllocateItem" );
|
|
|
|
HRESULT hr;
|
|
CPCHHelpSessionItem* hsiPrev = m_hsiCurrentPage;
|
|
|
|
//
|
|
// If we are flagged to recycle the current item, let's do so.
|
|
//
|
|
if(fNew && fLink && m_fOverwrite)
|
|
{
|
|
m_fOverwrite = false;
|
|
|
|
if(hsiPrev)
|
|
{
|
|
hsi = hsiPrev;
|
|
|
|
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Create a new item and link it to the system.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &hsi )); hsi->Initialize( this, /*fNew*/fNew );
|
|
|
|
//
|
|
// Build the chain of predecessor-successor.
|
|
//
|
|
if(fNewIndex)
|
|
{
|
|
hsi->m_iIndex = m_iLastIndex++;
|
|
}
|
|
|
|
if(fLink && hsiPrev && hsi->m_ths == hsiPrev->m_ths)
|
|
{
|
|
hsiPrev->m_iIndexNext = hsi ->m_iIndex;
|
|
hsi ->m_iIndexPrev = hsiPrev->m_iIndex;
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CPCHHelpSession::SetCurrentItem( /*[in]*/ bool fLink, /*[in]*/ CPCHHelpSessionItem* hsi )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::SetCurrentItem" );
|
|
|
|
HRESULT hr;
|
|
|
|
if(hsi != m_hsiCurrentPage)
|
|
{
|
|
//
|
|
// When navigating to a new page, "Leave" the previous one and "Enter" the new one.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, LeaveCurrentPage());
|
|
|
|
m_hsiCurrentPage = hsi; __MPC_EXIT_IF_METHOD_FAILS(hr, m_hsiCurrentPage->Enter());
|
|
|
|
if(fLink)
|
|
{
|
|
m_lstVisitedPages.push_front( hsi ); hsi->AddRef();
|
|
}
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, AppendToCached( hsi ));
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CPCHHelpSession::AppendToCached( /*[in]*/ CPCHHelpSessionItem* hsi )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::AppendToCached" );
|
|
|
|
HRESULT hr;
|
|
|
|
if(hsi)
|
|
{
|
|
IterConst it;
|
|
IterConst itOldest;
|
|
bool fGot = false;
|
|
CPCHHelpSessionItem* hsiOldest = NULL;
|
|
|
|
for(it = m_lstCachedVisitedPages.begin(); it != m_lstCachedVisitedPages.end(); it++)
|
|
{
|
|
CPCHHelpSessionItem* hsiObj = *it;
|
|
|
|
if(hsiObj == hsi) { fGot = true; break; }
|
|
|
|
if(!hsiOldest || hsiOldest->m_dLastVisited > hsiObj->m_dLastVisited)
|
|
{
|
|
itOldest = it;
|
|
hsiOldest = hsiObj;
|
|
}
|
|
}
|
|
|
|
if(fGot == false)
|
|
{
|
|
if(m_lstCachedVisitedPages.size() > l_iMaxCachedItems && hsiOldest)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, hsiOldest->m_state.ReleaseState( /*fForce*/false ));
|
|
|
|
m_lstCachedVisitedPages.erase( itOldest ); hsiOldest->Release();
|
|
}
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, hsi->m_state.AcquireState());
|
|
|
|
m_lstCachedVisitedPages.push_front( hsi ); hsi->AddRef();
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CPCHHelpSession::RegisterContextSwitch( /*[in ]*/ HscContext iVal ,
|
|
/*[in ]*/ BSTR bstrInfo ,
|
|
/*[in ]*/ BSTR bstrURL ,
|
|
/*[out]*/ CPCHHelpSessionItem* *pVal )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::RegisterContextSwitch" );
|
|
|
|
HRESULT hr;
|
|
|
|
if(pVal)
|
|
{
|
|
CComPtr<CPCHHelpSessionItem> hsi;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, AllocateItem( /*fNew*/true, /*fLink*/false, /*fNewIndex*/false, hsi ));
|
|
|
|
hsi->m_lContextID = iVal;
|
|
hsi->m_bstrContextInfo = bstrInfo;
|
|
hsi->m_bstrContextURL = bstrURL;
|
|
|
|
*pVal = hsi.Detach();
|
|
}
|
|
else
|
|
{
|
|
m_lContextID = iVal;
|
|
m_bstrContextInfo = bstrInfo;
|
|
m_bstrContextURL = bstrURL;
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CPCHHelpSession::RecordNavigationInAdvance( /*[in]*/ BSTR bstrURL )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::RecordNavigationInAdvance" );
|
|
|
|
HRESULT hr;
|
|
CComPtr<CPCHHelpSessionItem> hsi;
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, AllocateItem( /*fNew*/true, /*fLink*/true, /*fNewIndex*/true, hsi ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, hsi->put_URL ( bstrURL ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, hsi->put_Title( NULL ));
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, SetCurrentItem( /*fLink*/true, hsi ));
|
|
m_fAlreadyCreated = true;
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CPCHHelpSession::DuplicateNavigation()
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::DuplicateNavigation" );
|
|
|
|
HRESULT hr;
|
|
CComPtr<CPCHHelpSessionItem> hsi;
|
|
bool fAcquired = false;
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, AllocateItem( /*fNew*/true, /*fLink*/true, /*fNewIndex*/true, hsi ));
|
|
|
|
if(m_hsiCurrentPage)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, hsi->HistoryClone( /*fContext*/false, m_hsiCurrentPage )); fAcquired = true;
|
|
}
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, SetCurrentItem( /*fLink*/true, hsi ));
|
|
m_fAlreadyCreated = true;
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
if(fAcquired && hsi) (void)hsi->m_state.ReleaseState( /*fForce*/false );
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CPCHHelpSession::CancelNavigation()
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::CancelNavigation" );
|
|
|
|
HRESULT hr;
|
|
|
|
if(m_fAlreadyCreated) // The navigation has been cancelled but an entry was already created. Recycle it.
|
|
{
|
|
m_fOverwrite = true;
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
void CPCHHelpSession::SetThreshold()
|
|
{
|
|
m_dLastNavigation = MPC::GetSystemTimeEx( /*fHighPrecision*/false );
|
|
}
|
|
|
|
void CPCHHelpSession::CancelThreshold()
|
|
{
|
|
m_dLastNavigation = 0.0;
|
|
}
|
|
|
|
bool CPCHHelpSession::HasThresholdExpired()
|
|
{
|
|
DATE dStart = MPC::GetSystemTimeEx( /*fHighPrecision*/false );
|
|
|
|
#ifdef DEBUG
|
|
if(m_dLastNavigation)
|
|
{
|
|
DebugLog( L"Threshold: %g\n", (dStart - m_dLastNavigation) * 86400 );
|
|
}
|
|
#endif
|
|
|
|
if(m_dLastNavigation && (dStart - m_dLastNavigation) < l_dNewNavigationThreshold) return false;
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
bool CPCHHelpSession::IsUrlToIgnore( /*[in]*/ LPCWSTR szURL, /*[in]*/ bool fRemove )
|
|
{
|
|
if(szURL)
|
|
{
|
|
MPC::WStringUCIter it;
|
|
MPC::wstringUC str( szURL );
|
|
|
|
for(it = m_lstIgnore.begin(); it != m_lstIgnore.end(); it++)
|
|
{
|
|
if(str == *it)
|
|
{
|
|
if(fRemove) m_lstIgnore.erase( it );
|
|
|
|
return true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
HRESULT CPCHHelpSession::IgnoreUrl( /*[in]*/ LPCWSTR szURL )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::IgnoreUrl" );
|
|
|
|
HRESULT hr;
|
|
|
|
m_lstIgnore.push_back( szURL );
|
|
|
|
hr = S_OK;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CPCHHelpSession::StartNavigation( /*[in]*/ BSTR bstrURL ,
|
|
/*[in]*/ HscPanel idPanel )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::StartNavigation" );
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
if(IsUrlToIgnore( bstrURL, /*fRemove*/false ))
|
|
{
|
|
DebugLog( L"StartNavigation: IsUrlToIgnore %s\n", bstrURL );
|
|
__MPC_SET_ERROR_AND_EXIT(hr, S_FALSE);
|
|
}
|
|
|
|
//
|
|
// For now, we just consider content navigations.
|
|
//
|
|
if(idPanel != HSCPANEL_CONTENTS &&
|
|
idPanel != HSCPANEL_HHWINDOW )
|
|
{
|
|
DebugLog( L"StartNavigation: Wrong panel %d\n", (int)idPanel );
|
|
__MPC_SET_ERROR_AND_EXIT(hr, S_FALSE);
|
|
}
|
|
|
|
#ifdef DEBUG
|
|
{
|
|
WCHAR rgBuf[1024]; _snwprintf( rgBuf, MAXSTRLEN(rgBuf), L"StartNavigation: start %s", SAFEWSTR( bstrURL ) );
|
|
|
|
DEBUG_DumpState( rgBuf, /*fHeader*/true, /*fCurrent*/false, /*fAll*/false, /*fState*/false );
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// When we navigate away from the Homepage, let's change the context....
|
|
//
|
|
{
|
|
static const CComBSTR c_bstrURL_Home( L"hcp://system/HomePage.htm" );
|
|
|
|
if(m_lContextID == HSCCONTEXT_HOMEPAGE && MPC::StrICmp( bstrURL, c_bstrURL_Home ) != 0)
|
|
{
|
|
m_lContextID = HSCCONTEXT_FULLWINDOW;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check recursion.
|
|
//
|
|
if(m_dwTravelling++)
|
|
{
|
|
DebugLog( L"StartNavigation: Travelling %d\n", (int)m_dwTravelling );
|
|
SetThreshold();
|
|
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
|
}
|
|
|
|
//
|
|
// If it hasn't passed enough time, ignore navigation!
|
|
//
|
|
if(HasThresholdExpired() == false)
|
|
{
|
|
if(m_dwIgnore == 0) // But only if we are not inside another controlled navigation!
|
|
{
|
|
m_dwIgnore++;
|
|
m_dwNoEvents++;
|
|
|
|
DebugLog( L"StartNavigation: Threshold Expired\n" );
|
|
}
|
|
}
|
|
SetThreshold();
|
|
|
|
//
|
|
// Flag set, so we don't create a new node.
|
|
//
|
|
if(m_dwIgnore)
|
|
{
|
|
DebugLog( L"StartNavigation: Ignore Start %d\n", (int)m_dwIgnore );
|
|
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
|
}
|
|
|
|
if(m_fAlreadyCreated == false || m_hsiCurrentPage == NULL)
|
|
{
|
|
CComPtr<CPCHHelpSessionItem> hsi;
|
|
|
|
DebugLog( L"%%%%%%%%%%%%%%%%%%%% NEW ENTRY %s\n", SAFEBSTR( bstrURL ) );
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, AllocateItem( /*fNew*/true, /*fLink*/true, /*fNewIndex*/true, hsi ));
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, SetCurrentItem( /*fLink*/true, hsi ));
|
|
}
|
|
else
|
|
{
|
|
DebugLog( L"StartNavigation: Recycle entry\n" );
|
|
}
|
|
|
|
if(m_hsiCurrentPage)
|
|
{
|
|
m_hsiCurrentPage->m_fInitialized = true;
|
|
m_hsiCurrentPage->m_fUseHH = (idPanel == HSCPANEL_HHWINDOW);
|
|
m_fAlreadyCreated = false;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_hsiCurrentPage->put_URL ( bstrURL ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_hsiCurrentPage->put_Title( NULL ));
|
|
}
|
|
|
|
DEBUG_DumpState( L"StartNavigation: end", /*fHeader*/true, /*fCurrent*/true, /*fAll*/false, /*fState*/false );
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CPCHHelpSession::CompleteNavigation( /*[in]*/ HscPanel idPanel )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::CompleteNavigation" );
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
//
|
|
// For now, we just consider content navigations.
|
|
//
|
|
if(idPanel != HSCPANEL_CONTENTS &&
|
|
idPanel != HSCPANEL_HHWINDOW )
|
|
{
|
|
__MPC_SET_ERROR_AND_EXIT(hr, S_FALSE);
|
|
}
|
|
|
|
DEBUG_DumpState( L"CompleteNavigation", /*fHeader*/true, /*fCurrent*/true, /*fAll*/false, /*fState*/false );
|
|
|
|
|
|
//
|
|
// Handle startup scenario: we cannot rely on BeforeNavigate to occur.
|
|
//
|
|
if(!IsTravelling())
|
|
{
|
|
//
|
|
// Sometime, frequently on startup, the web browser embedded in HTMLHELP doesn't fire the BeforeNavigate event, so we are stuck with previous CPCHHelpSessionItem.
|
|
//
|
|
if(idPanel == HSCPANEL_HHWINDOW)
|
|
{
|
|
m_fAlreadyCreated = false;
|
|
}
|
|
|
|
__MPC_SET_ERROR_AND_EXIT(hr, S_OK); // Spurious notification.
|
|
}
|
|
|
|
SetThreshold();
|
|
m_fAlreadyCreated = false;
|
|
|
|
|
|
//
|
|
// Check recursion.
|
|
//
|
|
if(--m_dwTravelling)
|
|
{
|
|
if(m_dwIgnore ) m_dwIgnore--;
|
|
if(m_dwNoEvents) m_dwNoEvents--;
|
|
|
|
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
|
}
|
|
|
|
if(m_dwIgnore)
|
|
{
|
|
m_dwIgnore--;
|
|
}
|
|
|
|
|
|
if(m_dwNoEvents == 0)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_parent->Events().FireEvent_PersistLoad ( ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_parent->Events().FireEvent_NavigateComplete( m_hsiCurrentPage->GetURL(), idPanel ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_parent->Events().FireEvent_TravelDone ( ));
|
|
}
|
|
else
|
|
{
|
|
m_dwNoEvents--;
|
|
}
|
|
|
|
|
|
//
|
|
// Look up the title in the map, in the IE cache or in the document.
|
|
//
|
|
if(m_hsiCurrentPage)
|
|
{
|
|
m_hsiCurrentPage->ExtractTitle();
|
|
}
|
|
|
|
|
|
DEBUG_DumpState( L"CompleteNavigation: end", /*fHeader*/true, /*fCurrent*/true, /*fAll*/true, /*fState*/false );
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_parent->EnsurePlace());
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CPCHHelpSession::ForceHistoryPopulate()
|
|
{
|
|
return LeaveCurrentPage( /*fSaveHistory*/true, /*fClearPage*/false );
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
HRESULT CPCHHelpSession::LeaveCurrentPage( /*[in]*/ bool fSaveHistory, /*[in]*/ bool fClearPage )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::LeaveCurrentPage" );
|
|
|
|
HRESULT hr;
|
|
CComPtr<CPCHHelpSessionItem> hsi = m_hsiCurrentPage;
|
|
|
|
|
|
if(hsi)
|
|
{
|
|
hsi->ExtractTitle();
|
|
|
|
if(fSaveHistory && m_fAlreadySaved == false)
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, hsi->HistoryPopulate());
|
|
m_fAlreadySaved = true;
|
|
|
|
DEBUG_DumpState( L"Populate", /*fHeader*/false, /*fCurrent*/true, /*fAll*/false, /*fState*/true );
|
|
}
|
|
|
|
//
|
|
// Update the time spent on this page.
|
|
//
|
|
if(fClearPage)
|
|
{
|
|
hsi->Leave();
|
|
|
|
m_hsiCurrentPage.Release();
|
|
m_fAlreadySaved = false;
|
|
}
|
|
}
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
|
|
HRESULT CPCHHelpSession::FindTravelLog( /*[in]*/ long lLength, /*[out]*/ CPCHHelpSessionItem*& hsi )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::FindTravelLog" );
|
|
|
|
HRESULT hr;
|
|
|
|
hsi = m_hsiCurrentPage;
|
|
while(hsi && lLength)
|
|
{
|
|
if(lLength > 0)
|
|
{
|
|
lLength--;
|
|
|
|
hsi = FindPage( hsi->m_iIndexNext );
|
|
}
|
|
else
|
|
{
|
|
lLength++;
|
|
|
|
hsi = FindPage( hsi->m_iIndexPrev );
|
|
}
|
|
}
|
|
|
|
if(hsi == NULL)
|
|
{
|
|
__MPC_SET_ERROR_AND_EXIT(hr, E_INVALIDARG);
|
|
}
|
|
|
|
// DebugLog( L"Next %s\n", SAFEBSTR( hsi->GetURL() ) );
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CPCHHelpSession::Travel( /*[in]*/ CPCHHelpSessionItem* hsi )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::Travel" );
|
|
|
|
HRESULT hr;
|
|
HRESULT hr2;
|
|
VARIANT_BOOL Cancel;
|
|
|
|
|
|
m_fPossibleBack = false;
|
|
|
|
|
|
#ifdef DEBUG
|
|
{
|
|
WCHAR rgBuf[1024]; _snwprintf( rgBuf, MAXSTRLEN(rgBuf), L"Travel %d", hsi->m_iIndex );
|
|
|
|
DEBUG_DumpState( rgBuf, /*fHeader*/true, /*fCurrent*/false, /*fAll*/false, /*fState*/false );
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// Sorry, already navigating, abort...
|
|
//
|
|
if(IsTravelling())
|
|
{
|
|
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// Check if someone has something to say about the navigaiton.
|
|
//
|
|
|
|
m_dwTravelling++; // Fake counter, so scripts can check "IsNavigating" and find out this is an history navigation.
|
|
|
|
hr2 = m_parent->Events().FireEvent_BeforeNavigate( hsi->GetURL(), NULL, HSCPANEL_CONTENTS, &Cancel );
|
|
|
|
m_dwTravelling--; // Restore real counter.
|
|
|
|
if(SUCCEEDED(hr2))
|
|
{
|
|
if(Cancel == VARIANT_TRUE)
|
|
{
|
|
__MPC_SET_ERROR_AND_EXIT(hr, S_OK);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
|
|
//
|
|
// Update the state information for the page.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, SetCurrentItem( /*fLink*/false, hsi ));
|
|
|
|
|
|
//
|
|
// Set the new page as the current one (but don't generate a new history element!)
|
|
//
|
|
m_dwIgnore++;
|
|
|
|
DEBUG_DumpState( L"Restore", /*fHeader*/true, /*fCurrent*/true, /*fAll*/false, /*fState*/true );
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_parent->ChangeContext( (HscContext)hsi->m_lContextID, hsi->m_bstrContextInfo, hsi->m_bstrContextURL, /*fAlsoContent*/false ));
|
|
|
|
SetThreshold();
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, hsi->HistoryRestore());
|
|
|
|
|
|
DEBUG_DumpState( L"Travel: end", /*fHeader*/true, /*fCurrent*/true, /*fAll*/true, /*fState*/false );
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
HRESULT CPCHHelpSession::Travel( /*[in]*/ long lLength )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::Travel" );
|
|
|
|
HRESULT hr;
|
|
CPCHHelpSessionItem* hsi;
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, FindTravelLog( lLength, hsi ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, Travel ( hsi ));
|
|
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
void CPCHHelpSession::PossibleBack()
|
|
{
|
|
m_fPossibleBack = true;
|
|
m_dwPossibleBack = ::GetTickCount();
|
|
}
|
|
|
|
bool CPCHHelpSession::IsPossibleBack()
|
|
{
|
|
//
|
|
// 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.
|
|
// If the two events come within 100millisec, it's a Back navigation, not backspace.
|
|
//
|
|
if(m_fPossibleBack)
|
|
{
|
|
if(m_dwPossibleBack + 100 > ::GetTickCount())
|
|
{
|
|
return true;
|
|
}
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// IPCHHelpSession Methods.
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
STDMETHODIMP CPCHHelpSession::get_CurrentContext( /*[out, retval]*/ IPCHHelpSessionItem* *ppHSI )
|
|
{
|
|
if(ppHSI == NULL) return E_POINTER;
|
|
|
|
*ppHSI = NULL;
|
|
|
|
return m_hsiCurrentPage ? m_hsiCurrentPage->QueryInterface( IID_IPCHHelpSessionItem, (void**)ppHSI ) : S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CPCHHelpSession::VisitedHelpPages( /*[in]*/ HS_MODE hsMode ,
|
|
/*[out, retval]*/ IPCHCollection* *ppC )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::VisitedHelpPages" );
|
|
|
|
HRESULT hr;
|
|
List lstObject;
|
|
IterConst it;
|
|
CComPtr<CPCHCollection> pColl;
|
|
|
|
__MPC_PARAMCHECK_BEGIN(hr)
|
|
__MPC_PARAMCHECK_POINTER_AND_SET(ppC,NULL);
|
|
__MPC_PARAMCHECK_END();
|
|
|
|
|
|
//
|
|
// Create the Enumerator and fill it with jobs.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &pColl ));
|
|
|
|
//
|
|
// Get the list of items to return.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, FilterPages( hsMode, lstObject ));
|
|
|
|
//
|
|
// Fill the collection with results.
|
|
//
|
|
{
|
|
const Taxonomy::HelpSet& ths = m_parent->UserSettings()->THS();
|
|
|
|
for(it = lstObject.begin(); it != lstObject.end(); it++)
|
|
{
|
|
CPCHHelpSessionItem* hsi = *it;
|
|
|
|
if(hsi->SameSKU( ths ))
|
|
{
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, pColl->AddItem( hsi ));
|
|
}
|
|
}
|
|
}
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, pColl->QueryInterface( IID_IPCHCollection, (void**)ppC ));
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
STDMETHODIMP CPCHHelpSession::SetTitle( /*[in]*/ BSTR bstrURL ,
|
|
/*[in]*/ BSTR bstrTitle )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::SetTitle" );
|
|
|
|
HRESULT hr;
|
|
|
|
__MPC_PARAMCHECK_BEGIN(hr)
|
|
__MPC_PARAMCHECK_STRING_NOT_EMPTY(bstrURL);
|
|
__MPC_PARAMCHECK_NOTNULL(bstrTitle);
|
|
__MPC_PARAMCHECK_END();
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, RecordTitle( bstrURL, bstrTitle, /*fStrong*/true ) );
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
STDMETHODIMP CPCHHelpSession::ForceNavigation( /*[in]*/ BSTR bstrURL )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::ForceNavigation" );
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, StartNavigation ( bstrURL, HSCPANEL_CONTENTS ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, CompleteNavigation( HSCPANEL_CONTENTS ));
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
STDMETHODIMP CPCHHelpSession::IgnoreNavigation()
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::IgnoreNavigation" );
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
//
|
|
// Save the current state of the browser.
|
|
//
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, LeaveCurrentPage( /*fSaveHistory*/true, /*fClearPage*/false ));
|
|
|
|
m_dwIgnore++;
|
|
m_dwNoEvents++;
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
STDMETHODIMP CPCHHelpSession::EraseNavigation()
|
|
{
|
|
m_fOverwrite = true;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
STDMETHODIMP CPCHHelpSession::IsNavigating( /*[out, retval]*/ VARIANT_BOOL *pVal )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::IsNavigating" );
|
|
|
|
HRESULT hr;
|
|
|
|
|
|
*pVal = IsTravelling() ? VARIANT_TRUE : VARIANT_FALSE;
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
|
|
STDMETHODIMP CPCHHelpSession::Back( /*[in]*/ long lLength )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::Back" );
|
|
|
|
__HCP_FUNC_EXIT( Travel( -lLength ) );
|
|
}
|
|
|
|
STDMETHODIMP CPCHHelpSession::Forward( /*[in]*/ long lLength )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::Forward" );
|
|
|
|
__HCP_FUNC_EXIT( Travel( lLength ) );
|
|
}
|
|
|
|
STDMETHODIMP CPCHHelpSession::IsValid( /*[in]*/ long lLength ,
|
|
/*[out, retval]*/ VARIANT_BOOL *pVal )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::IsValid" );
|
|
|
|
HRESULT hr;
|
|
CPCHHelpSessionItem* hsi;
|
|
|
|
|
|
*pVal = (SUCCEEDED(FindTravelLog( lLength, hsi )) ? VARIANT_TRUE : VARIANT_FALSE);
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
STDMETHODIMP CPCHHelpSession::Navigate( /*[in]*/ IPCHHelpSessionItem* pHSI )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::Navigate" );
|
|
|
|
HRESULT hr;
|
|
CPCHHelpSessionItem* hsiSrc;
|
|
CComPtr<CPCHHelpSessionItem> hsi;
|
|
bool fAcquired = false;
|
|
|
|
__MPC_PARAMCHECK_BEGIN(hr)
|
|
__MPC_PARAMCHECK_NOTNULL(pHSI);
|
|
__MPC_PARAMCHECK_END();
|
|
|
|
|
|
hsiSrc = FindPage( pHSI );
|
|
if(hsiSrc == NULL)
|
|
{
|
|
__MPC_SET_ERROR_AND_EXIT(hr, E_INVALIDARG);
|
|
}
|
|
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, AllocateItem ( /*fNew */true, /*fLink*/true, /*fNewIndex*/true, hsi ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, hsi->HistoryClone( /*fContext*/true, hsiSrc )); fAcquired = true;
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, Travel( hsi ));
|
|
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
if(fAcquired && hsi) (void)hsi->m_state.ReleaseState( /*fForce*/false );
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|
|
|
|
STDMETHODIMP CPCHHelpSession::ChangeContext( /*[in]*/ BSTR bstrName, /*[in,optional]*/ VARIANT vInfo, /*[in,optional]*/ VARIANT vURL )
|
|
{
|
|
__HCP_FUNC_ENTRY( "CPCHHelpSession::ChangeContext" );
|
|
|
|
HRESULT hr;
|
|
HscContext lContextID = CPCHHelpSessionItem::LookupContext( bstrName );
|
|
CComBSTR bstrContextInfo;
|
|
CComBSTR bstrContextURL;
|
|
|
|
if(lContextID == HSCCONTEXT_INVALID || m_parent == NULL)
|
|
{
|
|
__MPC_SET_ERROR_AND_EXIT(hr, E_INVALIDARG);
|
|
}
|
|
|
|
CancelThreshold();
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::PutBSTR( bstrContextInfo, &vInfo ));
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, MPC::PutBSTR( bstrContextURL , &vURL ));
|
|
|
|
__MPC_EXIT_IF_METHOD_FAILS(hr, m_parent->ChangeContext( lContextID, bstrContextInfo, bstrContextURL ));
|
|
|
|
hr = S_OK;
|
|
|
|
|
|
__HCP_FUNC_CLEANUP;
|
|
|
|
__HCP_FUNC_EXIT(hr);
|
|
}
|