/****************************************************************************** Copyright (c) 2000 Microsoft Corporation Module Name: Favorites.cpp Abstract: This file contains the implementation of the CPCHFavorites class, which is used to store the list of favorite contents. Revision History: Davide Massarenti (Dmassare) 05/10/2000 created ******************************************************************************/ #include "stdafx.h" ///////////////////////////////////////////////////////////////////////////// const WCHAR c_szPersistFile[] = HC_ROOT_HELPCTR L"\\Favorites.stream"; static const DWORD l_dwVersion = 0x01564146; // FAV 01 ///////////////////////////////////////////////////////////////////////////// HRESULT CPCHFavorites::Entry::Init() { __HCP_FUNC_ENTRY( "CPCHFavorites::Entry::Init" ); HRESULT hr; if(m_Data == NULL) { __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::CreateInstance( &m_Data )); } hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } HRESULT CPCHFavorites::Entry::Load( /*[in]*/ MPC::Serializer& streamIn ) { __HCP_FUNC_ENTRY( "CPCHFavorites::Entry::Load" ); HRESULT hr; __MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_NOTNULL(m_Data); __MPC_PARAMCHECK_END(); __MPC_EXIT_IF_METHOD_FAILS(hr, m_Data->Load( streamIn )); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } HRESULT CPCHFavorites::Entry::Save( /*[in]*/ MPC::Serializer& streamOut ) { __HCP_FUNC_ENTRY( "CPCHFavorites::Entry::Save" ); HRESULT hr; if(m_Data) { __MPC_EXIT_IF_METHOD_FAILS(hr, m_Data->Save( streamOut, true )); } hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////// CPCHFavorites::CPCHFavorites() { __HCP_FUNC_ENTRY( "CPCHFavorites::CPCHFavorites" ); // List m_lstFavorites; m_fLoaded = false; // bool m_fLoaded; } CPCHFavorites::~CPCHFavorites() { __HCP_FUNC_ENTRY( "CPCHFavorites::~CPCHFavorites" ); } //////////////////// CPCHFavorites* CPCHFavorites::s_GLOBAL( NULL ); HRESULT CPCHFavorites::InitializeSystem() { if(s_GLOBAL) return S_OK; return MPC::CreateInstance( &CPCHFavorites::s_GLOBAL ); } void CPCHFavorites::FinalizeSystem() { if(s_GLOBAL) { s_GLOBAL->Release(); s_GLOBAL = NULL; } } //////////////////////////////////////////////////////////////////////////////// HRESULT CPCHFavorites::FindEntry( /*[in]*/ IPCHHelpSessionItem* pItem, /*[out]*/ Iter& it ) { __HCP_FUNC_ENTRY( "CPCHFavorites::FindEntry" ); HRESULT hr; // // First of all, look if the page is already present. // for(it = m_lstFavorites.begin(); it != m_lstFavorites.end(); it++) { if(it->m_Data == pItem) { __MPC_SET_ERROR_AND_EXIT(hr, S_OK); } } hr = HRESULT_FROM_WIN32( ERROR_NOT_FOUND ); __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } //////////////////////////////////////////////////////////////////////////////// HRESULT CPCHFavorites::Erase() { __HCP_FUNC_ENTRY( "CPCHFavorites::Erase" ); HRESULT hr; MPC::SmartLock<_ThreadModel> lock(this); CPCHFavorites_Parent::Erase(); m_lstFavorites.clear(); m_fLoaded = false; hr = S_OK; __HCP_FUNC_EXIT(hr); } HRESULT CPCHFavorites::Load() { __HCP_FUNC_ENTRY( "CPCHFavorites::Load" ); HRESULT hr; MPC::SmartLock<_ThreadModel> lock(this); HANDLE hFile = INVALID_HANDLE_VALUE; if(m_fLoaded == false) { MPC::wstring szFile; // // Open file and read it. // __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::GetUserWritablePath( szFile, c_szPersistFile )); __MPC_EXIT_IF_INVALID_HANDLE(hr, hFile, ::CreateFileW( szFile.c_str(), GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL )); { MPC::Serializer_File streamReal( hFile ); 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); while(1) { Iter it = m_lstFavorites.insert( m_lstFavorites.end() ); __MPC_EXIT_IF_METHOD_FAILS(hr, it->Init()); if(FAILED(it->Load( streamBuf ))) { m_lstFavorites.erase( it ); break; } } } } hr = S_OK; __HCP_FUNC_CLEANUP; if(FAILED(hr)) Erase(); if(hFile != INVALID_HANDLE_VALUE) ::CloseHandle( hFile ); m_fLoaded = true; // Anyway, flag the object as loaded. __HCP_FUNC_EXIT(S_OK); // Never fail. } HRESULT CPCHFavorites::Save() { __HCP_FUNC_ENTRY( "CPCHFavorites::Save" ); HRESULT hr; MPC::SmartLock<_ThreadModel> lock(this); HANDLE hFile = INVALID_HANDLE_VALUE; if(m_fLoaded) { MPC::wstring szFile; Iter it; // // Create the new file. // __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::GetUserWritablePath( szFile, c_szPersistFile )); __MPC_EXIT_IF_METHOD_FAILS(hr, MPC::MakeDir ( szFile )); __MPC_EXIT_IF_INVALID_HANDLE(hr, hFile, ::CreateFileW( szFile.c_str(), GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL )); { MPC::Serializer_File streamReal( hFile ); MPC::Serializer_Buffering streamBuf ( streamReal ); __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf << l_dwVersion); for(it = m_lstFavorites.begin(); it != m_lstFavorites.end(); it++) { __MPC_EXIT_IF_METHOD_FAILS(hr, it->Save( streamBuf )); } __MPC_EXIT_IF_METHOD_FAILS(hr, streamBuf.Flush()); } __MPC_EXIT_IF_METHOD_FAILS(hr, Synchronize( false )); __MPC_EXIT_IF_METHOD_FAILS(hr, CPCHHelpCenterExternal::s_GLOBAL->Events().FireEvent_FavoritesUpdate()); } hr = S_OK; __HCP_FUNC_CLEANUP; if(hFile != INVALID_HANDLE_VALUE) { ::FlushFileBuffers( hFile ); ::CloseHandle ( hFile ); } __HCP_FUNC_EXIT(hr); } ///////////////////////////////////////////////////////////////////////////// HRESULT CPCHFavorites::Synchronize( /*[in]*/ bool fForce ) { __HCP_FUNC_ENTRY( "CPCHFavorites::Synchronize" ); HRESULT hr; MPC::SmartLock<_ThreadModel> lock(this); if(fForce) Erase(); __MPC_EXIT_IF_METHOD_FAILS(hr, Load()); if(m_fLoaded) { Iter it; const Taxonomy::HelpSet& ths = CPCHHelpCenterExternal::s_GLOBAL->UserSettings()->THS(); // // We actually have two lists, the real one, m_lstFavorites, and the enumerator's one, m_coll. // So, whenever the real one changes, we need to rebuild the one held by the enumerator. // CPCHFavorites_Parent::Erase(); for(it = m_lstFavorites.begin(); it != m_lstFavorites.end(); it++) { CPCHHelpSessionItem* data = it->m_Data; if(data->SameSKU( ths )) { __MPC_EXIT_IF_METHOD_FAILS(hr, AddItem( data )); } } } hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } ///////////////////////////////////////////////////////////////////////////// STDMETHODIMP CPCHFavorites::IsDuplicate( /*[in]*/ BSTR bstrURL , /*[out, retval]*/ VARIANT_BOOL *pfDup ) { __HCP_FUNC_ENTRY( "CPCHFavorites::IsDuplicate" ); HRESULT hr; MPC::SmartLock<_ThreadModel> lock(this); const Taxonomy::HelpSet& ths = CPCHHelpCenterExternal::s_GLOBAL->UserSettings()->THS(); Iter it; __MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_POINTER_AND_SET(pfDup,VARIANT_FALSE); __MPC_PARAMCHECK_END(); __MPC_EXIT_IF_METHOD_FAILS(hr, Load()); for(it = m_lstFavorites.begin(); it != m_lstFavorites.end(); it++) { CPCHHelpSessionItem* data = it->m_Data; if(data->SameSKU( ths ) && data->SameURL( bstrURL ) ) { *pfDup = VARIANT_TRUE; break; } } hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } STDMETHODIMP CPCHFavorites::Add( /*[in]*/ BSTR bstrURL , /*[in,optional]*/ VARIANT vTitle , /*[out, retval]*/ IPCHHelpSessionItem* *ppItem ) { __HCP_FUNC_ENTRY( "CPCHFavorites::Add" ); HRESULT hr; MPC::SmartLock<_ThreadModel> lock(this); CPCHProxy_IPCHUserSettings2* us = CPCHHelpCenterExternal::s_GLOBAL->UserSettings(); CPCHHelpSessionItem* data; CComBSTR bstrTitleInfer; BSTR bstrTitle; Iter it; __MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_STRING_NOT_EMPTY(bstrURL); __MPC_PARAMCHECK_END(); __MPC_EXIT_IF_METHOD_FAILS(hr, Load()); if(vTitle.vt == VT_BSTR) { bstrTitle = vTitle.bstrVal; } else { __MPC_EXIT_IF_METHOD_FAILS(hr, CPCHHelpCenterExternal::s_GLOBAL->HelpSession()->LookupTitle( bstrURL, bstrTitleInfer, /*fUseCache*/false )); bstrTitle = bstrTitleInfer; } if(bstrTitle == NULL || bstrTitle[0] == 0) bstrTitle = bstrURL; // We need some sort of title. it = m_lstFavorites.insert( m_lstFavorites.end() ); __MPC_EXIT_IF_METHOD_FAILS(hr, it->Init()); data = it->m_Data; data->put_THS( us->THS() ); __MPC_EXIT_IF_METHOD_FAILS(hr, data->put_URL ( bstrURL )); __MPC_EXIT_IF_METHOD_FAILS(hr, data->put_Title( bstrTitle )); __MPC_EXIT_IF_METHOD_FAILS(hr, Save()); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } STDMETHODIMP CPCHFavorites::Rename( /*[in]*/ BSTR bstrTitle , /*[in]*/ IPCHHelpSessionItem* pItem ) { __HCP_FUNC_ENTRY( "CPCHFavorites::Rename" ); HRESULT hr; MPC::SmartLock<_ThreadModel> lock(this); Iter it; __MPC_PARAMCHECK_BEGIN(hr) __MPC_PARAMCHECK_STRING_NOT_EMPTY(bstrTitle); __MPC_PARAMCHECK_END(); __MPC_EXIT_IF_METHOD_FAILS(hr, Load()); __MPC_EXIT_IF_METHOD_FAILS(hr, FindEntry( pItem, it )); __MPC_EXIT_IF_METHOD_FAILS(hr, it->m_Data->put_Title( bstrTitle )); __MPC_EXIT_IF_METHOD_FAILS(hr, Save()); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); } STDMETHODIMP CPCHFavorites::Move( /*[in]*/ IPCHHelpSessionItem* pInsertBefore , /*[in]*/ IPCHHelpSessionItem* pItem ) { __HCP_FUNC_ENTRY( "CPCHFavorites::Move" ); HRESULT hr; MPC::SmartLock<_ThreadModel> lock(this); CPCHHelpSessionItem* data = NULL; Iter itBefore; Iter itOld; Iter itNew; __MPC_EXIT_IF_METHOD_FAILS(hr, Load()); // // If an element is passed, then we insert before it, otherwise we insert at the end. // if(pInsertBefore) { __MPC_EXIT_IF_METHOD_FAILS(hr, FindEntry( pInsertBefore, itBefore )); } else { itBefore = m_lstFavorites.end(); } __MPC_EXIT_IF_METHOD_FAILS(hr, FindEntry( pItem, itOld )); // // Trying to move the element on itself. // if(itOld == itBefore) { __MPC_SET_ERROR_AND_EXIT(hr, E_INVALIDARG); } // // Save pointer to data, erase old item, create a new one and restore pointer. // data = itOld->m_Data; data->AddRef(); m_lstFavorites.erase ( itOld ); itNew = m_lstFavorites.insert( itBefore ); itNew->m_Data = data; data = NULL; __MPC_EXIT_IF_METHOD_FAILS(hr, Save()); hr = S_OK; __HCP_FUNC_CLEANUP; MPC::Release( data ); __HCP_FUNC_EXIT(hr); } STDMETHODIMP CPCHFavorites::Delete( /*[in]*/ IPCHHelpSessionItem* pItem ) { __HCP_FUNC_ENTRY( "CPCHFavorites::Delete" ); HRESULT hr; MPC::SmartLock<_ThreadModel> lock(this); Iter it; __MPC_EXIT_IF_METHOD_FAILS(hr, Load()); __MPC_EXIT_IF_METHOD_FAILS(hr, FindEntry( pItem, it )); m_lstFavorites.erase( it ); __MPC_EXIT_IF_METHOD_FAILS(hr, Synchronize( false )); __MPC_EXIT_IF_METHOD_FAILS(hr, Save()); hr = S_OK; __HCP_FUNC_CLEANUP; __HCP_FUNC_EXIT(hr); }