Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1518 lines
32 KiB

  1. /*++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. HelpTab.cpp
  5. Abstract:
  6. Implementation of __HelpEntry structure and CHelpSessionTable.
  7. Author:
  8. HueiWang 06/29/2000
  9. --*/
  10. #include "stdafx.h"
  11. #include <time.h>
  12. #include <windows.h>
  13. #include <wincrypt.h>
  14. #include <stdio.h>
  15. #include <tchar.h>
  16. #include "helptab.h"
  17. #include "policy.h"
  18. #include "sessmgrmc.h"
  19. //
  20. //
  21. // __HelpEntry strucutre implementation
  22. //
  23. //
  24. HRESULT
  25. __HelpEntry::LoadEntryValues(
  26. IN HKEY hKey
  27. )
  28. /*++
  29. Routine Description:
  30. Load help session entry from registry key.
  31. Parameters:
  32. hKey : Handle to registry key containing help entry values.
  33. Returns:
  34. S_OK or error code.
  35. --*/
  36. {
  37. DWORD dwStatus;
  38. MYASSERT( NULL != hKey );
  39. if( NULL != hKey )
  40. {
  41. dwStatus = m_EntryStatus.DBLoadValue( hKey );
  42. if( ERROR_SUCCESS != dwStatus )
  43. {
  44. goto CLEANUPANDEXIT;
  45. }
  46. if( REGVALUE_HELPSESSION_ENTRY_DELETED == m_EntryStatus )
  47. {
  48. // entry already been deleted, no reason to continue loading
  49. dwStatus = ERROR_FILE_NOT_FOUND;
  50. goto CLEANUPANDEXIT;
  51. }
  52. dwStatus = m_SessionId.DBLoadValue(hKey);
  53. if( ERROR_SUCCESS != dwStatus )
  54. {
  55. goto CLEANUPANDEXIT;
  56. }
  57. if( m_SessionId->Length() == 0 )
  58. {
  59. // Help Session ID must exist, no default value.
  60. dwStatus = ERROR_INVALID_DATA;
  61. goto CLEANUPANDEXIT;
  62. }
  63. dwStatus = m_SessionName.DBLoadValue(hKey);
  64. if( ERROR_SUCCESS != dwStatus )
  65. {
  66. goto CLEANUPANDEXIT;
  67. }
  68. dwStatus = m_SessionPwd.DBLoadValue(hKey);
  69. if( ERROR_SUCCESS != dwStatus )
  70. {
  71. goto CLEANUPANDEXIT;
  72. }
  73. dwStatus = m_SessionDesc.DBLoadValue(hKey);
  74. if( ERROR_SUCCESS != dwStatus )
  75. {
  76. goto CLEANUPANDEXIT;
  77. }
  78. //dwStatus = m_SessResolverGUID.DBLoadValue(hKey);
  79. //if( ERROR_SUCCESS != dwStatus )
  80. //{
  81. // goto CLEANUPANDEXIT;
  82. //}
  83. dwStatus = m_EnableResolver.DBLoadValue(hKey);
  84. if( ERROR_SUCCESS != dwStatus )
  85. {
  86. goto CLEANUPANDEXIT;
  87. }
  88. dwStatus = m_SessResolverBlob.DBLoadValue(hKey);
  89. if( ERROR_SUCCESS != dwStatus )
  90. {
  91. goto CLEANUPANDEXIT;
  92. }
  93. dwStatus = m_UserSID.DBLoadValue(hKey);
  94. if( ERROR_SUCCESS != dwStatus )
  95. {
  96. goto CLEANUPANDEXIT;
  97. }
  98. dwStatus = m_CreationTime.DBLoadValue(hKey);
  99. if( ERROR_SUCCESS != dwStatus )
  100. {
  101. goto CLEANUPANDEXIT;
  102. }
  103. dwStatus = m_ExpirationTime.DBLoadValue(hKey);
  104. if( ERROR_SUCCESS != dwStatus )
  105. {
  106. goto CLEANUPANDEXIT;
  107. }
  108. dwStatus = m_SessionRdsSetting.DBLoadValue(hKey);
  109. if( ERROR_SUCCESS != dwStatus )
  110. {
  111. goto CLEANUPANDEXIT;
  112. }
  113. dwStatus = m_EntryStatus.DBLoadValue(hKey);
  114. if( ERROR_SUCCESS != dwStatus )
  115. {
  116. goto CLEANUPANDEXIT;
  117. }
  118. dwStatus = m_CreationTime.DBLoadValue(hKey);
  119. if( ERROR_SUCCESS != dwStatus )
  120. {
  121. goto CLEANUPANDEXIT;
  122. }
  123. dwStatus = m_IpAddress.DBLoadValue(hKey);
  124. if( ERROR_SUCCESS != dwStatus )
  125. {
  126. goto CLEANUPANDEXIT;
  127. }
  128. dwStatus = m_ICSPort.DBLoadValue(hKey);
  129. if( ERROR_SUCCESS != dwStatus )
  130. {
  131. goto CLEANUPANDEXIT;
  132. }
  133. dwStatus = m_SessionCreateBlob.DBLoadValue(hKey);
  134. }
  135. else
  136. {
  137. dwStatus = E_UNEXPECTED;
  138. }
  139. CLEANUPANDEXIT:
  140. return HRESULT_FROM_WIN32(dwStatus);
  141. }
  142. HRESULT
  143. __HelpEntry::UpdateEntryValues(
  144. IN HKEY hKey
  145. )
  146. /*++
  147. Routine Description:
  148. Update/store help entry value to registry.
  149. Parameters:
  150. hKey : Handle to registry to save help entry value.
  151. Returns:
  152. S_OK or error code.
  153. --*/
  154. {
  155. DWORD dwStatus;
  156. MYASSERT( NULL != hKey );
  157. if( NULL == hKey )
  158. {
  159. dwStatus = E_UNEXPECTED;
  160. goto CLEANUPANDEXIT;
  161. }
  162. if( REGVALUE_HELPSESSION_ENTRY_DELETED == m_EntryStatus )
  163. {
  164. // entry already deleted, error out
  165. dwStatus = ERROR_FILE_NOT_FOUND;
  166. goto CLEANUPANDEXIT;
  167. }
  168. // New entry value, entry status in registry is set
  169. // to delete so when we failed to completely writting
  170. // all value to registry, we can still assume it is
  171. // deleted.
  172. if( REGVALUE_HELPSESSION_ENTRY_NEW != m_EntryStatus )
  173. {
  174. // Mark entry dirty.
  175. m_EntryStatus = REGVALUE_HELPSESSION_ENTRY_DIRTY;
  176. dwStatus = m_EntryStatus.DBUpdateValue( hKey );
  177. if( ERROR_SUCCESS != dwStatus )
  178. {
  179. goto CLEANUPANDEXIT;
  180. }
  181. }
  182. dwStatus = m_SessionId.DBUpdateValue(hKey);
  183. if( ERROR_SUCCESS != dwStatus )
  184. {
  185. goto CLEANUPANDEXIT;
  186. }
  187. dwStatus = m_SessionName.DBUpdateValue(hKey);
  188. if( ERROR_SUCCESS != dwStatus )
  189. {
  190. goto CLEANUPANDEXIT;
  191. }
  192. dwStatus = m_SessionPwd.DBUpdateValue(hKey);
  193. if( ERROR_SUCCESS != dwStatus )
  194. {
  195. goto CLEANUPANDEXIT;
  196. }
  197. dwStatus = m_SessionDesc.DBUpdateValue(hKey);
  198. if( ERROR_SUCCESS != dwStatus )
  199. {
  200. goto CLEANUPANDEXIT;
  201. }
  202. //dwStatus = m_SessResolverGUID.DBUpdateValue(hKey);
  203. //if( ERROR_SUCCESS != dwStatus )
  204. //{
  205. // goto CLEANUPANDEXIT;
  206. //}
  207. dwStatus = m_EnableResolver.DBUpdateValue(hKey);
  208. if( ERROR_SUCCESS != dwStatus )
  209. {
  210. goto CLEANUPANDEXIT;
  211. }
  212. dwStatus = m_SessResolverBlob.DBUpdateValue(hKey);
  213. if( ERROR_SUCCESS != dwStatus )
  214. {
  215. goto CLEANUPANDEXIT;
  216. }
  217. dwStatus = m_UserSID.DBUpdateValue(hKey);
  218. if( ERROR_SUCCESS != dwStatus )
  219. {
  220. goto CLEANUPANDEXIT;
  221. }
  222. dwStatus = m_CreationTime.DBUpdateValue(hKey);
  223. if( ERROR_SUCCESS != dwStatus )
  224. {
  225. goto CLEANUPANDEXIT;
  226. }
  227. dwStatus = m_ExpirationTime.DBUpdateValue(hKey);
  228. if( ERROR_SUCCESS != dwStatus )
  229. {
  230. goto CLEANUPANDEXIT;
  231. }
  232. dwStatus = m_SessionRdsSetting.DBUpdateValue(hKey);
  233. if( ERROR_SUCCESS != dwStatus )
  234. {
  235. goto CLEANUPANDEXIT;
  236. }
  237. dwStatus = m_IpAddress.DBUpdateValue(hKey);
  238. if( ERROR_SUCCESS != dwStatus )
  239. {
  240. goto CLEANUPANDEXIT;
  241. }
  242. dwStatus = m_ICSPort.DBUpdateValue(hKey);
  243. if( ERROR_SUCCESS != dwStatus )
  244. {
  245. goto CLEANUPANDEXIT;
  246. }
  247. dwStatus = m_SessionCreateBlob.DBUpdateValue(hKey);
  248. if( ERROR_SUCCESS != dwStatus )
  249. {
  250. goto CLEANUPANDEXIT;
  251. }
  252. // Mark entry normal
  253. m_EntryStatus = REGVALUE_HELPSESSION_ENTRY_NORMAL;
  254. dwStatus = m_EntryStatus.DBUpdateValue( hKey );
  255. CLEANUPANDEXIT:
  256. return HRESULT_FROM_WIN32(dwStatus);
  257. }
  258. HRESULT
  259. __HelpEntry::BackupEntry()
  260. /*++
  261. Routine Description:
  262. Backup help entry, backup is stored under
  263. <Help Entry Registry>\\Backup registry key.
  264. Parameters:
  265. None.
  266. Returns:
  267. S_OK or error code.
  268. --*/
  269. {
  270. HKEY hKey = NULL;
  271. DWORD dwStatus;
  272. MYASSERT( NULL != m_hEntryKey );
  273. if( NULL != m_hEntryKey )
  274. {
  275. //
  276. // Delete current backup
  277. (void)DeleteEntryBackup();
  278. //
  279. // Create a backup registry key
  280. dwStatus = RegCreateKeyEx(
  281. m_hEntryKey,
  282. REGKEY_HELPENTRYBACKUP,
  283. 0,
  284. NULL,
  285. REG_OPTION_NON_VOLATILE,
  286. KEY_ALL_ACCESS,
  287. NULL,
  288. &hKey,
  289. NULL
  290. );
  291. if( ERROR_SUCCESS != dwStatus )
  292. {
  293. MYASSERT(FALSE);
  294. }
  295. else
  296. {
  297. dwStatus = UpdateEntryValues( hKey );
  298. }
  299. }
  300. else
  301. {
  302. dwStatus = E_UNEXPECTED;
  303. }
  304. if( NULL != hKey )
  305. {
  306. RegCloseKey( hKey );
  307. }
  308. return HRESULT_FROM_WIN32(dwStatus);
  309. }
  310. HRESULT
  311. __HelpEntry::RestoreEntryFromBackup()
  312. /*++
  313. Routine Description:
  314. Restore help entry from backup, backup is stored under
  315. <Help Entry Registry>\\Backup registry key.
  316. Parameters:
  317. None.
  318. Returns:
  319. S_OK or error code.
  320. --*/
  321. {
  322. DWORD dwStatus;
  323. HKEY hBackupKey = NULL;
  324. MYASSERT( NULL != m_hEntryKey );
  325. if( NULL != m_hEntryKey )
  326. {
  327. //
  328. // check if backup registry exists.
  329. dwStatus = RegOpenKeyEx(
  330. m_hEntryKey,
  331. REGKEY_HELPENTRYBACKUP,
  332. 0,
  333. KEY_ALL_ACCESS,
  334. &hBackupKey
  335. );
  336. if( ERROR_SUCCESS == dwStatus )
  337. {
  338. HELPENTRY backup( m_pHelpSessionTable, hBackupKey, ENTRY_VALID_PERIOD );
  339. // load backup values
  340. dwStatus = backup.LoadEntryValues( hBackupKey );
  341. if( ERROR_SUCCESS == dwStatus )
  342. {
  343. if( (DWORD)backup.m_EntryStatus == REGVALUE_HELPSESSION_ENTRY_NORMAL )
  344. {
  345. *this = backup;
  346. }
  347. else
  348. {
  349. (void)DeleteEntryBackup();
  350. dwStatus = ERROR_FILE_NOT_FOUND;
  351. }
  352. }
  353. // HELPSESSION destructor will close registry key
  354. }
  355. if( ERROR_SUCCESS == dwStatus )
  356. {
  357. //
  358. // update all values.
  359. dwStatus = UpdateEntryValues( m_hEntryKey );
  360. if( ERROR_SUCCESS == dwStatus )
  361. {
  362. //
  363. // Already restore entry, delete backup copy
  364. (void)DeleteEntryBackup();
  365. }
  366. }
  367. }
  368. else
  369. {
  370. dwStatus = E_UNEXPECTED;
  371. }
  372. return HRESULT_FROM_WIN32( dwStatus );
  373. }
  374. HRESULT
  375. __HelpEntry::DeleteEntryBackup()
  376. /*++
  377. Routine Description:
  378. Delete help entry backup from registry.
  379. Parameters:
  380. None.
  381. Returns:
  382. always S_OK
  383. --*/
  384. {
  385. DWORD dwStatus;
  386. dwStatus = RegDelKey(
  387. m_hEntryKey,
  388. REGKEY_HELPENTRYBACKUP
  389. );
  390. return HRESULT_FROM_WIN32(dwStatus);
  391. }
  392. BOOL
  393. __HelpEntry::IsEntryExpired()
  394. {
  395. FILETIME ft;
  396. ULARGE_INTEGER ul1, ul2;
  397. GetSystemTimeAsFileTime(&ft);
  398. ul1.LowPart = ft.dwLowDateTime;
  399. ul1.HighPart = ft.dwHighDateTime;
  400. ft = (FILETIME)m_ExpirationTime;
  401. ul2.LowPart = ft.dwLowDateTime;
  402. ul2.HighPart = ft.dwHighDateTime;
  403. #if DBG
  404. if( ul1.QuadPart >= ul2.QuadPart )
  405. {
  406. DebugPrintf(
  407. _TEXT("Help Entry %s has expired ...\n"),
  408. (LPCTSTR)(CComBSTR)m_SessionId
  409. );
  410. }
  411. #endif
  412. return (ul1.QuadPart >= ul2.QuadPart);
  413. }
  414. ////////////////////////////////////////////////////////////////////////////////
  415. //
  416. // CHelpSessionTable implementation
  417. //
  418. CHelpSessionTable::CHelpSessionTable() :
  419. m_hHelpSessionTableKey(NULL), m_NumHelp(0)
  420. {
  421. HKEY hKey = NULL;
  422. DWORD dwStatus;
  423. DWORD dwSize;
  424. DWORD dwType;
  425. //
  426. // Load entry valid period setting from registry
  427. //
  428. dwStatus = RegOpenKeyEx(
  429. HKEY_LOCAL_MACHINE,
  430. RDS_MACHINEPOLICY_SUBTREE,
  431. 0,
  432. KEY_READ,
  433. &hKey
  434. );
  435. if( ERROR_SUCCESS == dwStatus )
  436. {
  437. dwSize = sizeof(DWORD);
  438. dwStatus = RegQueryValueEx(
  439. hKey,
  440. RDS_HELPENTRY_VALID_PERIOD,
  441. NULL,
  442. &dwType,
  443. (PBYTE) &m_dwEntryValidPeriod,
  444. &dwSize
  445. );
  446. if( REG_DWORD != dwType )
  447. {
  448. dwStatus = ERROR_FILE_NOT_FOUND;
  449. }
  450. RegCloseKey(hKey);
  451. }
  452. if(ERROR_SUCCESS != dwStatus )
  453. {
  454. // pick default value
  455. m_dwEntryValidPeriod = ENTRY_VALID_PERIOD;
  456. }
  457. }
  458. HRESULT
  459. CHelpSessionTable::RestoreHelpSessionTable(
  460. IN HKEY hKey,
  461. IN LPTSTR pszKeyName,
  462. IN HANDLE userData
  463. )
  464. /*++
  465. Routine Description:
  466. Restore help session table. This routine is callback from RegEnumSubKeys().
  467. Parameters:
  468. hKey : Handle to registry.
  469. pszKeyName : registry sub-key name containing one help session entry
  470. userData : User defined data.
  471. Returns:
  472. S_OK or error code.
  473. --*/
  474. {
  475. HRESULT hRes;
  476. if( NULL == userData )
  477. {
  478. hRes = E_UNEXPECTED;
  479. MYASSERT(FALSE);
  480. }
  481. else
  482. {
  483. CHelpSessionTable* pTable = (CHelpSessionTable *) userData;
  484. hRes = pTable->RestoreHelpSessionEntry( hKey, pszKeyName );
  485. if( SUCCEEDED(hRes) )
  486. {
  487. pTable->m_NumHelp++;
  488. }
  489. hRes = S_OK;
  490. }
  491. return hRes;
  492. }
  493. BOOL
  494. CHelpSessionTable::IsEntryExpired(
  495. IN PHELPENTRY pEntry
  496. )
  497. /*++
  498. Routine Description:
  499. Determine if a help entry has expired.
  500. Paramters:
  501. pEntry : Pointer to help entry.
  502. Returns:
  503. TRUE if entry has expired, FALSE otherwise.
  504. --*/
  505. {
  506. MYASSERT( NULL != pEntry );
  507. return (NULL != pEntry) ? pEntry->IsEntryExpired() : TRUE;
  508. }
  509. HRESULT
  510. CHelpSessionTable::RestoreHelpSessionEntry(
  511. IN HKEY hKey,
  512. IN LPTSTR pszKeyName
  513. )
  514. /*++
  515. Routine Description:
  516. Restore a single help session entry.
  517. Parameters:
  518. hKey : Handle to help session table.
  519. pszKeyName : Registry sub-key name containing help entry.
  520. Returns:
  521. S_OK or error code.
  522. --*/
  523. {
  524. HKEY hEntryKey = NULL;
  525. DWORD dwStatus;
  526. DWORD dwDuplicate = REG_CREATED_NEW_KEY;
  527. LONG entryStatus;
  528. BOOL bDeleteEntry = FALSE;
  529. //
  530. // Open the registry key for session entry
  531. dwStatus = RegOpenKeyEx(
  532. hKey,
  533. pszKeyName,
  534. 0,
  535. KEY_ALL_ACCESS,
  536. &hEntryKey
  537. );
  538. if( ERROR_SUCCESS == dwStatus )
  539. {
  540. HELPENTRY helpEntry( *this, hEntryKey, m_dwEntryValidPeriod );
  541. // load help entry
  542. dwStatus = helpEntry.Refresh();
  543. if( dwStatus != ERROR_SUCCESS || helpEntry.m_SessionId->Length() == 0 ||
  544. REGVALUE_HELPSESSION_ENTRY_DELETEONSTARTUP == helpEntry.m_EntryStatus )
  545. {
  546. // Session ID must not be NULL.
  547. bDeleteEntry = TRUE;
  548. }
  549. else
  550. {
  551. if( REGVALUE_HELPSESSION_ENTRY_DELETED != helpEntry.m_EntryStatus )
  552. {
  553. if( TRUE != IsEntryExpired( &helpEntry ) )
  554. {
  555. if( REGVALUE_HELPSESSION_ENTRY_DIRTY == helpEntry.m_EntryStatus )
  556. {
  557. // Entry is partially updated, try to restore from backup,
  558. // is failed restoring, treat as bad entry.
  559. if( FAILED(helpEntry.RestoreEntryFromBackup()) )
  560. {
  561. bDeleteEntry = TRUE;
  562. }
  563. }
  564. }
  565. else
  566. {
  567. LPCTSTR eventString[1];
  568. eventString[0] = (LPCTSTR)(CComBSTR)helpEntry.m_SessionId;
  569. _Module.LogEventString(
  570. EVENTLOG_INFORMATION_TYPE,
  571. SESSMGR_I_HELPENTRYEXPIRED,
  572. 1,
  573. eventString
  574. );
  575. DebugPrintf(
  576. _TEXT("Help Entry has expired %s\n"),
  577. (CComBSTR)helpEntry.m_SessionId
  578. );
  579. }
  580. }
  581. else
  582. {
  583. bDeleteEntry = TRUE;
  584. }
  585. }
  586. }
  587. if( TRUE == bDeleteEntry )
  588. {
  589. dwStatus = RegDelKey( hKey, pszKeyName );
  590. //
  591. // Ignore error
  592. //
  593. DebugPrintf(
  594. _TEXT("RegDelKey on entry %s returns %d\n"),
  595. pszKeyName,
  596. dwStatus
  597. );
  598. dwStatus = ERROR_FILE_NOT_FOUND;
  599. }
  600. return HRESULT_FROM_WIN32( dwStatus );
  601. }
  602. HRESULT
  603. CHelpSessionTable::LoadHelpEntry(
  604. IN HKEY hKey,
  605. IN LPTSTR pszKeyName,
  606. OUT PHELPENTRY* ppHelpSession
  607. )
  608. /*++
  609. Routine description:
  610. Load a help entry from registry.
  611. Parameters:
  612. hKey : registry handle to help session table.
  613. pszKeyName : registry sub-key name (Help session ID).
  614. ppHelpSession : Pointer to PHELPENTRY to receive loaded help
  615. entry.
  616. Returns:
  617. S_OK or error code.
  618. --*/
  619. {
  620. PHELPENTRY pSess;
  621. HRESULT hRes;
  622. HKEY hEntryKey = NULL;
  623. DWORD dwStatus;
  624. MYASSERT( NULL != hKey );
  625. if( NULL != hKey )
  626. {
  627. // open the registry containing help entry
  628. dwStatus = RegOpenKeyEx(
  629. hKey,
  630. pszKeyName,
  631. 0,
  632. KEY_ALL_ACCESS,
  633. &hEntryKey
  634. );
  635. if( ERROR_SUCCESS == dwStatus )
  636. {
  637. pSess = new HELPENTRY( *this, hEntryKey, m_dwEntryValidPeriod );
  638. if( NULL == pSess )
  639. {
  640. hRes = E_OUTOFMEMORY;
  641. }
  642. else
  643. {
  644. // load help entry, Refresh() will failed if
  645. // session ID is NULL or emptry string
  646. hRes = pSess->Refresh();
  647. if( SUCCEEDED(hRes) )
  648. {
  649. if( (DWORD)pSess->m_EntryStatus == REGVALUE_HELPSESSION_ENTRY_NORMAL )
  650. {
  651. *ppHelpSession = pSess;
  652. }
  653. else
  654. {
  655. dwStatus = ERROR_FILE_NOT_FOUND;
  656. }
  657. }
  658. if( FAILED(hRes) )
  659. {
  660. pSess->Release();
  661. }
  662. }
  663. }
  664. else
  665. {
  666. hRes = HRESULT_FROM_WIN32( dwStatus );
  667. }
  668. }
  669. else
  670. {
  671. hRes = E_UNEXPECTED;
  672. }
  673. return hRes;
  674. }
  675. HRESULT
  676. CHelpSessionTable::OpenSessionTable(
  677. IN LPCTSTR pszFileName // reserverd.
  678. )
  679. /*++
  680. Routine Description:
  681. Open help session table, routine enumerate all help entry (registry sub-key),
  682. and restore/delete help entry if necessary.
  683. Parameters:
  684. pszFileName : reserved parameter, must be NULL.
  685. Returns:
  686. S_OK or error code.
  687. --*/
  688. {
  689. DWORD dwStatus;
  690. CCriticalSectionLocker l(m_TableLock);
  691. //
  692. // Go thru all sub-key containing help entry and restore or delete
  693. // help entry if necessary.
  694. dwStatus = RegEnumSubKeys(
  695. HKEY_LOCAL_MACHINE,
  696. REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE,
  697. RestoreHelpSessionTable,
  698. (HANDLE)this
  699. );
  700. if( ERROR_SUCCESS != dwStatus && ERROR_FILE_NOT_FOUND != dwStatus )
  701. {
  702. if( NULL != m_hHelpSessionTableKey )
  703. {
  704. // Make sure registry key is not opened.
  705. RegCloseKey(m_hHelpSessionTableKey);
  706. m_hHelpSessionTableKey = NULL;
  707. }
  708. // If table is bad, delete and re-create again
  709. dwStatus = RegDelKey(
  710. HKEY_LOCAL_MACHINE,
  711. REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE
  712. );
  713. if( ERROR_SUCCESS != dwStatus && ERROR_FILE_NOT_FOUND != dwStatus )
  714. {
  715. // Critical error
  716. MYASSERT(FALSE);
  717. goto CLEANUPANDEXIT;
  718. }
  719. }
  720. //
  721. // Open registry key containing our help session table.
  722. dwStatus = RegCreateKeyEx(
  723. HKEY_LOCAL_MACHINE,
  724. REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE,
  725. 0,
  726. NULL,
  727. REG_OPTION_NON_VOLATILE,
  728. KEY_ALL_ACCESS,
  729. NULL,
  730. &m_hHelpSessionTableKey,
  731. NULL
  732. );
  733. if( ERROR_SUCCESS != dwStatus )
  734. {
  735. MYASSERT(FALSE);
  736. goto CLEANUPANDEXIT;
  737. }
  738. else
  739. {
  740. m_bstrFileName = pszFileName;
  741. }
  742. CLEANUPANDEXIT:
  743. return HRESULT_FROM_WIN32(dwStatus);
  744. }
  745. HRESULT
  746. CHelpSessionTable::CloseSessionTable()
  747. /*++
  748. Routine Description:
  749. Close help session table.
  750. Parameters:
  751. None.
  752. Returns:
  753. S_OK or error code.
  754. --*/
  755. {
  756. // no help is opened.
  757. CCriticalSectionLocker l(m_TableLock);
  758. //
  759. // release all cached help entries
  760. for( HelpEntryCache::LOCK_ITERATOR it = m_HelpEntryCache.begin();
  761. it != m_HelpEntryCache.end();
  762. it++
  763. )
  764. {
  765. ((*it).second)->Release();
  766. }
  767. m_HelpEntryCache.erase_all();
  768. MYASSERT( m_HelpEntryCache.size() == 0 );
  769. if( NULL != m_hHelpSessionTableKey )
  770. {
  771. RegCloseKey( m_hHelpSessionTableKey );
  772. m_hHelpSessionTableKey = NULL;
  773. }
  774. return S_OK;
  775. }
  776. HRESULT
  777. CHelpSessionTable::DeleteSessionTable()
  778. /*++
  779. Routine description:
  780. Delete entire help session table.
  781. Parameters:
  782. None.
  783. Returns:
  784. S_OK or error code.
  785. --*/
  786. {
  787. HRESULT hRes;
  788. DWORD dwStatus;
  789. CCriticalSectionLocker l(m_TableLock);
  790. hRes = CloseSessionTable();
  791. if( SUCCEEDED(hRes) )
  792. {
  793. // Recursively delete registry key and its sub-keys.
  794. dwStatus = RegDelKey(
  795. HKEY_LOCAL_MACHINE,
  796. REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE
  797. );
  798. if( ERROR_SUCCESS == dwStatus )
  799. {
  800. hRes = OpenSessionTable( m_bstrFileName );
  801. }
  802. else
  803. {
  804. hRes = HRESULT_FROM_WIN32( dwStatus );
  805. }
  806. }
  807. return hRes;
  808. }
  809. HRESULT
  810. CHelpSessionTable::MemEntryToStorageEntry(
  811. IN PHELPENTRY pEntry
  812. )
  813. /*++
  814. Routine Description:
  815. Conver an in-memory help entry to persist help entry.
  816. Parameters:
  817. pEntry : Pointer to HELPENTRY to be converted.
  818. Returns:
  819. S_OK or error code.
  820. --*/
  821. {
  822. HRESULT hRes;
  823. CCriticalSectionLocker l(m_TableLock);
  824. if( NULL != pEntry )
  825. {
  826. //
  827. // Check to see if this is in-memory entry
  828. //
  829. if( FALSE == pEntry->IsInMemoryHelpEntry() )
  830. {
  831. hRes = E_INVALIDARG;
  832. }
  833. else
  834. {
  835. DWORD dwStatus;
  836. HKEY hKey;
  837. //
  838. // Create a help entry here
  839. //
  840. dwStatus = RegCreateKeyEx(
  841. m_hHelpSessionTableKey,
  842. (LPCTSTR)(CComBSTR)pEntry->m_SessionId,
  843. 0,
  844. NULL,
  845. REG_OPTION_NON_VOLATILE,
  846. KEY_ALL_ACCESS,
  847. NULL,
  848. &hKey,
  849. NULL
  850. );
  851. if( ERROR_SUCCESS == dwStatus )
  852. {
  853. hRes = pEntry->UpdateEntryValues(hKey);
  854. if( SUCCEEDED(hRes) )
  855. {
  856. pEntry->ConvertHelpEntry( hKey );
  857. m_HelpEntryCache[(CComBSTR)pEntry->m_SessionId] = pEntry;
  858. }
  859. }
  860. else
  861. {
  862. hRes = HRESULT_FROM_WIN32( dwStatus );
  863. MYASSERT(FALSE);
  864. }
  865. }
  866. }
  867. else
  868. {
  869. MYASSERT(FALSE);
  870. hRes = E_UNEXPECTED;
  871. }
  872. return hRes;
  873. }
  874. HRESULT
  875. CHelpSessionTable::CreateInMemoryHelpEntry(
  876. IN const CComBSTR& bstrHelpSession,
  877. OUT PHELPENTRY* ppHelpEntry
  878. )
  879. /*++
  880. Routine Description:
  881. Create an in-memory help entry, this help entry is not
  882. persisted into registry until MemEntryToStorageEntry() is called.
  883. Paramters:
  884. bstrHelpSession : Help Session ID.
  885. ppHelpEntry : Newly created HELPENTRY.
  886. Returns:
  887. S_OK or error code.
  888. --*/
  889. {
  890. HRESULT hRes = S_OK;
  891. CCriticalSectionLocker l(m_TableLock);
  892. MYASSERT( NULL != m_hHelpSessionTableKey );
  893. if( NULL != m_hHelpSessionTableKey )
  894. {
  895. DWORD dwStatus;
  896. HKEY hKey;
  897. DWORD dwDeposition;
  898. DWORD dwEntryStatus;
  899. // Create a key here so we can tell if this is a duplicate
  900. dwStatus = RegCreateKeyEx(
  901. m_hHelpSessionTableKey,
  902. bstrHelpSession,
  903. 0,
  904. NULL,
  905. REG_OPTION_NON_VOLATILE,
  906. KEY_ALL_ACCESS,
  907. NULL,
  908. &hKey,
  909. &dwDeposition
  910. );
  911. if( ERROR_SUCCESS == dwStatus )
  912. {
  913. if( REG_OPENED_EXISTING_KEY == dwDeposition )
  914. {
  915. hRes = HRESULT_FROM_WIN32( ERROR_FILE_EXISTS );
  916. }
  917. else
  918. {
  919. //
  920. // Mark entry status to be deleted so if we abnormally
  921. // terminated, this entry will be deleted on startup
  922. //
  923. dwEntryStatus = REGVALUE_HELPSESSION_ENTRY_DELETED;
  924. dwStatus = RegSetValueEx(
  925. hKey,
  926. COLUMNNAME_KEYSTATUS,
  927. 0,
  928. REG_DWORD,
  929. (LPBYTE)&dwEntryStatus,
  930. sizeof(dwEntryStatus)
  931. );
  932. if( ERROR_SUCCESS == dwStatus )
  933. {
  934. PHELPENTRY pSess;
  935. // Create a in-memory entry
  936. pSess = new HELPENTRY( *this, NULL, m_dwEntryValidPeriod );
  937. if( NULL != pSess )
  938. {
  939. pSess->m_SessionId = bstrHelpSession;
  940. *ppHelpEntry = pSess;
  941. //
  942. // In memory help entry should also be counted
  943. // since we still write out help session ID to
  944. // registry which on delete, will do m_NumHelp--.
  945. //
  946. m_NumHelp++;
  947. }
  948. else
  949. {
  950. hRes = E_OUTOFMEMORY;
  951. }
  952. }
  953. }
  954. RegCloseKey(hKey);
  955. }
  956. if(ERROR_SUCCESS != dwStatus )
  957. {
  958. hRes = HRESULT_FROM_WIN32( dwStatus );
  959. }
  960. }
  961. else
  962. {
  963. hRes = E_UNEXPECTED;
  964. }
  965. return hRes;
  966. }
  967. HRESULT
  968. CHelpSessionTable::OpenHelpEntry(
  969. IN const CComBSTR& bstrHelpSession,
  970. OUT PHELPENTRY* ppHelpEntry
  971. )
  972. /*++
  973. Routine Description:
  974. Open an existing help entry.
  975. Parameters:
  976. bstrHelpSession : ID of help entry to be opened.
  977. ppHelpEntry : Pointer to PHELPENTY to receive loaded
  978. help entry.
  979. Returns:
  980. S_OK or error code.
  981. --*/
  982. {
  983. CCriticalSectionLocker l(m_TableLock);
  984. HRESULT hRes = S_OK;
  985. DebugPrintf(
  986. _TEXT("OpenHelpEntry() %s\n"),
  987. bstrHelpSession
  988. );
  989. MYASSERT( bstrHelpSession.Length() > 0 );
  990. // check if entry already exists in cache
  991. HelpEntryCache::LOCK_ITERATOR it = m_HelpEntryCache.find( bstrHelpSession );
  992. if( it != m_HelpEntryCache.end() )
  993. {
  994. *ppHelpEntry = (*it).second;
  995. //
  996. // More reference to same object.
  997. //
  998. (*ppHelpEntry)->AddRef();
  999. // Should have one to one between HelpEntry and HelpSession.
  1000. MYASSERT(FALSE);
  1001. }
  1002. else
  1003. {
  1004. hRes = LoadHelpEntry(
  1005. m_hHelpSessionTableKey,
  1006. (LPTSTR)bstrHelpSession,
  1007. ppHelpEntry
  1008. );
  1009. DebugPrintf(
  1010. _TEXT("LoadHelpEntry() on %s returns 0x%08x\n"),
  1011. bstrHelpSession,
  1012. hRes
  1013. );
  1014. if( SUCCEEDED(hRes) )
  1015. {
  1016. m_HelpEntryCache[ bstrHelpSession ] = *ppHelpEntry;
  1017. }
  1018. }
  1019. return hRes;
  1020. }
  1021. HRESULT
  1022. CHelpSessionTable::DeleteHelpEntry(
  1023. IN const CComBSTR& bstrHelpSession
  1024. )
  1025. /*++
  1026. Routine Description:
  1027. Delete a help entry.
  1028. Parameters:
  1029. bstrHelpSession : ID of help session entry to be deleted.
  1030. Returns:
  1031. S_OK or error code.
  1032. --*/
  1033. {
  1034. HRESULT hRes = S_OK;
  1035. CCriticalSectionLocker l(m_TableLock);
  1036. DebugPrintf(
  1037. _TEXT("DeleteHelpEntry() %s\n"),
  1038. bstrHelpSession
  1039. );
  1040. // check if entry already exists in cache
  1041. HelpEntryCache::LOCK_ITERATOR it = m_HelpEntryCache.find( bstrHelpSession );
  1042. if( it != m_HelpEntryCache.end() )
  1043. {
  1044. // mark entry deleted in registry
  1045. hRes = ((*it).second)->DeleteEntry();
  1046. MYASSERT( SUCCEEDED(hRes) );
  1047. // release this entry ref. count.
  1048. ((*it).second)->Release();
  1049. // remove from our cache
  1050. m_HelpEntryCache.erase( it );
  1051. }
  1052. else
  1053. {
  1054. //
  1055. // unsolicited help will not be in our cache.
  1056. //
  1057. hRes = HRESULT_FROM_WIN32(ERROR_FILE_NOT_FOUND);
  1058. }
  1059. {
  1060. DWORD dwStatus;
  1061. dwStatus = RegDelKey( m_hHelpSessionTableKey, bstrHelpSession );
  1062. if( ERROR_SUCCESS == dwStatus )
  1063. {
  1064. m_NumHelp--;
  1065. }
  1066. }
  1067. return hRes;
  1068. }
  1069. CHelpSessionTable::~CHelpSessionTable()
  1070. {
  1071. CloseSessionTable();
  1072. return;
  1073. }
  1074. HRESULT
  1075. CHelpSessionTable::EnumHelpEntry(
  1076. IN EnumHelpEntryCallback pFunc,
  1077. IN HANDLE userData
  1078. )
  1079. /*++
  1080. Routine Description:
  1081. Enumerate all help entries.
  1082. Parameters:
  1083. pFunc : Call back function.
  1084. userData : User defined data.
  1085. Returns:
  1086. S_OK or error code.
  1087. --*/
  1088. {
  1089. EnumHelpEntryParm parm;
  1090. HRESULT hRes = S_OK;
  1091. DWORD dwStatus;
  1092. CCriticalSectionLocker l(m_TableLock);
  1093. if( NULL == pFunc )
  1094. {
  1095. hRes = E_POINTER;
  1096. }
  1097. else
  1098. {
  1099. try {
  1100. parm.userData = userData;
  1101. parm.pCallback = pFunc;
  1102. parm.pTable = this;
  1103. dwStatus = RegEnumSubKeys(
  1104. HKEY_LOCAL_MACHINE,
  1105. REGKEYCONTROL_REMDSK _TEXT("\\") REGKEY_HELPSESSIONTABLE,
  1106. EnumOpenHelpEntry,
  1107. (HANDLE) &parm
  1108. );
  1109. if( ERROR_SUCCESS != dwStatus )
  1110. {
  1111. hRes = HRESULT_FROM_WIN32( dwStatus );
  1112. }
  1113. }
  1114. catch(...) {
  1115. hRes = E_UNEXPECTED;
  1116. }
  1117. }
  1118. return hRes;
  1119. }
  1120. HRESULT
  1121. CHelpSessionTable::ReleaseHelpEntry(
  1122. IN CComBSTR& bstrHelpSessionId
  1123. )
  1124. /*++
  1125. Routine Description:
  1126. Release/unload a help entry from cached, this help
  1127. entry is not deleted.
  1128. Paramters:
  1129. bstrHelpSessionId : ID of help entry to be unloaded from memory.
  1130. Returns:
  1131. S_OK or error code
  1132. --*/
  1133. {
  1134. CCriticalSectionLocker l(m_TableLock);
  1135. HRESULT hRes = S_OK;
  1136. HelpEntryCache::LOCK_ITERATOR it = m_HelpEntryCache.find( bstrHelpSessionId );
  1137. if( it != m_HelpEntryCache.end() )
  1138. {
  1139. (*it).second->Release();
  1140. m_HelpEntryCache.erase( it );
  1141. }
  1142. else
  1143. {
  1144. hRes = HRESULT_FROM_WIN32( ERROR_FILE_NOT_FOUND );
  1145. }
  1146. return hRes;
  1147. }
  1148. HRESULT
  1149. CHelpSessionTable::EnumOpenHelpEntry(
  1150. IN HKEY hKey,
  1151. IN LPTSTR pszKeyName,
  1152. IN HANDLE userData
  1153. )
  1154. /*++
  1155. Routine Description:
  1156. Call back funtion for EnumHelpEntry() and RegEnumSubKeys().
  1157. Parameters:
  1158. hKey : Registry key handle to help session table.
  1159. pszKeyName : help entry id (registry sub-key name).
  1160. userData : User defined data.
  1161. Returns:
  1162. S_OK or error code.
  1163. --*/
  1164. {
  1165. HRESULT hRes = S_OK;
  1166. PEnumHelpEntryParm pParm = (PEnumHelpEntryParm)userData;
  1167. if( NULL == pParm )
  1168. {
  1169. hRes = E_UNEXPECTED;
  1170. }
  1171. else
  1172. {
  1173. hRes = pParm->pCallback( CComBSTR(pszKeyName), pParm->userData );
  1174. }
  1175. return hRes;
  1176. }