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.

891 lines
28 KiB

  1. // --------------------------------------------------------------------------
  2. // Module Name: ThemeServer.cpp
  3. //
  4. // Copyright (c) 2000, Microsoft Corporation
  5. //
  6. // Functions that implement server functionality. Functions in this file
  7. // cannot execute per instance win32k functions that are done on the client's
  8. // behalf. That work must be done on the client side.
  9. //
  10. // History: 2000-11-11 vtan created
  11. // --------------------------------------------------------------------------
  12. #include "stdafx.h"
  13. #include "ThemeServer.h"
  14. #include "uxthemeserver.h"
  15. #include <shfolder.h>
  16. #include "Loader.h"
  17. #include "Signing.h"
  18. #include "ThemeSection.h"
  19. #include "TmUtils.h"
  20. #include "sethook.h"
  21. #include "log.h"
  22. #include "services.h"
  23. #define TBOOL(x) ((BOOL)(x))
  24. #define TW32(x) ((DWORD)(x))
  25. #define THR(x) ((HRESULT)(x))
  26. #define TSTATUS(x) ((NTSTATUS)(x))
  27. #define goto !!DO NOT USE GOTO!! - DO NOT REMOVE THIS ON PAIN OF DEATH
  28. // --------------------------------------------------------------------------
  29. // CThemeServer::CThemeServer
  30. //
  31. // Arguments: hProcessRegisterHook = Process used to install hooks.
  32. // dwServerChangeNumber = Server change number.
  33. // pfnRegister = Address of install hook function.
  34. // pfnUnregister = Address of remove hook function.
  35. // pfnClearStockObjects = Address of function to remove stock objects from section
  36. //
  37. // Returns: <none>
  38. //
  39. // Purpose: Constructor for CThemeServer. Initializes member variables
  40. // with information relevant for the session. Keeps a handle to
  41. // the process that called this to use to inject threads in to
  42. // handle hook installation and removal.
  43. //
  44. // History: 2000-11-11 vtan created
  45. // --------------------------------------------------------------------------
  46. CThemeServer::CThemeServer (HANDLE hProcessRegisterHook, DWORD dwServerChangeNumber, void *pfnRegister, void *pfnUnregister, void *pfnClearStockObjects, DWORD dwStackSizeReserve, DWORD dwStackSizeCommit) :
  47. _hProcessRegisterHook(NULL),
  48. _dwServerChangeNumber(dwServerChangeNumber),
  49. _pfnRegister(pfnRegister),
  50. _pfnUnregister(pfnUnregister),
  51. _pfnClearStockObjects(pfnClearStockObjects),
  52. _dwStackSizeReserve(dwStackSizeReserve),
  53. _dwStackSizeCommit(dwStackSizeCommit),
  54. _dwSessionID(NtCurrentPeb()->SessionId),
  55. _fHostHooksSet(false),
  56. _hSectionGlobalTheme(NULL),
  57. _dwClientChangeNumber(0)
  58. {
  59. ULONG ulReturnLength;
  60. PROCESS_SESSION_INFORMATION processSessionInformation;
  61. ZeroMemory(&_lock, sizeof(_lock));
  62. if( !InitializeCriticalSectionAndSpinCount(&_lock, 0) )
  63. {
  64. ASSERT(!VALID_CRITICALSECTION(&_lock));
  65. }
  66. TBOOL(DuplicateHandle(GetCurrentProcess(),
  67. hProcessRegisterHook,
  68. GetCurrentProcess(),
  69. &_hProcessRegisterHook,
  70. 0,
  71. FALSE,
  72. DUPLICATE_SAME_ACCESS));
  73. if (NT_SUCCESS(NtQueryInformationProcess(hProcessRegisterHook,
  74. ProcessSessionInformation,
  75. &processSessionInformation,
  76. sizeof(processSessionInformation),
  77. &ulReturnLength)))
  78. {
  79. _dwSessionID = processSessionInformation.SessionId;
  80. }
  81. }
  82. // --------------------------------------------------------------------------
  83. // CThemeServer::~CThemeServer
  84. //
  85. // Arguments: <none>
  86. //
  87. // Returns: <none>
  88. //
  89. // Purpose: Destructor for CThemeServer. Releases resources used.
  90. //
  91. // History: 2000-11-11 vtan created
  92. // --------------------------------------------------------------------------
  93. CThemeServer::~CThemeServer (void)
  94. {
  95. //---- important: turn off hooks so everyone gets unthemed ----
  96. if (!GetSystemMetrics(SM_SHUTTINGDOWN)) // Don't do this on shutdown to keep winlogon themed
  97. {
  98. ThemeHooksOff();
  99. }
  100. //---- mark global theme invalid & release it ----
  101. if (_hSectionGlobalTheme != NULL)
  102. {
  103. SetGlobalTheme(NULL);
  104. }
  105. if (_hProcessRegisterHook != NULL)
  106. {
  107. TBOOL(CloseHandle(_hProcessRegisterHook));
  108. _hProcessRegisterHook = NULL;
  109. }
  110. SAFE_DELETECRITICALSECTION(&_lock);
  111. }
  112. // --------------------------------------------------------------------------
  113. // CThemeServer::ThemeHooksOn
  114. //
  115. // Arguments: <none>
  116. //
  117. // Returns: HRESULT
  118. //
  119. // Purpose: Install theme hooks via the session controlling process.
  120. //
  121. // History: 2000-11-11 vtan created
  122. // --------------------------------------------------------------------------
  123. HRESULT CThemeServer::ThemeHooksOn (void)
  124. {
  125. HRESULT hr;
  126. LockAcquire();
  127. if (!_fHostHooksSet)
  128. {
  129. if (ClassicGetSystemMetrics(SM_CLEANBOOT) == 0)
  130. {
  131. if (_hProcessRegisterHook != NULL)
  132. {
  133. hr = InjectClientSessionThread(_hProcessRegisterHook, FunctionRegisterUserApiHook, NULL);
  134. _fHostHooksSet = SUCCEEDED(hr);
  135. }
  136. else
  137. {
  138. hr = MakeError32(ERROR_SERVICE_REQUEST_TIMEOUT);
  139. }
  140. }
  141. else
  142. {
  143. hr = MakeError32(ERROR_BAD_ENVIRONMENT); // themes not allowed in safe mode
  144. }
  145. }
  146. else
  147. {
  148. hr = S_OK;
  149. }
  150. LockRelease();
  151. return(hr);
  152. }
  153. // --------------------------------------------------------------------------
  154. // CThemeServer::ThemeHooksOff
  155. //
  156. // Arguments: <none>
  157. //
  158. // Returns: HRESULT
  159. //
  160. // Purpose: Remove theme hooks via the session controlling process.
  161. //
  162. // History: 2000-11-11 vtan created
  163. // --------------------------------------------------------------------------
  164. HRESULT CThemeServer::ThemeHooksOff (void)
  165. {
  166. LockAcquire();
  167. if (_fHostHooksSet)
  168. {
  169. _fHostHooksSet = false;
  170. if (_hProcessRegisterHook != NULL)
  171. {
  172. THR(InjectClientSessionThread(_hProcessRegisterHook, FunctionUnregisterUserApiHook, NULL));
  173. }
  174. }
  175. LockRelease();
  176. return(S_OK);
  177. }
  178. // --------------------------------------------------------------------------
  179. // CThemeServer::AreThemeHooksActive
  180. //
  181. // Arguments: <none>
  182. //
  183. // Returns: bool
  184. //
  185. // Purpose: Returns whether theme hooks have been successfully installed.
  186. //
  187. // History: 2000-11-11 vtan created
  188. // --------------------------------------------------------------------------
  189. bool CThemeServer::AreThemeHooksActive (void)
  190. {
  191. bool fResult;
  192. LockAcquire();
  193. fResult = _fHostHooksSet;
  194. LockRelease();
  195. return(fResult);
  196. }
  197. // --------------------------------------------------------------------------
  198. // CThemeServer::GetCurrentChangeNumber
  199. //
  200. // Arguments: <none>
  201. //
  202. // Returns: int
  203. //
  204. // Purpose: Returns the current change number.
  205. //
  206. // History: 2000-11-11 vtan created
  207. // --------------------------------------------------------------------------
  208. int CThemeServer::GetCurrentChangeNumber (void)
  209. {
  210. int iCurrentChangeNumber;
  211. LockAcquire();
  212. iCurrentChangeNumber = static_cast<int>((_dwServerChangeNumber << 16) | _dwClientChangeNumber);
  213. LockRelease();
  214. Log(LOG_TMCHANGE, L"GetCurrentChangeNumber: server: %d, client: %d, change: 0x%x",
  215. _dwServerChangeNumber, _dwClientChangeNumber, iCurrentChangeNumber);
  216. return(iCurrentChangeNumber);
  217. }
  218. // --------------------------------------------------------------------------
  219. // CThemeServer::GetNewChangeNumber
  220. //
  221. // Arguments: <none>
  222. //
  223. // Returns: int
  224. //
  225. // Purpose: Returns a new change number.
  226. //
  227. // History: 2000-11-11 vtan created
  228. // --------------------------------------------------------------------------
  229. int CThemeServer::GetNewChangeNumber (void)
  230. {
  231. int iCurrentChangeNumber;
  232. LockAcquire();
  233. _dwClientChangeNumber = static_cast<WORD>(_dwClientChangeNumber + 1);
  234. iCurrentChangeNumber = static_cast<int>((_dwServerChangeNumber << 16) | _dwClientChangeNumber);
  235. Log(LOG_TMLOAD, L"GetNewChangeNumber: server: %d, client: %d, change: 0x%x",
  236. _dwServerChangeNumber, _dwClientChangeNumber, iCurrentChangeNumber);
  237. LockRelease();
  238. return(iCurrentChangeNumber);
  239. }
  240. // --------------------------------------------------------------------------
  241. // CThemeServer::SetGlobalTheme
  242. //
  243. // Arguments: hSection = Handle to section of new theme.
  244. //
  245. // Returns: HRESULT
  246. //
  247. // Purpose: Invalidates the old section and closes the handle to it.
  248. // Validates the new section and if valid sets it as the global
  249. // theme.
  250. //
  251. // History: 2000-11-11 vtan created
  252. // --------------------------------------------------------------------------
  253. HRESULT CThemeServer::SetGlobalTheme (HANDLE hSection)
  254. {
  255. HRESULT hr;
  256. LockAcquire();
  257. if (_hSectionGlobalTheme != NULL)
  258. {
  259. void *pV;
  260. HANDLE hSemaphore = NULL;
  261. // Before closing the section invalidate it.
  262. pV = MapViewOfFile(_hSectionGlobalTheme,
  263. FILE_MAP_WRITE,
  264. 0,
  265. 0,
  266. 0);
  267. #ifdef DEBUG
  268. if (LogOptionOn(LO_TMLOAD))
  269. {
  270. // Unexpected failure
  271. ASSERT(pV != NULL);
  272. }
  273. #endif
  274. if (pV != NULL)
  275. {
  276. // Create a semaphore so that no client will try to clean it before us, which would result in a double free
  277. // (as soon as we clear SECTION_GLOBAL, various CUxThemeFile destructors can call ClearStockObjects)
  278. WCHAR szName[64];
  279. StringCchPrintfW(szName, ARRAYSIZE(szName), L"Global\\ClearStockGlobal%d-%d", reinterpret_cast<THEMEHDR*>(pV)->iLoadId, _dwSessionID);
  280. hSemaphore = CreateSemaphore(NULL, 0, 1, szName);
  281. Log(LOG_TMLOAD, L"SetGlobalTheme clearing section %d, semaphore=%s, hSemaphore=%X, gle=%d", reinterpret_cast<THEMEHDR*>(pV)->iLoadId, szName, hSemaphore, GetLastError());
  282. reinterpret_cast<THEMEHDR*>(pV)->dwFlags &= ~(SECTION_READY | SECTION_GLOBAL);
  283. }
  284. HANDLE hSectionForInjection = NULL;
  285. //---- create a handle for CLIENT process to use to clear stock bitmaps ----
  286. if (DuplicateHandle(GetCurrentProcess(),
  287. _hSectionGlobalTheme,
  288. _hProcessRegisterHook,
  289. &hSectionForInjection,
  290. FILE_MAP_READ,
  291. FALSE,
  292. 0) != FALSE)
  293. {
  294. // This will close the handle
  295. THR(InjectClientSessionThread(_hProcessRegisterHook, FunctionClearStockObjects, hSectionForInjection));
  296. }
  297. if (pV != NULL)
  298. {
  299. reinterpret_cast<THEMEHDR*>(pV)->dwFlags &= ~SECTION_HASSTOCKOBJECTS;
  300. if (hSemaphore != NULL)
  301. {
  302. CloseHandle(hSemaphore);
  303. }
  304. TBOOL(UnmapViewOfFile(pV));
  305. }
  306. TBOOL(CloseHandle(_hSectionGlobalTheme));
  307. _hSectionGlobalTheme = NULL;
  308. }
  309. if (hSection != NULL)
  310. {
  311. CThemeSection themeSection;
  312. hr = themeSection.Open(hSection);
  313. if (SUCCEEDED(hr))
  314. {
  315. hr = themeSection.ValidateData(true);
  316. }
  317. if (SUCCEEDED(hr))
  318. {
  319. if (DuplicateHandle(GetCurrentProcess(),
  320. hSection,
  321. GetCurrentProcess(),
  322. &_hSectionGlobalTheme,
  323. FILE_MAP_ALL_ACCESS,
  324. FALSE,
  325. 0) != FALSE)
  326. {
  327. hr = S_OK;
  328. }
  329. else
  330. {
  331. hr = MakeErrorLast();
  332. }
  333. }
  334. }
  335. else
  336. {
  337. hr = S_OK;
  338. }
  339. if (SUCCEEDED(hr))
  340. {
  341. //---- bump the change number at the same time so everything is in sync. ----
  342. int iChangeNum = GetNewChangeNumber();
  343. if (_hSectionGlobalTheme)
  344. {
  345. //---- put changenum into theme hdr to help client keep things straight ----
  346. VOID *pv = MapViewOfFile(_hSectionGlobalTheme,
  347. FILE_MAP_WRITE,
  348. 0,
  349. 0,
  350. 0);
  351. if (pv != NULL)
  352. {
  353. reinterpret_cast<THEMEHDR*>(pv)->dwFlags |= SECTION_GLOBAL;
  354. reinterpret_cast<THEMEHDR*>(pv)->iLoadId = iChangeNum;
  355. Log(LOG_TMLOAD, L"SetGlobalTheme: new section is %d", reinterpret_cast<THEMEHDR*>(pv)->iLoadId);
  356. TBOOL(UnmapViewOfFile(pv));
  357. }
  358. }
  359. }
  360. LockRelease();
  361. return(hr);
  362. }
  363. // --------------------------------------------------------------------------
  364. // CThemeServer::GetGlobalTheme
  365. //
  366. // Arguments: phSection = Handle to the section received.
  367. //
  368. // Returns: HRESULT
  369. //
  370. // Purpose: Duplicates the section back to the caller.
  371. //
  372. // History: 2000-11-11 vtan created
  373. // --------------------------------------------------------------------------
  374. HRESULT CThemeServer::GetGlobalTheme (HANDLE *phSection)
  375. {
  376. HRESULT hr;
  377. LockAcquire();
  378. *phSection = NULL;
  379. if (_hSectionGlobalTheme != NULL)
  380. {
  381. if (DuplicateHandle(GetCurrentProcess(),
  382. _hSectionGlobalTheme,
  383. GetCurrentProcess(),
  384. phSection,
  385. 0,
  386. FALSE,
  387. DUPLICATE_SAME_ACCESS) != FALSE)
  388. {
  389. hr = S_OK;
  390. }
  391. else
  392. {
  393. hr = MakeErrorLast();
  394. }
  395. }
  396. else
  397. {
  398. hr = S_OK;
  399. }
  400. LockRelease();
  401. return(hr);
  402. }
  403. // --------------------------------------------------------------------------
  404. // CThemeServer::LoadTheme
  405. //
  406. // Arguments: hSection = Section created by the client.
  407. // phSection = Section created by the server returned.
  408. // pszName = Theme name.
  409. // pszColor = Theme size.
  410. // pszSize = Theme color.
  411. // fOwnStockObjects = TRUE to clear the stock objects bit on the
  412. // incoming section, on success, thereby taking
  413. // full responsibility for SO cleanup.
  414. //
  415. // Returns: HRESULT
  416. //
  417. // Purpose: Creates a new section in the server context based on the
  418. // section from the client. The contents are transferred across.
  419. // The section contents are also strictly verified.
  420. //
  421. // History: 2000-11-11 vtan created
  422. // 2002-03-21 scotthan Update incoming section header to
  423. // indicate change of ownership.
  424. // --------------------------------------------------------------------------
  425. HRESULT CThemeServer::LoadTheme (
  426. HANDLE hSection,
  427. HANDLE *phSection,
  428. LPCWSTR pszName,
  429. LPCWSTR pszColor,
  430. LPCWSTR pszSize,
  431. OPTIONAL DWORD dwFlags)
  432. {
  433. HRESULT hr;
  434. hr = CheckThemeSignature(pszName); // Check this is signed
  435. if (SUCCEEDED(hr))
  436. {
  437. CThemeSection themeSectionIn;
  438. if (SUCCEEDED(themeSectionIn.Open(hSection, FILE_MAP_READ|FILE_MAP_WRITE)))
  439. {
  440. if (ThemeMatch(themeSectionIn, pszName, pszColor, pszSize, 0) != FALSE)
  441. {
  442. hr = themeSectionIn.ValidateData(true);
  443. if (SUCCEEDED(hr))
  444. {
  445. CThemeSection themeSectionOut;
  446. // Only privileged clients can create a section with GDI stock objects
  447. if( 0 == (((THEMEHDR*)themeSectionIn.GetData())->dwFlags & SECTION_HASSTOCKOBJECTS) ||
  448. 0 != (dwFlags & LTF_GLOBALPRIVILEGEDCLIENT) )
  449. {
  450. // Note: we come here impersonating the user, we need for ThemeMatch.
  451. // However the theme section must be created in the system context, so that only
  452. // the system context has write access to it. We revert to self here based on the
  453. // knowledge that nothing after this call needs to be done in the user context.
  454. RevertToSelf();
  455. // make sure that we're TCB svchost. Nobody else should be able to do this in-proc.
  456. if( !TokenHasPrivilege( NULL, SE_TCB_PRIVILEGE ) )
  457. {
  458. hr = E_ACCESSDENIED;
  459. }
  460. else
  461. {
  462. hr = themeSectionOut.CreateFromSection(hSection);
  463. if (SUCCEEDED(hr))
  464. {
  465. *phSection = themeSectionOut.Get(); // We now own the handle
  466. if( (dwFlags & LTF_TRANSFERSTOCKOBJOWNERSHIP) != 0 )
  467. {
  468. // We're transfering ownership of stock bitmaps, if any, to the output (read-only)
  469. // section; this simply means removing the SECTION_HASSTOCKOBJECTS bit from the
  470. // incoming section so that the client doesn't attempt to clear them.
  471. ((THEMEHDR*)themeSectionIn.GetData())->dwFlags &= ~SECTION_HASSTOCKOBJECTS;
  472. }
  473. }
  474. }
  475. }
  476. else
  477. {
  478. hr = E_ACCESSDENIED;
  479. }
  480. }
  481. }
  482. else
  483. {
  484. hr = E_ACCESSDENIED;
  485. }
  486. }
  487. }
  488. return(hr);
  489. }
  490. // --------------------------------------------------------------------------
  491. // CThemeServer::IsSystemProcessContext
  492. //
  493. // Arguments: <none>
  494. //
  495. // Returns: bool
  496. //
  497. // Purpose: Is the current process executing in the SYSTEM context?
  498. //
  499. // History: 2000-11-11 vtan created
  500. // --------------------------------------------------------------------------
  501. bool CThemeServer::IsSystemProcessContext (void)
  502. {
  503. bool fResult;
  504. HANDLE hToken;
  505. fResult = false;
  506. if (OpenProcessToken(GetCurrentProcess(),
  507. TOKEN_QUERY,
  508. &hToken) != FALSE)
  509. {
  510. static const LUID sLUIDSystem = SYSTEM_LUID;
  511. ULONG ulReturnLength;
  512. TOKEN_STATISTICS tokenStatistics;
  513. fResult = ((GetTokenInformation(hToken,
  514. TokenStatistics,
  515. &tokenStatistics,
  516. sizeof(tokenStatistics),
  517. &ulReturnLength) != FALSE) &&
  518. RtlEqualLuid(&tokenStatistics.AuthenticationId, &sLUIDSystem));
  519. TBOOL(CloseHandle(hToken));
  520. }
  521. return(fResult);
  522. }
  523. // --------------------------------------------------------------------------
  524. // CThemeServer::ThemeHooksInstall
  525. //
  526. // Arguments: <none>
  527. //
  528. // Returns: DWORD
  529. //
  530. // Purpose: Thread entry point for injected thread running in session
  531. // creating process' context to call user32!RegisterUserApiHook.
  532. //
  533. // History: 2000-11-11 vtan created
  534. // --------------------------------------------------------------------------
  535. DWORD CThemeServer::ThemeHooksInstall (void)
  536. {
  537. DWORD dwErrorCode;
  538. if (IsSystemProcessContext())
  539. {
  540. INITUSERAPIHOOK pfnInitUserApiHook = ThemeInitApiHook;
  541. if (RegisterUserApiHook(g_hInst, pfnInitUserApiHook) != FALSE)
  542. {
  543. dwErrorCode = ERROR_SUCCESS;
  544. }
  545. else
  546. {
  547. dwErrorCode = GetLastError();
  548. }
  549. }
  550. else
  551. {
  552. dwErrorCode = ERROR_ACCESS_DENIED;
  553. }
  554. return(dwErrorCode);
  555. }
  556. // --------------------------------------------------------------------------
  557. // CThemeServer::ThemeHooksRemove
  558. //
  559. // Arguments: <none>
  560. //
  561. // Returns: DWORD
  562. //
  563. // Purpose: Thread entry point for injected thread running in session
  564. // creating process' context to call
  565. // user32!UnregisterUserApiHook.
  566. //
  567. // History: 2000-11-11 vtan created
  568. // --------------------------------------------------------------------------
  569. DWORD CThemeServer::ThemeHooksRemove (void)
  570. {
  571. DWORD dwErrorCode;
  572. if (IsSystemProcessContext())
  573. {
  574. if (UnregisterUserApiHook() != FALSE)
  575. {
  576. dwErrorCode = ERROR_SUCCESS;
  577. Log(LOG_TMLOAD, L"UnregisterUserApiHook() called");
  578. }
  579. else
  580. {
  581. dwErrorCode = GetLastError();
  582. }
  583. }
  584. else
  585. {
  586. dwErrorCode = ERROR_ACCESS_DENIED;
  587. }
  588. return(dwErrorCode);
  589. }
  590. // --------------------------------------------------------------------------
  591. // CThemeServer::ClearStockObjects
  592. //
  593. // Arguments: HANDLE hSection
  594. //
  595. // Returns: DWORD
  596. //
  597. // Purpose: Thread entry point for injected thread running in session
  598. // creating process' context to clear stock objects in theme
  599. // section.
  600. //
  601. //
  602. // History: 2001-05-01 rfernand created
  603. // --------------------------------------------------------------------------
  604. DWORD CThemeServer::ClearStockObjects (HANDLE hSection)
  605. {
  606. DWORD dwErrorCode = ERROR_SUCCESS;
  607. if (IsSystemProcessContext())
  608. {
  609. if (hSection)
  610. {
  611. //---- Clearing the stock bitmaps in the section ----
  612. //---- is OK here since we are running in the context ----
  613. //---- of the current USER session ----
  614. HRESULT hr = ClearTheme(hSection, TRUE);
  615. if (FAILED(hr))
  616. {
  617. Log(LOG_ALWAYS, L"ClearTheme() failed, hr=0x%x", hr);
  618. hr = S_OK; // not a fatal error
  619. }
  620. }
  621. }
  622. else
  623. {
  624. dwErrorCode = ERROR_ACCESS_DENIED;
  625. }
  626. return(dwErrorCode);
  627. }
  628. // --------------------------------------------------------------------------
  629. // CThemeServer::LockAcquire
  630. //
  631. // Arguments: <none>
  632. //
  633. // Returns: <none>
  634. //
  635. // Purpose: Acquires the object critical section.
  636. //
  637. // History: 2000-11-11 vtan created
  638. // --------------------------------------------------------------------------
  639. void CThemeServer::LockAcquire (void)
  640. {
  641. SAFE_ENTERCRITICALSECTION(&_lock);
  642. }
  643. // --------------------------------------------------------------------------
  644. // CThemeServer::LockRelease
  645. //
  646. // Arguments: <none>
  647. //
  648. // Returns: <none>
  649. //
  650. // Purpose: Releases the object critical section.
  651. //
  652. // History: 2000-11-11 vtan created
  653. // --------------------------------------------------------------------------
  654. void CThemeServer::LockRelease (void)
  655. {
  656. SAFE_LEAVECRITICALSECTION(&_lock);
  657. }
  658. // --------------------------------------------------------------------------
  659. // CThemeServer::InjectStockObjectCleanupThread
  660. //
  661. // Arguments: hSection = Handle of section to clean/clear
  662. //
  663. // Returns: HRESULT
  664. //
  665. // Purpose: Permits server to inject a thread into the process
  666. // in which stock object handles can be released.
  667. //
  668. // History: 2002-03-11 scotthan created
  669. // --------------------------------------------------------------------------
  670. HRESULT CThemeServer::InjectStockObjectCleanupThread(HANDLE hSection)
  671. {
  672. HANDLE hSectionClean;
  673. //---- create a handle for target process to use to clear stock bitmaps ----
  674. if (!DuplicateHandle(GetCurrentProcess(),
  675. hSection,
  676. _hProcessRegisterHook,
  677. &hSectionClean,
  678. FILE_MAP_READ,
  679. FALSE,
  680. 0))
  681. {
  682. return MakeErrorLast();
  683. }
  684. // This will close the duplicate we just created, but not the inbound handle
  685. BOOL fThreadCreated;
  686. HRESULT hr = InjectClientSessionThread(_hProcessRegisterHook, FunctionClearStockObjects, hSectionClean,
  687. &fThreadCreated);
  688. if( !fThreadCreated )
  689. {
  690. CloseHandle(hSectionClean);
  691. }
  692. return hr;
  693. }
  694. // --------------------------------------------------------------------------
  695. // CThemeServer::InjectClientSessionThread
  696. //
  697. // Arguments: hProcess = Handle to process to inject thread in.
  698. // iIndexFunction = Function to call on injected thread.
  699. // pvParam = Ptr to param for entry function
  700. //
  701. // Returns: HRESULT
  702. //
  703. // Purpose: Create a user mode thread in the remote process (possibly
  704. // across sessions) and execute the entry point specified at
  705. // object construction which is valid in the remote process
  706. // context. Wait for the thread to finish. It will signal its
  707. // success of failure in the exit code.
  708. //
  709. // History: 2000-11-11 vtan created
  710. // 2001-05-18 vtan generic function index
  711. // --------------------------------------------------------------------------
  712. HRESULT CThemeServer::InjectClientSessionThread (
  713. HANDLE hProcess, int iIndexFunction, void *pvParam,
  714. OUT OPTIONAL BOOL* pfThreadCreated )
  715. {
  716. HRESULT hr;
  717. PUSER_THREAD_START_ROUTINE pfnThreadStart;
  718. if( pfThreadCreated )
  719. *pfThreadCreated = FALSE;
  720. switch (iIndexFunction)
  721. {
  722. case FunctionRegisterUserApiHook:
  723. pfnThreadStart = reinterpret_cast<PUSER_THREAD_START_ROUTINE>(_pfnRegister);
  724. break;
  725. case FunctionUnregisterUserApiHook:
  726. pfnThreadStart = reinterpret_cast<PUSER_THREAD_START_ROUTINE>(_pfnUnregister);
  727. break;
  728. case FunctionClearStockObjects:
  729. pfnThreadStart = reinterpret_cast<PUSER_THREAD_START_ROUTINE>(_pfnClearStockObjects);
  730. break;
  731. default:
  732. pfnThreadStart = NULL;
  733. break;
  734. }
  735. if (pfnThreadStart != NULL)
  736. {
  737. NTSTATUS status;
  738. HANDLE hThread;
  739. status = RtlCreateUserThread(hProcess,
  740. NULL,
  741. FALSE,
  742. 0,
  743. _dwStackSizeReserve,
  744. _dwStackSizeCommit,
  745. pfnThreadStart,
  746. pvParam,
  747. &hThread,
  748. NULL);
  749. if (NT_SUCCESS(status))
  750. {
  751. DWORD dwWaitResult, dwExitCode;
  752. if( pfThreadCreated )
  753. *pfThreadCreated = TRUE;
  754. dwWaitResult = WaitForSingleObject(hThread, INFINITE);
  755. if (GetExitCodeThread(hThread, &dwExitCode) != FALSE)
  756. {
  757. hr = HRESULT_FROM_WIN32(dwExitCode);
  758. }
  759. else
  760. {
  761. hr = E_FAIL;
  762. }
  763. TBOOL(CloseHandle(hThread));
  764. }
  765. else
  766. {
  767. hr = HRESULT_FROM_NT(status);
  768. }
  769. }
  770. else
  771. {
  772. hr = E_FAIL;
  773. }
  774. return(hr);
  775. }