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.

1979 lines
48 KiB

  1. #include "precomp.h"
  2. //
  3. // UT.CPP
  4. // Utility Functions
  5. //
  6. #include <limits.h>
  7. #include <process.h>
  8. #include <mmsystem.h>
  9. #include <confreg.h>
  10. #define MLZ_FILE_ZONE ZONE_UT
  11. //
  12. //
  13. // UT_InitTask(...)
  14. //
  15. //
  16. BOOL UT_InitTask
  17. (
  18. UT_TASK task,
  19. PUT_CLIENT * pputTask
  20. )
  21. {
  22. BOOL fInit = FALSE;
  23. BOOL locked = FALSE;
  24. PUT_CLIENT putTask = NULL;
  25. DebugEntry(UT_InitTask);
  26. UT_Lock(UTLOCK_UT);
  27. //
  28. // Initialise handle to NULL
  29. //
  30. *pputTask = NULL;
  31. ASSERT(task >= UTTASK_FIRST);
  32. ASSERT(task < UTTASK_MAX);
  33. //
  34. // The UT_TASK is an index into the tasks array.
  35. //
  36. putTask = &(g_autTasks[task]);
  37. if (putTask->dwThreadId)
  38. {
  39. ERROR_OUT(("Task %d already exists", task));
  40. putTask = NULL;
  41. DC_QUIT;
  42. }
  43. ZeroMemory(putTask, sizeof(UT_CLIENT));
  44. //
  45. // Call routine to set up the process id information in the task CB.
  46. //
  47. putTask->dwThreadId = GetCurrentThreadId();
  48. //
  49. // Create the window
  50. //
  51. putTask->utHwnd = CreateWindow(MAKEINTATOM(g_utWndClass),
  52. NULL, // name
  53. 0, // style
  54. 1, // x
  55. 1, // y
  56. 200, // width
  57. 100, // height
  58. NULL, // parent
  59. NULL, // menu
  60. g_asInstance,
  61. NULL); // create struct
  62. if (!putTask->utHwnd)
  63. {
  64. ERROR_OUT(("Failed to create UT msg window"));
  65. DC_QUIT;
  66. }
  67. //
  68. // Now store the UT handle in the user data associated with the
  69. // window. We will use this to get the UT handle when we are in
  70. // the event procedure.
  71. //
  72. SetWindowLongPtr(putTask->utHwnd, GWLP_USERDATA, (LPARAM)putTask);
  73. fInit = TRUE;
  74. DC_EXIT_POINT:
  75. //
  76. // Callers will call UT_TermTask() on error, which will bump down
  77. // the shared memory count. So we have no clean up on error here.
  78. //
  79. *pputTask = putTask;
  80. //
  81. // Release access to task stuff
  82. //
  83. UT_Unlock(UTLOCK_UT);
  84. DebugExitBOOL(UT_InitTask, fInit);
  85. return(fInit);
  86. }
  87. //
  88. // UT_TermTask(...)
  89. //
  90. void UT_TermTask(PUT_CLIENT * pputTask)
  91. {
  92. DebugEntry(UT_TermTask);
  93. //
  94. // Check that the putTask is valid
  95. //
  96. if (!*pputTask)
  97. {
  98. WARNING_OUT(("UT_TermTask: null task"));
  99. DC_QUIT;
  100. }
  101. UTTaskEnd(*pputTask);
  102. *pputTask = NULL;
  103. DC_EXIT_POINT:
  104. DebugExitVOID(UT_TermTask);
  105. }
  106. //
  107. //
  108. // UTTaskEnd(...)
  109. //
  110. //
  111. void UTTaskEnd(PUT_CLIENT putTask)
  112. {
  113. int i;
  114. PUTEXIT_PROC_INFO pExit;
  115. PUTEVENT_INFO pEventInfo;
  116. DebugEntry(UTTaskEnd);
  117. UT_Lock(UTLOCK_UT);
  118. if (!putTask->dwThreadId)
  119. {
  120. // Nothing to do
  121. DC_QUIT;
  122. }
  123. ValidateUTClient(putTask);
  124. //
  125. // Call any registered exit procedures. Since we guarantee to call
  126. // exit procs in the reverse order to the order they were registered,
  127. // we start at the end of the array and call each proc in turn back to
  128. // the first one registered:
  129. //
  130. TRACE_OUT(("Calling exit procedures..."));
  131. for (i = UTEXIT_PROCS_MAX-1 ; i >= 0; i--)
  132. {
  133. pExit = &(putTask->exitProcs[i]);
  134. if (pExit->exitProc != NULL)
  135. {
  136. pExit->exitProc(pExit->exitData);
  137. //
  138. // If any exit proc still exists in slot i, then this proc has
  139. // failed to deregister itself. This is not mandatory but is
  140. // expected.
  141. //
  142. if (pExit->exitProc != NULL)
  143. {
  144. TRACE_OUT(("Exit proc 0x%08x failed to deregister itself when called",
  145. pExit->exitProc));
  146. }
  147. }
  148. }
  149. //
  150. // Free delayed events
  151. //
  152. pEventInfo = (PUTEVENT_INFO)COM_BasedListFirst(&(putTask->delayedEvents),
  153. FIELD_OFFSET(UTEVENT_INFO, chain));
  154. while (pEventInfo != NULL)
  155. {
  156. COM_BasedListRemove(&(pEventInfo->chain));
  157. delete pEventInfo;
  158. pEventInfo = (PUTEVENT_INFO)COM_BasedListFirst(&(putTask->delayedEvents),
  159. FIELD_OFFSET(UTEVENT_INFO, chain));
  160. }
  161. //
  162. // Free pending events
  163. //
  164. pEventInfo = (PUTEVENT_INFO)COM_BasedListFirst(&(putTask->pendingEvents),
  165. FIELD_OFFSET(UTEVENT_INFO, chain));
  166. while (pEventInfo != NULL)
  167. {
  168. COM_BasedListRemove(&(pEventInfo->chain));
  169. delete pEventInfo;
  170. pEventInfo = (PUTEVENT_INFO)COM_BasedListFirst(&(putTask->pendingEvents),
  171. FIELD_OFFSET(UTEVENT_INFO, chain));
  172. }
  173. //
  174. // If we created a window to post UT events to for this task, then
  175. // destroy the window. This will also kill all the timers which are
  176. // pending for this window.
  177. //
  178. if (putTask->utHwnd != NULL)
  179. {
  180. DestroyWindow(putTask->utHwnd);
  181. putTask->utHwnd = NULL;
  182. }
  183. //
  184. // Clear out the thread ID
  185. //
  186. putTask->dwThreadId = 0;
  187. DC_EXIT_POINT:
  188. UT_Unlock(UTLOCK_UT);
  189. DebugExitVOID(UTTaskEnd);
  190. }
  191. //
  192. //
  193. // UT_RegisterEvent(...)
  194. //
  195. //
  196. void WINAPI UT_RegisterEvent
  197. (
  198. PUT_CLIENT putTask,
  199. UTEVENT_PROC eventProc,
  200. LPVOID eventData,
  201. UT_PRIORITY priority
  202. )
  203. {
  204. int i;
  205. PUTEVENT_PROC_INFO pEventProcData;
  206. DebugEntry(UT_RegisterEvent);
  207. ValidateUTClient(putTask);
  208. //
  209. // Check that the priority is valid
  210. //
  211. ASSERT(priority <= UT_PRIORITY_MAX);
  212. //
  213. // Check that we have room for this event handler
  214. //
  215. pEventProcData = putTask->eventHandlers;
  216. ASSERT(pEventProcData[UTEVENT_HANDLERS_MAX-1].eventProc == NULL);
  217. //
  218. // Find the place to insert this event handler
  219. //
  220. TRACE_OUT(("Looking for pos for event proc at priority %d", priority));
  221. for (i = 0; i < UTEVENT_HANDLERS_MAX; i++)
  222. {
  223. if (pEventProcData[i].eventProc == NULL)
  224. {
  225. TRACE_OUT(("Found NULL slot at position %d", i));
  226. break;
  227. }
  228. if (pEventProcData[i].priority <= priority)
  229. {
  230. TRACE_OUT(("Found event proc of priority %d at pos %d",
  231. pEventProcData[i].priority, i));
  232. break;
  233. }
  234. }
  235. //
  236. // Shift all lower and equal priority event handlers down a slot
  237. //
  238. UT_MoveMemory(&pEventProcData[i+1], &pEventProcData[i],
  239. sizeof(UTEVENT_PROC_INFO) * (UTEVENT_HANDLERS_MAX - 1 - i));
  240. pEventProcData[i].eventProc = eventProc;
  241. pEventProcData[i].eventData = eventData;
  242. pEventProcData[i].priority = priority;
  243. DebugExitVOID(UT_RegisterEvent);
  244. }
  245. //
  246. //
  247. // UT_DeregisterEvent(...)
  248. //
  249. //
  250. void UT_DeregisterEvent
  251. (
  252. PUT_CLIENT putTask,
  253. UTEVENT_PROC eventProc,
  254. LPVOID eventData
  255. )
  256. {
  257. int i;
  258. BOOL found = FALSE;
  259. DebugEntry(UT_DeregisterEvent);
  260. ValidateUTClient(putTask);
  261. //
  262. // Find the Event handler
  263. //
  264. for (i = 0; i < UTEVENT_HANDLERS_MAX; i++)
  265. {
  266. if ( (putTask->eventHandlers[i].eventProc == eventProc) &&
  267. (putTask->eventHandlers[i].eventData == eventData) )
  268. {
  269. //
  270. // Found handler - shuffle down stack on top of it
  271. //
  272. TRACE_OUT(("Deregistering event proc 0x%08x from position %d",
  273. eventProc, i));
  274. found = TRUE;
  275. //
  276. // Slide all the other event procs up one
  277. //
  278. UT_MoveMemory(&putTask->eventHandlers[i],
  279. &putTask->eventHandlers[i+1],
  280. sizeof(UTEVENT_PROC_INFO) * (UTEVENT_HANDLERS_MAX - 1 - i));
  281. putTask->eventHandlers[UTEVENT_HANDLERS_MAX-1].eventProc = NULL;
  282. break;
  283. }
  284. }
  285. //
  286. // Check that we found the event handler
  287. //
  288. ASSERT(found);
  289. DebugExitVOID(UT_DeregisterEvent);
  290. }
  291. //
  292. //
  293. // UT_PostEvent(...)
  294. //
  295. //
  296. void UT_PostEvent
  297. (
  298. PUT_CLIENT putFrom,
  299. PUT_CLIENT putTo,
  300. UINT delay,
  301. UINT eventNo,
  302. UINT_PTR param1,
  303. UINT_PTR param2
  304. )
  305. {
  306. DebugEntry(UT_PostEvent);
  307. //
  308. // Get exclusive access to the UTM while we move event pool entries --
  309. // we are changing fields in a task, so we need to protect it.
  310. //
  311. UT_Lock(UTLOCK_UT);
  312. if (!putTo || (putTo->utHwnd == NULL))
  313. {
  314. TRACE_OUT(("NULL destination task %x in UT_PostEvent", putTo));
  315. DC_QUIT;
  316. }
  317. ValidateUTClient(putFrom);
  318. ValidateUTClient(putTo);
  319. if (delay != 0)
  320. {
  321. //
  322. // A delay was specified...
  323. //
  324. UTPostDelayedEvt(putFrom, putTo, delay, eventNo, param1, param2);
  325. }
  326. else
  327. {
  328. //
  329. // No delay specified - post the event now
  330. //
  331. UTPostImmediateEvt(putFrom, putTo, eventNo, param1, param2);
  332. }
  333. DC_EXIT_POINT:
  334. UT_Unlock(UTLOCK_UT);
  335. DebugExitVOID(UT_PostEvent);
  336. }
  337. //
  338. // UTPostImmediateEvt(...)
  339. //
  340. void UTPostImmediateEvt
  341. (
  342. PUT_CLIENT putFrom,
  343. PUT_CLIENT putTo,
  344. UINT event,
  345. UINT_PTR param1,
  346. UINT_PTR param2
  347. )
  348. {
  349. PUTEVENT_INFO pEventInfo;
  350. BOOL destQueueEmpty;
  351. DebugEntry(UTPostImmediateEvt);
  352. TRACE_OUT(("Posting event %d (%#.4hx, %#.8lx) from 0x%08x to 0x%08x",
  353. event,
  354. param1,
  355. param2,
  356. putFrom, putTo));
  357. //
  358. // Allocate an event.
  359. //
  360. pEventInfo = new UTEVENT_INFO;
  361. if (!pEventInfo)
  362. {
  363. WARNING_OUT(("UTPostImmediateEvent failed; out of memory"));
  364. DC_QUIT;
  365. }
  366. ZeroMemory(pEventInfo, sizeof(*pEventInfo));
  367. SET_STAMP(pEventInfo, UTEVENT);
  368. //
  369. // Determine whether the target queue is empty
  370. //
  371. destQueueEmpty = COM_BasedListIsEmpty(&(putTo->pendingEvents));
  372. //
  373. // Copy the event into the memory
  374. //
  375. pEventInfo->putTo = putTo;
  376. pEventInfo->popTime = 0;
  377. pEventInfo->event = event;
  378. pEventInfo->param1 = param1;
  379. pEventInfo->param2 = param2;
  380. //
  381. // Add to the end of the target queue
  382. //
  383. COM_BasedListInsertBefore(&(putTo->pendingEvents), &(pEventInfo->chain));
  384. //
  385. // If the target queue was empty, or the destination task is currently
  386. // waiting for an event (in UT_WaitEvent()), we have to post a trigger
  387. // event to get it to check its event queue.
  388. //
  389. if (destQueueEmpty)
  390. {
  391. UTTriggerEvt(putFrom, putTo);
  392. }
  393. DC_EXIT_POINT:
  394. DebugExitVOID(UTPostImmediateEvt);
  395. }
  396. //
  397. //
  398. // UTPostDelayedEvt(...)
  399. //
  400. //
  401. void UTPostDelayedEvt
  402. (
  403. PUT_CLIENT putFrom,
  404. PUT_CLIENT putTo,
  405. UINT delay,
  406. UINT event,
  407. UINT_PTR param1,
  408. UINT_PTR param2
  409. )
  410. {
  411. PUTEVENT_INFO pDelayedEventInfo;
  412. PUTEVENT_INFO pTempEventInfo;
  413. BOOL firstDelayed = TRUE;
  414. DebugEntry(UTPostDelayedEvt);
  415. TRACE_OUT(("Posting delayed event %d (%#.4hx, %#.8lx) " \
  416. "from 0x%08x to 0x%08x, delay %u ms",
  417. event,
  418. param1,
  419. param2, putFrom, putTo, delay));
  420. //
  421. // Get an entry from the event pool of the destination
  422. //
  423. pDelayedEventInfo = new UTEVENT_INFO;
  424. if (!pDelayedEventInfo)
  425. {
  426. ERROR_OUT(("UTPostDelayedEvt failed; out of memory"));
  427. DC_QUIT;
  428. }
  429. ZeroMemory(pDelayedEventInfo, sizeof(*pDelayedEventInfo));
  430. SET_STAMP(pDelayedEventInfo, UTEVENT);
  431. //
  432. // Copy the event into the memory
  433. //
  434. pDelayedEventInfo->putTo = putTo;
  435. pDelayedEventInfo->popTime = GetTickCount() + delay;
  436. pDelayedEventInfo->event = event;
  437. pDelayedEventInfo->param1 = param1;
  438. pDelayedEventInfo->param2 = param2;
  439. TRACE_OUT(("This event set to pop at %x",
  440. pDelayedEventInfo->popTime));
  441. //
  442. // Insert the delayed event into the delayed queue at the sender. The
  443. // list is ordered by the time the event needs to be scheduled.
  444. //
  445. pTempEventInfo = (PUTEVENT_INFO)COM_BasedListFirst(&(putFrom->delayedEvents),
  446. FIELD_OFFSET(UTEVENT_INFO, chain));
  447. while (pTempEventInfo != NULL)
  448. {
  449. ValidateEventInfo(pTempEventInfo);
  450. TRACE_OUT(("Check if before %d popTime %x",
  451. pTempEventInfo->event, pTempEventInfo->popTime));
  452. if (pTempEventInfo->popTime > pDelayedEventInfo->popTime)
  453. {
  454. //
  455. // we have found the first event in the list which pops after
  456. // this event so insert before it.
  457. //
  458. break;
  459. }
  460. pTempEventInfo = (PUTEVENT_INFO)COM_BasedListNext(&(putFrom->delayedEvents),
  461. pTempEventInfo, FIELD_OFFSET(UTEVENT_INFO, chain));
  462. //
  463. // Flag that we are not the first delayed event so we know not to
  464. // (re)start a timer.
  465. //
  466. firstDelayed = FALSE;
  467. }
  468. if (pTempEventInfo == NULL)
  469. {
  470. //
  471. // After all in queue so add to end
  472. //
  473. COM_BasedListInsertBefore(&(putFrom->delayedEvents),
  474. &(pDelayedEventInfo->chain));
  475. }
  476. else
  477. {
  478. //
  479. // Delayed event pops before pTempEventInfo so insert before.
  480. //
  481. COM_BasedListInsertBefore(&(pTempEventInfo->chain),
  482. &(pDelayedEventInfo->chain));
  483. }
  484. //
  485. // If we have inserted the delayed event at the front of the queue then
  486. // restart the timer with the time this event is set to pop.
  487. //
  488. if (firstDelayed)
  489. {
  490. UTStartDelayedEventTimer(putFrom, pDelayedEventInfo->popTime);
  491. }
  492. DC_EXIT_POINT:
  493. DebugExitVOID(UTPostDelayedEvt);
  494. }
  495. //
  496. //
  497. // UTCheckDelayedEvents(...)
  498. //
  499. //
  500. void UTCheckDelayedEvents
  501. (
  502. PUT_CLIENT putTask
  503. )
  504. {
  505. PUT_CLIENT putTo;
  506. UINT timeNow;
  507. PUTEVENT_INFO pEventInfo;
  508. DebugEntry(UTCheckDelayedEvents);
  509. //
  510. // Get exclusive access to the UTM while we move event pool entries
  511. // (these are in shared memory)
  512. //
  513. UT_Lock(UTLOCK_UT);
  514. ValidateUTClient(putTask);
  515. //
  516. // Get time now to check against popTime.
  517. //
  518. timeNow = GetTickCount();
  519. TRACE_OUT(("time now is %x", timeNow));
  520. //
  521. // Move through the queue of delayed events to see if any have popped.
  522. // If so send them immediately. When we get to the first one that
  523. // hasn't popped restart a timer to schedule it.
  524. //
  525. pEventInfo = (PUTEVENT_INFO)COM_BasedListFirst(&(putTask->delayedEvents),
  526. FIELD_OFFSET(UTEVENT_INFO, chain));
  527. while (pEventInfo != NULL)
  528. {
  529. ValidateEventInfo(pEventInfo);
  530. //
  531. // Got an event so check to see if it has popped
  532. //
  533. TRACE_OUT(("Event popTime is %x", pEventInfo->popTime));
  534. if (timeNow >= pEventInfo->popTime)
  535. {
  536. TRACE_OUT(("Event popped so post now"));
  537. //
  538. // Event has popped so remove from delayed queue and post as an
  539. // immediate event.
  540. //
  541. COM_BasedListRemove(&(pEventInfo->chain));
  542. //
  543. // The check on the destination handle should be less strict
  544. // than that on the source (we shouldn't assert). This is
  545. // because the caller may be pre-empted before this check is
  546. // done, and the destination may shut down in this time.
  547. //
  548. ValidateUTClient(pEventInfo->putTo);
  549. UTPostImmediateEvt(putTask, pEventInfo->putTo,
  550. pEventInfo->event,
  551. pEventInfo->param1,
  552. pEventInfo->param2);
  553. //
  554. // Free the event
  555. //
  556. delete pEventInfo;
  557. //
  558. // Last one popped so move on to next to see if that has popped
  559. // too.
  560. //
  561. pEventInfo = (PUTEVENT_INFO)COM_BasedListFirst(&(putTask->delayedEvents),
  562. FIELD_OFFSET(UTEVENT_INFO, chain));
  563. }
  564. else
  565. {
  566. //
  567. // got to an event which hasn't popped yet. Start timer to pop
  568. // for this one. The OS specific code in UTStartDelayedEventTimer checks
  569. // to see if the new timer is required (not already running)
  570. // and will stop and restart if already running but has the
  571. // incorrect timeout.
  572. //
  573. TRACE_OUT(("Event not popped so restart timer and leave"));
  574. UTStartDelayedEventTimer(putTask, pEventInfo->popTime);
  575. break;
  576. }
  577. }
  578. UT_Unlock(UTLOCK_UT);
  579. DebugExitVOID(UTCheckDelayedEvents);
  580. }
  581. //
  582. // UTProcessEvent(...)
  583. //
  584. void UTProcessEvent
  585. (
  586. PUT_CLIENT putTask,
  587. UINT event,
  588. UINT_PTR param1,
  589. UINT_PTR param2
  590. )
  591. {
  592. int i;
  593. PUTEVENT_PROC_INFO pEventHandler;
  594. DebugEntry(UTProcessEvent);
  595. ValidateUTClient(putTask);
  596. //
  597. // Call all registered event handlers until somebody returns TRUE, that
  598. // the event has been processed.
  599. //
  600. for (i = 0; i < UTEVENT_HANDLERS_MAX ; i++)
  601. {
  602. pEventHandler = &(putTask->eventHandlers[i]);
  603. if (pEventHandler->eventProc == NULL)
  604. {
  605. //
  606. // Nothing's here.
  607. //
  608. break;
  609. }
  610. //
  611. // Call the registered event handler
  612. //
  613. TRACE_OUT(("Call event proc 0x%08x priority %d from position %d",
  614. pEventHandler->eventProc,
  615. pEventHandler->priority,
  616. i));
  617. if ((pEventHandler->eventProc)(pEventHandler->eventData, event,
  618. param1, param2))
  619. {
  620. //
  621. // Event handler processed event
  622. //
  623. break;
  624. }
  625. }
  626. DebugExitVOID(UTProcessEvent);
  627. }
  628. //
  629. //
  630. //
  631. // EXIT PROCS
  632. //
  633. // Our strategy for registering/deregistering/calling exit procs is as
  634. // follows:
  635. //
  636. // - we register procs in the first free slot in the array hung off the
  637. // task data
  638. //
  639. // - we deregister procs by shuffling down other procs after it in the
  640. // array
  641. //
  642. // - we call procs starting at the last entry in the array and working
  643. // backwards.
  644. //
  645. // The above ensures that
  646. //
  647. // - if a proc deregisters itself before task termination, no gaps are
  648. // left in the array
  649. //
  650. // - if a proc deregisters itself during task termination, all
  651. // remaining procs are called in the correct order
  652. //
  653. // - if a proc doesn't deregister itself during task termination, it is
  654. // left in the array but does not affect future processing as the task
  655. // end loop will call the previous one anyway.
  656. //
  657. //
  658. //
  659. //
  660. //
  661. // UT_RegisterExit(...)
  662. //
  663. //
  664. void UT_RegisterExit
  665. (
  666. PUT_CLIENT putTask,
  667. UTEXIT_PROC exitProc,
  668. LPVOID exitData
  669. )
  670. {
  671. int i;
  672. PUTEXIT_PROC_INFO pExitProcs;
  673. DebugEntry(UT_RegisterExit);
  674. ValidateUTClient(putTask);
  675. pExitProcs = putTask->exitProcs;
  676. ASSERT(pExitProcs[UTEXIT_PROCS_MAX-1].exitProc == NULL);
  677. //
  678. // Now we look for the first free slot in the array, since we guarantee
  679. // to call exit procs in the order they were registered in:
  680. //
  681. for (i = 0; i < UTEXIT_PROCS_MAX; i++)
  682. {
  683. if (pExitProcs[i].exitProc == NULL)
  684. {
  685. TRACE_OUT(("Storing exit proc 0x%08x data 0x%08x at position %d",
  686. exitProc, exitData, i));
  687. pExitProcs[i].exitProc = exitProc;
  688. pExitProcs[i].exitData = exitData;
  689. break;
  690. }
  691. }
  692. ASSERT(i < UTEXIT_PROCS_MAX);
  693. DebugExitVOID(UT_RegisterExit);
  694. }
  695. //
  696. //
  697. // UT_DeregisterExit(...)
  698. //
  699. //
  700. void UT_DeregisterExit
  701. (
  702. PUT_CLIENT putTask,
  703. UTEXIT_PROC exitProc,
  704. LPVOID exitData
  705. )
  706. {
  707. int i;
  708. BOOL found = FALSE;
  709. PUTEXIT_PROC_INFO pExitProcs;
  710. DebugEntry(UT_DeregisterExit);
  711. ValidateUTClient(putTask);
  712. pExitProcs = putTask->exitProcs;
  713. //
  714. // Find this exit proc
  715. //
  716. for (i = 0 ; i < UTEXIT_PROCS_MAX; i++)
  717. {
  718. if ((pExitProcs[i].exitProc == exitProc) &&
  719. (pExitProcs[i].exitData == exitData))
  720. {
  721. //
  722. // Found exit proc. Shuffle list down.
  723. //
  724. TRACE_OUT(("Deregistering exit proc 0x%08x from position %d",
  725. exitProc, i));
  726. found = TRUE;
  727. UT_MoveMemory(&pExitProcs[i],
  728. &pExitProcs[i+1],
  729. sizeof(UTEXIT_PROC_INFO) * (UTEXIT_PROCS_MAX - 1 - i));
  730. pExitProcs[UTEXIT_PROCS_MAX-1].exitProc = NULL;
  731. break;
  732. }
  733. }
  734. //
  735. // Check that we found the exit procs
  736. //
  737. ASSERT(found);
  738. DebugExitVOID(UT_DeregisterExit);
  739. }
  740. //
  741. // UTTriggerEvt()
  742. //
  743. void UTTriggerEvt
  744. (
  745. PUT_CLIENT putFrom,
  746. PUT_CLIENT putTo
  747. )
  748. {
  749. DebugEntry(UTTriggerEvt);
  750. ValidateUTClient(putFrom);
  751. ValidateUTClient(putTo);
  752. if (putTo->utHwnd)
  753. {
  754. if (!PostMessage(putTo->utHwnd, WM_UTTRIGGER_MSG, 0, 0))
  755. {
  756. //
  757. // Failed to send event
  758. //
  759. WARNING_OUT(("Failed to post trigger message from %x to %x",
  760. putFrom, putTo));
  761. }
  762. }
  763. DebugExitVOID(UTTriggerEvt);
  764. }
  765. //
  766. //
  767. // UTStartDelayedEventTimer(...)
  768. //
  769. //
  770. void UTStartDelayedEventTimer(PUT_CLIENT putTask, UINT popTime)
  771. {
  772. UINT currentTickCount;
  773. UINT delay = 1;
  774. DebugEntry(UTStartDelayedEventTimer);
  775. //
  776. // Work out the delay from the current time to popTime (popTime is
  777. // given in terms of the system tick count). Be careful in the case
  778. // where we have already passed popTime...
  779. //
  780. currentTickCount = GetTickCount();
  781. if (popTime > currentTickCount)
  782. {
  783. delay = popTime - currentTickCount;
  784. }
  785. //
  786. // Set the timer going. Note that if the timer has already been
  787. // started, this call will reset it using the new delay.
  788. //
  789. if (!SetTimer(putTask->utHwnd, UT_DELAYED_TIMER_ID, delay, NULL))
  790. {
  791. ERROR_OUT(("Could not create timer for delayed event"));
  792. }
  793. DebugExitVOID(UTStartDelayedEventTimer);
  794. }
  795. //
  796. // UT_HandleProcessStart()
  797. //
  798. BOOL UT_HandleProcessStart(HINSTANCE hInstance)
  799. {
  800. BOOL rc = FALSE;
  801. int lock;
  802. WNDCLASS windowClass;
  803. DebugEntry(UT_HandleProcessStart);
  804. //
  805. // Save our dll handle.
  806. //
  807. g_asInstance = hInstance;
  808. //
  809. // Init our critical sections
  810. //
  811. for (lock = UTLOCK_FIRST; lock < UTLOCK_MAX; lock++)
  812. {
  813. InitializeCriticalSection(&g_utLocks[lock]);
  814. }
  815. //
  816. // Register the UT window class
  817. //
  818. windowClass.style = 0;
  819. windowClass.lpfnWndProc = UT_WndProc;
  820. windowClass.cbClsExtra = 0;
  821. windowClass.cbWndExtra = 0;
  822. windowClass.hInstance = g_asInstance;
  823. windowClass.hIcon = NULL;
  824. windowClass.hCursor = NULL;
  825. windowClass.hbrBackground = NULL;
  826. windowClass.lpszMenuName = NULL;
  827. windowClass.lpszClassName = UT_WINDOW_CLASS;
  828. g_utWndClass = RegisterClass(&windowClass);
  829. if (!g_utWndClass)
  830. {
  831. ERROR_OUT(("Failed to register class"));
  832. DC_QUIT;
  833. }
  834. rc = TRUE;
  835. DC_EXIT_POINT:
  836. DebugExitBOOL(UT_HandleProcessStart, rc);
  837. return(rc);
  838. }
  839. //
  840. // UT_HandleProcessEnd()
  841. //
  842. void UT_HandleProcessEnd(void)
  843. {
  844. int lock;
  845. PUT_CLIENT putTask;
  846. int task;
  847. DebugEntry(UT_HandleProcessEnd);
  848. TRACE_OUT(("Process is ending"));
  849. //
  850. // Loop through all the registered UT tasks looking for those on this
  851. // process. Start at the end, and work up to the front.
  852. //
  853. putTask = &(g_autTasks[UTTASK_MAX - 1]);
  854. for (task = UTTASK_MAX - 1; task >= UTTASK_FIRST; task--, putTask--)
  855. {
  856. //
  857. // Is this entry in the UTM in use ?
  858. //
  859. if (putTask->dwThreadId)
  860. {
  861. //
  862. // Clean up after this UT task
  863. //
  864. TRACE_OUT(("Task %x ending without calling UT_TermTask", putTask));
  865. //
  866. // On ProcessEnd, the windows are no longer valid. If it took
  867. // too long to shutdown, we might not have received a thread
  868. // detach notification. In which case we wouldn't have cleaned
  869. // up the thread objects.
  870. //
  871. if (putTask->dwThreadId != GetCurrentThreadId())
  872. {
  873. putTask->utHwnd = NULL;
  874. }
  875. UTTaskEnd(putTask);
  876. }
  877. }
  878. if (g_utWndClass)
  879. {
  880. UnregisterClass(MAKEINTATOM(g_utWndClass), g_asInstance);
  881. g_utWndClass = 0;
  882. }
  883. //
  884. // Clean up the critical sections. Do this last to first, in inverse
  885. // order that they are created.
  886. //
  887. for (lock = UTLOCK_MAX-1; lock >= UTLOCK_FIRST; lock--)
  888. {
  889. DeleteCriticalSection(&g_utLocks[lock]);
  890. }
  891. DebugExitVOID(UT_HandleProcessEnd);
  892. }
  893. //
  894. // UT_HandleThreadEnd()
  895. //
  896. void UT_HandleThreadEnd(void)
  897. {
  898. PUT_CLIENT putTask;
  899. DWORD dwThreadId;
  900. int task;
  901. DebugEntry(UT_HandleThreadEnd);
  902. UT_Lock(UTLOCK_UT);
  903. //
  904. // Get the current thread ID
  905. //
  906. dwThreadId = GetCurrentThreadId();
  907. //
  908. // Loop through all the registered UT tasks looking for one on this
  909. // process and thread. Note that there should only be one entry in the
  910. // UTM for each thread, so we can break out of the loop if we get a
  911. // match.
  912. //
  913. putTask = &(g_autTasks[UTTASK_MAX - 1]);
  914. for (task = UTTASK_MAX - 1; task >= UTTASK_FIRST; task--, putTask--)
  915. {
  916. //
  917. // Is there a task here that matches the current thread?
  918. // Tasks not present have 0 for the thread ID, which won't match
  919. //
  920. if (putTask->dwThreadId == dwThreadId)
  921. {
  922. //
  923. // Clean up after this UT task
  924. //
  925. WARNING_OUT(("Task %x ending without calling UT_TermTask", putTask));
  926. UTTaskEnd(putTask);
  927. }
  928. }
  929. UT_Unlock(UTLOCK_UT);
  930. DebugExitVOID(UT_HandleThreadEnd);
  931. }
  932. //
  933. //
  934. // UT_WndProc(...)
  935. //
  936. //
  937. LRESULT CALLBACK UT_WndProc
  938. (
  939. HWND hwnd,
  940. UINT message,
  941. WPARAM wParam,
  942. LPARAM lParam
  943. )
  944. {
  945. LRESULT retVal = 0;
  946. PUT_CLIENT putTask;
  947. DebugEntry(UT_WndProc);
  948. //
  949. // This isn't a UT message, so we should handle it
  950. //
  951. switch (message)
  952. {
  953. case WM_TIMER:
  954. //
  955. // WM_TIMER is used for delayed events...
  956. //
  957. TRACE_OUT(("Timer Id is 0x%08x", wParam));
  958. if (wParam == UT_DELAYED_TIMER_ID) // defined as 0x10101010
  959. {
  960. //
  961. // Get our UT handle from the window data
  962. //
  963. putTask = (PUT_CLIENT)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  964. ValidateUTClient(putTask);
  965. //
  966. // Stop the timer before it ticks again !
  967. //
  968. KillTimer(putTask->utHwnd, UT_DELAYED_TIMER_ID);
  969. //
  970. // Process the delayed event
  971. //
  972. UTCheckDelayedEvents(putTask);
  973. }
  974. break;
  975. case WM_UTTRIGGER_MSG:
  976. putTask = (PUT_CLIENT)GetWindowLongPtr(hwnd, GWLP_USERDATA);
  977. ValidateUTClient(putTask);
  978. //
  979. // Distribute pending events
  980. //
  981. UTCheckEvents(putTask);
  982. break;
  983. default:
  984. //
  985. // Call on to the default handler
  986. //
  987. retVal = DefWindowProc(hwnd, message, wParam, lParam);
  988. break;
  989. }
  990. DebugExitDWORD(UT_WndProc, retVal);
  991. return(retVal);
  992. }
  993. //
  994. //
  995. // UTCheckEvents()
  996. // This delivers any normal pending events
  997. //
  998. //
  999. void UTCheckEvents
  1000. (
  1001. PUT_CLIENT putTask
  1002. )
  1003. {
  1004. PUTEVENT_INFO pEventInfo;
  1005. BOOL eventsOnQueue = TRUE;
  1006. int eventsProcessed = 0;
  1007. UINT event;
  1008. UINT_PTR param1, param2;
  1009. DebugEntry(UTCheckEvents);
  1010. UT_Lock(UTLOCK_UT);
  1011. //
  1012. // This while-loop picks any events off our queue and calls the
  1013. // handers. We only process a certain number, to be a well behaved
  1014. // task. Many event handlers in turn post other events...
  1015. //
  1016. while (eventsOnQueue && (eventsProcessed < MAX_EVENTS_TO_PROCESS))
  1017. {
  1018. //
  1019. // Are there any events waiting on the queue?
  1020. //
  1021. pEventInfo = (PUTEVENT_INFO)COM_BasedListFirst(&(putTask->pendingEvents),
  1022. FIELD_OFFSET(UTEVENT_INFO, chain));
  1023. if (pEventInfo != NULL)
  1024. {
  1025. ValidateEventInfo(pEventInfo);
  1026. TRACE_OUT(("Event(s) pending - returning first one in queue"));
  1027. //
  1028. // Return event from queue
  1029. //
  1030. event = pEventInfo->event;
  1031. param1 = pEventInfo->param1;
  1032. param2 = pEventInfo->param2;
  1033. //
  1034. // Remove event from queue
  1035. //
  1036. COM_BasedListRemove(&(pEventInfo->chain));
  1037. //
  1038. // Free the event
  1039. //
  1040. delete pEventInfo;
  1041. }
  1042. else
  1043. {
  1044. //
  1045. // No events on the queue - this can happen if we
  1046. // process the event queue between the trigger event
  1047. // being sent, amd the trigger event being received.
  1048. //
  1049. TRACE_OUT(("Got event trigger but no events on queue!"));
  1050. DC_QUIT;
  1051. }
  1052. //
  1053. // Check now if there are still events on the queue.
  1054. //
  1055. // NOTE:
  1056. // We set up eventsOnQueue now, rather than after the call
  1057. // to ProcessEvent - this means that if processing the last
  1058. // event on the queue (say, event A) causes event B to be
  1059. // posted back to ourselves, we will not process B until
  1060. // later, when the event arrives for it. This may seem
  1061. // like an unnecessary delay but it is vital to prevent
  1062. // yield nesting.
  1063. //
  1064. pEventInfo = (PUTEVENT_INFO)COM_BasedListFirst(&(putTask->pendingEvents),
  1065. FIELD_OFFSET(UTEVENT_INFO, chain));
  1066. if (pEventInfo == NULL)
  1067. {
  1068. eventsOnQueue = FALSE;
  1069. }
  1070. //
  1071. // Unlock access to shared memory -- we're about to yield
  1072. //
  1073. UT_Unlock(UTLOCK_UT);
  1074. UTProcessEvent(putTask, event, param1, param2);
  1075. UT_Lock(UTLOCK_UT);
  1076. if (!putTask->dwThreadId)
  1077. {
  1078. //
  1079. // The task was terminated by the event. bail out.
  1080. //
  1081. WARNING_OUT(("Task %x terminated in event handler", putTask));
  1082. DC_QUIT;
  1083. }
  1084. //
  1085. // Increment the number of events we've processed in this
  1086. // loop.
  1087. //
  1088. eventsProcessed++;
  1089. }
  1090. //
  1091. // There is an upper limit to the number of events we try to
  1092. // process in one loop. If we've reached this limit, post a
  1093. // trigger event to ensure that we process the remaining events
  1094. // later, then quit.
  1095. //
  1096. if (eventsProcessed >= MAX_EVENTS_TO_PROCESS)
  1097. {
  1098. TRACE_OUT(("Another trigger event required"));
  1099. UTTriggerEvt(putTask, putTask);
  1100. }
  1101. DC_EXIT_POINT:
  1102. UT_Unlock(UTLOCK_UT);
  1103. DebugExitVOID(UTUtilitiesWndProc);
  1104. }
  1105. //
  1106. // UT_MallocRefCount()
  1107. //
  1108. // This allocates a ref-count block, one that doesn't go away until
  1109. // the ref-count reaches zero.
  1110. //
  1111. void * UT_MallocRefCount
  1112. (
  1113. UINT cbSizeMem,
  1114. BOOL fZeroMem
  1115. )
  1116. {
  1117. PUTREFCOUNTHEADER pHeader;
  1118. void * pMemory = NULL;
  1119. DebugEntry(UT_MallocRefCount);
  1120. //
  1121. // Allocate a block the client's size + our header's size
  1122. //
  1123. pHeader = (PUTREFCOUNTHEADER)new BYTE[sizeof(UTREFCOUNTHEADER) + cbSizeMem];
  1124. if (!pHeader)
  1125. {
  1126. ERROR_OUT(("UT_MallocRefCount failed; out of memory"));
  1127. DC_QUIT;
  1128. }
  1129. if (fZeroMem)
  1130. {
  1131. ZeroMemory(pHeader, sizeof(UTREFCOUNTHEADER) + cbSizeMem);
  1132. }
  1133. SET_STAMP(pHeader, UTREFCOUNTHEADER);
  1134. pHeader->refCount = 1;
  1135. pMemory = (pHeader + 1);
  1136. DC_EXIT_POINT:
  1137. DebugExitPTR(UT_MallocRefCount, pMemory);
  1138. return(pMemory);
  1139. }
  1140. //
  1141. // UT_BumpUpRefCount()
  1142. //
  1143. void UT_BumpUpRefCount
  1144. (
  1145. void * pMemory
  1146. )
  1147. {
  1148. PUTREFCOUNTHEADER pHeader;
  1149. DebugEntry(UT_BumpUpRefCount);
  1150. ASSERT(pMemory);
  1151. pHeader = (PUTREFCOUNTHEADER)((LPBYTE)pMemory - sizeof(UTREFCOUNTHEADER));
  1152. ASSERT(!IsBadWritePtr(pHeader, sizeof(UTREFCOUNTHEADER)));
  1153. ASSERT(pHeader->stamp.idStamp[0] == 'A');
  1154. ASSERT(pHeader->stamp.idStamp[1] == 'S');
  1155. ASSERT(pHeader->refCount);
  1156. pHeader->refCount++;
  1157. TRACE_OUT(("Bumped up ref-counted memory block 0x%08x to %d", pHeader, pHeader->refCount));
  1158. DebugExitVOID(UT_BumpUpRefCount);
  1159. }
  1160. //
  1161. // UT_FreeRefCount()
  1162. //
  1163. void UT_FreeRefCount
  1164. (
  1165. void ** ppMemory,
  1166. BOOL fNullOnlyWhenFreed
  1167. )
  1168. {
  1169. void * pMemory;
  1170. PUTREFCOUNTHEADER pHeader;
  1171. DebugEntry(UT_FreeRefCount);
  1172. ASSERT(ppMemory);
  1173. pMemory = *ppMemory;
  1174. ASSERT(pMemory);
  1175. pHeader = (PUTREFCOUNTHEADER)((LPBYTE)pMemory - sizeof(UTREFCOUNTHEADER));
  1176. ASSERT(!IsBadWritePtr(pHeader, sizeof(UTREFCOUNTHEADER)));
  1177. ASSERT(pHeader->stamp.idStamp[0] == 'A');
  1178. ASSERT(pHeader->stamp.idStamp[1] == 'S');
  1179. ASSERT(pHeader->refCount);
  1180. if (--(pHeader->refCount) == 0)
  1181. {
  1182. TRACE_OUT(("Freeing ref-counted memory block 0x%08x", pHeader));
  1183. delete[] pHeader;
  1184. *ppMemory = NULL;
  1185. }
  1186. else
  1187. {
  1188. TRACE_OUT(("Bumped down ref-counted memory block 0x%08x to %d", pHeader, pHeader->refCount));
  1189. if (!fNullOnlyWhenFreed)
  1190. *ppMemory = NULL;
  1191. }
  1192. DebugExitVOID(UT_FreeRefCount);
  1193. }
  1194. //
  1195. // UT_MoveMemory - Copy source buffer to destination buffer
  1196. //
  1197. // Purpose:
  1198. // UT_MoveMemory() copies a source memory buffer to a destination memory buffer.
  1199. // This routine recognize overlapping buffers to avoid propogation.
  1200. // For cases where propogation is not a problem, memcpy() can be used.
  1201. //
  1202. // Entry:
  1203. // void *dst = pointer to destination buffer
  1204. // const void *src = pointer to source buffer
  1205. // size_t count = number of bytes to copy
  1206. //
  1207. // Exit:
  1208. // Returns a pointer to the destination buffer
  1209. //
  1210. //Exceptions:
  1211. //
  1212. void * UT_MoveMemory (
  1213. void * dst,
  1214. const void * src,
  1215. size_t count
  1216. )
  1217. {
  1218. void * ret = dst;
  1219. if (dst <= src || (char *)dst >= ((char *)src + count)) {
  1220. //
  1221. // Non-Overlapping Buffers
  1222. // copy from lower addresses to higher addresses
  1223. //
  1224. while (count--) {
  1225. *(char *)dst = *(char *)src;
  1226. dst = (char *)dst + 1;
  1227. src = (char *)src + 1;
  1228. }
  1229. }
  1230. else {
  1231. //
  1232. // Overlapping Buffers
  1233. // copy from higher addresses to lower addresses
  1234. //
  1235. dst = (char *)dst + count - 1;
  1236. src = (char *)src + count - 1;
  1237. while (count--) {
  1238. *(char *)dst = *(char *)src;
  1239. dst = (char *)dst - 1;
  1240. src = (char *)src - 1;
  1241. }
  1242. }
  1243. return(ret);
  1244. }
  1245. //
  1246. // COM_BasedListInsertBefore(...)
  1247. //
  1248. // See ut.h for description.
  1249. //
  1250. void COM_BasedListInsertBefore(PBASEDLIST pExisting, PBASEDLIST pNew)
  1251. {
  1252. PBASEDLIST pTemp;
  1253. DebugEntry(COM_BasedListInsertBefore);
  1254. //
  1255. // Check for bad parameters.
  1256. //
  1257. ASSERT((pNew != NULL));
  1258. ASSERT((pExisting != NULL));
  1259. //
  1260. // Find the item before pExisting:
  1261. //
  1262. pTemp = COM_BasedPrevListField(pExisting);
  1263. ASSERT((pTemp != NULL));
  1264. TRACE_OUT(("Inserting item at 0x%08x into list between 0x%08x and 0x%08x",
  1265. pNew, pTemp, pExisting));
  1266. //
  1267. // Set its <next> field to point to the new item
  1268. //
  1269. pTemp->next = PTRBASE_TO_OFFSET(pNew, pTemp);
  1270. pNew->prev = PTRBASE_TO_OFFSET(pTemp, pNew);
  1271. //
  1272. // Set <prev> field of pExisting to point to new item:
  1273. //
  1274. pExisting->prev = PTRBASE_TO_OFFSET(pNew, pExisting);
  1275. pNew->next = PTRBASE_TO_OFFSET(pExisting, pNew);
  1276. DebugExitVOID(COM_BasedListInsertBefore);
  1277. } // COM_BasedListInsertBefore
  1278. //
  1279. // COM_BasedListInsertAfter(...)
  1280. //
  1281. // See ut.h for description.
  1282. //
  1283. void COM_BasedListInsertAfter(PBASEDLIST pExisting,
  1284. PBASEDLIST pNew)
  1285. {
  1286. PBASEDLIST pTemp;
  1287. DebugEntry(COM_BasedListInsertAfter);
  1288. //
  1289. // Check for bad parameters.
  1290. //
  1291. ASSERT((pNew != NULL));
  1292. ASSERT((pExisting != NULL));
  1293. //
  1294. // Find the item after pExisting:
  1295. //
  1296. pTemp = COM_BasedNextListField(pExisting);
  1297. ASSERT((pTemp != NULL));
  1298. TRACE_OUT(("Inserting item at 0x%08x into list between 0x%08x and 0x%08x",
  1299. pNew, pExisting, pTemp));
  1300. //
  1301. // Set its <prev> field to point to the new item
  1302. //
  1303. pTemp->prev = PTRBASE_TO_OFFSET(pNew, pTemp);
  1304. pNew->next = PTRBASE_TO_OFFSET(pTemp, pNew);
  1305. //
  1306. // Set <next> field of pExisting to point to new item:
  1307. //
  1308. pExisting->next = PTRBASE_TO_OFFSET(pNew, pExisting);
  1309. pNew->prev = PTRBASE_TO_OFFSET(pExisting, pNew);
  1310. DebugExitVOID(COM_BasedListInsertAfter);
  1311. } // COM_BasedListInsertAfter
  1312. //
  1313. // COM_BasedListRemove(...)
  1314. //
  1315. // See ut.h for description.
  1316. //
  1317. void COM_BasedListRemove(PBASEDLIST pListItem)
  1318. {
  1319. PBASEDLIST pNext = NULL;
  1320. PBASEDLIST pPrev = NULL;
  1321. DebugEntry(COM_BasedListRemove);
  1322. //
  1323. // Check for bad parameters.
  1324. //
  1325. ASSERT((pListItem != NULL));
  1326. pPrev = COM_BasedPrevListField(pListItem);
  1327. pNext = COM_BasedNextListField(pListItem);
  1328. ASSERT((pPrev != NULL));
  1329. ASSERT((pNext != NULL));
  1330. TRACE_OUT(("Removing item 0x%08x from list", pListItem));
  1331. pPrev->next = PTRBASE_TO_OFFSET(pNext, pPrev);
  1332. pNext->prev = PTRBASE_TO_OFFSET(pPrev, pNext);
  1333. DebugExitVOID(COM_BasedListRemove);
  1334. }
  1335. void FAR * COM_BasedListNext ( PBASEDLIST pHead, void FAR * pEntry, UINT nOffset )
  1336. {
  1337. PBASEDLIST p;
  1338. ASSERT(pHead != NULL);
  1339. ASSERT(pEntry != NULL);
  1340. p = COM_BasedNextListField(COM_BasedStructToField(pEntry, nOffset));
  1341. return ((p == pHead) ? NULL : COM_BasedFieldToStruct(p, nOffset));
  1342. }
  1343. void FAR * COM_BasedListPrev ( PBASEDLIST pHead, void FAR * pEntry, UINT nOffset )
  1344. {
  1345. PBASEDLIST p;
  1346. ASSERT(pHead != NULL);
  1347. ASSERT(pEntry != NULL);
  1348. p = COM_BasedPrevListField(COM_BasedStructToField(pEntry, nOffset));
  1349. return ((p == pHead) ? NULL : COM_BasedFieldToStruct(p, nOffset));
  1350. }
  1351. void FAR * COM_BasedListFirst ( PBASEDLIST pHead, UINT nOffset )
  1352. {
  1353. return (COM_BasedListIsEmpty(pHead) ?
  1354. NULL :
  1355. COM_BasedFieldToStruct(COM_BasedNextListField(pHead), nOffset));
  1356. }
  1357. void FAR * COM_BasedListLast ( PBASEDLIST pHead, UINT nOffset )
  1358. {
  1359. return (COM_BasedListIsEmpty(pHead) ?
  1360. NULL :
  1361. COM_BasedFieldToStruct(COM_BasedPrevListField(pHead), nOffset));
  1362. }
  1363. void COM_BasedListFind ( LIST_FIND_TYPE eType,
  1364. PBASEDLIST pHead,
  1365. void FAR * FAR* ppEntry,
  1366. UINT nOffset,
  1367. int nOffsetKey,
  1368. DWORD_PTR Key,
  1369. int cbKeySize )
  1370. {
  1371. void *p = *ppEntry;
  1372. DWORD val;
  1373. switch (eType)
  1374. {
  1375. case LIST_FIND_FROM_FIRST:
  1376. p = COM_BasedListFirst(pHead, nOffset);
  1377. break;
  1378. case LIST_FIND_FROM_NEXT:
  1379. p = COM_BasedListNext(pHead, p, nOffset);
  1380. break;
  1381. default:
  1382. ASSERT(FALSE);
  1383. }
  1384. // make sure the key size is no more than a dword
  1385. ASSERT(cbKeySize <= sizeof(DWORD_PTR));
  1386. while (p != NULL)
  1387. {
  1388. val = 0;
  1389. CopyMemory(&val, (void *) ((DWORD_PTR) p + nOffsetKey), cbKeySize);
  1390. if (val == Key)
  1391. {
  1392. break;
  1393. }
  1394. p = COM_BasedListNext(pHead, p, nOffset);
  1395. }
  1396. *ppEntry = p;
  1397. }
  1398. //
  1399. // COM_SimpleListAppend()
  1400. //
  1401. // For simple lists, such as hwnd list, app name list, proc id list
  1402. //
  1403. PSIMPLE_LIST COM_SimpleListAppend ( PBASEDLIST pHead, void FAR * pData )
  1404. {
  1405. PSIMPLE_LIST p = new SIMPLE_LIST;
  1406. if (p != NULL)
  1407. {
  1408. ZeroMemory(p, sizeof(*p));
  1409. p->pData = pData;
  1410. COM_BasedListInsertBefore(pHead, &(p->chain));
  1411. }
  1412. return p;
  1413. }
  1414. void FAR * COM_SimpleListRemoveHead ( PBASEDLIST pHead )
  1415. {
  1416. void *pData = NULL;
  1417. PBASEDLIST pdclist;
  1418. PSIMPLE_LIST p;
  1419. if (! COM_BasedListIsEmpty(pHead))
  1420. {
  1421. // get the first entry in the list
  1422. pdclist = COM_BasedNextListField(pHead);
  1423. p = (PSIMPLE_LIST) COM_BasedFieldToStruct(pdclist,
  1424. offsetof(SIMPLE_LIST, chain));
  1425. pData = p->pData;
  1426. // remove the first entry in the list
  1427. COM_BasedListRemove(pdclist);
  1428. delete p;
  1429. }
  1430. return pData;
  1431. }
  1432. //
  1433. // COM_ReadProfInt(...)
  1434. //
  1435. // See ut.h for description.
  1436. //
  1437. void COM_ReadProfInt
  1438. (
  1439. LPSTR pSection,
  1440. LPSTR pEntry,
  1441. int defaultValue,
  1442. int * pValue
  1443. )
  1444. {
  1445. int localValue;
  1446. DebugEntry(COM_ReadProfInt);
  1447. //
  1448. // Check for NULL parameters
  1449. //
  1450. ASSERT(pSection != NULL);
  1451. ASSERT(pEntry != NULL);
  1452. //
  1453. // First try to read the value from the current user section.
  1454. // Then try to read the value from the global local machine section.
  1455. //
  1456. if (COMReadEntry(HKEY_CURRENT_USER, pSection, pEntry, (LPSTR)&localValue,
  1457. sizeof(int), REG_DWORD) ||
  1458. COMReadEntry(HKEY_LOCAL_MACHINE, pSection, pEntry, (LPSTR)&localValue,
  1459. sizeof(int), REG_DWORD))
  1460. {
  1461. *pValue = localValue;
  1462. }
  1463. else
  1464. {
  1465. *pValue = defaultValue;
  1466. }
  1467. DebugExitVOID(COM_ReadProfInt);
  1468. }
  1469. //
  1470. // FUNCTION: COMReadEntry(...)
  1471. //
  1472. // DESCRIPTION:
  1473. // ============
  1474. // Read an entry from the given section of the registry. Allow type
  1475. // REG_BINARY (4 bytes) if REG_DWORD was requested.
  1476. //
  1477. //
  1478. // PARAMETERS:
  1479. // ===========
  1480. // topLevelKey : one of:
  1481. // - HKEY_CURRENT_USER
  1482. // - HKEY_LOCAL_MACHINE
  1483. // pSection : the section name to read from. The DC_REG_PREFIX
  1484. // string is prepended to give the full name.
  1485. // pEntry : the entry name to read.
  1486. // pBuffer : a buffer to read the entry to.
  1487. // bufferSize : the size of the buffer.
  1488. // expectedDataType : the type of data stored in the entry.
  1489. //
  1490. // RETURNS:
  1491. // ========
  1492. // Nothing.
  1493. //
  1494. //
  1495. BOOL COMReadEntry(HKEY topLevelKey,
  1496. LPSTR pSection,
  1497. LPSTR pEntry,
  1498. LPSTR pBuffer,
  1499. int bufferSize,
  1500. ULONG expectedDataType)
  1501. {
  1502. LONG sysrc;
  1503. HKEY key;
  1504. ULONG dataType;
  1505. ULONG dataSize;
  1506. char subKey[COM_MAX_SUBKEY];
  1507. BOOL keyOpen = FALSE;
  1508. BOOL rc = FALSE;
  1509. DebugEntry(COMReadEntry);
  1510. //
  1511. // Get a subkey for the value.
  1512. //
  1513. wsprintf(subKey, "%s%s", DC_REG_PREFIX, pSection);
  1514. //
  1515. // Try to open the key. If the entry does not exist, RegOpenKeyEx will
  1516. // fail.
  1517. //
  1518. sysrc = RegOpenKeyEx(topLevelKey,
  1519. subKey,
  1520. 0, // reserved
  1521. KEY_ALL_ACCESS,
  1522. &key);
  1523. if (sysrc != ERROR_SUCCESS)
  1524. {
  1525. //
  1526. // Don't trace an error here since the subkey may not exist...
  1527. //
  1528. TRACE_OUT(("Failed to open key %s, rc = %d", subKey, sysrc));
  1529. DC_QUIT;
  1530. }
  1531. keyOpen = TRUE;
  1532. //
  1533. // We successfully opened the key so now try to read the value. Again
  1534. // it may not exist.
  1535. //
  1536. dataSize = bufferSize;
  1537. sysrc = RegQueryValueEx(key,
  1538. pEntry,
  1539. 0, // reserved
  1540. &dataType,
  1541. (LPBYTE)pBuffer,
  1542. &dataSize);
  1543. if (sysrc != ERROR_SUCCESS)
  1544. {
  1545. TRACE_OUT(("Failed to read value of [%s] %s, rc = %d",
  1546. pSection,
  1547. pEntry,
  1548. sysrc));
  1549. DC_QUIT;
  1550. }
  1551. //
  1552. // Check that the type is correct. Special case: allow REG_BINARY
  1553. // instead of REG_DWORD, as long as the length is 32 bits.
  1554. //
  1555. if ((dataType != expectedDataType) &&
  1556. ((dataType != REG_BINARY) ||
  1557. (expectedDataType != REG_DWORD) ||
  1558. (dataSize != 4)))
  1559. {
  1560. WARNING_OUT(("Read value from [%s] %s, but type is %d - expected %d",
  1561. pSection,
  1562. pEntry,
  1563. dataType,
  1564. expectedDataType));
  1565. DC_QUIT;
  1566. }
  1567. rc = TRUE;
  1568. DC_EXIT_POINT:
  1569. //
  1570. // Close the key (if required).
  1571. //
  1572. if (keyOpen)
  1573. {
  1574. sysrc = RegCloseKey(key);
  1575. if (sysrc != ERROR_SUCCESS)
  1576. {
  1577. ERROR_OUT(("Failed to close key, rc = %d", sysrc));
  1578. }
  1579. }
  1580. DebugExitBOOL(COMReadEntry, rc);
  1581. return(rc);
  1582. }
  1583. //
  1584. // COM_GetSiteName()
  1585. //
  1586. void COM_GetSiteName(LPSTR siteName, UINT siteNameLen)
  1587. {
  1588. LRESULT rc;
  1589. HKEY hkeyUserDetails;
  1590. DWORD cbData;
  1591. TCHAR szNameBuffer[MAX_PATH];
  1592. DebugEntry(COM_GetSiteName);
  1593. //
  1594. // Get this site address from the registry
  1595. //
  1596. rc = RegOpenKey(HKEY_CURRENT_USER,
  1597. ISAPI_KEY TEXT("\\") REGKEY_USERDETAILS,
  1598. &hkeyUserDetails);
  1599. if (rc == ERROR_SUCCESS)
  1600. {
  1601. //
  1602. // We read the data into our own local buffer, rather than directly
  1603. // into the passed buffer, because the passed buffer is normally 48
  1604. // bytes long, but if the registry has been mis-setup it may be
  1605. // longer than this.
  1606. //
  1607. // Unfortunately Windows stubbornly returns an error when the
  1608. // buffer is smaller than is required, and has no way of returning
  1609. // the truncated string.
  1610. //
  1611. // To avoid this we get the value into a good size buffer, then
  1612. // copy just the bit we want.
  1613. //
  1614. cbData = sizeof(szNameBuffer);
  1615. rc = RegQueryValueEx(hkeyUserDetails,
  1616. REGVAL_ULS_NAME,
  1617. NULL,
  1618. NULL,
  1619. (LPBYTE)szNameBuffer,
  1620. &cbData);
  1621. RegCloseKey(hkeyUserDetails);
  1622. }
  1623. if (rc == ERROR_SUCCESS)
  1624. {
  1625. //
  1626. // Copy from our local buffer into the passed buffer.
  1627. // Ensure there is a NUL terminator at the end.
  1628. //
  1629. lstrcpyn(siteName, szNameBuffer, siteNameLen);
  1630. }
  1631. else
  1632. {
  1633. //
  1634. // Failing to read the site name is not an error.
  1635. // Use the computer name instead.
  1636. //
  1637. DWORD dwComputerNameLength = siteNameLen;
  1638. GetComputerName(siteName, &dwComputerNameLength);
  1639. }
  1640. TRACE_OUT(("Site name is <%s>", siteName));
  1641. DebugExitVOID(COM_GetSiteName);
  1642. }