/*++ Copyright (c) 1999-2000 Microsoft Corporation Module Name: HelpTab.cpp Abstract: Implementation of __HelpEntry structure and CHelpSessionTable. Author: HueiWang 06/29/2000 --*/ #include "stdafx.h" #include #include #include #include #include #include "helptab.h" #include "policy.h" #include "remotedesktoputils.h" #include "helper.h" // // // __HelpEntry strucutre implementation // // HRESULT __HelpEntry::LoadEntryValues( IN HKEY hKey ) /*++ Routine Description: Load help session entry from registry key. Parameters: hKey : Handle to registry key containing help entry values. Returns: S_OK or error code. --*/ { DWORD dwStatus; MYASSERT( NULL != hKey ); if( NULL != hKey ) { dwStatus = m_EntryStatus.DBLoadValue( hKey ); if( ERROR_SUCCESS != dwStatus ) { goto CLEANUPANDEXIT; } if( REGVALUE_HELPSESSION_ENTRY_DELETED == m_EntryStatus ) { // entry already been deleted, no reason to continue loading dwStatus = ERROR_FILE_NOT_FOUND; goto CLEANUPANDEXIT; } dwStatus = m_SessionId.DBLoadValue(hKey); if( ERROR_SUCCESS != dwStatus ) { goto CLEANUPANDEXIT; } if( m_SessionId->Length() == 0 ) { // Help Session ID must exist, no default value. dwStatus = ERROR_INVALID_DATA; goto CLEANUPANDEXIT; } dwStatus = m_EnableResolver.DBLoadValue(hKey); if( ERROR_SUCCESS != dwStatus ) { goto CLEANUPANDEXIT; } dwStatus = m_SessResolverBlob.DBLoadValue(hKey); if( ERROR_SUCCESS != dwStatus ) { goto CLEANUPANDEXIT; } dwStatus = m_UserSID.DBLoadValue(hKey); if( ERROR_SUCCESS != dwStatus ) { goto CLEANUPANDEXIT; } dwStatus = m_CreationTime.DBLoadValue(hKey); if( ERROR_SUCCESS != dwStatus ) { goto CLEANUPANDEXIT; } dwStatus = m_ExpirationTime.DBLoadValue(hKey); if( ERROR_SUCCESS != dwStatus ) { goto CLEANUPANDEXIT; } dwStatus = m_SessionRdsSetting.DBLoadValue(hKey); if( ERROR_SUCCESS != dwStatus ) { goto CLEANUPANDEXIT; } dwStatus = m_EntryStatus.DBLoadValue(hKey); if( ERROR_SUCCESS != dwStatus ) { goto CLEANUPANDEXIT; } dwStatus = m_CreationTime.DBLoadValue(hKey); if( ERROR_SUCCESS != dwStatus ) { goto CLEANUPANDEXIT; } dwStatus = m_IpAddress.DBLoadValue(hKey); if( ERROR_SUCCESS != dwStatus ) { goto CLEANUPANDEXIT; } dwStatus = m_ICSPort.DBLoadValue(hKey); if( ERROR_SUCCESS != dwStatus ) { goto CLEANUPANDEXIT; } dwStatus = m_SessionCreateBlob.DBLoadValue(hKey); } else { dwStatus = E_UNEXPECTED; } CLEANUPANDEXIT: return HRESULT_FROM_WIN32(dwStatus); } HRESULT __HelpEntry::UpdateEntryValues( IN HKEY hKey ) /*++ Routine Description: Update/store help entry value to registry. Parameters: hKey : Handle to registry to save help entry value. Returns: S_OK or error code. --*/ { DWORD dwStatus; MYASSERT( NULL != hKey ); if( NULL == hKey ) { dwStatus = E_UNEXPECTED; goto CLEANUPANDEXIT; } if( REGVALUE_HELPSESSION_ENTRY_DELETED == m_EntryStatus ) { // entry already deleted, error out dwStatus = ERROR_FILE_NOT_FOUND; goto CLEANUPANDEXIT; } // New entry value, entry status in registry is set // to delete so when we failed to completely writting // all value to registry, we can still assume it is // deleted. if( REGVALUE_HELPSESSION_ENTRY_NEW != m_EntryStatus ) { // Mark entry dirty. m_EntryStatus = REGVALUE_HELPSESSION_ENTRY_DIRTY; dwStatus = m_EntryStatus.DBUpdateValue( hKey ); if( ERROR_SUCCESS != dwStatus ) { goto CLEANUPANDEXIT; } } dwStatus = m_SessionId.DBUpdateValue(hKey); if( ERROR_SUCCESS != dwStatus ) { goto CLEANUPANDEXIT; } dwStatus = m_EnableResolver.DBUpdateValue(hKey); if( ERROR_SUCCESS != dwStatus ) { goto CLEANUPANDEXIT; } dwStatus = m_SessResolverBlob.DBUpdateValue(hKey); if( ERROR_SUCCESS != dwStatus ) { goto CLEANUPANDEXIT; } dwStatus = m_UserSID.DBUpdateValue(hKey); if( ERROR_SUCCESS != dwStatus ) { goto CLEANUPANDEXIT; } dwStatus = m_CreationTime.DBUpdateValue(hKey); if( ERROR_SUCCESS != dwStatus ) { goto CLEANUPANDEXIT; } dwStatus = m_ExpirationTime.DBUpdateValue(hKey); if( ERROR_SUCCESS != dwStatus ) { goto CLEANUPANDEXIT; } dwStatus = m_SessionRdsSetting.DBUpdateValue(hKey); if( ERROR_SUCCESS != dwStatus ) { goto CLEANUPANDEXIT; } dwStatus = m_IpAddress.DBUpdateValue(hKey); if( ERROR_SUCCESS != dwStatus ) { goto CLEANUPANDEXIT; } dwStatus = m_ICSPort.DBUpdateValue(hKey); if( ERROR_SUCCESS != dwStatus ) { goto CLEANUPANDEXIT; } dwStatus = m_SessionCreateBlob.DBUpdateValue(hKey); if( ERROR_SUCCESS != dwStatus ) { goto CLEANUPANDEXIT; } // Mark entry normal m_EntryStatus = REGVALUE_HELPSESSION_ENTRY_NORMAL; dwStatus = m_EntryStatus.DBUpdateValue( hKey ); CLEANUPANDEXIT: return HRESULT_FROM_WIN32(dwStatus); } HRESULT __HelpEntry::BackupEntry() /*++ Routine Description: Backup help entry, backup is stored under \\Backup registry key. Parameters: None. Returns: S_OK or error code. --*/ { HKEY hKey = NULL; DWORD dwStatus; MYASSERT( NULL != m_hEntryKey ); if( NULL != m_hEntryKey ) { // // Delete current backup (void)DeleteEntryBackup(); // // Create a backup registry key dwStatus = RegCreateKeyEx( m_hEntryKey, REGKEY_HELPENTRYBACKUP, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL ); if( ERROR_SUCCESS != dwStatus ) { MYASSERT(FALSE); } else { dwStatus = UpdateEntryValues( hKey ); } } else { dwStatus = E_UNEXPECTED; } if( NULL != hKey ) { RegCloseKey( hKey ); } return HRESULT_FROM_WIN32(dwStatus); } HRESULT __HelpEntry::RestoreEntryFromBackup() /*++ Routine Description: Restore help entry from backup, backup is stored under \\Backup registry key. Parameters: None. Returns: S_OK or error code. --*/ { DWORD dwStatus; HKEY hBackupKey = NULL; MYASSERT( NULL != m_hEntryKey ); if( NULL != m_hEntryKey ) { // // check if backup registry exists. dwStatus = RegOpenKeyEx( m_hEntryKey, REGKEY_HELPENTRYBACKUP, 0, KEY_ALL_ACCESS, &hBackupKey ); if( ERROR_SUCCESS == dwStatus ) { HELPENTRY backup( m_pHelpSessionTable, hBackupKey, ENTRY_VALID_PERIOD ); // load backup values dwStatus = backup.LoadEntryValues( hBackupKey ); if( ERROR_SUCCESS == dwStatus ) { if( (DWORD)backup.m_EntryStatus == REGVALUE_HELPSESSION_ENTRY_NORMAL ) { *this = backup; } else { (void)DeleteEntryBackup(); dwStatus = ERROR_FILE_NOT_FOUND; } } // HELPSESSION destructor will close registry key } if( ERROR_SUCCESS == dwStatus ) { // // update all values. dwStatus = UpdateEntryValues( m_hEntryKey ); if( ERROR_SUCCESS == dwStatus ) { // // Already restore entry, delete backup copy (void)DeleteEntryBackup(); } } } else { dwStatus = E_UNEXPECTED; } return HRESULT_FROM_WIN32( dwStatus ); } HRESULT __HelpEntry::DeleteEntryBackup() /*++ Routine Description: Delete help entry backup from registry. Parameters: None. Returns: always S_OK --*/ { DWORD dwStatus; dwStatus = RegDelKey( m_hEntryKey, REGKEY_HELPENTRYBACKUP ); return HRESULT_FROM_WIN32(dwStatus); } BOOL __HelpEntry::IsEntryExpired() { FILETIME ft; ULARGE_INTEGER ul1, ul2; GetSystemTimeAsFileTime(&ft); ul1.LowPart = ft.dwLowDateTime; ul1.HighPart = ft.dwHighDateTime; ft = (FILETIME)m_ExpirationTime; ul2.LowPart = ft.dwLowDateTime; ul2.HighPart = ft.dwHighDateTime; #if DBG if( ul1.QuadPart >= ul2.QuadPart ) { DebugPrintf( _TEXT("Help Entry %s has expired ...\n"), (LPCTSTR)(CComBSTR)m_SessionId ); } #endif return (ul1.QuadPart >= ul2.QuadPart); } //////////////////////////////////////////////////////////////////////////////// // // CHelpSessionTable implementation // CHelpSessionTable::CHelpSessionTable() : m_hHelpSessionTableKey(NULL), m_NumHelp(0) { HKEY hKey = NULL; DWORD dwStatus; DWORD dwSize; DWORD dwType; // // Load entry valid period setting from registry // dwStatus = RegOpenKeyEx( HKEY_LOCAL_MACHINE, RDS_MACHINEPOLICY_SUBTREE, 0, KEY_READ, &hKey ); if( ERROR_SUCCESS == dwStatus ) { dwSize = sizeof(DWORD); dwStatus = RegQueryValueEx( hKey, RDS_HELPENTRY_VALID_PERIOD, NULL, &dwType, (PBYTE) &m_dwEntryValidPeriod, &dwSize ); if( REG_DWORD != dwType ) { dwStatus = ERROR_FILE_NOT_FOUND; } RegCloseKey(hKey); } if(ERROR_SUCCESS != dwStatus ) { // pick default value m_dwEntryValidPeriod = ENTRY_VALID_PERIOD; } } HRESULT CHelpSessionTable::RestoreHelpSessionTable( IN HKEY hKey, IN LPTSTR pszKeyName, IN HANDLE userData ) /*++ Routine Description: Restore help session table. This routine is callback from RegEnumSubKeys(). Parameters: hKey : Handle to registry. pszKeyName : registry sub-key name containing one help session entry userData : User defined data. Returns: S_OK or error code. --*/ { HRESULT hRes; if( NULL == userData ) { hRes = E_UNEXPECTED; MYASSERT(FALSE); } else { CHelpSessionTable* pTable = (CHelpSessionTable *) userData; hRes = pTable->RestoreHelpSessionEntry( hKey, pszKeyName ); if( SUCCEEDED(hRes) ) { pTable->m_NumHelp++; } hRes = S_OK; } return hRes; } BOOL CHelpSessionTable::IsEntryExpired( IN PHELPENTRY pEntry ) /*++ Routine Description: Determine if a help entry has expired. Paramters: pEntry : Pointer to help entry. Returns: TRUE if entry has expired, FALSE otherwise. --*/ { MYASSERT( NULL != pEntry ); return (NULL != pEntry) ? pEntry->IsEntryExpired() : TRUE; } HRESULT CHelpSessionTable::RestoreHelpSessionEntry( IN HKEY hKey, IN LPTSTR pszKeyName ) /*++ Routine Description: Restore a single help session entry. Parameters: hKey : Handle to help session table. pszKeyName : Registry sub-key name containing help entry. Returns: S_OK or error code. --*/ { HKEY hEntryKey = NULL; DWORD dwStatus; DWORD dwDuplicate = REG_CREATED_NEW_KEY; LONG entryStatus; BOOL bDeleteEntry = FALSE; // // Open the registry key for session entry dwStatus = RegOpenKeyEx( hKey, pszKeyName, 0, KEY_ALL_ACCESS, &hEntryKey ); if( ERROR_SUCCESS == dwStatus ) { HELPENTRY helpEntry( *this, hEntryKey, m_dwEntryValidPeriod ); // load help entry dwStatus = helpEntry.Refresh(); if( dwStatus != ERROR_SUCCESS || helpEntry.m_SessionId->Length() == 0 || REGVALUE_HELPSESSION_ENTRY_DELETEONSTARTUP == helpEntry.m_EntryStatus ) { // Session ID must not be NULL. bDeleteEntry = TRUE; } else { if( REGVALUE_HELPSESSION_ENTRY_DELETED != helpEntry.m_EntryStatus ) { if( TRUE != IsEntryExpired( &helpEntry ) ) { if( REGVALUE_HELPSESSION_ENTRY_DIRTY == helpEntry.m_EntryStatus ) { // Entry is partially updated, try to restore from backup, // is failed restoring, treat as bad entry. if( FAILED(helpEntry.RestoreEntryFromBackup()) ) { bDeleteEntry = TRUE; } } } else { LPTSTR eventString[2]; BSTR pszNoviceDomain = NULL; BSTR pszNoviceName = NULL; HRESULT hr; // // Log the event indicate that ticket was deleted, non-critical // since we can still continue to run. // hr = ConvertSidToAccountName( (CComBSTR)helpEntry.m_UserSID, &pszNoviceDomain, &pszNoviceName ); if( SUCCEEDED(hr) ) { eventString[0] = pszNoviceDomain; eventString[1] = pszNoviceName; LogRemoteAssistanceEventString( EVENTLOG_INFORMATION_TYPE, SESSMGR_I_REMOTEASSISTANCE_DELETEDTICKET, 2, eventString ); DebugPrintf( _TEXT("Help Entry has expired %s\n"), (CComBSTR)helpEntry.m_SessionId ); } if( pszNoviceDomain ) { SysFreeString( pszNoviceDomain ); } if( pszNoviceName ) { SysFreeString( pszNoviceName ); } } } else { bDeleteEntry = TRUE; } } } if( TRUE == bDeleteEntry ) { dwStatus = RegDelKey( hKey, pszKeyName ); // // Ignore error // DebugPrintf( _TEXT("RegDelKey on entry %s returns %d\n"), pszKeyName, dwStatus ); dwStatus = ERROR_FILE_NOT_FOUND; } return HRESULT_FROM_WIN32( dwStatus ); } HRESULT CHelpSessionTable::LoadHelpEntry( IN HKEY hKey, IN LPTSTR pszKeyName, OUT PHELPENTRY* ppHelpSession ) /*++ Routine description: Load a help entry from registry. Parameters: hKey : registry handle to help session table. pszKeyName : registry sub-key name (Help session ID). ppHelpSession : Pointer to PHELPENTRY to receive loaded help entry. Returns: S_OK or error code. --*/ { PHELPENTRY pSess; HRESULT hRes; HKEY hEntryKey = NULL; DWORD dwStatus; MYASSERT( NULL != hKey ); if( NULL != hKey ) { // open the registry containing help entry dwStatus = RegOpenKeyEx( hKey, pszKeyName, 0, KEY_ALL_ACCESS, &hEntryKey ); if( ERROR_SUCCESS == dwStatus ) { pSess = new HELPENTRY( *this, hEntryKey, m_dwEntryValidPeriod ); if( NULL == pSess ) { hRes = E_OUTOFMEMORY; } else { // load help entry, Refresh() will failed if // session ID is NULL or emptry string hRes = pSess->Refresh(); if( SUCCEEDED(hRes) ) { if( (DWORD)pSess->m_EntryStatus == REGVALUE_HELPSESSION_ENTRY_NORMAL ) { *ppHelpSession = pSess; } else { dwStatus = ERROR_FILE_NOT_FOUND; } } if( FAILED(hRes) ) { pSess->Release(); } } } else { hRes = HRESULT_FROM_WIN32( dwStatus ); } } else { hRes = E_UNEXPECTED; } return hRes; } HRESULT CHelpSessionTable::OpenSessionTable( IN LPCTSTR pszFileName // reserverd. ) /*++ Routine Description: Open help session table, routine enumerate all help entry (registry sub-key), and restore/delete help entry if necessary. Parameters: pszFileName : reserved parameter, must be NULL. Returns: S_OK or error code. --*/ { DWORD dwStatus; HRESULT hr; CCriticalSectionLocker l(m_TableLock); // // Go thru all sub-key containing help entry and restore or delete // help entry if necessary. dwStatus = RegEnumSubKeys( HKEY_LOCAL_MACHINE, REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE, RestoreHelpSessionTable, (HANDLE)this ); if( ERROR_SUCCESS != dwStatus ) { if( NULL != m_hHelpSessionTableKey ) { // Make sure registry key is not opened. RegCloseKey(m_hHelpSessionTableKey); m_hHelpSessionTableKey = NULL; } // If table is bad, delete and re-create again dwStatus = RegDelKey( HKEY_LOCAL_MACHINE, REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE ); if( ERROR_SUCCESS != dwStatus && ERROR_FILE_NOT_FOUND != dwStatus ) { // Critical error MYASSERT(FALSE); goto CLEANUPANDEXIT; } hr = CreatePendingHelpTable(); dwStatus = HRESULT_CODE(hr); if( ERROR_SUCCESS != dwStatus ) { // we need registry key be ACLed. MYASSERT(FALSE); goto CLEANUPANDEXIT; } } dwStatus = RegOpenKeyEx( HKEY_LOCAL_MACHINE, REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE, 0, KEY_ALL_ACCESS, &m_hHelpSessionTableKey ); if( ERROR_SUCCESS != dwStatus ) { MYASSERT(FALSE); goto CLEANUPANDEXIT; } else { m_bstrFileName = pszFileName; } CLEANUPANDEXIT: return HRESULT_FROM_WIN32(dwStatus); } HRESULT CHelpSessionTable::CloseSessionTable() /*++ Routine Description: Close help session table. Parameters: None. Returns: S_OK or error code. --*/ { // no help is opened. CCriticalSectionLocker l(m_TableLock); // // release all cached help entries for( HelpEntryCache::LOCK_ITERATOR it = m_HelpEntryCache.begin(); it != m_HelpEntryCache.end(); it++ ) { if( ((*it).second)->m_RefCount > 1 ) { MYASSERT(FALSE); } ((*it).second)->Release(); } m_HelpEntryCache.erase_all(); MYASSERT( m_HelpEntryCache.size() == 0 ); if( NULL != m_hHelpSessionTableKey ) { RegCloseKey( m_hHelpSessionTableKey ); m_hHelpSessionTableKey = NULL; } return S_OK; } HRESULT CHelpSessionTable::DeleteSessionTable() /*++ Routine description: Delete entire help session table. Parameters: None. Returns: S_OK or error code. --*/ { HRESULT hRes; DWORD dwStatus; CCriticalSectionLocker l(m_TableLock); hRes = CloseSessionTable(); if( SUCCEEDED(hRes) ) { // Recursively delete registry key and its sub-keys. dwStatus = RegDelKey( HKEY_LOCAL_MACHINE, REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE ); if( ERROR_SUCCESS == dwStatus ) { hRes = OpenSessionTable( m_bstrFileName ); } else { hRes = HRESULT_FROM_WIN32( dwStatus ); } } return hRes; } HRESULT CHelpSessionTable::MemEntryToStorageEntry( IN PHELPENTRY pEntry ) /*++ Routine Description: Conver an in-memory help entry to persist help entry. Parameters: pEntry : Pointer to HELPENTRY to be converted. Returns: S_OK or error code. --*/ { HRESULT hRes; CCriticalSectionLocker l(m_TableLock); if( NULL != pEntry ) { // // Check to see if this is in-memory entry // if( FALSE == pEntry->IsInMemoryHelpEntry() ) { hRes = E_INVALIDARG; } else { DWORD dwStatus; HKEY hKey; // // Create a help entry here // dwStatus = RegCreateKeyEx( m_hHelpSessionTableKey, (LPCTSTR)(CComBSTR)pEntry->m_SessionId, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL ); if( ERROR_SUCCESS == dwStatus ) { hRes = pEntry->UpdateEntryValues(hKey); if( SUCCEEDED(hRes) ) { pEntry->ConvertHelpEntry( hKey ); try { m_HelpEntryCache[(CComBSTR)pEntry->m_SessionId] = pEntry; } catch(CMAPException e) { hRes = HRESULT_FROM_WIN32( e.m_ErrorCode ); } catch(...) { hRes = E_UNEXPECTED; throw; } } } else { hRes = HRESULT_FROM_WIN32( dwStatus ); MYASSERT(FALSE); } } } else { MYASSERT(FALSE); hRes = E_UNEXPECTED; } return hRes; } HRESULT CHelpSessionTable::CreateInMemoryHelpEntry( IN const CComBSTR& bstrHelpSession, OUT PHELPENTRY* ppHelpEntry ) /*++ Routine Description: Create an in-memory help entry, this help entry is not persisted into registry until MemEntryToStorageEntry() is called. Paramters: bstrHelpSession : Help Session ID. ppHelpEntry : Newly created HELPENTRY. Returns: S_OK or error code. --*/ { HRESULT hRes = S_OK; CCriticalSectionLocker l(m_TableLock); MYASSERT( NULL != m_hHelpSessionTableKey ); if( NULL != m_hHelpSessionTableKey ) { DWORD dwStatus; HKEY hKey; DWORD dwDeposition; DWORD dwEntryStatus; // Create a key here so we can tell if this is a duplicate dwStatus = RegCreateKeyEx( m_hHelpSessionTableKey, bstrHelpSession, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dwDeposition ); if( ERROR_SUCCESS == dwStatus ) { if( REG_OPENED_EXISTING_KEY == dwDeposition ) { hRes = HRESULT_FROM_WIN32( ERROR_FILE_EXISTS ); } else { // // Mark entry status to be deleted so if we abnormally // terminated, this entry will be deleted on startup // dwEntryStatus = REGVALUE_HELPSESSION_ENTRY_DELETED; dwStatus = RegSetValueEx( hKey, COLUMNNAME_KEYSTATUS, 0, REG_DWORD, (LPBYTE)&dwEntryStatus, sizeof(dwEntryStatus) ); if( ERROR_SUCCESS == dwStatus ) { PHELPENTRY pSess; // Create a in-memory entry pSess = new HELPENTRY( *this, NULL, m_dwEntryValidPeriod ); if( NULL != pSess ) { pSess->m_SessionId = bstrHelpSession; *ppHelpEntry = pSess; // // In memory help entry should also be counted // since we still write out help session ID to // registry which on delete, will do m_NumHelp--. // m_NumHelp++; } else { hRes = E_OUTOFMEMORY; } } } RegCloseKey(hKey); } if(ERROR_SUCCESS != dwStatus ) { hRes = HRESULT_FROM_WIN32( dwStatus ); } } else { hRes = E_UNEXPECTED; } return hRes; } HRESULT CHelpSessionTable::OpenHelpEntry( IN const CComBSTR& bstrHelpSession, OUT PHELPENTRY* ppHelpEntry ) /*++ Routine Description: Open an existing help entry. Parameters: bstrHelpSession : ID of help entry to be opened. ppHelpEntry : Pointer to PHELPENTY to receive loaded help entry. Returns: S_OK or error code. --*/ { CCriticalSectionLocker l(m_TableLock); HRESULT hRes = S_OK; DebugPrintf( _TEXT("OpenHelpEntry() %s\n"), bstrHelpSession ); MYASSERT( bstrHelpSession.Length() > 0 ); // check if entry already exists in cache HelpEntryCache::LOCK_ITERATOR it = m_HelpEntryCache.find( bstrHelpSession ); if( it != m_HelpEntryCache.end() ) { *ppHelpEntry = (*it).second; // // More reference to same object. // (*ppHelpEntry)->AddRef(); // timing, it is possible to have many-to-one mapping, // helpmgr delete from its internal cache but has not // release the help entry. } else { hRes = LoadHelpEntry( m_hHelpSessionTableKey, (LPTSTR)bstrHelpSession, ppHelpEntry ); DebugPrintf( _TEXT("LoadHelpEntry() on %s returns 0x%08x\n"), bstrHelpSession, hRes ); if( SUCCEEDED(hRes) ) { try { m_HelpEntryCache[ bstrHelpSession ] = *ppHelpEntry; } catch( CMAPException e ) { hRes = HRESULT_FROM_WIN32( e.m_ErrorCode ); } catch( ... ) { hRes = E_UNEXPECTED; throw; } } } return hRes; } HRESULT CHelpSessionTable::DeleteHelpEntry( IN const CComBSTR& bstrHelpSession ) /*++ Routine Description: Delete a help entry. Parameters: bstrHelpSession : ID of help session entry to be deleted. Returns: S_OK or error code. --*/ { HRESULT hRes = S_OK; CCriticalSectionLocker l(m_TableLock); DebugPrintf( _TEXT("DeleteHelpEntry() %s\n"), bstrHelpSession ); // check if entry already exists in cache HelpEntryCache::LOCK_ITERATOR it = m_HelpEntryCache.find( bstrHelpSession ); if( it != m_HelpEntryCache.end() ) { // mark entry deleted in registry hRes = ((*it).second)->DeleteEntry(); MYASSERT( SUCCEEDED(hRes) ); // release this entry ref. count. ((*it).second)->Release(); // remove from our cache m_HelpEntryCache.erase( it ); } else { // // unsolicited help will not be in our cache. // hRes = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND); } { DWORD dwStatus; dwStatus = RegDelKey( m_hHelpSessionTableKey, bstrHelpSession ); if( ERROR_SUCCESS == dwStatus ) { m_NumHelp--; } } return hRes; } CHelpSessionTable::~CHelpSessionTable() { CloseSessionTable(); return; } HRESULT CHelpSessionTable::EnumHelpEntry( IN EnumHelpEntryCallback pFunc, IN HANDLE userData ) /*++ Routine Description: Enumerate all help entries. Parameters: pFunc : Call back function. userData : User defined data. Returns: S_OK or error code. --*/ { EnumHelpEntryParm parm; HRESULT hRes = S_OK; DWORD dwStatus; CCriticalSectionLocker l(m_TableLock); if( NULL == pFunc ) { hRes = E_POINTER; } else { try { parm.userData = userData; parm.pCallback = pFunc; parm.pTable = this; dwStatus = RegEnumSubKeys( HKEY_LOCAL_MACHINE, REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE, EnumOpenHelpEntry, (HANDLE) &parm ); if( ERROR_SUCCESS != dwStatus ) { hRes = HRESULT_FROM_WIN32( dwStatus ); } } catch(...) { hRes = E_UNEXPECTED; } } return hRes; } HRESULT CHelpSessionTable::ReleaseHelpEntry( IN CComBSTR& bstrHelpSessionId ) /*++ Routine Description: Release/unload a help entry from cached, this help entry is not deleted. Paramters: bstrHelpSessionId : ID of help entry to be unloaded from memory. Returns: S_OK or error code --*/ { CCriticalSectionLocker l(m_TableLock); HRESULT hRes = S_OK; HelpEntryCache::LOCK_ITERATOR it = m_HelpEntryCache.find( bstrHelpSessionId ); if( it != m_HelpEntryCache.end() ) { (*it).second->Release(); m_HelpEntryCache.erase( it ); } else { hRes = HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND ); } return hRes; } HRESULT CHelpSessionTable::EnumOpenHelpEntry( IN HKEY hKey, IN LPTSTR pszKeyName, IN HANDLE userData ) /*++ Routine Description: Call back funtion for EnumHelpEntry() and RegEnumSubKeys(). Parameters: hKey : Registry key handle to help session table. pszKeyName : help entry id (registry sub-key name). userData : User defined data. Returns: S_OK or error code. --*/ { HRESULT hRes = S_OK; PEnumHelpEntryParm pParm = (PEnumHelpEntryParm)userData; if( NULL == pParm ) { hRes = E_UNEXPECTED; } else { hRes = pParm->pCallback( CComBSTR(pszKeyName), pParm->userData ); } return hRes; } HRESULT CHelpSessionTable::CreatePendingHelpTable() /*++ Routine to create pending help table registry key, if registry key already exist, set the DACL to system context only. --*/ { PACL pAcl=NULL; DWORD dwStatus = ERROR_SUCCESS; PSECURITY_DESCRIPTOR pSecurityDescriptor = NULL; DWORD cbAcl = 0; PSID pSidSystem = NULL; HKEY hKey = NULL; pSecurityDescriptor = (PSECURITY_DESCRIPTOR)LocalAlloc(LPTR, sizeof(SECURITY_DESCRIPTOR)); if( NULL == pSecurityDescriptor ) { dwStatus = GetLastError(); goto CLEANUPANDEXIT; } // // Initialize the security descriptor. // if (!InitializeSecurityDescriptor( pSecurityDescriptor, SECURITY_DESCRIPTOR_REVISION )) { dwStatus = GetLastError(); goto CLEANUPANDEXIT; } dwStatus = CreateSystemSid( &pSidSystem ); if( ERROR_SUCCESS != dwStatus ) { goto CLEANUPANDEXIT; } cbAcl = GetLengthSid( pSidSystem ) + sizeof(ACL) + (2 * (sizeof(ACCESS_ALLOWED_ACE) - sizeof(DWORD))); pAcl = (PACL) LocalAlloc( LPTR, cbAcl ); if( NULL == pAcl ) { dwStatus = GetLastError(); goto CLEANUPANDEXIT; } // // Initialize the ACL. // if (!InitializeAcl(pAcl, cbAcl, ACL_REVISION)) { dwStatus = GetLastError(); goto CLEANUPANDEXIT; } // if (!AddAccessAllowedAce(pAcl, ACL_REVISION, GENERIC_READ | GENERIC_WRITE | GENERIC_ALL, pSidSystem )) { dwStatus = GetLastError(); goto CLEANUPANDEXIT; } if (!SetSecurityDescriptorDacl(pSecurityDescriptor, TRUE, pAcl, FALSE)) { dwStatus = GetLastError(); goto CLEANUPANDEXIT; } // // Create/open the pending table registry key // dwStatus = RegCreateKeyEx( HKEY_LOCAL_MACHINE, REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE, 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, NULL ); if( ERROR_SUCCESS != dwStatus ) { goto CLEANUPANDEXIT; } // // Set table (registry) DACL // dwStatus = RegSetKeySecurity( hKey, DACL_SECURITY_INFORMATION, pSecurityDescriptor ); CLEANUPANDEXIT: if( NULL != hKey ) { RegCloseKey(hKey); } if( pAcl != NULL ) { LocalFree(pAcl); } if( pSecurityDescriptor != NULL ) { LocalFree( pSecurityDescriptor ); } if( pSidSystem != NULL ) { FreeSid( pSidSystem ); } return HRESULT_FROM_WIN32(dwStatus); }