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.

767 lines
25 KiB

  1. // --------------------------------------------------------------------------
  2. // Module Name: ThemeServerClient.cpp
  3. //
  4. // Copyright (c) 2000, Microsoft Corporation
  5. //
  6. // This file contains a class that implements the theme server functions that
  7. // are executed in a client context (winlogon context).
  8. //
  9. // History: 2000-11-29 vtan created
  10. // --------------------------------------------------------------------------
  11. #include "StandardHeader.h"
  12. #include "ThemeServerClient.h"
  13. #include <lpcthemes.h>
  14. #include <uxthemep.h>
  15. #include <UxThemeServer.h>
  16. #include "SingleThreadedExecution.h"
  17. #include "StatusCode.h"
  18. #include "ThemeManagerService.h"
  19. #include <Impersonation.h>
  20. // --------------------------------------------------------------------------
  21. // CThemeManagerAPI::s_pThemeManagerAPIServer
  22. // CThemeManagerAPI::s_hPort
  23. // CThemeManagerAPI::s_hToken
  24. // CThemeManagerAPI::s_hEvent
  25. // CThemeManagerAPI::s_hWaitObject
  26. // CThemeManagerAPI::s_pLock
  27. //
  28. // Purpose: Static member variables.
  29. //
  30. // History: 2000-11-29 vtan created
  31. // --------------------------------------------------------------------------
  32. CThemeManagerAPIServer* CThemeServerClient::s_pThemeManagerAPIServer = NULL;
  33. HANDLE CThemeServerClient::s_hPort = NULL;
  34. HANDLE CThemeServerClient::s_hToken = NULL;
  35. HANDLE CThemeServerClient::s_hEvent = NULL;
  36. HANDLE CThemeServerClient::s_hWaitObject = NULL;
  37. HMODULE CThemeServerClient::s_hModuleUxTheme = NULL;
  38. CCriticalSection* CThemeServerClient::s_pLock = NULL;
  39. // --------------------------------------------------------------------------
  40. // CThemeServerClient::WaitForServiceReady
  41. //
  42. // Arguments: dwTimeout = Number of ticks to wait.
  43. //
  44. // Returns: DWORD
  45. //
  46. // Purpose: Check if the service is autostart. If so then wait the
  47. // designated amount of time for the service. If the service
  48. // is then running or was running but isn't autostart then
  49. // re-establish the connection to the server.
  50. //
  51. // History: 2000-10-10 vtan created
  52. // 2000-11-29 vtan converted to a Win32 service
  53. // --------------------------------------------------------------------------
  54. DWORD CThemeServerClient::WaitForServiceReady (DWORD dwTimeout)
  55. {
  56. DWORD dwWaitResult;
  57. NTSTATUS status;
  58. dwWaitResult = WAIT_TIMEOUT;
  59. if (s_pThemeManagerAPIServer->IsAutoStart())
  60. {
  61. status = s_pThemeManagerAPIServer->Wait(dwTimeout);
  62. #ifdef DBG
  63. if (STATUS_TIMEOUT == status)
  64. {
  65. INFORMATIONMSG("Wait on auto start theme service timed out.");
  66. }
  67. #endif /* DBG */
  68. }
  69. else
  70. {
  71. status = STATUS_SUCCESS;
  72. }
  73. if (NT_SUCCESS(status) && s_pThemeManagerAPIServer->IsRunning())
  74. {
  75. status = ReestablishConnection();
  76. if (NT_SUCCESS(status))
  77. {
  78. THR(InitUserRegistry());
  79. THR(InitUserTheme(FALSE));
  80. dwWaitResult = WAIT_OBJECT_0;
  81. }
  82. }
  83. return(dwWaitResult);
  84. }
  85. // --------------------------------------------------------------------------
  86. // CThemeServerClient::WatchForStart
  87. //
  88. // Arguments: <none>
  89. //
  90. // Returns: NTSTATUS
  91. //
  92. // Purpose: Opens or creates the theme server announce event. This is a
  93. // manual reset event which the theme server pulses when it
  94. // starts up. This allows winlogon to initiate new connections
  95. // to the theme server without having to wait for logon or
  96. // logoff events to happen.
  97. //
  98. // This event is intentionally leaked and cleaned up when the
  99. // winlogon process for the session goes away.
  100. //
  101. // History: 2000-11-29 vtan created
  102. // --------------------------------------------------------------------------
  103. NTSTATUS CThemeServerClient::WatchForStart (void)
  104. {
  105. NTSTATUS status;
  106. s_hEvent = CThemeManagerService::OpenStartEvent(NtCurrentPeb()->SessionId, SYNCHRONIZE);
  107. if (s_hEvent != NULL)
  108. {
  109. if (RegisterWaitForSingleObject(&s_hWaitObject,
  110. s_hEvent,
  111. CB_ServiceStart,
  112. NULL,
  113. INFINITE,
  114. WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE) != FALSE)
  115. {
  116. status = STATUS_SUCCESS;
  117. }
  118. else
  119. {
  120. status = CStatusCode::StatusCodeOfLastError();
  121. }
  122. }
  123. else
  124. {
  125. status = CStatusCode::StatusCodeOfLastError();
  126. }
  127. return(status);
  128. }
  129. // --------------------------------------------------------------------------
  130. // CThemeServerClient::UserLogon
  131. //
  132. // Arguments: hToken = Token of user logging on.
  133. //
  134. // Returns: NTSTATUS
  135. //
  136. // Purpose: Signals the server that a user is logging on and gives the
  137. // server the handle to the token. The server will grant access
  138. // to the port based on the user's logon SID. Then perform work
  139. // to initialize the environment for the user logging on.
  140. //
  141. // History: 2000-10-10 vtan created
  142. // 2000-11-29 vtan converted to a Win32 service
  143. // --------------------------------------------------------------------------
  144. NTSTATUS CThemeServerClient::UserLogon (HANDLE hToken)
  145. {
  146. NTSTATUS status;
  147. status = NotifyUserLogon(hToken);
  148. if (STATUS_PORT_DISCONNECTED == status)
  149. {
  150. status = ReestablishConnection();
  151. if (NT_SUCCESS(status))
  152. {
  153. status = NotifyUserLogon(hToken);
  154. }
  155. }
  156. return(status);
  157. }
  158. // --------------------------------------------------------------------------
  159. // CThemeServerClient::UserLogoff
  160. //
  161. // Arguments: <none>
  162. //
  163. // Returns: NTSTATUS
  164. //
  165. // Purpose: Signals the server that the current user for this session is
  166. // logging off. The server will remove the access that was
  167. // granted at logon and reinitialize the theme settings to the
  168. // ".Default" settings.
  169. //
  170. // History: 2000-10-10 vtan created
  171. // 2000-11-29 vtan converted to a Win32 service
  172. // --------------------------------------------------------------------------
  173. NTSTATUS CThemeServerClient::UserLogoff (void)
  174. {
  175. NTSTATUS status;
  176. status = NotifyUserLogoff();
  177. if (STATUS_PORT_DISCONNECTED == status)
  178. {
  179. status = ReestablishConnection();
  180. if (NT_SUCCESS(status))
  181. {
  182. status = NotifyUserLogoff();
  183. }
  184. }
  185. return(status);
  186. }
  187. // --------------------------------------------------------------------------
  188. // CThemeServerClient::UserInitTheme
  189. //
  190. // Arguments: BOOL
  191. //
  192. // Returns: NTSTATUS
  193. //
  194. // Purpose: Called at logon, or when Terminal Server connects a user to a
  195. // remote session or reconnects to a local session. Needs to
  196. // evaluate the environment and decide if themes need to be loaded
  197. // or unloaded.
  198. //
  199. // History: 2000-01-18 rfernand created
  200. // --------------------------------------------------------------------------
  201. NTSTATUS CThemeServerClient::UserInitTheme (BOOL fPolicyCheckOnly)
  202. {
  203. bool fSuccessfulImpersonation;
  204. // If there's a token impersonate the user. Otherwise use the system context.
  205. if (s_hToken != NULL)
  206. {
  207. fSuccessfulImpersonation = NT_SUCCESS(CImpersonation::ImpersonateUser(GetCurrentThread(), s_hToken));
  208. }
  209. else
  210. {
  211. fSuccessfulImpersonation = true;
  212. }
  213. if (fSuccessfulImpersonation)
  214. {
  215. (HRESULT)InitUserTheme(fPolicyCheckOnly);
  216. }
  217. if (fSuccessfulImpersonation && (s_hToken != NULL))
  218. {
  219. TBOOL(RevertToSelf());
  220. }
  221. return STATUS_SUCCESS;
  222. }
  223. // --------------------------------------------------------------------------
  224. // CThemeServerClient::StaticInitialize
  225. //
  226. // Arguments: <none>
  227. //
  228. // Returns: NTSTATUS
  229. //
  230. // Purpose: Initializes static member variables. Allocate a
  231. // CThemeManagerAPIServer and a lock for this object.
  232. //
  233. // History: 2000-11-29 vtan created
  234. // --------------------------------------------------------------------------
  235. NTSTATUS CThemeServerClient::StaticInitialize (void)
  236. {
  237. NTSTATUS status;
  238. if (s_pThemeManagerAPIServer == NULL)
  239. {
  240. status = STATUS_NO_MEMORY;
  241. s_pThemeManagerAPIServer = new CThemeManagerAPIServer;
  242. if (s_pThemeManagerAPIServer != NULL)
  243. {
  244. s_pLock = new CCriticalSection;
  245. if (s_pLock != NULL)
  246. {
  247. status = STATUS_SUCCESS;
  248. }
  249. }
  250. }
  251. else
  252. {
  253. status = STATUS_SUCCESS;
  254. }
  255. return(status);
  256. }
  257. // --------------------------------------------------------------------------
  258. // CThemeServerClient::StaticTerminate
  259. //
  260. // Arguments: <none>
  261. //
  262. // Returns: NTSTATUS
  263. //
  264. // Purpose: Release static member variables initialized.
  265. //
  266. // History: 2000-11-29 vtan created
  267. // --------------------------------------------------------------------------
  268. NTSTATUS CThemeServerClient::StaticTerminate (void)
  269. {
  270. if (s_pLock != NULL)
  271. {
  272. delete s_pLock;
  273. s_pLock = NULL;
  274. }
  275. if (s_pThemeManagerAPIServer != NULL)
  276. {
  277. s_pThemeManagerAPIServer->Release();
  278. s_pThemeManagerAPIServer = NULL;
  279. }
  280. return(STATUS_SUCCESS);
  281. }
  282. // --------------------------------------------------------------------------
  283. // CThemeServerClient::NotifyUserLogon
  284. //
  285. // Arguments: <none>
  286. //
  287. // Returns: NTSTATUS
  288. //
  289. // Purpose: Execute the send message to the server and tell it that the
  290. // given user is now logged on. This will instruct the server
  291. // to grant access to the ThemeApiPort.
  292. //
  293. // History: 2000-11-29 vtan created
  294. // --------------------------------------------------------------------------
  295. NTSTATUS CThemeServerClient::NotifyUserLogon (HANDLE hToken)
  296. {
  297. NTSTATUS status;
  298. CSingleThreadedExecution lock(*s_pLock);
  299. if (s_hPort != NULL)
  300. {
  301. status = InformServerUserLogon(hToken);
  302. }
  303. else
  304. {
  305. status = STATUS_PORT_DISCONNECTED;
  306. }
  307. // Keep a copy of the token as well in case of demand start of
  308. // the theme server so we can impersonate the user when we load
  309. // their theme using InitUserTheme. Don't copy it if it already
  310. // exists.
  311. if (s_hToken == NULL)
  312. {
  313. TBOOL(DuplicateHandle(GetCurrentProcess(),
  314. hToken,
  315. GetCurrentProcess(),
  316. &s_hToken,
  317. 0,
  318. FALSE,
  319. DUPLICATE_SAME_ACCESS));
  320. }
  321. return(status);
  322. }
  323. // --------------------------------------------------------------------------
  324. // CThemeServerClient::NotifyUserLogoff
  325. //
  326. // Arguments: <none>
  327. //
  328. // Returns: NTSTATUS
  329. //
  330. // Purpose: Tell the server that the logged on user is logged off. This
  331. // will remove access to ThemeApiPort.
  332. //
  333. // History: 2000-11-29 vtan created
  334. // --------------------------------------------------------------------------
  335. NTSTATUS CThemeServerClient::NotifyUserLogoff (void)
  336. {
  337. NTSTATUS status;
  338. CSingleThreadedExecution lock(*s_pLock);
  339. if (s_hToken != NULL)
  340. {
  341. ReleaseHandle(s_hToken);
  342. if (s_hPort != NULL)
  343. {
  344. status = InformServerUserLogoff();
  345. }
  346. else
  347. {
  348. status = STATUS_PORT_DISCONNECTED;
  349. }
  350. }
  351. else
  352. {
  353. status = STATUS_SUCCESS;
  354. }
  355. return(status);
  356. }
  357. // --------------------------------------------------------------------------
  358. // CThemeServerClient::InformServerUserLogon
  359. //
  360. // Arguments: <none>
  361. //
  362. // Returns: NTSTATUS
  363. //
  364. // Purpose: Tell the server that the logged on user is logged off. This
  365. // will remove access to ThemeApiPort.
  366. //
  367. // History: 2000-12-05 vtan created
  368. // --------------------------------------------------------------------------
  369. NTSTATUS CThemeServerClient::InformServerUserLogon (HANDLE hToken)
  370. {
  371. NTSTATUS status;
  372. THEMESAPI_PORT_MESSAGE portMessageIn, portMessageOut;
  373. ZeroMemory(&portMessageIn, sizeof(portMessageIn));
  374. ZeroMemory(&portMessageOut, sizeof(portMessageOut));
  375. portMessageIn.apiThemes.apiGeneric.ulAPINumber = API_THEMES_USERLOGON;
  376. portMessageIn.apiThemes.apiSpecific.apiUserLogon.in.hToken = hToken;
  377. portMessageIn.portMessage.u1.s1.DataLength = sizeof(API_THEMES);
  378. portMessageIn.portMessage.u1.s1.TotalLength = static_cast<CSHORT>(sizeof(THEMESAPI_PORT_MESSAGE));
  379. status = NtRequestWaitReplyPort(s_hPort,
  380. &portMessageIn.portMessage,
  381. &portMessageOut.portMessage);
  382. if (NT_SUCCESS(status))
  383. {
  384. status = portMessageOut.apiThemes.apiGeneric.status;
  385. if (NT_SUCCESS(status))
  386. {
  387. THR(InitUserTheme(FALSE));
  388. }
  389. }
  390. return(status);
  391. }
  392. // --------------------------------------------------------------------------
  393. // CThemeServerClient::InformServerUserLogoff
  394. //
  395. // Arguments: <none>
  396. //
  397. // Returns: NTSTATUS
  398. //
  399. // Purpose: Tell the server that the logged on user is logged off. This
  400. // will remove access to ThemeApiPort.
  401. //
  402. // History: 2000-12-05 vtan created
  403. // --------------------------------------------------------------------------
  404. NTSTATUS CThemeServerClient::InformServerUserLogoff (void)
  405. {
  406. NTSTATUS status;
  407. THEMESAPI_PORT_MESSAGE portMessageIn, portMessageOut;
  408. ZeroMemory(&portMessageIn, sizeof(portMessageIn));
  409. ZeroMemory(&portMessageOut, sizeof(portMessageOut));
  410. portMessageIn.apiThemes.apiGeneric.ulAPINumber = API_THEMES_USERLOGOFF;
  411. portMessageIn.portMessage.u1.s1.DataLength = sizeof(API_THEMES);
  412. portMessageIn.portMessage.u1.s1.TotalLength = static_cast<CSHORT>(sizeof(THEMESAPI_PORT_MESSAGE));
  413. status = NtRequestWaitReplyPort(s_hPort,
  414. &portMessageIn.portMessage,
  415. &portMessageOut.portMessage);
  416. if (NT_SUCCESS(status))
  417. {
  418. status = portMessageOut.apiThemes.apiGeneric.status;
  419. if (NT_SUCCESS(status))
  420. {
  421. THR(InitUserRegistry());
  422. THR(InitUserTheme(FALSE));
  423. }
  424. }
  425. return(status);
  426. }
  427. // --------------------------------------------------------------------------
  428. // CThemeServerClient::SessionCreate
  429. //
  430. // Arguments: <none>
  431. //
  432. // Returns: NTSTATUS
  433. //
  434. // Purpose: Signal the server that a new session is being created. This
  435. // allows the server to allocate a data blob for this session.
  436. //
  437. // History: 2000-11-11 vtan created
  438. // --------------------------------------------------------------------------
  439. NTSTATUS CThemeServerClient::SessionCreate (void)
  440. {
  441. NTSTATUS status;
  442. CSingleThreadedExecution lock(*s_pLock);
  443. if (s_hModuleUxTheme == NULL)
  444. {
  445. s_hModuleUxTheme = LoadLibrary(TEXT("uxtheme.dll"));
  446. }
  447. if (s_hModuleUxTheme != NULL)
  448. {
  449. void *pfnRegister, *pfnUnregister, *pfnClearStockObjects;
  450. // Get the uxtheme function addresses in this process address space.
  451. // 34 = ThemeHooksInstall
  452. // 35 = ThemeHooksRemove
  453. // 62 = ServerClearStockObjects
  454. pfnRegister = GetProcAddress(s_hModuleUxTheme, MAKEINTRESOURCEA(34));
  455. pfnUnregister = GetProcAddress(s_hModuleUxTheme, MAKEINTRESOURCEA(35));
  456. pfnClearStockObjects = GetProcAddress(s_hModuleUxTheme, MAKEINTRESOURCEA(62));
  457. if ((pfnRegister != NULL) && (pfnUnregister != NULL) && (pfnClearStockObjects != NULL))
  458. {
  459. DWORD dwStackSizeReserve, dwStackSizeCommit;
  460. ULONG ulReturnLength;
  461. IMAGE_NT_HEADERS *pNTHeaders;
  462. SYSTEM_BASIC_INFORMATION systemBasicInformation;
  463. THEMESAPI_PORT_MESSAGE portMessageIn, portMessageOut;
  464. // Get system basic information for stack size defaults.
  465. status = NtQuerySystemInformation(SystemBasicInformation,
  466. &systemBasicInformation,
  467. sizeof(systemBasicInformation),
  468. &ulReturnLength);
  469. if (NT_SUCCESS(status))
  470. {
  471. dwStackSizeReserve = systemBasicInformation.AllocationGranularity;
  472. dwStackSizeCommit = systemBasicInformation.PageSize;
  473. }
  474. else
  475. {
  476. dwStackSizeReserve = dwStackSizeCommit = 0;
  477. }
  478. // Go to the image header for this process and get the stack size
  479. // defaults if they are specified. Otherwise use system defaults (above).
  480. pNTHeaders = RtlImageNtHeader(NtCurrentPeb()->ImageBaseAddress);
  481. if (pNTHeaders != NULL)
  482. {
  483. dwStackSizeReserve = static_cast<DWORD>(pNTHeaders->OptionalHeader.SizeOfStackReserve);
  484. dwStackSizeCommit = static_cast<DWORD>(pNTHeaders->OptionalHeader.SizeOfStackCommit);
  485. }
  486. // Make the call.
  487. ZeroMemory(&portMessageIn, sizeof(portMessageIn));
  488. ZeroMemory(&portMessageOut, sizeof(portMessageOut));
  489. portMessageIn.apiThemes.apiGeneric.ulAPINumber = API_THEMES_SESSIONCREATE;
  490. portMessageIn.apiThemes.apiSpecific.apiSessionCreate.in.pfnRegister = pfnRegister;
  491. portMessageIn.apiThemes.apiSpecific.apiSessionCreate.in.pfnUnregister = pfnUnregister;
  492. portMessageIn.apiThemes.apiSpecific.apiSessionCreate.in.pfnClearStockObjects = pfnClearStockObjects;
  493. portMessageIn.apiThemes.apiSpecific.apiSessionCreate.in.dwStackSizeReserve = dwStackSizeReserve;
  494. portMessageIn.apiThemes.apiSpecific.apiSessionCreate.in.dwStackSizeCommit = dwStackSizeCommit;
  495. portMessageIn.portMessage.u1.s1.DataLength = sizeof(API_THEMES);
  496. portMessageIn.portMessage.u1.s1.TotalLength = static_cast<CSHORT>(sizeof(THEMESAPI_PORT_MESSAGE));
  497. status = NtRequestWaitReplyPort(s_hPort,
  498. &portMessageIn.portMessage,
  499. &portMessageOut.portMessage);
  500. if (NT_SUCCESS(status))
  501. {
  502. status = portMessageOut.apiThemes.apiGeneric.status;
  503. }
  504. }
  505. else
  506. {
  507. status = CStatusCode::StatusCodeOfLastError();
  508. }
  509. }
  510. else
  511. {
  512. status = CStatusCode::StatusCodeOfLastError();
  513. }
  514. return(status);
  515. }
  516. // --------------------------------------------------------------------------
  517. // CThemeServerClient::SessionDestroy
  518. //
  519. // Arguments: <none>
  520. //
  521. // Returns: NTSTATUS
  522. //
  523. // Purpose: Signal the server that the current session is about to be
  524. // destroyed. This allows the server to release the data blob
  525. // allocated.
  526. //
  527. // History: 2000-11-11 vtan created
  528. // --------------------------------------------------------------------------
  529. NTSTATUS CThemeServerClient::SessionDestroy (void)
  530. {
  531. NTSTATUS status;
  532. THEMESAPI_PORT_MESSAGE portMessageIn, portMessageOut;
  533. CSingleThreadedExecution lock(*s_pLock);
  534. ZeroMemory(&portMessageIn, sizeof(portMessageIn));
  535. ZeroMemory(&portMessageOut, sizeof(portMessageOut));
  536. portMessageIn.apiThemes.apiGeneric.ulAPINumber = API_THEMES_SESSIONDESTROY;
  537. portMessageIn.portMessage.u1.s1.DataLength = sizeof(API_THEMES);
  538. portMessageIn.portMessage.u1.s1.TotalLength = static_cast<CSHORT>(sizeof(THEMESAPI_PORT_MESSAGE));
  539. status = NtRequestWaitReplyPort(s_hPort,
  540. &portMessageIn.portMessage,
  541. &portMessageOut.portMessage);
  542. if (NT_SUCCESS(status))
  543. {
  544. status = portMessageOut.apiThemes.apiGeneric.status;
  545. }
  546. if (s_hModuleUxTheme != NULL)
  547. {
  548. TBOOL(FreeLibrary(s_hModuleUxTheme));
  549. s_hModuleUxTheme = NULL;
  550. }
  551. return(status);
  552. }
  553. // --------------------------------------------------------------------------
  554. // CThemeServerClient::ReestablishConnection
  555. //
  556. // Arguments: <none>
  557. //
  558. // Returns: NTSTATUS
  559. //
  560. // Purpose: Reconnects to theme server. If the reconnection is established
  561. // the re-create the session data. This will not correct any
  562. // disconnected ports that some clients may have but because this
  563. // is called in winlogon it re-establish this correctly for
  564. // session 0 in all cases.
  565. //
  566. // UnregisterUserApiHook must be called to clear any left over
  567. // registrations from a server that died. Then go ahead and
  568. // re-initialize the environment anyway.
  569. //
  570. // History: 2000-11-17 vtan created
  571. // --------------------------------------------------------------------------
  572. NTSTATUS CThemeServerClient::ReestablishConnection (void)
  573. {
  574. NTSTATUS status;
  575. ReleaseHandle(s_hPort);
  576. status = s_pThemeManagerAPIServer->ConnectToServer(&s_hPort);
  577. if (NT_SUCCESS(status))
  578. {
  579. status = SessionCreate();
  580. if (NT_SUCCESS(status))
  581. {
  582. (BOOL)UnregisterUserApiHook();
  583. THR(ReestablishServerConnection());
  584. }
  585. }
  586. return(status);
  587. }
  588. // --------------------------------------------------------------------------
  589. // CThemeServerClient::CB_ServiceStart
  590. //
  591. // Arguments: pParameter = User parameter.
  592. // TimerOrWaitFired = Timer or wait fired.
  593. //
  594. // Returns: <none>
  595. //
  596. // Purpose: Callback called when the theme server ready event is signaled.
  597. // This indicates that the service was demand started or
  598. // restarted in the event of failure.
  599. //
  600. // History: 2000-11-29 vtan created
  601. // --------------------------------------------------------------------------
  602. void CALLBACK CThemeServerClient::CB_ServiceStart (void *pParameter, BOOLEAN TimerOrWaitFired)
  603. {
  604. UNREFERENCED_PARAMETER(pParameter);
  605. UNREFERENCED_PARAMETER(TimerOrWaitFired);
  606. NTSTATUS status;
  607. CSingleThreadedExecution lock(*s_pLock);
  608. // If there is a connection ping it.
  609. if (s_hPort != NULL)
  610. {
  611. THEMESAPI_PORT_MESSAGE portMessageIn, portMessageOut;
  612. ZeroMemory(&portMessageIn, sizeof(portMessageIn));
  613. ZeroMemory(&portMessageOut, sizeof(portMessageOut));
  614. portMessageIn.apiThemes.apiGeneric.ulAPINumber = API_THEMES_PING;
  615. portMessageIn.portMessage.u1.s1.DataLength = sizeof(API_THEMES);
  616. portMessageIn.portMessage.u1.s1.TotalLength = static_cast<CSHORT>(sizeof(THEMESAPI_PORT_MESSAGE));
  617. status = NtRequestWaitReplyPort(s_hPort,
  618. &portMessageIn.portMessage,
  619. &portMessageOut.portMessage);
  620. if (NT_SUCCESS(status))
  621. {
  622. status = portMessageOut.apiThemes.apiGeneric.status;
  623. }
  624. }
  625. else
  626. {
  627. status = STATUS_PORT_DISCONNECTED;
  628. }
  629. if (STATUS_PORT_DISCONNECTED == status)
  630. {
  631. HDESK hDeskCurrent, hDeskInput;
  632. // Set this thread's desktop to the input desktop so
  633. // that the theme change can be broadcast to the input
  634. // desktop. This is Default in most cases where a logged
  635. // on user is active but in the non-logged on user case
  636. // this will be Winlogon. Restore the thread's desktop
  637. // when done.
  638. TSTATUS(ReestablishConnection());
  639. hDeskCurrent = hDeskInput = NULL;
  640. if (s_hToken != NULL)
  641. {
  642. hDeskCurrent = GetThreadDesktop(GetCurrentThreadId());
  643. hDeskInput = OpenInputDesktop(0, FALSE, MAXIMUM_ALLOWED);
  644. if ((hDeskCurrent != NULL) && (hDeskInput != NULL))
  645. {
  646. TBOOL(SetThreadDesktop(hDeskInput));
  647. }
  648. if (NT_SUCCESS(CImpersonation::ImpersonateUser(GetCurrentThread(), s_hToken)))
  649. {
  650. TSTATUS(InformServerUserLogon(s_hToken));
  651. }
  652. if ((hDeskCurrent != NULL) && (hDeskInput != NULL))
  653. {
  654. SetThreadDesktop(hDeskCurrent);
  655. (BOOL)CloseDesktop(hDeskInput);
  656. }
  657. TBOOL(RevertToSelf());
  658. }
  659. else
  660. {
  661. THR(InitUserRegistry());
  662. THR(InitUserTheme(FALSE));
  663. }
  664. }
  665. // Reset the event here and now.
  666. TBOOL(ResetEvent(s_hEvent));
  667. // Unregister the original wait (it only executes once anyway). This
  668. // call will return a failure code with the callback in progress.
  669. // Ignore this error. The thread pool will clean up the wait.
  670. (BOOL)UnregisterWait(s_hWaitObject);
  671. // Reregister the wait as execute once only again waiting for
  672. // the next time the event is signaled.
  673. TBOOL(RegisterWaitForSingleObject(&s_hWaitObject,
  674. s_hEvent,
  675. CB_ServiceStart,
  676. NULL,
  677. INFINITE,
  678. WT_EXECUTEDEFAULT | WT_EXECUTEONLYONCE));
  679. }