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.

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