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.

690 lines
18 KiB

  1. //---------------------------------------------------------------------------
  2. // AppInfo.cpp - manages app-level theme information
  3. //---------------------------------------------------------------------------
  4. #include "stdafx.h"
  5. #include "info.h"
  6. #include "AppInfo.h"
  7. #include "sethook.h"
  8. #include "services.h"
  9. #include "themefile.h"
  10. #include "tmreg.h"
  11. #include "renderlist.h"
  12. #include "nctheme.h"
  13. #include "loader.h"
  14. #include "tmutils.h"
  15. //---------------------------------------------------------------------------
  16. //---- values for _pThemeFile, besides valid ptrs ----
  17. //---- if we have no windows open, we cannot track if theme is active ----
  18. #define THEME_UNKNOWN NULL
  19. //---- if we are unhooked, we no that no theme file is avail for us ----
  20. #define THEME_NONE (CUxThemeFile *)(-1)
  21. //---------------------------------------------------------------------------
  22. CAppInfo::CAppInfo()
  23. {
  24. _fCustomAppTheme = FALSE;
  25. _hwndPreview = NULL;
  26. _pPreviewThemeFile = NULL;
  27. _fFirstTimeHooksOn = TRUE;
  28. _fNewThemeDiscovered = FALSE;
  29. _pAppThemeFile = THEME_NONE; // no hooks
  30. _iChangeNum = -1;
  31. _dwAppFlags = (STAP_ALLOW_NONCLIENT | STAP_ALLOW_CONTROLS);
  32. //---- compositing ON by default ----
  33. _fCompositing = TRUE;
  34. GetCurrentUserThemeInt(THEMEPROP_COMPOSITING, TRUE, &_fCompositing);
  35. InitializeCriticalSection(&_csAppInfo);
  36. }
  37. //---------------------------------------------------------------------------
  38. CAppInfo::~CAppInfo()
  39. {
  40. ClosePreviewThemeFile();
  41. //---- ignore iRefCount here - force elements to be deleted ----
  42. for (int i=0; i < _ThemeEntries.m_nSize; i++)
  43. {
  44. _ThemeEntries[i].pThemeFile->ValidateObj();
  45. delete _ThemeEntries[i].pThemeFile;
  46. }
  47. DeleteCriticalSection(&_csAppInfo);
  48. }
  49. //---------------------------------------------------------------------------
  50. void CAppInfo::ResetAppTheme(int iChangeNum, BOOL fMsgCheck, BOOL *pfChanged, BOOL *pfFirstMsg)
  51. {
  52. CAutoCS cs(&_csAppInfo);
  53. if (pfChanged)
  54. *pfChanged = FALSE;
  55. //---- NOTE: "_pAppThemeFile" doesn't hold a refcount on the shared memory map file ----
  56. //---- this is done so that, processes who close all of their windows but continue ----
  57. //---- to run (like WinLogon), will not hold a refcount on old themes (since ----
  58. //---- they never receive any more WM_THEMECHANGED msgs until they create ----
  59. //---- another window. If we were to remove HOOKS between every theme change, ----
  60. //---- we could use the OnHooksDisableld code to remove the theme file hold ----
  61. //---- but design is to let hooks stay ON why we apply and unapply themes. ----
  62. if ((iChangeNum == -1) || (_iChangeNum != iChangeNum) || (_fNewThemeDiscovered))
  63. {
  64. //---- new change number for this process ----
  65. if (HOOKSACTIVE())
  66. _pAppThemeFile = THEME_UNKNOWN;
  67. else
  68. _pAppThemeFile = THEME_NONE;
  69. Log(LOG_TMCHANGE, L"ResetAppTheme - CHANGE: iChangeNum=0x%x, _pAppThemeFile=%d",
  70. iChangeNum, _pAppThemeFile);
  71. _iChangeNum = iChangeNum;
  72. _fNewThemeDiscovered = FALSE;
  73. //---- update caller's info ----
  74. if (pfChanged)
  75. *pfChanged = TRUE;
  76. }
  77. if (fMsgCheck)
  78. {
  79. *pfFirstMsg = FALSE;
  80. if ((iChangeNum != -1) && (_iFirstMsgChangeNum != iChangeNum))
  81. {
  82. //---- new WM_THEMECHANGED_TRIGGER msg for this process ----
  83. _iFirstMsgChangeNum = iChangeNum;
  84. //---- update caller's info ----
  85. *pfFirstMsg = TRUE;
  86. }
  87. }
  88. }
  89. //---------------------------------------------------------------------------
  90. BOOL CAppInfo::HasThemeChanged()
  91. {
  92. CAutoCS cs(&_csAppInfo);
  93. BOOL fChanged = _fNewThemeDiscovered;
  94. _fNewThemeDiscovered = FALSE;
  95. return fChanged;
  96. }
  97. //---------------------------------------------------------------------------
  98. void CAppInfo::ClosePreviewThemeFile()
  99. {
  100. CAutoCS cs(&_csAppInfo);
  101. if (_pPreviewThemeFile)
  102. {
  103. CloseThemeFile(_pPreviewThemeFile);
  104. _pPreviewThemeFile = NULL;
  105. }
  106. _hwndPreview = NULL;
  107. }
  108. //---------------------------------------------------------------------------
  109. BOOL CAppInfo::CompositingEnabled()
  110. {
  111. CAutoCS cs(&_csAppInfo);
  112. return (_fCompositing);
  113. }
  114. //---------------------------------------------------------------------------
  115. HRESULT CAppInfo::LoadCustomAppThemeIfFound()
  116. {
  117. CAutoCS cs(&_csAppInfo);
  118. CCurrentUser hkeyCurrentUser(KEY_READ);
  119. RESOURCE HKEY hklm = NULL;
  120. HTHEMEFILE hThemeFile = NULL;
  121. HRESULT hr = S_OK;
  122. int code32;
  123. if (! _fFirstTimeHooksOn)
  124. goto exit;
  125. _fFirstTimeHooksOn = FALSE;
  126. //---- see if this app has custom theme ----
  127. WCHAR szCustomKey[2*MAX_PATH];
  128. wsprintf(szCustomKey, L"%s\\%s\\%s", THEMEMGR_REGKEY,
  129. THEMEPROP_CUSTOMAPPS, g_szProcessName);
  130. //---- open hkcu ----
  131. code32 = RegOpenKeyEx(hkeyCurrentUser, szCustomKey, 0, KEY_READ, &hklm);
  132. if (code32 != ERROR_SUCCESS)
  133. goto exit;
  134. //---- read the "DllValue" value ----
  135. WCHAR szDllName[MAX_PATH];
  136. hr = RegistryStrRead(hklm, THEMEPROP_DLLNAME, szDllName, ARRAYSIZE(szDllName));
  137. if (FAILED(hr))
  138. goto exit;
  139. //---- read the "color" value ----
  140. WCHAR szColorName[MAX_PATH];
  141. hr = RegistryStrRead(hklm, THEMEPROP_COLORNAME, szColorName, ARRAYSIZE(szColorName));
  142. if (FAILED(hr))
  143. *szColorName = 0;
  144. //---- read the "size" value ----
  145. WCHAR szSizeName[MAX_PATH];
  146. hr = RegistryStrRead(hklm, THEMEPROP_SIZENAME, szSizeName, ARRAYSIZE(szSizeName));
  147. if (FAILED(hr))
  148. *szSizeName = 0;
  149. Log(LOG_TMCHANGE, L"Custom app theme found: %s, %s, %s", szDllName, szColorName, szSizeName);
  150. hr = ::OpenThemeFile(szDllName, szColorName, szSizeName, &hThemeFile, FALSE);
  151. if (FAILED(hr))
  152. goto exit;
  153. _fCustomAppTheme = TRUE;
  154. //---- tell every window in our process that theme has changed ----
  155. hr = ApplyTheme(hThemeFile, AT_PROCESS, NULL);
  156. if (FAILED(hr))
  157. goto exit;
  158. exit:
  159. if (FAILED(hr))
  160. {
  161. if (hThemeFile)
  162. ::CloseThemeFile(hThemeFile);
  163. }
  164. if (hklm)
  165. RegCloseKey(hklm);
  166. return hr;
  167. }
  168. //---------------------------------------------------------------------------
  169. BOOL CAppInfo::AppIsThemed()
  170. {
  171. CAutoCS cs(&_csAppInfo);
  172. return HOOKSACTIVE();
  173. }
  174. //---------------------------------------------------------------------------
  175. BOOL CAppInfo::CustomAppTheme()
  176. {
  177. CAutoCS cs(&_csAppInfo);
  178. return _fCustomAppTheme;
  179. }
  180. //---------------------------------------------------------------------------
  181. BOOL CAppInfo::IsSystemThemeActive()
  182. {
  183. HANDLE handle;
  184. BOOL fActive = FALSE;
  185. HRESULT hr = CThemeServices::GetGlobalTheme(&handle);
  186. if (SUCCEEDED(hr))
  187. {
  188. if (handle)
  189. {
  190. fActive = TRUE;
  191. CloseHandle(handle);
  192. }
  193. }
  194. return fActive;
  195. }
  196. //---------------------------------------------------------------------------
  197. BOOL CAppInfo::WindowHasTheme(HWND hwnd)
  198. {
  199. //---- keep this logic in sync with "OpenWindowThemeFile()" ----
  200. CAutoCS cs(&_csAppInfo);
  201. BOOL fHasTheme = FALSE;
  202. if (HOOKSACTIVE())
  203. {
  204. //---- check for preview window match ----
  205. if ((ISWINDOW(hwnd)) && (ISWINDOW(_hwndPreview)))
  206. {
  207. if ((hwnd == _hwndPreview) || (IsChild(_hwndPreview, hwnd)))
  208. {
  209. if (_pPreviewThemeFile)
  210. fHasTheme = TRUE;
  211. }
  212. }
  213. //---- if not preview, just use app theme file ----
  214. if ((! fHasTheme) && (_pAppThemeFile != THEME_NONE))
  215. {
  216. fHasTheme = TRUE;
  217. }
  218. }
  219. return fHasTheme;
  220. }
  221. //---------------------------------------------------------------------------
  222. HRESULT CAppInfo::OpenWindowThemeFile(HWND hwnd, CUxThemeFile **ppThemeFile)
  223. {
  224. //---- keep this logic in sync with "WindowHasTheme()" ----
  225. HRESULT hr = S_OK;
  226. CUxThemeFile *pThemeFile = NULL;
  227. CAutoCS cs(&_csAppInfo);
  228. if (hwnd)
  229. TrackForeignWindow(hwnd);
  230. if (HOOKSACTIVE())
  231. {
  232. //---- check for preview window match ----
  233. if ((ISWINDOW(hwnd)) && (ISWINDOW(_hwndPreview)))
  234. {
  235. if ((hwnd == _hwndPreview) || (IsChild(_hwndPreview, hwnd)))
  236. {
  237. if (_pPreviewThemeFile)
  238. {
  239. //---- bump ref count ----
  240. hr = BumpRefCount(_pPreviewThemeFile);
  241. if (FAILED(hr))
  242. goto exit;
  243. pThemeFile = _pPreviewThemeFile;
  244. }
  245. }
  246. }
  247. //---- if not preview, just use app theme file ----
  248. if ((! pThemeFile) && (_pAppThemeFile != THEME_NONE))
  249. {
  250. if (_pAppThemeFile == THEME_UNKNOWN || !_pAppThemeFile->IsReady())
  251. {
  252. HANDLE handle = NULL;
  253. hr = CThemeServices::GetGlobalTheme(&handle);
  254. if (FAILED(hr))
  255. goto exit;
  256. Log(LOG_TMCHANGE, L"New App Theme handle=0x%x", handle);
  257. if (handle)
  258. {
  259. //---- get a shared CUxThemeFile object for the handle ----
  260. hr = OpenThemeFile(handle, &pThemeFile);
  261. if (FAILED(hr))
  262. {
  263. // Since it's the global theme, no need to clean stock objects
  264. CloseHandle(handle);
  265. goto exit;
  266. }
  267. //---- set our app theme file ----
  268. _pAppThemeFile = pThemeFile;
  269. //---- update our cached change number to match ----
  270. _iChangeNum = GetLoadIdFromTheme(_pAppThemeFile);
  271. _fNewThemeDiscovered = TRUE;
  272. }
  273. }
  274. else
  275. {
  276. //---- bump ref count ----
  277. hr = BumpRefCount(_pAppThemeFile);
  278. if (FAILED(hr))
  279. goto exit;
  280. pThemeFile = _pAppThemeFile;
  281. }
  282. }
  283. }
  284. exit:
  285. if (pThemeFile)
  286. {
  287. *ppThemeFile = pThemeFile;
  288. }
  289. else
  290. {
  291. hr = MakeError32(ERROR_NOT_FOUND);
  292. }
  293. return hr;
  294. }
  295. //---------------------------------------------------------------------------
  296. DWORD CAppInfo::GetAppFlags()
  297. {
  298. CAutoCS cs(&_csAppInfo);
  299. return _dwAppFlags;
  300. }
  301. //---------------------------------------------------------------------------
  302. void CAppInfo::SetAppFlags(DWORD dwFlags)
  303. {
  304. CAutoCS cs(&_csAppInfo);
  305. _dwAppFlags = dwFlags;
  306. }
  307. //---------------------------------------------------------------------------
  308. void CAppInfo::SetPreviewThemeFile(HANDLE handle, HWND hwnd)
  309. {
  310. CAutoCS cs(&_csAppInfo);
  311. ClosePreviewThemeFile();
  312. //---- set new file ----
  313. if (handle)
  314. {
  315. HRESULT hr = OpenThemeFile(handle, &_pPreviewThemeFile);
  316. if (FAILED(hr))
  317. {
  318. // We don't own the handle, so no clean up
  319. Log(LOG_ALWAYS, L"Failed to add theme file to list");
  320. _pPreviewThemeFile = NULL;
  321. }
  322. }
  323. _hwndPreview = hwnd;
  324. }
  325. //---------------------------------------------------------------------------
  326. HWND CAppInfo::PreviewHwnd()
  327. {
  328. CAutoCS cs(&_csAppInfo);
  329. return _hwndPreview;
  330. }
  331. //---------------------------------------------------------------------------
  332. //---------------------------------------------------------------------------
  333. // If we fail, dont return a theme file and let the caller clean up
  334. //---------------------------------------------------------------------------
  335. HRESULT CAppInfo::OpenThemeFile(HANDLE handle, CUxThemeFile **ppThemeFile)
  336. {
  337. CAutoCS autoCritSect(&_csAppInfo);
  338. CUxThemeFile *pFile = NULL;
  339. HRESULT hr = S_OK;
  340. BOOL fGotit = FALSE;
  341. if (! handle)
  342. {
  343. hr = MakeError32(ERROR_INVALID_HANDLE);
  344. goto exit;
  345. }
  346. for (int i=0; i < _ThemeEntries.m_nSize; i++)
  347. {
  348. THEME_FILE_ENTRY *pEntry = &_ThemeEntries[i];
  349. pEntry->pThemeFile->ValidateObj();
  350. if (pEntry->pThemeFile->_hMemoryMap == handle)
  351. {
  352. pEntry->iRefCount++;
  353. fGotit = TRUE;
  354. *ppThemeFile = pEntry->pThemeFile;
  355. break;
  356. }
  357. }
  358. if (! fGotit)
  359. {
  360. pFile = new CUxThemeFile;
  361. if (! pFile)
  362. {
  363. hr = MakeError32(E_OUTOFMEMORY);
  364. goto exit;
  365. }
  366. hr = pFile->OpenFromHandle(handle);
  367. if (FAILED(hr))
  368. {
  369. goto exit;
  370. }
  371. THEME_FILE_ENTRY entry = {1, pFile};
  372. if (! _ThemeEntries.Add(entry))
  373. {
  374. hr = MakeError32(E_OUTOFMEMORY);
  375. goto exit;
  376. }
  377. pFile->ValidateObj();
  378. *ppThemeFile = pFile;
  379. }
  380. exit:
  381. if ((FAILED(hr)) && (pFile))
  382. {
  383. delete pFile;
  384. }
  385. return hr;
  386. }
  387. //---------------------------------------------------------------------------
  388. HRESULT CAppInfo::BumpRefCount(CUxThemeFile *pThemeFile)
  389. {
  390. HRESULT hr = S_OK;
  391. CAutoCS autoCritSect(&_csAppInfo);
  392. pThemeFile->ValidateObj();
  393. BOOL fGotit = FALSE;
  394. for (int i=0; i < _ThemeEntries.m_nSize; i++)
  395. {
  396. THEME_FILE_ENTRY *pEntry = &_ThemeEntries[i];
  397. pEntry->pThemeFile->ValidateObj();
  398. if (pEntry->pThemeFile == pThemeFile)
  399. {
  400. pEntry->iRefCount++;
  401. fGotit = TRUE;
  402. break;
  403. }
  404. }
  405. if (! fGotit)
  406. hr = MakeError32(ERROR_NOT_FOUND);
  407. return hr;
  408. }
  409. //---------------------------------------------------------------------------
  410. void CAppInfo::CloseThemeFile(CUxThemeFile *pThemeFile)
  411. {
  412. CAutoCS autoCritSect(&_csAppInfo);
  413. BOOL fGotit = FALSE;
  414. pThemeFile->ValidateObj();
  415. for (int i=0; i < _ThemeEntries.m_nSize; i++)
  416. {
  417. THEME_FILE_ENTRY *pEntry = &_ThemeEntries[i];
  418. pEntry->pThemeFile->ValidateObj();
  419. if (pEntry->pThemeFile == pThemeFile)
  420. {
  421. pEntry->iRefCount--;
  422. fGotit = TRUE;
  423. if (! pEntry->iRefCount)
  424. {
  425. //---- clear app themefile? ----
  426. if (pEntry->pThemeFile == _pAppThemeFile)
  427. {
  428. _pAppThemeFile = THEME_UNKNOWN;
  429. }
  430. delete pEntry->pThemeFile;
  431. _ThemeEntries.RemoveAt(i);
  432. }
  433. break;
  434. }
  435. }
  436. if (! fGotit)
  437. Log(LOG_ERROR, L"Could not find ThemeFile in list: 0x%x", pThemeFile);
  438. }
  439. //---------------------------------------------------------------------------
  440. #ifdef DEBUG
  441. void CAppInfo::DumpFileHolders()
  442. {
  443. CAutoCS autoCritSect(&_csAppInfo);
  444. if (LogOptionOn(LO_TMHANDLE))
  445. {
  446. int iCount = _ThemeEntries.m_nSize;
  447. if (! iCount)
  448. {
  449. Log(LOG_TMHANDLE, L"---- No CUxThemeFile objects ----");
  450. }
  451. else
  452. {
  453. Log(LOG_TMHANDLE, L"---- Dump of %d CUxThemeFile objects ----", iCount);
  454. for (int i=0; i < _ThemeEntries.m_nSize; i++)
  455. {
  456. THEME_FILE_ENTRY *pEntry = &_ThemeEntries[i];
  457. pEntry->pThemeFile->ValidateObj();
  458. if (pEntry->pThemeFile)
  459. {
  460. CUxThemeFile *tf = pEntry->pThemeFile;
  461. THEMEHDR *th = (THEMEHDR *)tf->_pbThemeData;
  462. Log(LOG_TMHANDLE, L"CUxThemeFile[%d]: refcnt=%d, memfile=%d",
  463. i, pEntry->iRefCount, th->iLoadId);
  464. }
  465. }
  466. }
  467. }
  468. }
  469. #endif
  470. //---------------------------------------------------------------------------
  471. BOOL CAppInfo::TrackForeignWindow(HWND hwnd)
  472. {
  473. CAutoCS autoCritSect(&_csAppInfo);
  474. WCHAR szDeskName[MAX_PATH] = {0};
  475. BOOL fForeign = TRUE;
  476. //---- get desktop name for window ----
  477. if (GetWindowDesktopName(hwnd, szDeskName, ARRAYSIZE(szDeskName)))
  478. {
  479. if (AsciiStrCmpI(szDeskName, L"default")==0)
  480. {
  481. fForeign = FALSE;
  482. }
  483. }
  484. if (fForeign)
  485. {
  486. BOOL fNeedToAdd = TRUE;
  487. //---- see if we already know about this window ----
  488. for (int i=0; i < _ForeignWindows.m_nSize; i++)
  489. {
  490. if (_ForeignWindows[i] == hwnd)
  491. {
  492. fNeedToAdd = FALSE;
  493. break;
  494. }
  495. }
  496. if (fNeedToAdd)
  497. {
  498. if (_ForeignWindows.Add(hwnd))
  499. {
  500. //Log(LOG_TMHANDLE, L"**** ADDED Foreign Window: hwnd=0x%x, desktop=%s ****", hwnd, szDeskName);
  501. }
  502. else
  503. {
  504. Log(LOG_TMHANDLE, L"Could not add foreign window=0x%x to tracking list", hwnd);
  505. }
  506. }
  507. }
  508. return fForeign;
  509. }
  510. //---------------------------------------------------------------------------
  511. BOOL CAppInfo::OnWindowDestroyed(HWND hwnd)
  512. {
  513. CAutoCS autoCritSect(&_csAppInfo);
  514. BOOL fFound = FALSE;
  515. //---- remove from the foreign list, if present ----
  516. for (int i=0; i < _ForeignWindows.m_nSize; i++)
  517. {
  518. if (_ForeignWindows[i] == hwnd)
  519. {
  520. _ForeignWindows.RemoveAt(i);
  521. fFound = TRUE;
  522. //Log(LOG_TMHANDLE, L"**** REMOVED Foreign Window: hwnd=0x%x", hwnd);
  523. break;
  524. }
  525. }
  526. //---- see if preview window went away ----
  527. if ((_hwndPreview) && (hwnd == _hwndPreview))
  528. {
  529. ClosePreviewThemeFile();
  530. }
  531. return fFound;
  532. }
  533. //---------------------------------------------------------------------------
  534. BOOL CAppInfo::GetForeignWindows(HWND **ppHwnds, int *piCount)
  535. {
  536. CAutoCS autoCritSect(&_csAppInfo);
  537. //---- note: we don't see window creates (OpenThemeData) and ----
  538. //---- destroys (WM_NCDESTROY) when hooks are off; therefore ----
  539. //---- this data may be incomplete. hopefully, vtan or USER ----
  540. //---- can give us a more reliable way to enumerate windows ----
  541. //---- on secured desktops ----
  542. //---- validate windows in list, from last to first ----
  543. int i = _ForeignWindows.m_nSize;
  544. while (--i >= 0)
  545. {
  546. if (! IsWindow(_ForeignWindows[i]))
  547. {
  548. _ForeignWindows.RemoveAt(i);
  549. }
  550. }
  551. BOOL fOk = FALSE;
  552. int iCount = _ForeignWindows.m_nSize;
  553. if (iCount)
  554. {
  555. //---- allocate memory to hold window list ----
  556. HWND *pHwnds = new HWND[iCount];
  557. if (pHwnds)
  558. {
  559. //---- copy windows to caller's new list ----
  560. for (int i=0; i < iCount; i++)
  561. {
  562. pHwnds[i] = _ForeignWindows[i];
  563. }
  564. *ppHwnds = pHwnds;
  565. *piCount = iCount;
  566. fOk = TRUE;
  567. }
  568. }
  569. return fOk;
  570. }
  571. //---------------------------------------------------------------------------