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.

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