Leaked source code of windows server 2003
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.

801 lines
35 KiB

  1. /****************************************************************************/
  2. /* Module: nutint.cpp */
  3. /* */
  4. /* Purpose: Utilities - Win32 version */
  5. /* */
  6. /* Copyright(C) Microsoft Corporation 1997-1998 */
  7. /****************************************************************************/
  8. #include <adcg.h>
  9. #undef TRC_FILE
  10. #define TRC_FILE "nutint"
  11. #define TRC_GROUP TRC_GROUP_UTILITIES
  12. extern "C" {
  13. #include <atrcapi.h>
  14. #ifndef OS_WINCE
  15. #include <process.h>
  16. #endif
  17. }
  18. #include "autil.h"
  19. /****************************************************************************/
  20. /* Name: UTStartThread */
  21. /* */
  22. /* Purpose: Start a new thread */
  23. /* */
  24. /* Returns: TRUE if successful, FALSE otherwise */
  25. /* */
  26. /* Params: IN entryFunction - pointer to thread entry point */
  27. /* OUT threadID - thread ID */
  28. /* */
  29. /* Operation: Call UTThreadEntry: new thread (Win32) / immediate (Win16) */
  30. /* */
  31. /****************************************************************************/
  32. DCBOOL DCINTERNAL CUT::UTStartThread( UTTHREAD_PROC entryFunction,
  33. PUT_THREAD_DATA pThreadData,
  34. PDCVOID threadParam )
  35. {
  36. HANDLE hndArray[2];
  37. DCUINT32 rc = FALSE;
  38. DWORD dwrc;
  39. DWORD threadID;
  40. UT_THREAD_INFO info;
  41. DC_BEGIN_FN("UTStartThread");
  42. info.pFunc = entryFunction;
  43. /************************************************************************/
  44. /* For Win32, create a thread - use an Event to signal when the thread */
  45. /* has started OK. */
  46. /* Create event - initially non-signalled; manual control. */
  47. /************************************************************************/
  48. hndArray[0] = CreateEvent(NULL, TRUE, FALSE, NULL);
  49. if (hndArray[0] == 0)
  50. {
  51. TRC_SYSTEM_ERROR("CreateEvent");
  52. DC_QUIT;
  53. }
  54. TRC_NRM((TB, _T("event %p created - now create thread"), hndArray[0]));
  55. info.sync = (ULONG_PTR)hndArray[0];
  56. info.threadParam = threadParam;
  57. /************************************************************************/
  58. /* Start a new thread to run the DC-Share core task. */
  59. /* Use C runtime (which calls CreateThread) to avoid memory leaks. */
  60. /************************************************************************/
  61. hndArray[1] = (HANDLE)
  62. #if i386
  63. _beginthreadex
  64. #else
  65. CreateThread
  66. #endif
  67. (NULL, /* security - default */
  68. 0, /* stack size - default */
  69. #if i386
  70. ((unsigned (__stdcall *)(void*))UTStaticThreadEntry),
  71. #else
  72. ((unsigned long (__stdcall *)(void*))UTStaticThreadEntry),
  73. #endif
  74. (PDCVOID)&info, /* thread parameter */
  75. 0, /* creation flags */
  76. #if i386
  77. (unsigned *)&threadID /* thread ID */
  78. #else
  79. (unsigned long *)&threadID/* thread ID */
  80. #endif
  81. );
  82. if (hndArray[1] == 0)
  83. {
  84. /********************************************************************/
  85. /* Failed! */
  86. /********************************************************************/
  87. TRC_SYSTEM_ERROR("_beginthreadex");
  88. DC_QUIT;
  89. }
  90. TRC_NRM((TB, _T("thread %p created - now wait signal"), hndArray[1]));
  91. /************************************************************************/
  92. /* Wait for thread exit or event to be set. */
  93. /************************************************************************/
  94. dwrc = WaitForMultipleObjects(2, hndArray, FALSE, INFINITE);
  95. switch (dwrc)
  96. {
  97. case WAIT_OBJECT_0:
  98. {
  99. /****************************************************************/
  100. /* Event triggered - thread initialised OK. */
  101. /****************************************************************/
  102. TRC_NRM((TB, _T("event signalled")));
  103. rc = TRUE;
  104. }
  105. break;
  106. case WAIT_OBJECT_0 + 1:
  107. {
  108. /****************************************************************/
  109. /* Thread exit */
  110. /****************************************************************/
  111. if (GetExitCodeThread(hndArray[1], &dwrc))
  112. {
  113. TRC_ERR((TB, _T("Thread exited with rc %x"), dwrc));
  114. }
  115. else
  116. {
  117. TRC_ERR((TB, _T("Thread exited with unknown rc")));
  118. }
  119. }
  120. break;
  121. default:
  122. {
  123. TRC_NRM((TB, _T("Wait returned %d"), dwrc));
  124. }
  125. break;
  126. }
  127. pThreadData->threadID = threadID;
  128. pThreadData->threadHnd = (ULONG_PTR)(hndArray[1]);
  129. TRC_ALT((TB, _T("Thread ID %#x handle %#x started"),
  130. pThreadData->threadID, pThreadData->threadHnd));
  131. DC_EXIT_POINT:
  132. /************************************************************************/
  133. /* Destroy event object. */
  134. /************************************************************************/
  135. if (hndArray[0] != 0)
  136. {
  137. TRC_NRM((TB, _T("Destroy event object")));
  138. CloseHandle(hndArray[0]);
  139. }
  140. DC_END_FN();
  141. return(rc);
  142. } /* UTStartThread */
  143. /****************************************************************************/
  144. /* Name: UTStaticThreadEntry */
  145. /* */
  146. /* Purpose: STATIC Thread entry point. */
  147. /* */
  148. /* Returns: 0 */
  149. /* */
  150. /* Params: IN pInfo - pointer to thread entry function+sync object */
  151. /* */
  152. /* Operation: signal started OK and call the thread enty function - which */
  153. /* enters a message loop. */
  154. /* */
  155. /****************************************************************************/
  156. DCUINT WINAPI CUT::UTStaticThreadEntry(UT_THREAD_INFO * pInfo)
  157. {
  158. UTTHREAD_PROC pFunc;
  159. PDCVOID pThreadParam;
  160. DC_BEGIN_FN("UTStaticThreadEntry");
  161. /************************************************************************/
  162. /* Take a copy of the target function, before signalling that the */
  163. /* thread has started. */
  164. /************************************************************************/
  165. pFunc = pInfo->pFunc;
  166. /************************************************************************/
  167. /* Take a copy of the instance info before signalling that the */
  168. /* thread has started. */
  169. /************************************************************************/
  170. pThreadParam = pInfo->threadParam;
  171. /************************************************************************/
  172. /* Flag that initialisation has succeeded. */
  173. /* NOTE: from now on, pInfo is not valid. Set it to NULL to make sure */
  174. /* no-one tries to dereference it. */
  175. /************************************************************************/
  176. SetEvent((HANDLE)pInfo->sync);
  177. pInfo = NULL;
  178. /************************************************************************/
  179. /* Call the thread entry point. This executes a message loop. */
  180. /************************************************************************/
  181. pFunc(pThreadParam);
  182. DC_END_FN();
  183. return(0);
  184. }
  185. /****************************************************************************/
  186. /* Name: UTStopThread */
  187. /* */
  188. /* Purpose: End a child thread */
  189. /* */
  190. /* Returns: TRUE if successful, FALSE otherwise */
  191. /* */
  192. /* Params: IN threadData - thread data */
  193. /* */
  194. /* Operation: Post WM_QUIT to the thread. */
  195. /* */
  196. /****************************************************************************/
  197. DCBOOL DCINTERNAL CUT::UTStopThread(UT_THREAD_DATA threadData,
  198. BOOL fPumpMessages)
  199. {
  200. DCBOOL rc;
  201. DWORD retval;
  202. DWORD dwThreadTimeout;
  203. DC_BEGIN_FN("UTStopThread");
  204. //
  205. // Bail out if we try to end a thread that never got created in the first
  206. // place
  207. //
  208. if (0 == threadData.threadID) {
  209. rc = FALSE;
  210. TRC_ERR((TB, _T("Trying to end thread ID %#x hnd: 0x%x"),
  211. threadData.threadID,
  212. threadData.threadHnd));
  213. DC_QUIT;
  214. }
  215. //
  216. // Post WM_QUIT to the thread.
  217. //
  218. TRC_NRM((TB, _T("Attempt to stop thread %#x"), threadData.threadID));
  219. if (PostThreadMessage(threadData.threadID, WM_QUIT, 0, 0))
  220. {
  221. rc = TRUE;
  222. }
  223. else
  224. {
  225. TRC_ERR((TB, _T("Failed to end thread ID %#x"), threadData.threadID));
  226. rc = FALSE;
  227. }
  228. //
  229. // Free build waits forever, checked build can be set to timeout
  230. // to help debug deadlocks. A lot of problems become apparent
  231. // in stress if the wait times out and the code is allowed to continue.
  232. //
  233. #ifdef DC_DEBUG
  234. dwThreadTimeout = _UT.dwDebugThreadWaitTimeout;
  235. #else
  236. dwThreadTimeout = INFINITE;
  237. #endif
  238. //
  239. // Wait for thread to complete.
  240. //
  241. TRC_NRM((TB, _T("Wait for thread %#x to die"), threadData.threadID));
  242. if (fPumpMessages) {
  243. retval = CUT::UT_WaitWithMessageLoop((HANDLE)(threadData.threadHnd),
  244. dwThreadTimeout);
  245. }
  246. else {
  247. retval = WaitForSingleObject((HANDLE)(threadData.threadHnd),
  248. dwThreadTimeout);
  249. }
  250. if (retval == WAIT_TIMEOUT)
  251. {
  252. TRC_ABORT((TB,
  253. _T("Timeout waiting for threadID %#x handle %#x termination"),
  254. threadData.threadID, threadData.threadHnd));
  255. }
  256. else
  257. {
  258. TRC_ALT((TB, _T("Thread id %#x exited."), threadData.threadID));
  259. }
  260. DC_EXIT_POINT:
  261. DC_END_FN();
  262. return(rc);
  263. } /* UTStopThread */
  264. /****************************************************************************/
  265. /* FUNCTION: UTGetCurrentTime(...) */
  266. /* */
  267. /* DESCRIPTION: */
  268. /* ============ */
  269. /* Get the current system time. */
  270. /* */
  271. /* PARAMETERS: */
  272. /* =========== */
  273. /* pTime : pointer to the time structure to be filled with the */
  274. /* current time. */
  275. /* */
  276. /* RETURNS: */
  277. /* ======== */
  278. /* Nothing. */
  279. /* */
  280. /****************************************************************************/
  281. DCVOID DCINTERNAL CUT::UTGetCurrentTime(PDC_TIME pTime)
  282. {
  283. SYSTEMTIME sysTime;
  284. DC_BEGIN_FN("UTGetCurrentTime");
  285. /************************************************************************/
  286. /* Get the system time */
  287. /************************************************************************/
  288. GetSystemTime(&sysTime);
  289. /************************************************************************/
  290. /* Now convert it to a DC_TIME - this isn't hard since the structures */
  291. /* are very similar. */
  292. /************************************************************************/
  293. pTime->hour = (DCUINT8)sysTime.wHour;
  294. pTime->min = (DCUINT8)sysTime.wMinute;
  295. pTime->sec = (DCUINT8)sysTime.wSecond;
  296. pTime->hundredths = (DCUINT8)(sysTime.wMilliseconds / 10);
  297. DC_END_FN();
  298. return;
  299. } /* UTGetCurrentTime */
  300. /****************************************************************************/
  301. /* FUNCTION: UTGetCurrentDate(...) */
  302. /* */
  303. /* DESCRIPTION: */
  304. /* ============ */
  305. /* Get the current system date. */
  306. /* */
  307. /* PARAMETERS: */
  308. /* =========== */
  309. /* pDate : pointer to the date structure to be filled with the */
  310. /* current date. */
  311. /* */
  312. /* RETURNS: */
  313. /* ======== */
  314. /* Nothing. */
  315. /* */
  316. /****************************************************************************/
  317. DCVOID DCINTERNAL CUT::UTGetCurrentDate(PDC_DATE pDate)
  318. {
  319. SYSTEMTIME sysTime;
  320. DC_BEGIN_FN("UTGetCurrentDate");
  321. /************************************************************************/
  322. /* Get the system time */
  323. /************************************************************************/
  324. GetSystemTime(&sysTime);
  325. /************************************************************************/
  326. /* Now convert it to a DC_DATE - this isn't hard since the structures */
  327. /* are very similar. */
  328. /************************************************************************/
  329. pDate->day = (DCUINT8)sysTime.wDay;
  330. pDate->month = (DCUINT8)sysTime.wMonth;
  331. pDate->year = (DCUINT16)sysTime.wYear;
  332. DC_END_FN();
  333. return;
  334. } /* UTGetCurrentDate */
  335. /****************************************************************************/
  336. /* Name: UTReadEntry */
  337. /* */
  338. /* Purpose: Read an entry from the given section of the registry */
  339. /* */
  340. /* Returns: TRUE if successful, FALSE otherwise */
  341. /* */
  342. /* Params: . */
  343. /* topLevelKey : one of: */
  344. /* - HKEY_CURRENT_USER */
  345. /* - HKEY_LOCAL_MACHINE */
  346. /* pSection : the section name to read from. The product prefix */
  347. /* string is prepended to give the full name. */
  348. /* pEntry : the entry name to read. */
  349. /* pBuffer : a buffer to read the entry to. */
  350. /* bufferSize : the size of the buffer. */
  351. /* expectedDataType : the type of data stored in the entry. */
  352. /* */
  353. /****************************************************************************/
  354. DCBOOL DCINTERNAL CUT::UTReadEntry(HKEY topLevelKey,
  355. PDCTCHAR pSection,
  356. PDCTCHAR pEntry,
  357. PDCUINT8 pBuffer,
  358. DCINT bufferSize,
  359. DCINT32 expectedDataType)
  360. {
  361. LONG sysrc;
  362. HKEY key;
  363. DCINT32 dataType;
  364. DCINT32 dataSize;
  365. DCTCHAR subKey[UT_MAX_SUBKEY];
  366. DCBOOL keyOpen = FALSE;
  367. DCBOOL rc = FALSE;
  368. DC_BEGIN_FN("UTReadEntry");
  369. /************************************************************************/
  370. /* Get a subkey for the value. */
  371. /************************************************************************/
  372. UtMakeSubKey(subKey, SIZE_TCHARS(subKey), pSection);
  373. /************************************************************************/
  374. /* Try to open the key. If the entry does not exist, RegOpenKeyEx will */
  375. /* fail. */
  376. /************************************************************************/
  377. sysrc = RegOpenKeyEx(topLevelKey,
  378. subKey,
  379. 0, /* reserved */
  380. KEY_READ,
  381. &key);
  382. if (sysrc != ERROR_SUCCESS)
  383. {
  384. /********************************************************************/
  385. /* Don't trace an error here since the subkey may not exist... */
  386. /********************************************************************/
  387. TRC_NRM((TB, _T("Failed to open key %s, rc = %ld"), subKey, sysrc));
  388. DC_QUIT;
  389. }
  390. keyOpen = TRUE;
  391. /************************************************************************/
  392. /* We successfully opened the key so now try to read the value. Again */
  393. /* it may not exist. */
  394. /************************************************************************/
  395. dataSize = (DCINT32)bufferSize;
  396. sysrc = RegQueryValueEx(key,
  397. pEntry,
  398. 0, /* reserved */
  399. (LPDWORD)&dataType,
  400. (LPBYTE)pBuffer,
  401. (LPDWORD)&dataSize);
  402. if (sysrc != ERROR_SUCCESS)
  403. {
  404. TRC_NRM((TB, _T("Failed to read value of [%s] %s, rc = %ld"),
  405. pSection,
  406. pEntry,
  407. sysrc));
  408. DC_QUIT;
  409. }
  410. /************************************************************************/
  411. /* Check that the type is correct. Special case: allow REG_BINARY */
  412. /* instead of REG_DWORD, as long as the length is 32 bits. */
  413. /************************************************************************/
  414. if ((dataType != expectedDataType) &&
  415. ((dataType != REG_BINARY) ||
  416. (expectedDataType != REG_DWORD) ||
  417. (dataSize != 4)))
  418. {
  419. TRC_ALT((TB,_T("Read value from [%s] %s, but type is %ld - expected %ld"),
  420. pSection,
  421. pEntry,
  422. dataType,
  423. expectedDataType));
  424. DC_QUIT;
  425. }
  426. rc = TRUE;
  427. DC_EXIT_POINT:
  428. /************************************************************************/
  429. /* Close the key (if required). */
  430. /************************************************************************/
  431. if (keyOpen)
  432. {
  433. sysrc = RegCloseKey(key);
  434. if (sysrc != ERROR_SUCCESS)
  435. {
  436. TRC_ERR((TB, _T("Failed to close key, rc = %ld"), sysrc));
  437. }
  438. }
  439. DC_END_FN();
  440. return(rc);
  441. } /* UTReadEntry */
  442. /****************************************************************************/
  443. /* Name: UTWriteEntry */
  444. /* */
  445. /* Purpose: Write an entry to the given section of the registry */
  446. /* */
  447. /* Returns: TRUE if successful, FALSE otherwise */
  448. /* */
  449. /* Params: . */
  450. /* topLevelKey : one of: */
  451. /* - HKEY_CURRENT_USER */
  452. /* - HKEY_LOCAL_MACHINE */
  453. /* pSection : the section name to write to. The product prefix */
  454. /* string is prepended to give the full name. */
  455. /* pEntry : the entry name to write */
  456. /* pData : a pointer to the data to write */
  457. /* dataSize : the size of the data to be written. For strings */
  458. /* this must include the NULL terminator */
  459. /* expectedDataType : the type of data to be written */
  460. /* */
  461. /****************************************************************************/
  462. DCBOOL DCINTERNAL CUT::UTWriteEntry(HKEY topLevelKey,
  463. PDCTCHAR pSection,
  464. PDCTCHAR pEntry,
  465. PDCUINT8 pData,
  466. DCINT dataSize,
  467. DCINT32 dataType)
  468. {
  469. LONG sysrc;
  470. HKEY key;
  471. DCTCHAR subKey[UT_MAX_SUBKEY];
  472. DWORD disposition;
  473. DCBOOL keyOpen = FALSE;
  474. DCBOOL rc = FALSE;
  475. DC_BEGIN_FN("UTWriteEntry");
  476. /************************************************************************/
  477. /* Get a subkey for the value. */
  478. /************************************************************************/
  479. UtMakeSubKey(subKey, SIZE_TCHARS(subKey), pSection);
  480. /************************************************************************/
  481. /* Try to create the key. If the entry already exists, RegCreateKeyEx */
  482. /* will open the existing entry. */
  483. /************************************************************************/
  484. sysrc = RegCreateKeyEx(topLevelKey,
  485. subKey,
  486. 0, /* reserved */
  487. NULL, /* class */
  488. REG_OPTION_NON_VOLATILE,
  489. KEY_WRITE,
  490. NULL, /* security attributes */
  491. &key,
  492. &disposition);
  493. if (sysrc != ERROR_SUCCESS)
  494. {
  495. TRC_ERR((TB, _T("Failed to create / open key %s, rc = %ld"),
  496. subKey, sysrc));
  497. DC_QUIT;
  498. }
  499. keyOpen = TRUE;
  500. TRC_NRM((TB, _T("%s key %s"),
  501. (disposition == REG_CREATED_NEW_KEY) ? "Created" : "Opened",
  502. subKey));
  503. /************************************************************************/
  504. /* We've got the key, so set the value. */
  505. /************************************************************************/
  506. sysrc = RegSetValueEx(key,
  507. pEntry,
  508. 0, /* reserved */
  509. dataType,
  510. (LPBYTE)pData,
  511. (DCINT32)dataSize);
  512. if (sysrc != ERROR_SUCCESS)
  513. {
  514. TRC_ERR((TB, _T("Failed to write value to [%s] %s, rc = %ld"),
  515. pSection,
  516. pEntry,
  517. sysrc));
  518. DC_QUIT;
  519. }
  520. rc = TRUE;
  521. DC_EXIT_POINT:
  522. /************************************************************************/
  523. /* Close the key (if required) */
  524. /************************************************************************/
  525. if (keyOpen)
  526. {
  527. sysrc = RegCloseKey(key);
  528. if (sysrc != ERROR_SUCCESS)
  529. {
  530. TRC_ERR((TB, _T("Failed to close key, rc = %ld"), sysrc));
  531. }
  532. }
  533. DC_END_FN();
  534. return(rc);
  535. } /* UTWriteEntry */
  536. /****************************************************************************/
  537. /* Name: UTDeleteEntry */
  538. /* */
  539. /* Purpose: Deletes an entry from the registry */
  540. /* */
  541. /* Returns: TRUE if successful, FALSE otherwise */
  542. /* */
  543. /* Params: IN pSection - the section name of the entry to delete */
  544. /* IN pEntry - the actual entry to delete */
  545. /* */
  546. /****************************************************************************/
  547. DCBOOL DCINTERNAL CUT::UTDeleteEntry(PDCTCHAR pSection,
  548. PDCTCHAR pEntry)
  549. {
  550. LONG sysrc;
  551. HKEY key;
  552. DCTCHAR subKey[UT_MAX_SUBKEY];
  553. DCBOOL keyOpen = FALSE;
  554. DCBOOL rc = FALSE;
  555. DC_BEGIN_FN("UTDeleteEntry");
  556. /************************************************************************/
  557. /* Get a subkey for the value. */
  558. /************************************************************************/
  559. UtMakeSubKey(subKey, SIZE_TCHARS(subKey), pSection);
  560. /************************************************************************/
  561. /* Try to open the key. If the entry does not exist, RegOpenKeyEx will */
  562. /* fail. */
  563. /************************************************************************/
  564. sysrc = RegOpenKeyEx(HKEY_CURRENT_USER,
  565. subKey,
  566. 0, /* reserved */
  567. KEY_WRITE,
  568. &key);
  569. if (sysrc != ERROR_SUCCESS)
  570. {
  571. /********************************************************************/
  572. /* Don't trace an error here since the subkey may not exist... */
  573. /********************************************************************/
  574. TRC_NRM((TB, _T("Failed to open key %s, rc = %ld"), subKey, sysrc));
  575. DC_QUIT;
  576. }
  577. keyOpen = TRUE;
  578. /************************************************************************/
  579. /* Now try to delete the entry. */
  580. /************************************************************************/
  581. sysrc = RegDeleteValue(key, pEntry);
  582. if (sysrc != ERROR_SUCCESS)
  583. {
  584. /********************************************************************/
  585. /* We failed to delete the entry - this is quite acceptable as it */
  586. /* may never have existed... */
  587. /********************************************************************/
  588. TRC_NRM((TB, _T("Failed to delete entry %s from section %s"),
  589. pEntry,
  590. pSection));
  591. }
  592. rc = TRUE;
  593. DC_EXIT_POINT:
  594. /************************************************************************/
  595. /* Close the key (if required). */
  596. /************************************************************************/
  597. if (keyOpen)
  598. {
  599. sysrc = RegCloseKey(key);
  600. if (sysrc != ERROR_SUCCESS)
  601. {
  602. TRC_ERR((TB, _T("Failed to close key, rc = %ld"), sysrc));
  603. }
  604. }
  605. DC_END_FN();
  606. return(rc);
  607. } /* UTDeleteEntry */
  608. /****************************************************************************/
  609. /* Name: UTEnumRegistry */
  610. /* */
  611. /* Purpose: Enumerate keys from registry */
  612. /* */
  613. /* Returns: TRUE - registry key returned */
  614. /* FALSE - no more registry keys to enumerate */
  615. /* */
  616. /* Params: IN pSection - registy section */
  617. /* IN index - index of key to enumerate */
  618. /* OUT pBuffer - output buffer */
  619. /* IN bufferSize - output buffer size */
  620. /* */
  621. /* Operation: */
  622. /* */
  623. /****************************************************************************/
  624. DCBOOL DCINTERNAL CUT::UTEnumRegistry( PDCTCHAR pSection,
  625. DCUINT32 index,
  626. PDCTCHAR pBuffer,
  627. PDCINT pBufferSize )
  628. {
  629. LONG sysrc;
  630. DCTCHAR subKey[UT_MAX_SUBKEY];
  631. DCBOOL rc = FALSE;
  632. FILETIME fileTime;
  633. DC_BEGIN_FN("UTEnumRegistry");
  634. /************************************************************************/
  635. /* Get a subkey for the value. */
  636. /************************************************************************/
  637. UtMakeSubKey(subKey, SIZE_TCHARS(subKey), pSection);
  638. /************************************************************************/
  639. /* First time - open the key. Try HKCU first. */
  640. /************************************************************************/
  641. if (index == 0)
  642. {
  643. sysrc = RegOpenKeyEx(HKEY_CURRENT_USER,
  644. subKey,
  645. 0,
  646. KEY_READ,
  647. &_UT.enumHKey);
  648. TRC_NRM((TB, _T("Open HKCU %s, rc %d"), subKey, sysrc));
  649. if (sysrc != ERROR_SUCCESS)
  650. {
  651. /****************************************************************/
  652. /* Didn't find HKCU - try HKLM */
  653. /****************************************************************/
  654. sysrc = RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  655. subKey,
  656. 0,
  657. KEY_READ,
  658. &_UT.enumHKey);
  659. TRC_NRM((TB, _T("Open HKLM %s, rc %d"), subKey, sysrc));
  660. if (sysrc != ERROR_SUCCESS)
  661. {
  662. /************************************************************/
  663. /* Didn't find HKLM either - give up */
  664. /************************************************************/
  665. TRC_ALT((TB, _T("Didn't find subkey %s - give up"), subKey));
  666. DC_QUIT;
  667. }
  668. }
  669. }
  670. TRC_ASSERT((_UT.enumHKey != 0), (TB,_T("0 hKey")));
  671. /************************************************************************/
  672. /* If we get here, we have opened a key - do the enumeration now */
  673. /************************************************************************/
  674. sysrc = RegEnumKeyEx(_UT.enumHKey,
  675. index,
  676. pBuffer,
  677. (PDCUINT32)pBufferSize,
  678. NULL, NULL, NULL,
  679. &fileTime);
  680. /************************************************************************/
  681. /* If it worked, set the return code */
  682. /************************************************************************/
  683. if (sysrc == ERROR_SUCCESS)
  684. {
  685. TRC_NRM((TB, _T("Enumerated key OK")));
  686. rc = TRUE;
  687. }
  688. else
  689. {
  690. /********************************************************************/
  691. /* End of enumeration - close the key */
  692. /********************************************************************/
  693. TRC_NRM((TB, _T("End of enumeration, rc %ld"), sysrc));
  694. sysrc = RegCloseKey(_UT.enumHKey);
  695. if (sysrc != ERROR_SUCCESS)
  696. {
  697. TRC_ERR((TB, _T("Failed to close key, rc = %ld"), sysrc));
  698. }
  699. _UT.enumHKey = 0;
  700. }
  701. DC_EXIT_POINT:
  702. DC_END_FN();
  703. return(rc);
  704. } /* UTEnumRegistry */