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.

486 lines
15 KiB

  1. //---------------------------------------------------------------------------
  2. // Info.cpp - implements the information services of the CRenderObj object
  3. //---------------------------------------------------------------------------
  4. #include "stdafx.h"
  5. #include "Render.h"
  6. #include "Utils.h"
  7. #include "Loader.h"
  8. #include "sethook.h"
  9. #include "info.h"
  10. #include "RenderList.h"
  11. #include "Services.h"
  12. #include "appinfo.h"
  13. #include "tmutils.h"
  14. #include "borderfill.h"
  15. #include "imagefile.h"
  16. #include "textdraw.h"
  17. //---------------------------------------------------------------------------
  18. HRESULT MatchThemeClass(LPCTSTR pszAppName, LPCTSTR pszClassId,
  19. CUxThemeFile *pThemeFile, int *piOffset, int *piClassNameOffset)
  20. {
  21. THEMEHDR *pHdr = (THEMEHDR *)pThemeFile->_pbThemeData;
  22. MIXEDPTRS u;
  23. u.pb = pThemeFile->_pbThemeData + pHdr->iSectionIndexOffset;
  24. DWORD dwCount = pHdr->iSectionIndexLength/sizeof(APPCLASSLIVE);
  25. APPCLASSLIVE *acl = (APPCLASSLIVE *)u.pb;
  26. for (DWORD i=0; i < dwCount; i++, acl++)
  27. {
  28. if (acl->dwAppNameIndex)
  29. {
  30. if ((! pszAppName) || (! *pszAppName))
  31. continue; // not a match
  32. LPCWSTR pszApp = ThemeString(pThemeFile, acl->dwAppNameIndex);
  33. if (AsciiStrCmpI(pszAppName, pszApp) != 0)
  34. continue; // not a match
  35. }
  36. if (acl->dwClassNameIndex)
  37. {
  38. LPCWSTR pszClass = ThemeString(pThemeFile, acl->dwClassNameIndex);
  39. if (AsciiStrCmpI(pszClassId, pszClass)==0) // matches
  40. {
  41. *piOffset = acl->iIndex;
  42. *piClassNameOffset = acl->dwClassNameIndex;
  43. return S_OK;
  44. }
  45. }
  46. }
  47. return MakeError32(ERROR_NOT_FOUND); // not found
  48. }
  49. //---------------------------------------------------------------------------
  50. HRESULT MatchThemeClassList(HWND hwnd, LPCTSTR pszClassIdList,
  51. CUxThemeFile *pThemeFile, int *piOffset, int *piClassNameOffset)
  52. {
  53. LPCTSTR pszAppName = NULL;
  54. WCHAR *pszIdListBuff = NULL;
  55. WCHAR szAppSubName[MAX_PATH];
  56. WCHAR szIdSubName[MAX_PATH];
  57. int len;
  58. Log(LOG_TM, L"MatchThemeClassList(): classlist=%s", pszClassIdList);
  59. HRESULT hr = S_OK;
  60. if (! pszClassIdList)
  61. return MakeError32(E_INVALIDARG);
  62. //---- first check Hwnd IdList substitutions ----
  63. if (hwnd)
  64. {
  65. ATOM atomIdSub = (ATOM)GetProp(hwnd, MAKEINTATOM(GetThemeAtom(THEMEATOM_SUBIDLIST)));
  66. if (atomIdSub)
  67. {
  68. if (GetAtomName(atomIdSub, szIdSubName, ARRAYSIZE(szIdSubName)))
  69. {
  70. pszClassIdList = szIdSubName;
  71. Log(LOG_TM, L"MatchThemeClassList: hwnd prop IdList OVERRIDE: %s", pszClassIdList);
  72. }
  73. }
  74. }
  75. //---- now check Hwnd AppName substitutions ----
  76. if (hwnd)
  77. {
  78. ATOM atomAppSub = (ATOM)GetProp(hwnd, MAKEINTATOM(GetThemeAtom(THEMEATOM_SUBAPPNAME)));
  79. if (atomAppSub)
  80. {
  81. if (GetAtomName(atomAppSub, szAppSubName, ARRAYSIZE(szAppSubName)))
  82. {
  83. pszAppName = szAppSubName;
  84. Log(LOG_TM, L"MatchThemeClassList: hwnd prop AppName OVERRIDE: %s", pszAppName);
  85. }
  86. }
  87. }
  88. //---- make a copy of pszClassIdList ----
  89. len = lstrlen(pszClassIdList);
  90. pszIdListBuff = new WCHAR[len+1];
  91. if (! pszIdListBuff)
  92. {
  93. hr = MakeError32(E_OUTOFMEMORY);
  94. goto exit;
  95. }
  96. lstrcpy(pszIdListBuff, pszClassIdList);
  97. LPTSTR classId;
  98. BOOL fContinue;
  99. classId = pszIdListBuff;
  100. fContinue = TRUE;
  101. //---- check each ClassId in the list ----
  102. while (fContinue)
  103. {
  104. fContinue = lstrtoken(classId, _TEXT(';'));
  105. hr = MatchThemeClass(pszAppName, classId, pThemeFile, piOffset, piClassNameOffset);
  106. if (SUCCEEDED(hr))
  107. break;
  108. classId += lstrlen(classId)+1;
  109. }
  110. exit:
  111. if (pszIdListBuff)
  112. delete [] pszIdListBuff;
  113. return hr;
  114. }
  115. //---------------------------------------------------------------------------
  116. HTHEME _OpenThemeDataFromFile(HTHEMEFILE hLoadedThemeFile, HWND hwnd,
  117. LPCWSTR pszClassIdList, DWORD dwFlags)
  118. {
  119. HRESULT hr = S_OK;
  120. RESOURCE CUxThemeFile *pThemeFile = (CUxThemeFile *)hLoadedThemeFile;
  121. int iOffset;
  122. int iClassNameOffset;
  123. HTHEME hTheme = NULL;
  124. //---- match classid list to theme and get the offset ----
  125. hr = MatchThemeClassList(hwnd, pszClassIdList, pThemeFile, &iOffset,
  126. &iClassNameOffset);
  127. if (FAILED(hr))
  128. {
  129. Log(LOG_TMOPEN, L"hLoadedThemeFile: No match for class=%s", pszClassIdList);
  130. goto exit;
  131. }
  132. hr = g_pRenderList->OpenRenderObject(pThemeFile, iOffset, iClassNameOffset, NULL,
  133. NULL, hwnd, dwFlags, &hTheme);
  134. if (FAILED(hr))
  135. goto exit;
  136. //---- store hTheme with window ----
  137. if (! (dwFlags & OTD_NONCLIENT))
  138. {
  139. //---- store the hTheme so we know its themed ----
  140. if (hwnd)
  141. SetProp(hwnd, MAKEINTATOM(GetThemeAtom(THEMEATOM_HTHEME)), (void *)hTheme);
  142. }
  143. Log(LOG_TMOPEN, L"hLoadedThemeFile: returning hTheme=0x%x", hTheme);
  144. exit:
  145. SET_LAST_ERROR(hr);
  146. return hTheme;
  147. }
  148. //---------------------------------------------------------------------------
  149. HTHEME _OpenThemeData(HWND hwnd, LPCWSTR pszClassIdList, DWORD dwFlags)
  150. {
  151. HRESULT hr = S_OK;
  152. RESOURCE CUxThemeFile *pThemeFile = NULL;
  153. HTHEME hTheme = NULL;
  154. BOOL fOk;
  155. DWORD dwAppFlags;
  156. SET_LAST_ERROR(hr);
  157. if (! g_fUxthemeInitialized)
  158. goto exit;
  159. Log(LOG_TMOPEN, L"_OpenThemeData: hwnd=0x%x, ClassIdList=%s", hwnd, pszClassIdList);
  160. //---- remove previous HTHEME property ----
  161. if (hwnd)
  162. RemoveProp(hwnd, MAKEINTATOM(GetThemeAtom(THEMEATOM_HTHEME)));
  163. if (! g_pAppInfo->AppIsThemed()) // this process has been excluded from theming
  164. {
  165. Log(LOG_TMOPEN, L"App not themed");
  166. hr = MakeError32(ERROR_NOT_FOUND);
  167. SET_LAST_ERROR(hr);
  168. goto exit;
  169. }
  170. //---- ensure app allows this type of themeing ----
  171. dwAppFlags = g_pAppInfo->GetAppFlags();
  172. if (dwFlags & OTD_NONCLIENT)
  173. {
  174. fOk = ((dwAppFlags & STAP_ALLOW_NONCLIENT) != 0);
  175. }
  176. else
  177. {
  178. fOk = ((dwAppFlags & STAP_ALLOW_CONTROLS) != 0);
  179. }
  180. if (! fOk)
  181. {
  182. Log(LOG_TMOPEN, L"AppFlags don't allow theming client/nonclient windows");
  183. hr = MakeError32(ERROR_NOT_FOUND);
  184. SET_LAST_ERROR(hr);
  185. goto exit;
  186. }
  187. //---- find Theme File for this HWND and REFCOUNT it for _OpenThemeDataFromFile call ----
  188. hr = GetHwndThemeFile(hwnd, pszClassIdList, &pThemeFile);
  189. if (FAILED(hr))
  190. {
  191. Log(LOG_TMOPEN, L"no theme entry for this classidlist: %s", pszClassIdList);
  192. SET_LAST_ERROR(hr);
  193. goto exit;
  194. }
  195. hTheme = _OpenThemeDataFromFile(pThemeFile, hwnd, pszClassIdList, dwFlags);
  196. exit:
  197. //---- always close the pThemeFile here and decrement its refcnt ----
  198. //---- case 1: if we failed to get an HTHEME, we don't want a refcnt on it ----
  199. //---- case 2: if we do get an HTHEME, it get's its own refcnt on it ----
  200. if (pThemeFile)
  201. g_pAppInfo->CloseThemeFile(pThemeFile);
  202. return hTheme;
  203. }
  204. //---------------------------------------------------------------------------
  205. HRESULT GetHwndThemeFile(HWND hwnd, LPCWSTR pszClassIdList, CUxThemeFile **ppThemeFile)
  206. {
  207. HRESULT hr = S_OK;
  208. //----- check input params ----
  209. if ((! pszClassIdList) || (! *pszClassIdList))
  210. {
  211. hr = MakeError32(E_INVALIDARG);
  212. goto exit;
  213. }
  214. //---- get a shared CUxThemeFile object for the hwnd ----
  215. hr = g_pAppInfo->OpenWindowThemeFile(hwnd, ppThemeFile);
  216. if (FAILED(hr))
  217. goto exit;
  218. exit:
  219. return hr;
  220. }
  221. //---------------------------------------------------------------------------
  222. HRESULT _OpenThemeFileFromData(CRenderObj *pRender, HTHEMEFILE *phThemeFile)
  223. {
  224. LogEntry(L"OpenThemeFileFromData");
  225. HRESULT hr = S_OK;
  226. *phThemeFile = pRender->_pThemeFile;
  227. LogExit(L"OpenThemeFileFromData");
  228. return hr;
  229. }
  230. //---------------------------------------------------------------------------
  231. void ClearExStyleBits(HWND hwnd)
  232. {
  233. Log(LOG_COMPOSITE, L"ClearExStyleBits called for hwnd=0x%x", hwnd);
  234. //---- see if window needs its exstyle cleared ----
  235. DWORD dwFlags = PtrToInt(GetProp(hwnd, MAKEINTATOM(GetThemeAtom(THEMEATOM_PROPFLAGS))));
  236. if (dwFlags & (PROPFLAGS_RESET_TRANSPARENT | PROPFLAGS_RESET_COMPOSITED))
  237. {
  238. DWORD dwExStyle = GetWindowLong(hwnd, GWL_EXSTYLE);
  239. if (dwFlags & PROPFLAGS_RESET_TRANSPARENT)
  240. {
  241. Log(LOG_COMPOSITE, L"Clearning WS_EX_TRANSPARENT for hwnd=0x%x", hwnd);
  242. dwExStyle &= ~(WS_EX_TRANSPARENT);
  243. }
  244. if (dwFlags & PROPFLAGS_RESET_COMPOSITED)
  245. {
  246. Log(LOG_COMPOSITE, L"Clearning WS_EX_COMPOSITED for hwnd=0x%x", hwnd);
  247. dwExStyle &= ~(WS_EX_COMPOSITED);
  248. }
  249. //---- reset the correct ExStyle bits ----
  250. SetWindowLong(hwnd, GWL_EXSTYLE, dwExStyle);
  251. //---- reset the property flags ----
  252. dwFlags &= ~(PROPFLAGS_RESET_TRANSPARENT | PROPFLAGS_RESET_COMPOSITED);
  253. SetProp(hwnd, MAKEINTATOM(GetThemeAtom(THEMEATOM_PROPFLAGS)), IntToPtr(dwFlags));
  254. }
  255. }
  256. //---------------------------------------------------------------------------
  257. void AddPropFlags(HWND hwnd, DWORD dwNewFlags)
  258. {
  259. DWORD dwFlags = PtrToInt(GetProp(hwnd, MAKEINTATOM(GetThemeAtom(THEMEATOM_PROPFLAGS))));
  260. dwFlags |= dwNewFlags;
  261. if (dwNewFlags & PROPFLAGS_RESET_TRANSPARENT)
  262. Log(LOG_COMPOSITE, L"Setting TRANSPARENT prop flag for hwnd=0x%x", hwnd);
  263. if (dwNewFlags & PROPFLAGS_RESET_COMPOSITED)
  264. Log(LOG_COMPOSITE, L"Setting COMPOSITED prop flag for hwnd=0x%x", hwnd);
  265. SetProp(hwnd, MAKEINTATOM(GetThemeAtom(THEMEATOM_PROPFLAGS)), IntToPtr(dwFlags));
  266. }
  267. //---------------------------------------------------------------------------
  268. //---------------------------------------------------------------------------
  269. //---------------------------------------------------------------------------
  270. struct EPW
  271. {
  272. WNDENUMPROC lpCallBackCaller;
  273. LPARAM lParamCaller;
  274. HWND *pHwnds; // OPTIONAL list of hwnds to remove as they are enum-ed
  275. int iCountHwnds; // count of remaining HWND's in pHwnds
  276. };
  277. //---------------------------------------------------------------------------
  278. BOOL CALLBACK ChildWinCallBack(HWND hwnd, LPARAM lParam)
  279. {
  280. BOOL fResult = TRUE;
  281. if (IsWindowProcess(hwnd, g_dwProcessId))
  282. {
  283. EPW *pEpw = (EPW *)lParam;
  284. fResult = pEpw->lpCallBackCaller(hwnd, pEpw->lParamCaller);
  285. //---- remove from list ----
  286. if (pEpw->pHwnds)
  287. {
  288. for (int i=0; i < pEpw->iCountHwnds; i++)
  289. {
  290. if (pEpw->pHwnds[i] == hwnd) // found it
  291. {
  292. pEpw->iCountHwnds--;
  293. if (i != pEpw->iCountHwnds) // switch last with current
  294. pEpw->pHwnds[i] = pEpw->pHwnds[pEpw->iCountHwnds];
  295. break;
  296. }
  297. }
  298. }
  299. }
  300. return fResult;
  301. }
  302. //---------------------------------------------------------------------------
  303. BOOL CALLBACK TopWinCallBack(HWND hwnd, LPARAM lParam)
  304. {
  305. BOOL fResult = ChildWinCallBack(hwnd, lParam);
  306. if (fResult)
  307. {
  308. //---- we need to check for hwnd having at least one child ----
  309. //---- since EnumChildWindows() of a hwnd without children ----
  310. //---- returns an error ----
  311. if (GetWindow(hwnd, GW_CHILD)) // if hwnd has at least one child
  312. {
  313. fResult = EnumChildWindows(hwnd, ChildWinCallBack, lParam);
  314. }
  315. }
  316. return fResult;
  317. }
  318. //---------------------------------------------------------------------------
  319. BOOL CALLBACK DesktopWinCallBack(LPTSTR lpszDesktop, LPARAM lParam)
  320. {
  321. //---- open the desktop ----
  322. HDESK hDesk = OpenDesktop(lpszDesktop, DF_ALLOWOTHERACCOUNTHOOK, FALSE,
  323. DESKTOP_READOBJECTS | DESKTOP_ENUMERATE);
  324. if (hDesk)
  325. {
  326. //---- enum windows on desktop ----
  327. EnumDesktopWindows(hDesk, TopWinCallBack, lParam);
  328. CloseDesktop(hDesk);
  329. }
  330. return TRUE; // return values from EnumDesktopWindows() not reliable
  331. }
  332. //---------------------------------------------------------------------------
  333. BOOL EnumProcessWindows(WNDENUMPROC lpEnumFunc, LPARAM lParam)
  334. {
  335. HWND *pHwnds = NULL;
  336. int iCount = 0;
  337. EPW epw = {lpEnumFunc, lParam};
  338. //---- get list of themed windows on "foreign" desktops for this process ----
  339. BOOL fGotForeignList = g_pAppInfo->GetForeignWindows(&pHwnds, &iCount);
  340. if (fGotForeignList)
  341. {
  342. epw.pHwnds = pHwnds;
  343. epw.iCountHwnds = iCount;
  344. }
  345. //---- this will enum all windows for this process (all desktops, all child levels) ----
  346. BOOL fOk = EnumDesktops(GetProcessWindowStation(), DesktopWinCallBack, (LPARAM)&epw);
  347. if ((fOk) && (fGotForeignList) && (epw.iCountHwnds))
  348. {
  349. //---- get updated count ----
  350. iCount = epw.iCountHwnds;
  351. //---- turn off list maintainance ----
  352. epw.pHwnds = NULL;
  353. epw.iCountHwnds = 0;
  354. Log(LOG_TMHANDLE, L"---- Enuming %d Foreign Windows ----", iCount);
  355. //---- enumerate remaining hwnd's in list ----
  356. for (int i=0; i < iCount; i++)
  357. {
  358. fOk = ChildWinCallBack(pHwnds[i], (LPARAM)&epw);
  359. if (! fOk)
  360. break;
  361. }
  362. }
  363. if (pHwnds)
  364. delete [] pHwnds;
  365. return fOk;
  366. }
  367. //---------------------------------------------------------------------------
  368. //---------------------------------------------------------------------------
  369. //---------------------------------------------------------------------------
  370. BOOL CALLBACK DumpCallback(HWND hwnd, LPARAM lParam)
  371. {
  372. WCHAR szName[MAX_PATH];
  373. WCHAR szDeskName[MAX_PATH] = {0};
  374. BOOL fIsForeign = TRUE;
  375. //---- get classname of window ----
  376. GetClassName(hwnd, szName, MAX_PATH);
  377. //---- get desktop name for window ----
  378. if (GetWindowDesktopName(hwnd, szDeskName, ARRAYSIZE(szDeskName)))
  379. {
  380. if (AsciiStrCmpI(szDeskName, L"default")==0)
  381. {
  382. fIsForeign = FALSE;
  383. }
  384. }
  385. if (fIsForeign)
  386. {
  387. Log(LOG_WINDUMP, L" hwnd=0x%x, class=%s, DESK=%s", hwnd, szName, szDeskName);
  388. }
  389. else
  390. {
  391. Log(LOG_WINDUMP, L" hwnd=0x%x, class=%s", hwnd, szName);
  392. }
  393. return TRUE;
  394. }
  395. //---------------------------------------------------------------------------
  396. void WindowDump(LPCWSTR pszWhere)
  397. {
  398. if (LogOptionOn(LO_WINDUMP))
  399. {
  400. Log(LOG_WINDUMP, L"---- Window Dump for Process [%s] ----", pszWhere);
  401. EnumProcessWindows(DumpCallback, NULL);
  402. }
  403. else
  404. {
  405. Log(LOG_TMHANDLE, L"---- %s ----", pszWhere);
  406. }
  407. }
  408. //---------------------------------------------------------------------------