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.

2181 lines
76 KiB

  1. // --------------------------------------------------------------------------
  2. // Module Name: Services.cpp
  3. //
  4. // Copyright (c) 2000, Microsoft Corporation
  5. //
  6. // APIs to communicate with the theme service running in the winlogon
  7. // process context.
  8. //
  9. // History: 2000-08-10 vtan created
  10. // 2000-10-11 vtan rewrite for LPC
  11. // --------------------------------------------------------------------------
  12. #include "stdafx.h"
  13. #include "Services.h"
  14. #include <uxthemep.h>
  15. #include <LPCThemes.h>
  16. #include "errors.h"
  17. #include "info.h"
  18. #include "MessageBroadcast.h"
  19. #include "stringtable.h"
  20. #include "themefile.h"
  21. #include "ThemeSection.h"
  22. #include "ThemeServer.h"
  23. #include "tmreg.h"
  24. #include "tmutils.h"
  25. #include <regstr.h> // REGSTR_PATH_POLICIES
  26. // Will statically link to this later (needs gdi32p.lib)
  27. static HBRUSH (*s_pfnClearBrushAttributes)(HBRUSH, DWORD) = NULL;
  28. #ifdef DEBUG
  29. // TODO: Isn't symchronized anymore (different processes), need to use a volatile reg key instead
  30. extern DWORD g_dwStockSize;
  31. #endif
  32. #define TBOOL(x) ((BOOL)(x))
  33. #define TW32(x) ((DWORD)(x))
  34. #define THR(x) ((HRESULT)(x))
  35. #define TSTATUS(x) ((NTSTATUS)(x))
  36. #undef ASSERTMSG
  37. #define ASSERTMSG(x, y)
  38. #define goto !!DO NOT USE GOTO!! - DO NOT REMOVE THIS ON PAIN OF DEATH
  39. // --------------------------------------------------------------------------
  40. // CThemeServices::s_hAPIPort
  41. //
  42. // Purpose: Static member variables for CThemeServices.
  43. //
  44. // NOTE: The critical section provides a lock for s_hAPIPort.
  45. // It's not acquired consistently because most of the API calls
  46. // would block trying to acquire the lock while another API call
  47. // is holding the lock across a request. The handle could be
  48. // copied to a local variable but this would defeat the purpose
  49. // of the lock. So the lock isn't used. It's possible for the
  50. // handle to become invalid. If so the request will just fail.
  51. //
  52. // History: 2000-11-09 vtan created
  53. // --------------------------------------------------------------------------
  54. CRITICAL_SECTION CThemeServices::s_lock;
  55. HANDLE CThemeServices::s_hAPIPort = INVALID_HANDLE_VALUE;
  56. // --------------------------------------------------------------------------
  57. // CThemeServices::StaticInitialize
  58. //
  59. // Arguments: <none>
  60. //
  61. // Returns: <none>
  62. //
  63. // Purpose: Initialize static member variables.
  64. //
  65. // History: 2000-10-11 vtan created
  66. // 2000-11-09 vtan make static
  67. // --------------------------------------------------------------------------
  68. void CThemeServices::StaticInitialize (void)
  69. {
  70. (NTSTATUS)RtlInitializeCriticalSection(&s_lock);
  71. }
  72. // --------------------------------------------------------------------------
  73. // CThemeServices::~CThemeServices
  74. //
  75. // Arguments: <none>
  76. //
  77. // Returns: <none>
  78. //
  79. // Purpose: Release static resources used by CThemeServices.
  80. //
  81. // History: 2000-10-11 vtan created
  82. // 2000-11-09 vtan make static
  83. // --------------------------------------------------------------------------
  84. void CThemeServices::StaticTerminate (void)
  85. {
  86. ReleaseConnection();
  87. (NTSTATUS)RtlDeleteCriticalSection(&s_lock);
  88. }
  89. // --------------------------------------------------------------------------
  90. // CThemeServices::ThemeHooksOn
  91. //
  92. // Arguments: <none>
  93. //
  94. // Returns: HRESULT
  95. //
  96. // Purpose: Ask the server what the hook DLL HMODULE and
  97. // pfnInitUserApiHook is and call user32!RegisterUserApiHook on
  98. // the client side. This is done because it's specific to the
  99. // session on which the client runs.
  100. //
  101. // History: 2000-11-09 vtan created
  102. // --------------------------------------------------------------------------
  103. HRESULT CThemeServices::ThemeHooksOn (HWND hwndTarget)
  104. {
  105. HRESULT hr = MakeError32(ERROR_SERVICE_REQUEST_TIMEOUT);
  106. if (ConnectedToService())
  107. {
  108. NTSTATUS status;
  109. THEMESAPI_PORT_MESSAGE portMessageIn, portMessageOut;
  110. ZeroMemory(&portMessageIn, sizeof(portMessageIn));
  111. ZeroMemory(&portMessageOut, sizeof(portMessageOut));
  112. portMessageIn.apiThemes.apiGeneric.ulAPINumber = API_THEMES_THEMEHOOKSON;
  113. portMessageIn.portMessage.u1.s1.DataLength = sizeof(API_THEMES);
  114. portMessageIn.portMessage.u1.s1.TotalLength = static_cast<CSHORT>(sizeof(THEMESAPI_PORT_MESSAGE));
  115. status = NtRequestWaitReplyPort(s_hAPIPort,
  116. &portMessageIn.portMessage,
  117. &portMessageOut.portMessage);
  118. CheckForDisconnectedPort(status);
  119. if (NT_SUCCESS(status))
  120. {
  121. status = portMessageOut.apiThemes.apiGeneric.status;
  122. if (NT_SUCCESS(status))
  123. {
  124. hr = portMessageOut.apiThemes.apiSpecific.apiThemeHooksOn.out.hr;
  125. }
  126. }
  127. if (!NT_SUCCESS(status))
  128. {
  129. hr = HRESULT_FROM_NT(status);
  130. }
  131. //---- send the WM_UAHINIT msg to engage hooking now ----
  132. if (SUCCEEDED(hr))
  133. {
  134. if (hwndTarget)
  135. {
  136. (LRESULT)SendMessage(hwndTarget, WM_UAHINIT, 0, 0);
  137. }
  138. else
  139. {
  140. CMessageBroadcast messageBroadcast;
  141. messageBroadcast.PostAllThreadsMsg(WM_UAHINIT, 0, 0);
  142. //Log(LOG_TMCHANGEMSG, L"Just sent WM_UAHINIT, hwndTarget=0x%x", hwndTarget);
  143. }
  144. }
  145. Log(LOG_TMCHANGE, L"ThemeHooksOn called, hr=0x%x", hr);
  146. }
  147. return hr;
  148. }
  149. // --------------------------------------------------------------------------
  150. // CThemeServices::ThemeHooksOff
  151. //
  152. // Arguments: <none>
  153. //
  154. // Returns: HRESULT
  155. //
  156. // Purpose: Tell the server that this session is unregistering hooks.
  157. // Call user32!UnregisterUserApiHook either way.
  158. //
  159. // History: 2000-11-09 vtan created
  160. // --------------------------------------------------------------------------
  161. HRESULT CThemeServices::ThemeHooksOff (void)
  162. {
  163. HRESULT hr;
  164. hr = MakeError32(ERROR_SERVICE_REQUEST_TIMEOUT);
  165. if (ConnectedToService())
  166. {
  167. NTSTATUS status;
  168. THEMESAPI_PORT_MESSAGE portMessageIn, portMessageOut;
  169. ZeroMemory(&portMessageIn, sizeof(portMessageIn));
  170. ZeroMemory(&portMessageOut, sizeof(portMessageOut));
  171. portMessageIn.apiThemes.apiGeneric.ulAPINumber = API_THEMES_THEMEHOOKSOFF;
  172. portMessageIn.portMessage.u1.s1.DataLength = sizeof(API_THEMES);
  173. portMessageIn.portMessage.u1.s1.TotalLength = static_cast<CSHORT>(sizeof(THEMESAPI_PORT_MESSAGE));
  174. status = NtRequestWaitReplyPort(s_hAPIPort,
  175. &portMessageIn.portMessage,
  176. &portMessageOut.portMessage);
  177. CheckForDisconnectedPort(status);
  178. if (NT_SUCCESS(status))
  179. {
  180. status = portMessageOut.apiThemes.apiGeneric.status;
  181. if (NT_SUCCESS(status))
  182. {
  183. hr = portMessageOut.apiThemes.apiSpecific.apiThemeHooksOff.out.hr;
  184. }
  185. if (SUCCEEDED(hr))
  186. {
  187. //---- real unhooking happens on next window message in each process ----
  188. //---- so post a dummy msg to everyone to make it happen asap ----
  189. PostMessage(HWND_BROADCAST, WM_THEMECHANGED, WPARAM(-1), 0);
  190. Log(LOG_TMLOAD, L"Message to kick all window threads in session posted");
  191. }
  192. }
  193. if (!NT_SUCCESS(status))
  194. {
  195. hr = HRESULT_FROM_NT(status);
  196. }
  197. }
  198. return(hr);
  199. }
  200. // --------------------------------------------------------------------------
  201. // CThemeServices::GetStatusFlags
  202. //
  203. // Arguments: pdwFlags = Status flags returned from the theme services.
  204. //
  205. // Returns: HRESULT
  206. //
  207. // Purpose: Gets status flags from the theme services.
  208. //
  209. // History: 2000-08-10 vtan created
  210. // 2000-10-11 vtan rewrite for LPC
  211. // --------------------------------------------------------------------------
  212. HRESULT CThemeServices::GetStatusFlags (DWORD *pdwFlags)
  213. {
  214. HRESULT hr;
  215. hr = MakeError32(ERROR_SERVICE_REQUEST_TIMEOUT);
  216. if (ConnectedToService())
  217. {
  218. NTSTATUS status;
  219. THEMESAPI_PORT_MESSAGE portMessageIn, portMessageOut;
  220. ZeroMemory(&portMessageIn, sizeof(portMessageIn));
  221. ZeroMemory(&portMessageOut, sizeof(portMessageOut));
  222. portMessageIn.apiThemes.apiGeneric.ulAPINumber = API_THEMES_GETSTATUSFLAGS;
  223. portMessageIn.portMessage.u1.s1.DataLength = sizeof(API_THEMES);
  224. portMessageIn.portMessage.u1.s1.TotalLength = static_cast<CSHORT>(sizeof(THEMESAPI_PORT_MESSAGE));
  225. status = NtRequestWaitReplyPort(s_hAPIPort,
  226. &portMessageIn.portMessage,
  227. &portMessageOut.portMessage);
  228. CheckForDisconnectedPort(status);
  229. if (NT_SUCCESS(status))
  230. {
  231. status = portMessageOut.apiThemes.apiGeneric.status;
  232. if (NT_SUCCESS(status))
  233. {
  234. *pdwFlags = portMessageOut.apiThemes.apiSpecific.apiGetStatusFlags.out.dwFlags;
  235. hr = S_OK;
  236. }
  237. }
  238. if (!NT_SUCCESS(status))
  239. {
  240. hr = HRESULT_FROM_NT(status);
  241. }
  242. }
  243. return(hr);
  244. }
  245. // --------------------------------------------------------------------------
  246. // CThemeServices::GetCurrentChangeNumber
  247. //
  248. // Arguments: piValue = Current change number returned to caller.
  249. //
  250. // Returns: HRESULT
  251. //
  252. // Purpose: Gets the current change number of the theme services.
  253. //
  254. // History: 2000-08-10 vtan created
  255. // 2000-10-11 vtan rewrite for LPC
  256. // --------------------------------------------------------------------------
  257. HRESULT CThemeServices::GetCurrentChangeNumber (int *piValue)
  258. {
  259. HRESULT hr;
  260. hr = MakeError32(ERROR_SERVICE_REQUEST_TIMEOUT);
  261. if (ConnectedToService())
  262. {
  263. NTSTATUS status;
  264. THEMESAPI_PORT_MESSAGE portMessageIn, portMessageOut;
  265. ZeroMemory(&portMessageIn, sizeof(portMessageIn));
  266. ZeroMemory(&portMessageOut, sizeof(portMessageOut));
  267. portMessageIn.apiThemes.apiGeneric.ulAPINumber = API_THEMES_GETCURRENTCHANGENUMBER;
  268. portMessageIn.portMessage.u1.s1.DataLength = sizeof(API_THEMES);
  269. portMessageIn.portMessage.u1.s1.TotalLength = static_cast<CSHORT>(sizeof(THEMESAPI_PORT_MESSAGE));
  270. status = NtRequestWaitReplyPort(s_hAPIPort,
  271. &portMessageIn.portMessage,
  272. &portMessageOut.portMessage);
  273. CheckForDisconnectedPort(status);
  274. if (NT_SUCCESS(status))
  275. {
  276. status = portMessageOut.apiThemes.apiGeneric.status;
  277. if (NT_SUCCESS(status))
  278. {
  279. *piValue = portMessageOut.apiThemes.apiSpecific.apiGetCurrentChangeNumber.out.iChangeNumber;
  280. hr = S_OK;
  281. }
  282. Log(LOG_TMLOAD, L"*** GetCurrentChangeNumber: num=%d, hr=0x%x", *piValue, hr);
  283. }
  284. if (!NT_SUCCESS(status))
  285. {
  286. hr = HRESULT_FROM_NT(status);
  287. }
  288. }
  289. return(hr);
  290. }
  291. // --------------------------------------------------------------------------
  292. // CThemeServices::GetNewChangeNumber
  293. //
  294. // Arguments: piValue = New change number returned to caller.
  295. //
  296. // Returns: HRESULT
  297. //
  298. // Purpose: Gets a new change number from the theme services.
  299. //
  300. // History: 2000-08-10 vtan created
  301. // 2000-10-11 vtan rewrite for LPC
  302. // --------------------------------------------------------------------------
  303. HRESULT CThemeServices::GetNewChangeNumber (int *piValue)
  304. {
  305. HRESULT hr;
  306. hr = MakeError32(ERROR_SERVICE_REQUEST_TIMEOUT);
  307. if (ConnectedToService())
  308. {
  309. NTSTATUS status;
  310. THEMESAPI_PORT_MESSAGE portMessageIn, portMessageOut;
  311. ZeroMemory(&portMessageIn, sizeof(portMessageIn));
  312. ZeroMemory(&portMessageOut, sizeof(portMessageOut));
  313. portMessageIn.apiThemes.apiGeneric.ulAPINumber = API_THEMES_GETNEWCHANGENUMBER;
  314. portMessageIn.portMessage.u1.s1.DataLength = sizeof(API_THEMES);
  315. portMessageIn.portMessage.u1.s1.TotalLength = static_cast<CSHORT>(sizeof(THEMESAPI_PORT_MESSAGE));
  316. status = NtRequestWaitReplyPort(s_hAPIPort,
  317. &portMessageIn.portMessage,
  318. &portMessageOut.portMessage);
  319. CheckForDisconnectedPort(status);
  320. if (NT_SUCCESS(status))
  321. {
  322. status = portMessageOut.apiThemes.apiGeneric.status;
  323. if (NT_SUCCESS(status))
  324. {
  325. *piValue = portMessageOut.apiThemes.apiSpecific.apiGetNewChangeNumber.out.iChangeNumber;
  326. hr = S_OK;
  327. }
  328. }
  329. if (!NT_SUCCESS(status))
  330. {
  331. hr = HRESULT_FROM_NT(status);
  332. }
  333. }
  334. return(hr);
  335. }
  336. // --------------------------------------------------------------------------
  337. // CThemeServices::SetGlobalTheme
  338. //
  339. // Arguments: hSection = Section to set as the global theme.
  340. //
  341. // Returns: HRESULT
  342. //
  343. // Purpose: Sets the current global theme section handle.
  344. //
  345. // History: 2000-08-10 vtan created
  346. // 2000-10-11 vtan rewrite for LPC
  347. // --------------------------------------------------------------------------
  348. HRESULT CThemeServices::SetGlobalTheme (HANDLE hSection)
  349. {
  350. HRESULT hr;
  351. hr = MakeError32(ERROR_SERVICE_REQUEST_TIMEOUT);
  352. if (ConnectedToService())
  353. {
  354. NTSTATUS status;
  355. THEMESAPI_PORT_MESSAGE portMessageIn, portMessageOut;
  356. ZeroMemory(&portMessageIn, sizeof(portMessageIn));
  357. ZeroMemory(&portMessageOut, sizeof(portMessageOut));
  358. portMessageIn.apiThemes.apiGeneric.ulAPINumber = API_THEMES_SETGLOBALTHEME;
  359. portMessageIn.apiThemes.apiSpecific.apiSetGlobalTheme.in.hSection = hSection;
  360. portMessageIn.portMessage.u1.s1.DataLength = sizeof(API_THEMES);
  361. portMessageIn.portMessage.u1.s1.TotalLength = static_cast<CSHORT>(sizeof(THEMESAPI_PORT_MESSAGE));
  362. status = NtRequestWaitReplyPort(s_hAPIPort,
  363. &portMessageIn.portMessage,
  364. &portMessageOut.portMessage);
  365. CheckForDisconnectedPort(status);
  366. if (NT_SUCCESS(status))
  367. {
  368. status = portMessageOut.apiThemes.apiGeneric.status;
  369. if (NT_SUCCESS(status))
  370. {
  371. hr = portMessageOut.apiThemes.apiSpecific.apiSetGlobalTheme.out.hr;
  372. }
  373. }
  374. if (!NT_SUCCESS(status))
  375. {
  376. hr = HRESULT_FROM_NT(status);
  377. }
  378. }
  379. return(hr);
  380. }
  381. // --------------------------------------------------------------------------
  382. // CThemeServices::GetGlobalTheme
  383. //
  384. // Arguments: phSection = Section object returned from theme services.
  385. //
  386. // Returns: HRESULT
  387. //
  388. // Purpose: Gets the current global theme section handle.
  389. //
  390. // History: 2000-08-10 vtan created
  391. // 2000-10-11 vtan rewrite for LPC
  392. // --------------------------------------------------------------------------
  393. HRESULT CThemeServices::GetGlobalTheme (HANDLE *phSection)
  394. {
  395. HRESULT hr;
  396. hr = MakeError32(ERROR_SERVICE_REQUEST_TIMEOUT);
  397. if (ConnectedToService())
  398. {
  399. NTSTATUS status;
  400. THEMESAPI_PORT_MESSAGE portMessageIn, portMessageOut;
  401. ZeroMemory(&portMessageIn, sizeof(portMessageIn));
  402. ZeroMemory(&portMessageOut, sizeof(portMessageOut));
  403. portMessageIn.apiThemes.apiGeneric.ulAPINumber = API_THEMES_GETGLOBALTHEME;
  404. portMessageIn.portMessage.u1.s1.DataLength = sizeof(API_THEMES);
  405. portMessageIn.portMessage.u1.s1.TotalLength = static_cast<CSHORT>(sizeof(THEMESAPI_PORT_MESSAGE));
  406. status = NtRequestWaitReplyPort(s_hAPIPort,
  407. &portMessageIn.portMessage,
  408. &portMessageOut.portMessage);
  409. CheckForDisconnectedPort(status);
  410. if (NT_SUCCESS(status))
  411. {
  412. status = portMessageOut.apiThemes.apiGeneric.status;
  413. if (NT_SUCCESS(status))
  414. {
  415. hr = portMessageOut.apiThemes.apiSpecific.apiGetGlobalTheme.out.hr;
  416. if (SUCCEEDED(hr))
  417. {
  418. *phSection = portMessageOut.apiThemes.apiSpecific.apiGetGlobalTheme.out.hSection;
  419. }
  420. }
  421. }
  422. if (!NT_SUCCESS(status))
  423. {
  424. hr = HRESULT_FROM_NT(status);
  425. }
  426. }
  427. return(hr);
  428. }
  429. // --------------------------------------------------------------------------
  430. // CThemeServices::CheckThemeSignature
  431. //
  432. // Arguments: pszThemeName = File path of theme to check.
  433. //
  434. // Returns: HRESULT
  435. //
  436. // Purpose: Checks the given theme's signature.
  437. //
  438. // History: 2000-08-10 vtan created
  439. // 2000-10-11 vtan rewrite for LPC
  440. // --------------------------------------------------------------------------
  441. HRESULT CThemeServices::CheckThemeSignature (const WCHAR *pszThemeName)
  442. {
  443. HRESULT hr;
  444. hr = MakeError32(ERROR_SERVICE_REQUEST_TIMEOUT);
  445. if (ConnectedToService())
  446. {
  447. NTSTATUS status;
  448. THEMESAPI_PORT_MESSAGE portMessageIn, portMessageOut;
  449. ZeroMemory(&portMessageIn, sizeof(portMessageIn));
  450. ZeroMemory(&portMessageOut, sizeof(portMessageOut));
  451. portMessageIn.apiThemes.apiGeneric.ulAPINumber = API_THEMES_CHECKTHEMESIGNATURE;
  452. portMessageIn.apiThemes.apiSpecific.apiCheckThemeSignature.in.pszName = pszThemeName;
  453. portMessageIn.apiThemes.apiSpecific.apiCheckThemeSignature.in.cchName = lstrlen(pszThemeName) + sizeof('\0');
  454. portMessageIn.portMessage.u1.s1.DataLength = sizeof(API_THEMES);
  455. portMessageIn.portMessage.u1.s1.TotalLength = static_cast<CSHORT>(sizeof(THEMESAPI_PORT_MESSAGE));
  456. status = NtRequestWaitReplyPort(s_hAPIPort,
  457. &portMessageIn.portMessage,
  458. &portMessageOut.portMessage);
  459. CheckForDisconnectedPort(status);
  460. if (NT_SUCCESS(status))
  461. {
  462. status = portMessageOut.apiThemes.apiGeneric.status;
  463. if (NT_SUCCESS(status))
  464. {
  465. hr = portMessageOut.apiThemes.apiSpecific.apiCheckThemeSignature.out.hr;
  466. }
  467. }
  468. if (!NT_SUCCESS(status))
  469. {
  470. hr = HRESULT_FROM_NT(status);
  471. }
  472. }
  473. return(hr);
  474. }
  475. // --------------------------------------------------------------------------
  476. // CThemeServices::LoadTheme
  477. //
  478. // Arguments: phSection = Section object to theme returned.
  479. // pszThemeName = Theme file to load.
  480. // pszColorParam = Color.
  481. // pszSizeParam = Size.
  482. // fGlobal = FALSE for a preview.
  483. //
  484. // Returns: HRESULT
  485. //
  486. // Purpose: Loads the given theme and creates a section object for it.
  487. //
  488. // History: 2000-08-10 vtan created
  489. // 2000-10-11 vtan rewrite for LPC
  490. // --------------------------------------------------------------------------
  491. HRESULT CThemeServices::LoadTheme (HANDLE *phSection,
  492. const WCHAR *pszThemeName, const WCHAR *pszColor, const WCHAR *pszSize, BOOL fGlobal)
  493. {
  494. HRESULT hr;
  495. *phSection = NULL; // Result if failure
  496. hr = MakeError32(ERROR_SERVICE_REQUEST_TIMEOUT);
  497. if (ConnectedToService())
  498. {
  499. HANDLE hSection;
  500. CThemeLoader *pLoader;
  501. WCHAR szColor[MAX_PATH];
  502. WCHAR szSize[MAX_PATH];
  503. // Because the loader makes GDI calls that directly affect the
  504. // client instance of win32k the theme must be loaded on the
  505. // client side. Once the theme is loaded it is handed to the
  506. // server (which creates a new section) and copies the data to
  507. // it. The server then controls the theme data and the client
  508. // discards the temporary theme.
  509. hSection = NULL;
  510. pLoader = new CThemeLoader;
  511. if (pLoader != NULL)
  512. {
  513. HINSTANCE hInst = NULL;
  514. // Keep the DLL loaded to avoid loading it 3 times below
  515. hr = LoadThemeLibrary(pszThemeName, &hInst);
  516. if (SUCCEEDED(hr) && (pszColor == NULL || *pszColor == L'\0'))
  517. {
  518. hr = GetThemeDefaults(pszThemeName, szColor, ARRAYSIZE(szColor), NULL, 0);
  519. pszColor = szColor;
  520. }
  521. if (SUCCEEDED(hr) && (pszSize == NULL || *pszSize == L'\0'))
  522. {
  523. hr = GetThemeDefaults(pszThemeName, NULL, 0, szSize, ARRAYSIZE(szSize));
  524. pszSize = szSize;
  525. }
  526. if (SUCCEEDED(hr))
  527. {
  528. hr = pLoader->LoadTheme(pszThemeName, pszColor, pszSize, &hSection, fGlobal);
  529. }
  530. delete pLoader;
  531. if (hInst)
  532. {
  533. FreeLibrary(hInst);
  534. }
  535. }
  536. else
  537. {
  538. hr = MakeError32(E_OUTOFMEMORY);
  539. }
  540. if (SUCCEEDED(hr) && (hSection != NULL))
  541. {
  542. NTSTATUS status;
  543. THEMESAPI_PORT_MESSAGE portMessageIn, portMessageOut;
  544. ZeroMemory(&portMessageIn, sizeof(portMessageIn));
  545. ZeroMemory(&portMessageOut, sizeof(portMessageOut));
  546. portMessageIn.apiThemes.apiGeneric.ulAPINumber = API_THEMES_LOADTHEME;
  547. portMessageIn.apiThemes.apiSpecific.apiLoadTheme.in.pszName = pszThemeName;
  548. portMessageIn.apiThemes.apiSpecific.apiLoadTheme.in.cchName = lstrlen(pszThemeName) + sizeof('\0');
  549. portMessageIn.apiThemes.apiSpecific.apiLoadTheme.in.pszColor = pszColor;
  550. portMessageIn.apiThemes.apiSpecific.apiLoadTheme.in.cchColor = lstrlen(pszColor) + sizeof('\0');
  551. portMessageIn.apiThemes.apiSpecific.apiLoadTheme.in.pszSize = pszSize;
  552. portMessageIn.apiThemes.apiSpecific.apiLoadTheme.in.cchSize = lstrlen(pszSize) + sizeof('\0');
  553. portMessageIn.apiThemes.apiSpecific.apiLoadTheme.in.hSection = hSection;
  554. portMessageIn.portMessage.u1.s1.DataLength = sizeof(API_THEMES);
  555. portMessageIn.portMessage.u1.s1.TotalLength = static_cast<CSHORT>(sizeof(THEMESAPI_PORT_MESSAGE));
  556. status = NtRequestWaitReplyPort(s_hAPIPort,
  557. &portMessageIn.portMessage,
  558. &portMessageOut.portMessage);
  559. CheckForDisconnectedPort(status);
  560. if (NT_SUCCESS(status))
  561. {
  562. status = portMessageOut.apiThemes.apiGeneric.status;
  563. if (NT_SUCCESS(status))
  564. {
  565. hr = portMessageOut.apiThemes.apiSpecific.apiLoadTheme.out.hr;
  566. if (SUCCEEDED(hr))
  567. {
  568. *phSection = portMessageOut.apiThemes.apiSpecific.apiLoadTheme.out.hSection;
  569. }
  570. else
  571. {
  572. }
  573. }
  574. }
  575. if (!NT_SUCCESS(status))
  576. {
  577. hr = HRESULT_FROM_NT(status);
  578. }
  579. }
  580. // Clear our temporary section
  581. if (hSection != NULL)
  582. {
  583. // If we didn't transfer the stock objects handles to a new section, clear them always
  584. if (*phSection == NULL)
  585. {
  586. THR(ClearStockObjects(hSection));
  587. }
  588. TBOOL(CloseHandle(hSection));
  589. }
  590. }
  591. return(hr);
  592. }
  593. // --------------------------------------------------------------------------
  594. HRESULT CThemeServices::CheckColorDepth(CUxThemeFile *pThemeFile)
  595. {
  596. HRESULT hr = S_OK;
  597. THEMEMETRICS *pMetrics = GetThemeMetricsPtr(pThemeFile);
  598. DWORD dwDepthRequired = pMetrics->iInts[TMT_MINCOLORDEPTH - TMT_FIRSTINT];
  599. if (MinimumDisplayColorDepth() < dwDepthRequired)
  600. {
  601. hr = MakeError32(ERROR_BAD_ENVIRONMENT);
  602. }
  603. return hr;
  604. }
  605. // --------------------------------------------------------------------------
  606. HRESULT CThemeServices::UpdateThemeRegistry(BOOL fThemeActive,
  607. LPCWSTR pszThemeFileName, LPCWSTR pszColorParam, LPCWSTR pszSizeParam, BOOL fJustSetActive,
  608. BOOL fJustApplied)
  609. {
  610. if (fThemeActive)
  611. {
  612. if (fJustSetActive)
  613. {
  614. //---- see if a theme was previously active ----
  615. WCHAR szThemeName[MAX_PATH];
  616. THR(GetCurrentUserThemeString(THEMEPROP_DLLNAME, L"", szThemeName, ARRAYSIZE(szThemeName)));
  617. if (szThemeName[0] != L'\0')
  618. {
  619. THR(SetCurrentUserThemeInt(THEMEPROP_THEMEACTIVE, 1));
  620. }
  621. }
  622. else
  623. {
  624. WCHAR szFullName[MAX_PATH];
  625. if (GetFullPathName(pszThemeFileName, ARRAYSIZE(szFullName), szFullName, NULL) == 0)
  626. {
  627. lstrcpy_truncate(szFullName, pszThemeFileName, ARRAYSIZE(szFullName));
  628. }
  629. THR(SetCurrentUserThemeInt(THEMEPROP_THEMEACTIVE, 1));
  630. if (fJustApplied)
  631. {
  632. THR(SetCurrentUserThemeInt(THEMEPROP_LOADEDBEFORE, 1));
  633. THR(SetCurrentUserThemeInt(THEMEPROP_LANGID, (int) GetUserDefaultUILanguage()));
  634. // Theme identification
  635. THR(SetCurrentUserThemeStringExpand(THEMEPROP_DLLNAME, szFullName));
  636. THR(SetCurrentUserThemeString(THEMEPROP_COLORNAME, pszColorParam));
  637. THR(SetCurrentUserThemeString(THEMEPROP_SIZENAME, pszSizeParam));
  638. }
  639. else // for forcing theme to be loaded from InitUserTheme()
  640. {
  641. WCHAR szThemeName[MAX_PATH];
  642. THR(GetCurrentUserThemeString(THEMEPROP_DLLNAME, L"", szThemeName, ARRAYSIZE(szThemeName)));
  643. if (lstrcmpiW(szThemeName, szFullName) != 0)
  644. {
  645. THR(SetCurrentUserThemeString(THEMEPROP_DLLNAME, szFullName));
  646. TW32(DeleteCurrentUserThemeValue(THEMEPROP_LOADEDBEFORE));
  647. TW32(DeleteCurrentUserThemeValue(THEMEPROP_LANGID));
  648. TW32(DeleteCurrentUserThemeValue(THEMEPROP_COLORNAME));
  649. TW32(DeleteCurrentUserThemeValue(THEMEPROP_SIZENAME));
  650. } else
  651. {
  652. return S_FALSE; // S_FALSE means we did nothing really
  653. }
  654. }
  655. }
  656. }
  657. else
  658. {
  659. THR(SetCurrentUserThemeInt(THEMEPROP_THEMEACTIVE, 0));
  660. if (! fJustSetActive) // wipe out all theme info
  661. {
  662. THR(DeleteCurrentUserThemeValue(THEMEPROP_DLLNAME));
  663. THR(DeleteCurrentUserThemeValue(THEMEPROP_COLORNAME));
  664. THR(DeleteCurrentUserThemeValue(THEMEPROP_SIZENAME));
  665. THR(DeleteCurrentUserThemeValue(THEMEPROP_LOADEDBEFORE));
  666. THR(DeleteCurrentUserThemeValue(THEMEPROP_LANGID));
  667. }
  668. }
  669. return S_OK;
  670. }
  671. // --------------------------------------------------------------------------
  672. void CThemeServices::SendThemeChangedMsg(BOOL fNewTheme, HWND hwndTarget, DWORD dwFlags,
  673. int iLoadId)
  674. {
  675. WPARAM wParam;
  676. LPARAM lParamBits, lParamMixed;
  677. BOOL fExcluding = ((dwFlags & AT_EXCLUDE) != 0);
  678. BOOL fCustom = ((dwFlags & AT_PROCESS) != 0);
  679. //---- change number was set in ApplyTheme() for both global and preview cases ----
  680. int iChangeNum;
  681. GetCurrentChangeNumber(&iChangeNum);
  682. wParam = iChangeNum;
  683. lParamBits = 0;
  684. if (fNewTheme)
  685. {
  686. lParamBits |= WTC_THEMEACTIVE;
  687. }
  688. if (fCustom)
  689. {
  690. lParamBits |= WTC_CUSTOMTHEME;
  691. }
  692. if ((hwndTarget) && (! fExcluding))
  693. {
  694. SendMessage(hwndTarget, WM_THEMECHANGED, wParam, lParamBits);
  695. }
  696. else
  697. {
  698. lParamMixed = (iLoadId << 4) | (lParamBits & 0xf);
  699. CMessageBroadcast messageBroadcast;
  700. // POST the WM_THEMECHANGED_TRIGGER msg to all targeted windows
  701. // messageBroadcast.PostFilteredMsg(WM_THEMECHANGED_TRIGGER, wParam, lParamMixed,
  702. // hwndTarget, fCustom, fExcluding);
  703. messageBroadcast.PostAllThreadsMsg(WM_THEMECHANGED_TRIGGER, wParam, lParamMixed);
  704. Log(LOG_TMCHANGEMSG, L"Just Broadcasted WM_THEMECHANGED_TRIGGER: iLoadId=%d", iLoadId);
  705. }
  706. }
  707. // --------------------------------------------------------------------------
  708. int CThemeServices::GetLoadId(HANDLE hSectionOld)
  709. {
  710. int iLoadId = 0;
  711. //---- extract LoadId from old section ----
  712. if (hSectionOld)
  713. {
  714. CThemeSection pThemeSectionFile;
  715. if (SUCCEEDED(pThemeSectionFile.Open(hSectionOld)))
  716. {
  717. CUxThemeFile *pThemeFile = pThemeSectionFile;
  718. if (pThemeFile)
  719. {
  720. THEMEHDR *hdr = (THEMEHDR *)(pThemeFile->_pbThemeData);
  721. if (hdr)
  722. {
  723. iLoadId = hdr->iLoadId;
  724. }
  725. }
  726. }
  727. }
  728. return iLoadId;
  729. }
  730. // --------------------------------------------------------------------------
  731. // CThemeServices::ApplyTheme
  732. //
  733. // Arguments: pThemeFile = Object wrapping the theme section to apply.
  734. // dwFlags = Flags.
  735. // hwndTarget = HWND.
  736. //
  737. // Returns: HRESULT
  738. //
  739. // Purpose: Applies the given theme. Do some metric and color depth
  740. // validation, clear the stock bitmaps of the old theme, set
  741. // the given theme as the current theme and broadcast this fact.
  742. //
  743. // History: 2000-08-10 vtan created
  744. // 2000-10-11 vtan rewrite for LPC
  745. // --------------------------------------------------------------------------
  746. // In the design notes below, note that SEND and POST differences are
  747. // significant.
  748. //
  749. // Also, when the "WM_THEMECHANGED_TRIGGER" msg is sent,
  750. // the uxtheme hooking code in each process will:
  751. //
  752. // 1. enumerate all windows for process (using desktop enumeration and
  753. // the per-process "foreign window list") to:
  754. //
  755. // a. process WM_THEMECHANGED for nonclient area
  756. // b. SEND a WM_THEMECHANGED msg to regular window
  757. //
  758. // 2. call FreeRenderObjects() for old theme, if any
  759. // --------------------------------------------------------------------------
  760. // To ensure correct window notification of theme changes and correct removal
  761. // of old theme file RefCounts, the following CRITICAL STEPS must be taken
  762. // in the 4 basic theme transition sequences:
  763. //
  764. // turning ON preview theme:
  765. // a. turn ON global UAE hooks
  766. // b. SEND WM_UAHINIT msg to hwndTarget
  767. // c. SEND WM_THEMECHANGED to hwndTarget
  768. //
  769. // turning ON global theme:
  770. // a. turn ON global UAE hooks
  771. // b. POST WM_UAHINIT msg to all accessible windows
  772. // c. POST WM_THEMECHANGED_TRIGGER to all accessible window threads
  773. //
  774. // turning OFF preview theme:
  775. // c. SEND WM_THEMECHANGED to hwndTarget
  776. //
  777. // turning OFF global theme:
  778. // a. turn OFF global UAE hooks
  779. // b. step "a" will cause WM_THEMECHANGED_TRIGGER-type processing
  780. // to occur from OnHooksDisabled() in each process
  781. // --------------------------------------------------------------------------
  782. HRESULT CThemeServices::ApplyTheme (CUxThemeFile *pThemeFile, DWORD dwFlags, HWND hwndTarget)
  783. {
  784. HRESULT hr;
  785. bool fNewTheme, fGlobal;
  786. int iLoadId;
  787. WCHAR szThemeFileName[MAX_PATH];
  788. WCHAR szColorParam[MAX_PATH];
  789. WCHAR szSizeParam[MAX_PATH];
  790. HANDLE hSection = NULL;
  791. if (pThemeFile != NULL)
  792. {
  793. hSection = pThemeFile->Handle();
  794. }
  795. fGlobal = (((dwFlags & AT_EXCLUDE) != 0) ||
  796. ((hwndTarget == NULL) && ((dwFlags & AT_PROCESS) == 0)));
  797. fNewTheme = (hSection != NULL);
  798. iLoadId = 0;
  799. Log(LOG_TMHANDLE, L"ApplyTheme: hSection=0x%x, dwFlags=0x%x, hwndTarget=0x%x",
  800. hSection, dwFlags, hwndTarget);
  801. if (fNewTheme)
  802. {
  803. if (pThemeFile->HasStockObjects() && !fGlobal) // Don't do this
  804. {
  805. hr = E_INVALIDARG;
  806. }
  807. else
  808. {
  809. //---- get some basic info used thruout this function ----
  810. hr = GetThemeNameId(pThemeFile,
  811. szThemeFileName, ARRAYSIZE(szThemeFileName),
  812. szColorParam, ARRAYSIZE(szColorParam),
  813. szSizeParam, ARRAYSIZE(szSizeParam),
  814. NULL, NULL);
  815. if (SUCCEEDED(hr))
  816. {
  817. //---- ensure color depth of monitor(s) are enough for theme ----
  818. if (GetSystemMetrics(SM_REMOTESESSION)) // only check for terminal server sessions
  819. {
  820. hr = CheckColorDepth(pThemeFile);
  821. }
  822. if (SUCCEEDED(hr))
  823. {
  824. //---- ensure hooks are on ----
  825. hr = ThemeHooksOn(hwndTarget);
  826. }
  827. }
  828. }
  829. }
  830. else
  831. {
  832. hr = S_OK;
  833. }
  834. if (SUCCEEDED(hr) && fGlobal)
  835. {
  836. HANDLE hSectionOld;
  837. //---- get a handle to the old global theme (for stock cleanup) ----
  838. hr = GetGlobalTheme(&hSectionOld);
  839. if (SUCCEEDED(hr))
  840. {
  841. //---- extract Load ID before theme becomes invalid (dwFlags & SECTION_READY=0) ----
  842. if (hSectionOld != NULL)
  843. {
  844. iLoadId = GetLoadId(hSectionOld);
  845. }
  846. //---- tell server to switch global themes ----
  847. hr = SetGlobalTheme(hSection);
  848. if (SUCCEEDED(hr))
  849. {
  850. //---- update needed registry settings ----
  851. if ((dwFlags & AT_NOREGUPDATE) == 0) // if caller allows update
  852. {
  853. hr = UpdateThemeRegistry(fNewTheme, szThemeFileName, szColorParam, szSizeParam,
  854. FALSE, TRUE);
  855. if (FAILED(hr))
  856. {
  857. Log(LOG_ALWAYS, L"UpdateThemeRegistry call failed, hr=0x%x", hr);
  858. hr = S_OK; // not a fatal error
  859. }
  860. }
  861. //---- set system metrics, if requested ----
  862. if ((dwFlags & AT_LOAD_SYSMETRICS) != 0)
  863. {
  864. BOOL fSync = ((dwFlags & AT_SYNC_LOADMETRICS) != 0);
  865. if (fNewTheme)
  866. {
  867. SetSystemMetrics(GetThemeMetricsPtr(pThemeFile), fSync);
  868. }
  869. else // just load classic metrics
  870. {
  871. LOADTHEMEMETRICS tm;
  872. hr = InitThemeMetrics(&tm);
  873. if (SUCCEEDED(hr))
  874. {
  875. SetSystemMetrics(&tm, fSync);
  876. }
  877. }
  878. }
  879. }
  880. if (hSectionOld != NULL)
  881. {
  882. TBOOL(CloseHandle(hSectionOld));
  883. }
  884. }
  885. }
  886. //---- if we turned off global theme, turn hooks off now ----
  887. if (SUCCEEDED(hr))
  888. {
  889. if (!fNewTheme && fGlobal)
  890. {
  891. hr = ThemeHooksOff();
  892. }
  893. else
  894. {
  895. //---- send the correct WM_THEMECHANGED_XXX msg to window(s) ----
  896. SendThemeChangedMsg(fNewTheme, hwndTarget, dwFlags, iLoadId);
  897. }
  898. }
  899. return(hr);
  900. }
  901. // --------------------------------------------------------------------------
  902. // CThemeServices::AdjustTheme
  903. //
  904. // Arguments: BOOL fEnable - if TRUE, enable CU theme; if FALSE, disable it
  905. //
  906. // Returns: HRESULT
  907. //
  908. // Purpose: for 3rd party skinning apps to cooperate better with theme mgr
  909. //
  910. // History: 2001-03-12 rfernand created
  911. // --------------------------------------------------------------------------
  912. HRESULT CThemeServices::AdjustTheme(BOOL fEnable)
  913. {
  914. HRESULT hr = UpdateThemeRegistry(fEnable, NULL, NULL, NULL, TRUE, FALSE);
  915. if (SUCCEEDED(hr))
  916. {
  917. hr = InitUserTheme(FALSE);
  918. }
  919. return hr;
  920. }
  921. // --------------------------------------------------------------------------
  922. // CThemeServices::ApplyDefaultMetrics
  923. //
  924. // Arguments: <none>
  925. //
  926. // Returns: <none>
  927. //
  928. // Purpose: Make sure the user metrics gets reset to Windows Standard
  929. //
  930. // History: 2001-03-30 lmouton created
  931. // --------------------------------------------------------------------------
  932. void CThemeServices::ApplyDefaultMetrics(void)
  933. {
  934. HKEY hKeyThemes;
  935. CCurrentUser hKeyCurrentUser(KEY_READ | KEY_WRITE);
  936. Log(LOG_TMLOAD, L"Applying default metrics");
  937. if ((ERROR_SUCCESS == RegOpenKeyEx(hKeyCurrentUser,
  938. THEMES_REGKEY L"\\" SZ_DEFAULTVS_OFF,
  939. 0,
  940. KEY_QUERY_VALUE,
  941. &hKeyThemes)))
  942. {
  943. WCHAR szVisualStyle[MAX_PATH] = {L'\0'};
  944. WCHAR szColor[MAX_PATH] = {L'\0'};
  945. WCHAR szSize[MAX_PATH] = {L'\0'};
  946. BOOL fGotOne;
  947. // Note: These will fail for the first user logon, themeui sets these keys and needs to call InstallVS itself
  948. fGotOne = SUCCEEDED(RegistryStrRead(hKeyThemes, SZ_INSTALLVISUALSTYLE, szVisualStyle, ARRAYSIZE(szVisualStyle)));
  949. fGotOne = SUCCEEDED(RegistryStrRead(hKeyThemes, SZ_INSTALLVISUALSTYLECOLOR, szColor, ARRAYSIZE(szColor)))
  950. || fGotOne;
  951. fGotOne = SUCCEEDED(RegistryStrRead(hKeyThemes, SZ_INSTALLVISUALSTYLESIZE, szSize, ARRAYSIZE(szSize)))
  952. || fGotOne;
  953. if (fGotOne)
  954. {
  955. // At least one key is present in the registry, it may be enough
  956. WCHAR szSysDir[MAX_PATH];
  957. if (0 < GetSystemDirectory(szSysDir, ARRAYSIZE(szSysDir)))
  958. {
  959. WCHAR *pszCmdLine = (LPWSTR) LocalAlloc(LPTR, MAX_PATH * 5);
  960. if (pszCmdLine)
  961. {
  962. wsprintf(pszCmdLine, L"%s\\regsvr32.exe /s /n /i:\"" SZ_INSTALL_VS L"%s','%s','%s'\" %s\\themeui.dll", szSysDir, szVisualStyle, szColor, szSize, szSysDir);
  963. // Set a reg key to have themeui install the proper settings instead of defaults
  964. // We can't do this now because the user could not be completely logged on
  965. HKEY hKeyRun;
  966. if ((ERROR_SUCCESS == RegOpenKeyEx(hKeyCurrentUser, REGSTR_PATH_RUNONCE, 0, KEY_SET_VALUE, &hKeyRun)))
  967. {
  968. THR(RegistryStrWrite(hKeyRun, szColor, pszCmdLine));
  969. TW32(RegCloseKey(hKeyRun));
  970. }
  971. LocalFree(pszCmdLine);
  972. }
  973. }
  974. }
  975. TW32(RegCloseKey(hKeyThemes));
  976. }
  977. }
  978. // --------------------------------------------------------------------------
  979. // CThemeServices::InitUserTheme
  980. //
  981. // Arguments: BOOL fPolicyCheckOnly
  982. // TRUE means
  983. // "only do something if the policy is different from the current loaded theme"
  984. //
  985. // Returns: HRESULT
  986. //
  987. // Purpose: Special entry point for winlogon/msgina to control themes
  988. // for user logon/logoff.
  989. //
  990. // History: 2000-11-11 vtan created
  991. // --------------------------------------------------------------------------
  992. HRESULT CThemeServices::InitUserTheme (BOOL fPolicyCheckOnly)
  993. {
  994. BOOL fActive = FALSE;
  995. BOOL fOldActive = FALSE;
  996. BOOL fPolicyActive = FALSE;
  997. //---- should theme be active for this user? ----
  998. if (! IsRemoteThemeDisabled())
  999. {
  1000. THR(GetCurrentUserThemeInt(THEMEPROP_THEMEACTIVE, FALSE, &fActive));
  1001. fOldActive = fActive;
  1002. fPolicyActive = ThemeEnforcedByPolicy(fActive != FALSE);
  1003. if (fPolicyActive)
  1004. {
  1005. // Refresh fActive because the policy changed it
  1006. THR(GetCurrentUserThemeInt(THEMEPROP_THEMEACTIVE, FALSE, &fActive));
  1007. }
  1008. if ((fActive) && (ThemeSettingsModified()))
  1009. {
  1010. fActive = FALSE;
  1011. }
  1012. }
  1013. #ifdef DEBUG
  1014. if (LogOptionOn(LO_TMLOAD))
  1015. {
  1016. WCHAR szUserName[MAX_PATH];
  1017. DWORD dwSize = ARRAYSIZE(szUserName);
  1018. GetUserName(szUserName, &dwSize);
  1019. Log(LOG_TMLOAD, L"InitUserTheme: User=%s, ThemeActive=%d, SM_REMOTESESSION=%d, fPolicyActive=%d, fPolicyCheckOnly=%d",
  1020. szUserName, fActive, GetSystemMetrics(SM_REMOTESESSION), fPolicyActive, fPolicyCheckOnly);
  1021. }
  1022. #endif
  1023. BOOL fEarlyExit = FALSE;
  1024. if (fPolicyCheckOnly)
  1025. {
  1026. // Bail out early if nothing has changed since last time, which is most of the time
  1027. if (!fPolicyActive)
  1028. {
  1029. Log(LOG_TMLOAD, L"InitUserTheme: Nothing to do after Policy check");
  1030. fEarlyExit = TRUE;
  1031. } else
  1032. {
  1033. Log(LOG_TMLOAD, L"InitUserTheme: Reloading after Policy check");
  1034. }
  1035. }
  1036. if (!fEarlyExit)
  1037. {
  1038. if (fActive)
  1039. {
  1040. //---- load this user's theme ----
  1041. HRESULT hr = LoadCurrentTheme();
  1042. if (FAILED(hr))
  1043. {
  1044. fActive = FALSE;
  1045. }
  1046. }
  1047. if (! fActive) // turn off themes
  1048. {
  1049. // if fPolicyActive, force refresh system metrics from temporary defaults
  1050. THR(ApplyTheme(NULL, AT_NOREGUPDATE | (fPolicyActive ? AT_LOAD_SYSMETRICS | AT_SYNC_LOADMETRICS: 0), false));
  1051. // Apply the proper default metrics
  1052. if (fPolicyActive)
  1053. {
  1054. ApplyDefaultMetrics();
  1055. }
  1056. }
  1057. }
  1058. return S_OK; // never fail this guy
  1059. }
  1060. // --------------------------------------------------------------------------
  1061. // CThemeServices::InitUserRegistry
  1062. //
  1063. // Arguments: <none>
  1064. //
  1065. // Returns: HRESULT
  1066. //
  1067. // Purpose: Propogate settings from HKLM to HKCU. This should only be
  1068. // invoked for ".Default" hives. Assert to ensure this.
  1069. //
  1070. // History: 2000-11-11 vtan created (ported from themeldr.cpp)
  1071. // --------------------------------------------------------------------------
  1072. HRESULT CThemeServices::InitUserRegistry (void)
  1073. {
  1074. HRESULT hr;
  1075. DWORD dwErrorCode;
  1076. HKEY hklm;
  1077. CCurrentUser hkeyCurrentUser(KEY_READ | KEY_WRITE);
  1078. #ifdef DEBUG
  1079. ASSERT(CThemeServer::IsSystemProcessContext());
  1080. #endif /* DEBUG */
  1081. if (ERROR_SUCCESS == RegOpenKeyEx(HKEY_LOCAL_MACHINE,
  1082. THEMEMGR_REGKEY,
  1083. 0,
  1084. KEY_QUERY_VALUE,
  1085. &hklm))
  1086. {
  1087. HKEY hkcu;
  1088. if (ERROR_SUCCESS == RegCreateKeyEx(hkeyCurrentUser,
  1089. THEMEMGR_REGKEY,
  1090. 0,
  1091. NULL,
  1092. 0,
  1093. KEY_QUERY_VALUE | KEY_SET_VALUE,
  1094. NULL,
  1095. &hkcu,
  1096. NULL))
  1097. {
  1098. int iLMVersion;
  1099. hr = RegistryIntRead(hklm, THEMEPROP_LMVERSION, &iLMVersion);
  1100. if (SUCCEEDED(hr))
  1101. {
  1102. int iCUVersion;
  1103. if (FAILED(RegistryIntRead(hkcu, THEMEPROP_LMVERSION, &iCUVersion)))
  1104. {
  1105. iCUVersion = 0;
  1106. }
  1107. if (iLMVersion != iCUVersion)
  1108. {
  1109. BOOL fOverride;
  1110. WCHAR szValueData[MAX_PATH];
  1111. hr = RegistryIntWrite(hkcu, THEMEPROP_LMVERSION, iLMVersion);
  1112. if (FAILED(hr) || FAILED(RegistryIntRead(hklm, THEMEPROP_LMOVERRIDE, &fOverride)))
  1113. {
  1114. fOverride = FALSE;
  1115. }
  1116. if ((fOverride != FALSE) ||
  1117. FAILED(RegistryStrRead(hkcu, THEMEPROP_DLLNAME, szValueData, ARRAYSIZE(szValueData))) ||
  1118. (lstrlenW(szValueData) == 0))
  1119. {
  1120. DWORD dwIndex;
  1121. dwIndex = 0;
  1122. do
  1123. {
  1124. DWORD dwType, dwValueNameSize, dwValueDataSize;
  1125. WCHAR szValueName[MAX_PATH];
  1126. dwValueNameSize = ARRAYSIZE(szValueName);
  1127. dwValueDataSize = sizeof(szValueData);
  1128. dwErrorCode = RegEnumValue(hklm,
  1129. dwIndex++,
  1130. szValueName,
  1131. &dwValueNameSize,
  1132. NULL,
  1133. &dwType,
  1134. reinterpret_cast<LPBYTE>(szValueData),
  1135. &dwValueDataSize);
  1136. if ((ERROR_SUCCESS == dwErrorCode) &&
  1137. ((REG_SZ == dwType) || (REG_EXPAND_SZ == dwType)) &&
  1138. (AsciiStrCmpI(szValueName, THEMEPROP_LMOVERRIDE) != 0))
  1139. {
  1140. if (AsciiStrCmpI(szValueName, THEMEPROP_DLLNAME) == 0)
  1141. {
  1142. hr = RegistryStrWriteExpand(hkcu, szValueName, szValueData);
  1143. }
  1144. else
  1145. {
  1146. hr = RegistryStrWrite(hkcu, szValueName, szValueData);
  1147. }
  1148. }
  1149. } while ((dwErrorCode == ERROR_SUCCESS) && SUCCEEDED(hr));
  1150. // Since we wrote a new DLL name, erase the old names
  1151. (DWORD)RegDeleteValue(hkcu, THEMEPROP_COLORNAME);
  1152. (DWORD)RegDeleteValue(hkcu, THEMEPROP_SIZENAME);
  1153. }
  1154. }
  1155. }
  1156. else
  1157. {
  1158. hr = S_OK;
  1159. }
  1160. TW32(RegCloseKey(hkcu));
  1161. }
  1162. else
  1163. {
  1164. dwErrorCode = GetLastError();
  1165. hr = HRESULT_FROM_WIN32(dwErrorCode);
  1166. }
  1167. TW32(RegCloseKey(hklm));
  1168. }
  1169. else
  1170. {
  1171. // It's possible for this key to be absent. Ignore the error.
  1172. hr = S_OK;
  1173. }
  1174. return(hr);
  1175. }
  1176. // --------------------------------------------------------------------------
  1177. // CThemeServices::ReestablishServerConnection
  1178. //
  1179. // Arguments: <none>
  1180. //
  1181. // Returns: HRESULT
  1182. //
  1183. // Purpose: Forces an attempt to reconnect to the theme server. Used when
  1184. // the port was disconnected but a refresh is desired because the
  1185. // server came back up.
  1186. //
  1187. // History: 2000-11-17 vtan created
  1188. // --------------------------------------------------------------------------
  1189. HRESULT CThemeServices::ReestablishServerConnection (void)
  1190. {
  1191. HRESULT hr;
  1192. NTSTATUS status;
  1193. //---- do we have a good looking handle that as gone bad? ----
  1194. if ((s_hAPIPort != NULL) && (s_hAPIPort != INVALID_HANDLE_VALUE))
  1195. {
  1196. THEMESAPI_PORT_MESSAGE portMessageIn, portMessageOut;
  1197. ZeroMemory(&portMessageIn, sizeof(portMessageIn));
  1198. ZeroMemory(&portMessageOut, sizeof(portMessageOut));
  1199. portMessageIn.apiThemes.apiGeneric.ulAPINumber = API_THEMES_PING;
  1200. portMessageIn.portMessage.u1.s1.DataLength = sizeof(API_THEMES);
  1201. portMessageIn.portMessage.u1.s1.TotalLength = static_cast<CSHORT>(sizeof(THEMESAPI_PORT_MESSAGE));
  1202. status = NtRequestWaitReplyPort(s_hAPIPort,
  1203. &portMessageIn.portMessage,
  1204. &portMessageOut.portMessage);
  1205. if (NT_SUCCESS(status))
  1206. {
  1207. status = portMessageOut.apiThemes.apiGeneric.status;
  1208. }
  1209. }
  1210. else
  1211. {
  1212. status = STATUS_PORT_DISCONNECTED;
  1213. }
  1214. if (NT_SUCCESS(status))
  1215. {
  1216. hr = S_OK;
  1217. }
  1218. else
  1219. {
  1220. //---- our handle has gone bad; reset for another try on next service call ----
  1221. LockAcquire();
  1222. if ((s_hAPIPort != NULL) && (s_hAPIPort != INVALID_HANDLE_VALUE))
  1223. {
  1224. TBOOL(CloseHandle(s_hAPIPort));
  1225. }
  1226. s_hAPIPort = INVALID_HANDLE_VALUE;
  1227. LockRelease();
  1228. hr = S_FALSE;
  1229. }
  1230. return(hr);
  1231. }
  1232. // --------------------------------------------------------------------------
  1233. // CThemeServices::LockAcquire
  1234. //
  1235. // Arguments: <none>
  1236. //
  1237. // Returns: <none>
  1238. //
  1239. // Purpose: Acquire the critical section.
  1240. //
  1241. // History: 2000-12-01 vtan created
  1242. // --------------------------------------------------------------------------
  1243. void CThemeServices::LockAcquire (void)
  1244. {
  1245. EnterCriticalSection(&s_lock);
  1246. }
  1247. // --------------------------------------------------------------------------
  1248. // CThemeServices::LockRelease
  1249. //
  1250. // Arguments: <none>
  1251. //
  1252. // Returns: <none>
  1253. //
  1254. // Purpose: Release the critical section.
  1255. //
  1256. // History: 2000-12-01 vtan created
  1257. // --------------------------------------------------------------------------
  1258. void CThemeServices::LockRelease (void)
  1259. {
  1260. LeaveCriticalSection(&s_lock);
  1261. }
  1262. // --------------------------------------------------------------------------
  1263. // CThemeServices::ConnectedToService
  1264. //
  1265. // Arguments: <none>
  1266. //
  1267. // Returns: bool
  1268. //
  1269. // Purpose: Demand connect to service. Only do this once. This function
  1270. // has knowledge of where the port exists within the NT object
  1271. // namespace.
  1272. //
  1273. // History: 2000-10-27 vtan created
  1274. // --------------------------------------------------------------------------
  1275. bool CThemeServices::ConnectedToService (void)
  1276. {
  1277. if (s_hAPIPort == INVALID_HANDLE_VALUE)
  1278. {
  1279. ULONG ulConnectionInfoLength;
  1280. UNICODE_STRING portName;
  1281. SECURITY_QUALITY_OF_SERVICE sqos;
  1282. WCHAR szConnectionInfo[32];
  1283. RtlInitUnicodeString(&portName, THEMES_PORT_NAME);
  1284. sqos.Length = sizeof(sqos);
  1285. sqos.ImpersonationLevel = SecurityImpersonation;
  1286. sqos.ContextTrackingMode = SECURITY_DYNAMIC_TRACKING;
  1287. sqos.EffectiveOnly = TRUE;
  1288. lstrcpyW(szConnectionInfo, THEMES_CONNECTION_REQUEST);
  1289. ulConnectionInfoLength = sizeof(szConnectionInfo);
  1290. LockAcquire();
  1291. if (!NT_SUCCESS(NtConnectPort(&s_hAPIPort,
  1292. &portName,
  1293. &sqos,
  1294. NULL,
  1295. NULL,
  1296. NULL,
  1297. szConnectionInfo,
  1298. &ulConnectionInfoLength)))
  1299. {
  1300. s_hAPIPort = NULL;
  1301. }
  1302. LockRelease();
  1303. }
  1304. return(s_hAPIPort != NULL);
  1305. }
  1306. // --------------------------------------------------------------------------
  1307. // CThemeServices::ReleaseConnection
  1308. //
  1309. // Arguments: <none>
  1310. //
  1311. // Returns: <none>
  1312. //
  1313. // Purpose: Releases the API port connection.
  1314. //
  1315. // History: 2000-11-17 vtan created
  1316. // --------------------------------------------------------------------------
  1317. void CThemeServices::ReleaseConnection (void)
  1318. {
  1319. if ((s_hAPIPort != INVALID_HANDLE_VALUE) && (s_hAPIPort != NULL))
  1320. {
  1321. LockAcquire();
  1322. TBOOL(CloseHandle(s_hAPIPort));
  1323. s_hAPIPort = INVALID_HANDLE_VALUE;
  1324. LockRelease();
  1325. }
  1326. }
  1327. // --------------------------------------------------------------------------
  1328. // CThemeServices::CheckForDisconnectedPort
  1329. //
  1330. // Arguments: status = NTSTATUS of last API request.
  1331. //
  1332. // Returns: <none>
  1333. //
  1334. // Purpose: Checks for STATUS_PORT_DISCONNECTED. If found then it
  1335. // releases the port object and NULL out the handle.
  1336. //
  1337. // History: 2000-11-17 vtan created
  1338. // --------------------------------------------------------------------------
  1339. void CThemeServices::CheckForDisconnectedPort (NTSTATUS status)
  1340. {
  1341. if (STATUS_PORT_DISCONNECTED == status)
  1342. {
  1343. ReleaseConnection();
  1344. }
  1345. }
  1346. // --------------------------------------------------------------------------
  1347. // CThemeServices::CurrentThemeMatch
  1348. //
  1349. // Arguments: pszThemeName = Name of theme.
  1350. // pszColor = Color.
  1351. // pszSize = Size.
  1352. // fLoadMetricsOnMatch = Load metrics.
  1353. //
  1354. // Returns: HRESULT
  1355. //
  1356. // Purpose: Is the current theme the same as the theme specified? This
  1357. // can be used to save reloading a theme when it's the same.
  1358. //
  1359. // History: 2000-11-11 vtan created (ported from themeldr.cpp)
  1360. // --------------------------------------------------------------------------
  1361. bool CThemeServices::CurrentThemeMatch (LPCWSTR pszThemeName, LPCWSTR pszColor, LPCWSTR pszSize, LANGID wLangID, bool fLoadMetricsOnMatch)
  1362. {
  1363. bool fMatch;
  1364. HANDLE hSection;
  1365. fMatch = false;
  1366. if (SUCCEEDED(GetGlobalTheme(&hSection)) && (hSection != NULL))
  1367. {
  1368. CThemeSection pThemeSectionFile;
  1369. if (SUCCEEDED(pThemeSectionFile.Open(hSection)))
  1370. {
  1371. fMatch = (ThemeMatch(pThemeSectionFile, pszThemeName, pszColor, pszSize, wLangID) != FALSE);
  1372. if (fMatch)
  1373. {
  1374. //---- ensure color depth of monitor(s) are enough for theme ----
  1375. if (GetSystemMetrics(SM_REMOTESESSION)) // only check for terminal server sessions
  1376. {
  1377. if (FAILED(CheckColorDepth(pThemeSectionFile)))
  1378. {
  1379. fMatch = FALSE;
  1380. }
  1381. }
  1382. }
  1383. if (fMatch && fLoadMetricsOnMatch)
  1384. {
  1385. SetSystemMetrics(GetThemeMetricsPtr(pThemeSectionFile), FALSE);
  1386. }
  1387. }
  1388. TBOOL(CloseHandle(hSection));
  1389. }
  1390. return(fMatch);
  1391. }
  1392. // --------------------------------------------------------------------------
  1393. // CThemeServices::LoadCurrentTheme
  1394. //
  1395. // Arguments: <none>
  1396. //
  1397. // Returns: HRESULT
  1398. //
  1399. // Purpose: Loads the current theme as set in the registry for the
  1400. // impersonated user.
  1401. //
  1402. // History: 2000-11-11 vtan created (ported from themeldr.cpp)
  1403. // --------------------------------------------------------------------------
  1404. HRESULT CThemeServices::LoadCurrentTheme (void)
  1405. {
  1406. HRESULT hr = S_OK;
  1407. WCHAR szThemeName[MAX_PATH];
  1408. WCHAR szColorName[MAX_PATH];
  1409. WCHAR szSizeName[MAX_PATH];
  1410. THR(GetCurrentUserThemeString(THEMEPROP_DLLNAME, L"", szThemeName, ARRAYSIZE(szThemeName)));
  1411. if (szThemeName[0] != L'\0')
  1412. {
  1413. int iLoadedBefore;
  1414. HANDLE hSection;
  1415. int nLangID;
  1416. THR(GetCurrentUserThemeString(THEMEPROP_COLORNAME, L"", szColorName, ARRAYSIZE(szColorName)));
  1417. THR(GetCurrentUserThemeString(THEMEPROP_SIZENAME, L"", szSizeName, ARRAYSIZE(szSizeName)));
  1418. THR(GetCurrentUserThemeInt(THEMEPROP_LOADEDBEFORE, 0, &iLoadedBefore));
  1419. THR(GetCurrentUserThemeInt(THEMEPROP_LANGID, -1, &nLangID));
  1420. // Does new user's theme match the current theme?
  1421. if (nLangID != -1 && CurrentThemeMatch(szThemeName, szColorName, szSizeName, (LANGID) nLangID, (iLoadedBefore == 0)))
  1422. {
  1423. DWORD dwFlags;
  1424. // Everything is done except this registry value.
  1425. if (iLoadedBefore == 0)
  1426. {
  1427. THR(SetCurrentUserThemeInt(THEMEPROP_LOADEDBEFORE, 1));
  1428. }
  1429. hr = GetStatusFlags(&dwFlags);
  1430. if (SUCCEEDED(hr))
  1431. {
  1432. if ((dwFlags & QTS_RUNNING) == 0)
  1433. {
  1434. hr = GetGlobalTheme(&hSection);
  1435. if (SUCCEEDED(hr))
  1436. {
  1437. CUxThemeFile file; // Will clean up on destruction
  1438. if (SUCCEEDED(file.OpenFromHandle(hSection, TRUE)))
  1439. {
  1440. hr = ApplyTheme(&file, 0, false);
  1441. }
  1442. }
  1443. }
  1444. }
  1445. }
  1446. else
  1447. {
  1448. hr = LoadTheme(&hSection, szThemeName, szColorName, szSizeName, TRUE);
  1449. if (SUCCEEDED(hr))
  1450. {
  1451. DWORD dwFlags;
  1452. dwFlags = 0;
  1453. // Has this theme been loaded before?
  1454. // or has the user changed his/her language?
  1455. if (iLoadedBefore == 0 || ((nLangID != -1) && ((LANGID) nLangID != GetUserDefaultUILanguage())))
  1456. {
  1457. dwFlags |= AT_LOAD_SYSMETRICS;
  1458. }
  1459. CUxThemeFile file; // Will clean up on destruction
  1460. if (SUCCEEDED(file.OpenFromHandle(hSection, TRUE)))
  1461. {
  1462. hr = ApplyTheme(&file, dwFlags, false);
  1463. }
  1464. }
  1465. }
  1466. }
  1467. else
  1468. {
  1469. hr = MakeError32(ERROR_NOT_FOUND);
  1470. }
  1471. return(hr);
  1472. }
  1473. // --------------------------------------------------------------------------
  1474. // CThemeServices::SectionProcessType
  1475. //
  1476. // Arguments: hSection = Section to walk and clear stock objects in.
  1477. //
  1478. // Returns: HRESULT
  1479. //
  1480. // Purpose: Walks the section (read-only) and finds HBITMAPs and corresponding
  1481. // HBRUSHes that are stock listed in the section and deletes these objects.
  1482. // This is work that needs to be done on the client.
  1483. //
  1484. // History: 2000-11-17 lmouton created
  1485. // vtan rewritten from themeldr.cpp
  1486. // 2000-12-11 lmouton added stock brushes
  1487. // --------------------------------------------------------------------------
  1488. int CThemeServices::SectionProcessType (const BYTE *pbThemeData, MIXEDPTRS& u)
  1489. {
  1490. UNPACKED_ENTRYHDR header;
  1491. FillAndSkipHdr(u, &header);
  1492. switch (header.ePrimVal)
  1493. {
  1494. case TMT_PARTJUMPTABLE:
  1495. case TMT_STATEJUMPTABLE:
  1496. break;
  1497. case TMT_DIBDATA:
  1498. TMBITMAPHEADER *pThemeBitmapHeader;
  1499. pThemeBitmapHeader = reinterpret_cast<TMBITMAPHEADER*>(u.pb);
  1500. ASSERT(pThemeBitmapHeader->dwSize == TMBITMAPSIZE);
  1501. // Clean up stock bitmaps
  1502. if (pThemeBitmapHeader->hBitmap != NULL)
  1503. {
  1504. HBITMAP hBitmap;
  1505. hBitmap = pThemeBitmapHeader->hBitmap;
  1506. hBitmap = ClearBitmapAttributes(hBitmap, SBA_STOCK);
  1507. #ifdef DEBUG
  1508. if (hBitmap == NULL)
  1509. {
  1510. Log(LOG_TMBITMAP, L"UxTheme: ClearBitmapAttributes failed for %8X in SetGlobalTheme", hBitmap);
  1511. }
  1512. else
  1513. {
  1514. BITMAP bm;
  1515. GetObject(hBitmap, sizeof bm, &bm);
  1516. g_dwStockSize -= bm.bmWidthBytes * bm.bmHeight;
  1517. if (DeleteObject(hBitmap))
  1518. {
  1519. //Log(LOG_TMBITMAP, L"Cleared stock bitmap:%8X, size is %d bytes, stock total is %d",
  1520. // pThemeBitmapHeader->hBitmap, bm.bmWidthBytes * bm.bmHeight, g_dwStockSize);
  1521. }
  1522. else
  1523. {
  1524. Log(LOG_TMBITMAP, L"Failed to delete bitmap:%8X", hBitmap);
  1525. }
  1526. }
  1527. #else
  1528. if (hBitmap != NULL)
  1529. {
  1530. DeleteObject(hBitmap);
  1531. }
  1532. #endif
  1533. }
  1534. // Clean up stock brushes
  1535. if (pThemeBitmapHeader->iBrushesOffset != 0)
  1536. {
  1537. HBRUSH hBrush;
  1538. HBRUSH *pBrushes;
  1539. pBrushes = (HBRUSH*) (pbThemeData + pThemeBitmapHeader->iBrushesOffset);
  1540. for (UINT iBrush = 0; iBrush < pThemeBitmapHeader->nBrushes; iBrush++)
  1541. {
  1542. if (pBrushes[iBrush] != NULL)
  1543. {
  1544. hBrush = NULL;
  1545. if (s_pfnClearBrushAttributes == NULL)
  1546. {
  1547. HMODULE hMod = LoadLibrary(L"GDI32.DLL"); // No need to free
  1548. if (hMod)
  1549. {
  1550. s_pfnClearBrushAttributes = (HBRUSH (*)(HBRUSH, DWORD)) GetProcAddress(hMod, "ClearBrushAttributes");
  1551. }
  1552. }
  1553. if (s_pfnClearBrushAttributes != NULL)
  1554. {
  1555. hBrush = (*s_pfnClearBrushAttributes)(pBrushes[iBrush], SBA_STOCK);
  1556. if (hBrush != NULL)
  1557. {
  1558. Log(LOG_TMBRUSHES, L"Cleared stock brush %8X", pBrushes[iBrush]);
  1559. } else
  1560. {
  1561. Log(LOG_TMBRUSHES, L"ClearBrushAttributes FAILED for stock brush %8X", pBrushes[iBrush]);
  1562. }
  1563. } else
  1564. {
  1565. Log(LOG_TMBRUSHES, L"ClearBrushAttributes: Function not in GDI32.DLL");
  1566. }
  1567. if (hBrush == NULL) // Have to try to clean the brush anyway
  1568. {
  1569. hBrush = pBrushes[iBrush];
  1570. }
  1571. if (!DeleteObject(hBrush))
  1572. {
  1573. Log(LOG_TMBRUSHES, L"Failed to delete former stock brush %8X", hBrush);
  1574. }
  1575. }
  1576. }
  1577. }
  1578. // Fall thru to the default case that increments the mixed pointer.
  1579. default:
  1580. u.pb += header.dwDataLen;
  1581. break;
  1582. }
  1583. return(header.ePrimVal);
  1584. }
  1585. // --------------------------------------------------------------------------
  1586. // CThemeServices::SectionWalkData
  1587. //
  1588. // Arguments: pV = Address of section data to walk.
  1589. // iIndex = Index into section.
  1590. //
  1591. // Returns: <none>
  1592. //
  1593. // Purpose:
  1594. //
  1595. // History: 2000-11-17 lmouton created
  1596. // vtan rewritten from themeldr.cpp
  1597. // --------------------------------------------------------------------------
  1598. void CThemeServices::SectionWalkData (const BYTE *pbThemeData, int iIndexIn)
  1599. {
  1600. bool fDone;
  1601. MIXEDPTRS u;
  1602. fDone = false;
  1603. u.pb = const_cast<BYTE*>(pbThemeData + iIndexIn);
  1604. while (!fDone)
  1605. {
  1606. //---- special post-handling ----
  1607. switch (SectionProcessType(pbThemeData, u))
  1608. {
  1609. int i, iLimit, iIndex;
  1610. case TMT_PARTJUMPTABLE:
  1611. u.pi++;
  1612. iLimit = *u.pb++;
  1613. for (i = 0; i < iLimit; ++i)
  1614. {
  1615. iIndex = *u.pi++;
  1616. if (iIndex > -1)
  1617. {
  1618. SectionWalkData(pbThemeData, iIndex);
  1619. }
  1620. }
  1621. fDone = true;
  1622. break;
  1623. case TMT_STATEJUMPTABLE:
  1624. iLimit = *u.pb++;
  1625. for (i = 0; i < iLimit; ++i)
  1626. {
  1627. iIndex = *u.pi++;
  1628. if (iIndex > -1)
  1629. {
  1630. SectionWalkData(pbThemeData, iIndex);
  1631. }
  1632. }
  1633. fDone = true;
  1634. break;
  1635. case TMT_JUMPTOPARENT:
  1636. fDone = true;
  1637. break;
  1638. default:
  1639. break;
  1640. }
  1641. }
  1642. }
  1643. // --------------------------------------------------------------------------
  1644. // CThemeServices::ClearStockObjects
  1645. //
  1646. // Arguments: hSection = Section to walk and clear bitmaps in.
  1647. //
  1648. // Returns: HRESULT
  1649. //
  1650. // Purpose: Walks the section (read-only) and finds HBITMAPs and corresponding
  1651. // HBRUSHes that are stock listed in the section and deletes these objects.
  1652. // This is work that needs to be done on the client.
  1653. //
  1654. // History: 2000-11-17 lmouton created
  1655. // vtan rewritten from themeldr.cpp
  1656. // 2001-05-15 lmouton Added semaphore support for cleaning from ~CUxThemeFile
  1657. // --------------------------------------------------------------------------
  1658. HRESULT CThemeServices::ClearStockObjects (HANDLE hSection, BOOL fForce)
  1659. {
  1660. HRESULT hr;
  1661. BYTE* pbThemeData;
  1662. bool bWriteable = true;
  1663. HANDLE hSectionWrite = NULL;
  1664. // If the section is global, we can't write to it since only the server can.
  1665. // So let's try to get write access, else we'll call the server
  1666. pbThemeData = static_cast<BYTE*>(MapViewOfFile(hSection,
  1667. FILE_MAP_WRITE,
  1668. 0,
  1669. 0,
  1670. 0));
  1671. if (pbThemeData == NULL)
  1672. {
  1673. // Let's try to reopen a write handle for ourselves
  1674. if (DuplicateHandle(GetCurrentProcess(),
  1675. hSection,
  1676. GetCurrentProcess(),
  1677. &hSectionWrite,
  1678. FILE_MAP_WRITE,
  1679. FALSE,
  1680. 0) != FALSE)
  1681. {
  1682. pbThemeData = static_cast<BYTE*>(MapViewOfFile(hSectionWrite,
  1683. FILE_MAP_WRITE,
  1684. 0,
  1685. 0,
  1686. 0));
  1687. }
  1688. if (pbThemeData == NULL)
  1689. {
  1690. // We can't open it for write, let's try read-only
  1691. pbThemeData = static_cast<BYTE*>(MapViewOfFile(hSection,
  1692. FILE_MAP_READ,
  1693. 0,
  1694. 0,
  1695. 0));
  1696. bWriteable = false;
  1697. }
  1698. #ifdef DEBUG
  1699. else
  1700. {
  1701. Log(LOG_TMLOAD, L"Reopened section %d for write", reinterpret_cast<THEMEHDR*>(pbThemeData)->iLoadId);
  1702. }
  1703. #endif
  1704. }
  1705. #ifdef DEBUG
  1706. if (LogOptionOn(LO_TMLOAD))
  1707. {
  1708. // Unexpected failure
  1709. ASSERT(pbThemeData != NULL);
  1710. }
  1711. #endif
  1712. if (pbThemeData != NULL)
  1713. {
  1714. int i, iLimit;
  1715. THEMEHDR *pThemeHdr;
  1716. APPCLASSLIVE *pACL;
  1717. pThemeHdr = reinterpret_cast<THEMEHDR*>(pbThemeData);
  1718. hr = S_OK;
  1719. Log(LOG_TMLOAD, L"ClearStockObjects for section %X, bWriteable=%d, dwFlags=%d, iLoadId=%d, fForce=%d",
  1720. hSection, bWriteable, pThemeHdr->dwFlags, pThemeHdr->iLoadId, fForce);
  1721. if ((pThemeHdr->dwFlags & SECTION_HASSTOCKOBJECTS) && !(pThemeHdr->dwFlags & SECTION_GLOBAL))
  1722. {
  1723. // Make sure only one thread can do this
  1724. WCHAR szName[64];
  1725. if (pThemeHdr->iLoadId != 0)
  1726. {
  1727. // Each section has a unique iLoadId but not across sessions
  1728. // It has to be global because the Theme service can create it
  1729. wsprintf(szName, L"Global\\ClearStockGlobal%d-%d", pThemeHdr->iLoadId, NtCurrentPeb()->SessionId);
  1730. }
  1731. else
  1732. {
  1733. // The session is local to the process
  1734. wsprintf(szName, L"ClearStockLocal%d-%d", GetCurrentProcessId(), NtCurrentPeb()->SessionId);
  1735. }
  1736. HANDLE hSemaphore = CreateSemaphore(NULL, 0, 1, szName);
  1737. DWORD dwError = GetLastError();
  1738. Log(LOG_TMLOAD, L"Opening semaphore %s, hSemaphore=%X, gle=%d", szName, hSemaphore, dwError);
  1739. // If CreateSemaphore fails for another reason, ignore the failure, we have to clean and we only
  1740. // risk a GDI assert on CHK builds.
  1741. // We'll get access denied if the semaphore was created in the service on SetGlobalTheme, but
  1742. // in this case fForce is true for winlogon, false for the other callers.
  1743. bool bAlreadyExists = (dwError == ERROR_ALREADY_EXISTS || dwError == ERROR_ACCESS_DENIED);
  1744. #ifdef DEBUG
  1745. if (LogOptionOn(LO_TMLOAD))
  1746. {
  1747. // Unexpected failure
  1748. ASSERT(dwError == 0 || bAlreadyExists);
  1749. }
  1750. #endif
  1751. // If nobody else is already doing it
  1752. if (!bAlreadyExists || fForce)
  1753. {
  1754. Log(LOG_TMLOAD, L"ClearStockObjects: Clearing data, semaphore = %s", szName);
  1755. #ifdef DEBUG
  1756. bool bDisconnected = false;
  1757. #endif
  1758. pACL = reinterpret_cast<APPCLASSLIVE*>(pbThemeData + pThemeHdr->iSectionIndexOffset);
  1759. iLimit = pThemeHdr->iSectionIndexLength / sizeof(APPCLASSLIVE);
  1760. for (i = 0; i < iLimit; ++pACL, ++i)
  1761. {
  1762. SectionWalkData(pbThemeData, pACL->iIndex);
  1763. }
  1764. if (bWriteable)
  1765. {
  1766. pThemeHdr->dwFlags &= ~SECTION_HASSTOCKOBJECTS; // To avoid doing it twice
  1767. }
  1768. else
  1769. {
  1770. // Can't write to it, let's call MarkSection in the service to do it
  1771. hr = MakeError32(ERROR_SERVICE_REQUEST_TIMEOUT);
  1772. if (ConnectedToService())
  1773. {
  1774. NTSTATUS status;
  1775. THEMESAPI_PORT_MESSAGE portMessageIn, portMessageOut;
  1776. ZeroMemory(&portMessageIn, sizeof(portMessageIn));
  1777. ZeroMemory(&portMessageOut, sizeof(portMessageOut));
  1778. portMessageIn.apiThemes.apiGeneric.ulAPINumber = API_THEMES_MARKSECTION;
  1779. portMessageIn.apiThemes.apiSpecific.apiMarkSection.in.hSection = hSection;
  1780. portMessageIn.apiThemes.apiSpecific.apiMarkSection.in.dwAdd = 0;
  1781. portMessageIn.apiThemes.apiSpecific.apiMarkSection.in.dwRemove = SECTION_HASSTOCKOBJECTS;
  1782. portMessageIn.portMessage.u1.s1.DataLength = sizeof(API_THEMES);
  1783. portMessageIn.portMessage.u1.s1.TotalLength = static_cast<CSHORT>(sizeof(THEMESAPI_PORT_MESSAGE));
  1784. status = NtRequestWaitReplyPort(s_hAPIPort,
  1785. &portMessageIn.portMessage,
  1786. &portMessageOut.portMessage);
  1787. CheckForDisconnectedPort(status);
  1788. #ifdef DEBUG
  1789. if (STATUS_PORT_DISCONNECTED == status)
  1790. {
  1791. bDisconnected = true; // This failure must not trigger the assert
  1792. }
  1793. #endif
  1794. if (NT_SUCCESS(status))
  1795. {
  1796. status = portMessageOut.apiThemes.apiGeneric.status;
  1797. if (NT_SUCCESS(status))
  1798. {
  1799. hr = S_OK;
  1800. }
  1801. }
  1802. if (!NT_SUCCESS(status))
  1803. {
  1804. hr = HRESULT_FROM_NT(status);
  1805. }
  1806. }
  1807. }
  1808. #ifdef DEBUG
  1809. // When the service goes down, we may fail ApplyTheme (so iLoadId is still 0),
  1810. // and we fail MarkSection too, ignore this error.
  1811. if (LogOptionOn(LO_TMLOAD) && !bDisconnected && pThemeHdr->iLoadId != 0)
  1812. {
  1813. ASSERT(!(pThemeHdr->dwFlags & SECTION_HASSTOCKOBJECTS));
  1814. }
  1815. #endif
  1816. }
  1817. else
  1818. {
  1819. Log(LOG_TMLOAD, L"ClearStockObjects: semaphore %s was already there", szName);
  1820. }
  1821. if (hSemaphore)
  1822. {
  1823. Log(LOG_TMLOAD, L"ClearStockObjects: Closing semaphore %X", hSemaphore);
  1824. CloseHandle(hSemaphore);
  1825. }
  1826. }
  1827. TBOOL(UnmapViewOfFile(pbThemeData));
  1828. }
  1829. else
  1830. {
  1831. DWORD dwErrorCode;
  1832. dwErrorCode = GetLastError();
  1833. hr = HRESULT_FROM_WIN32(dwErrorCode);
  1834. }
  1835. if (hSectionWrite != NULL)
  1836. {
  1837. CloseHandle(hSectionWrite);
  1838. }
  1839. return(hr);
  1840. }
  1841. // --------------------------------------------------------------------------
  1842. // CThemeServices::ThemeSettingsModified
  1843. //
  1844. // Returns: BOOL
  1845. //
  1846. // Purpose: Detects that appearance settings have been changed on a
  1847. // W2K machine by a roaming user.
  1848. //
  1849. // History: 2000-11-28 lmouton created
  1850. // --------------------------------------------------------------------------
  1851. bool CThemeServices::ThemeSettingsModified (void)
  1852. {
  1853. WCHAR szCurrent[MAX_PATH];
  1854. WCHAR szNewCurrent[MAX_PATH];
  1855. // If NewCurrent exists and is different from Current, Current
  1856. // has been tampered with on a roaming W2K machine
  1857. THR(GetCurrentUserString(CONTROLPANEL_APPEARANCE_REGKEY, THEMEPROP_CURRSCHEME, L" ", szCurrent, ARRAYSIZE(szCurrent)));
  1858. THR(GetCurrentUserString(CONTROLPANEL_APPEARANCE_REGKEY, THEMEPROP_NEWCURRSCHEME, L" ", szNewCurrent, ARRAYSIZE(szNewCurrent)));
  1859. return((lstrcmpW(szNewCurrent, L" ") != 0) && (lstrcmpW(szCurrent, szNewCurrent) != 0));
  1860. }
  1861. // --------------------------------------------------------------------------
  1862. // CThemeServices::ThemeEnforcedByPolicy
  1863. //
  1864. // Arguments: BOOL TRUE if a .msstyles file is currently active for the user
  1865. //
  1866. // Returns: BOOL TRUE if the policy changed something
  1867. //
  1868. // Purpose: Loads the .msstyles file specified in the SetVisualStyle policy.
  1869. //
  1870. // History: 2000-11-28 lmouton created
  1871. // --------------------------------------------------------------------------
  1872. bool CThemeServices::ThemeEnforcedByPolicy (bool fActive)
  1873. {
  1874. bool fPolicyPresent;
  1875. HKEY hKeyPol = NULL;
  1876. CCurrentUser hKeyCurrentUser(KEY_READ | KEY_WRITE);
  1877. fPolicyPresent = false;
  1878. // See if a policy overrides the theme name
  1879. if ((ERROR_SUCCESS == RegOpenKeyEx(hKeyCurrentUser,
  1880. REGSTR_PATH_POLICIES L"\\" SZ_THEME_POLICY_KEY,
  1881. 0,
  1882. KEY_QUERY_VALUE,
  1883. &hKeyPol)))
  1884. {
  1885. WCHAR szNewThemeName[MAX_PATH + 1];
  1886. lstrcpy(szNewThemeName, L" ");
  1887. if (SUCCEEDED(RegistryStrRead(hKeyPol,
  1888. SZ_POLICY_SETVISUALSTYLE,
  1889. szNewThemeName,
  1890. ARRAYSIZE(szNewThemeName))))
  1891. {
  1892. if (szNewThemeName[0] == L'\0') // Disable themes
  1893. {
  1894. if (fActive)
  1895. {
  1896. THR(UpdateThemeRegistry(FALSE, NULL, NULL, NULL, FALSE, FALSE));
  1897. fPolicyPresent = true;
  1898. }
  1899. }
  1900. else
  1901. {
  1902. if (FileExists(szNewThemeName))
  1903. {
  1904. HRESULT hr = UpdateThemeRegistry(TRUE, szNewThemeName, NULL, NULL, FALSE, FALSE);
  1905. THR(hr);
  1906. if (!fActive || hr == S_OK)
  1907. {
  1908. // If we had no theme before or a different one, say we changed something
  1909. fPolicyPresent = true;
  1910. }
  1911. }
  1912. }
  1913. }
  1914. TW32(RegCloseKey(hKeyPol));
  1915. }
  1916. return(fPolicyPresent);
  1917. }