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.

1483 lines
48 KiB

  1. //---------------------------------------------------------------------------//
  2. // sethook.cpp - Window and DefWindowProc hooking impl.
  3. //---------------------------------------------------------------------------//
  4. #include "stdafx.h"
  5. #include "sethook.h"
  6. #include "handlers.h"
  7. #include "scroll.h"
  8. #include "nctheme.h"
  9. #include "scroll.h"
  10. #include <uxthemep.h>
  11. #include "info.h"
  12. #include "services.h"
  13. #include "appinfo.h"
  14. #include "tmreg.h"
  15. #include "globals.h"
  16. #include "renderlist.h"
  17. //---------------------------------------------------//
  18. // statics
  19. //---------------------------------------------------//
  20. static int _fShouldEnableApiHooks = -1; // unitialized value
  21. static BOOL _fUnhooking = FALSE;
  22. static LONG _cInitUAH = 0;
  23. static BOOL _fSysMetCall = FALSE; // anti-recursion bit on classic sysmet calls.
  24. static CRITICAL_SECTION _csSysMetCall = {0}; // serialize ClassicXXX calls when hooks inactive.
  25. extern CRITICAL_SECTION _csThemeMet; // protects access to _nctmCurrent in nctheme.cpp
  26. extern CRITICAL_SECTION _csNcSysMet; // protects access to _ncmCurrent in nctheme.cpp
  27. extern CRITICAL_SECTION _csNcPaint; // protects thread-in-NCPAINT collection
  28. typedef enum { PRE, DEF, POST } ePROCTYPE;
  29. inline void ENTER_CLASSICSYSMETCALL() {
  30. if (IsAppThemed())
  31. {
  32. EnterCriticalSection(&_csSysMetCall);
  33. _fSysMetCall = TRUE;
  34. }
  35. }
  36. inline void LEAVE_CLASSICSYSMETCALL() {
  37. if (_fSysMetCall)
  38. {
  39. _fSysMetCall = FALSE;
  40. LeaveCriticalSection(&_csSysMetCall);
  41. }
  42. }
  43. inline BOOL IN_CLASSICSYSMETCALL() {
  44. return _fSysMetCall;
  45. }
  46. //---------------------------------------------------------------------------//
  47. typedef struct
  48. {
  49. HINSTANCE hInst; // DLL hook instance
  50. USERAPIHOOK uahReal;
  51. } UXTHEMEHOOKS, *PUXTHEMEHOOKS;
  52. //--------------------------------------------------------------------//
  53. //---- Hook Instance static (unprotected - thread unsafe) ----
  54. static UXTHEMEHOOKS _hookinf = {0}; // one-and-only instance.
  55. //---------------------------------------------------------------------------//
  56. // Module name for LoadLibrary
  57. #define DLLNAME TEXT(".\\UxTheme.dll")
  58. //---------------------------------------------------------------------------//
  59. // UserApiHook callback functions
  60. extern "C"
  61. {
  62. BOOL WINAPI ThemeInitApiHook( DWORD dwCmd, void * pvData );
  63. LRESULT WINAPI ThemeDefWindowProcA( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
  64. LRESULT CALLBACK ThemeDefWindowProcW( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam );
  65. int CALLBACK ThemeSetScrollInfoProc( HWND hwnd, int nBar, IN LPCSCROLLINFO psi, BOOL fRedraw );
  66. BOOL CALLBACK ThemeGetScrollInfoProc( HWND hwnd, int nBar, IN OUT LPSCROLLINFO psi );
  67. BOOL CALLBACK ThemeEnableScrollInfoProc( HWND hwnd, UINT nSBFlags, UINT nArrows );
  68. BOOL CALLBACK ThemeAdjustWindowRectEx( LPRECT lprc, DWORD dwStyle, BOOL bMenu, DWORD dwExStyle);
  69. BOOL CALLBACK ThemeSetWindowRgn( HWND hwnd, HRGN hrgn, BOOL fRedraw);
  70. int CALLBACK ThemeGetSystemMetrics( int iMetric );
  71. BOOL CALLBACK ThemeSystemParametersInfoA( UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni);
  72. BOOL CALLBACK ThemeSystemParametersInfoW( UINT uiAction, UINT uiParam, PVOID pvParam, UINT fWinIni);
  73. BOOL CALLBACK ThemeDrawFrameControl( IN HDC hdc, IN OUT LPRECT, IN UINT, IN UINT );
  74. BOOL CALLBACK ThemeDrawCaption( IN HWND, IN HDC, IN CONST RECT *, IN UINT);
  75. VOID CALLBACK ThemeMDIRedrawFrame( IN HWND hwndChild, BOOL fAdd );
  76. }
  77. //---------------------------------------------------------------------------//
  78. void OnHooksEnabled(); // forward
  79. void OnHooksDisabled(BOOL fShutDown); // forward
  80. BOOL NewThemeCheck(int iChangeNum, BOOL fMsgCheck); // forward
  81. //---------------------------------------------------------------------------//
  82. BOOL WINAPI ThemeHookStartup()
  83. {
  84. _hookinf.uahReal.cbSize = sizeof(_hookinf.uahReal);
  85. HandlerTableInit();
  86. InitializeCriticalSection( &_csSysMetCall );
  87. InitializeCriticalSection( &_csThemeMet );
  88. InitializeCriticalSection( &_csNcSysMet );
  89. InitializeCriticalSection( &_csNcPaint );
  90. InitNcThemeMetrics(NULL);
  91. Log(LOG_TMCHANGE, L"UxTheme - ThemeHookStartup");
  92. WindowDump(L"Startup");
  93. return TRUE;
  94. }
  95. //---------------------------------------------------------------------------//
  96. BOOL WINAPI ThemeHookShutdown()
  97. {
  98. _fUnhooking = TRUE;
  99. if (HOOKSACTIVE()) // we are hooking USER msgs
  100. {
  101. //---- tell user that we gotta go ----
  102. _hookinf.uahReal.pfnForceResetUserApiHook(g_hInst);
  103. InterlockedExchange( (LONG*)&g_eThemeHookState, HS_UNINITIALIZED );
  104. OnHooksDisabled(TRUE);
  105. }
  106. DeleteCriticalSection( &_csSysMetCall );
  107. DeleteCriticalSection( &_csThemeMet );
  108. DeleteCriticalSection( &_csNcSysMet );
  109. DeleteCriticalSection( &_csNcPaint );
  110. ClearNcThemeMetrics();
  111. NcClearNonclientMetrics();
  112. #ifdef DEBUG
  113. CThemeWnd::SpewLeaks();
  114. #endif DEBUG
  115. return TRUE;
  116. }
  117. //---------------------------------------------------------------------------//
  118. // Loads a DLL instance and retrieves addresses of key hook exports.
  119. BOOL LoadHookInstance()
  120. {
  121. if( _hookinf.hInst != NULL )
  122. {
  123. #ifdef DEBUG
  124. Log(LOG_ALWAYS, L"%s hook instance already protected; refcount mismatch. No-op'ing self-load\n", DLLNAME);
  125. #endif DEBUG
  126. return TRUE;
  127. }
  128. //-- Load a DLL instance
  129. _hookinf.hInst = LoadLibrary(DLLNAME);
  130. if( !_hookinf.hInst )
  131. {
  132. Log(LOG_ALWAYS, L"Cannot find dll: %s\r\r\n", DLLNAME);
  133. return FALSE;
  134. }
  135. return TRUE;
  136. }
  137. //---------------------------------------------------------------------------
  138. inline BOOL IsTargetProcess(HWND hwnd = NULL)
  139. {
  140. //---- if not initialize, leave everything alone ----
  141. if (! g_fUxthemeInitialized)
  142. return FALSE;
  143. //---- ensure this window is in our process ----
  144. return (HOOKSACTIVE() && (hwnd ? IsWindowProcess(hwnd, g_dwProcessId) : TRUE));
  145. }
  146. //---------------------------------------------------------------------------
  147. inline void SpewHookExceptionInfo(
  148. LPCSTR pszMsg,
  149. HWND hwnd,
  150. UINT uMsg,
  151. WPARAM wParam,
  152. LPARAM lParam )
  153. {
  154. #ifdef _ENABLE_HOOK_EXCEPTION_HANDLING_
  155. Log(LOG_ERROR, L"*** Theme Hook Exception Handler ***" );
  156. Log(LOG_ERROR, L"--- %s hwnd: %08lX, uMsg: %04lX, wParam: %08lX, lParam: %08lX.",
  157. pszMsg, hwnd, uMsg, wParam, lParam );
  158. #endif _ENABLE_HOOK_EXCEPTION_HANDLING_
  159. }
  160. //---------------------------------------------------------------------------
  161. // Helper: initializes THEME_MSG structure in prep for call to msg handler
  162. inline void _InitThemeMsg(
  163. PTHEME_MSG ptm,
  164. MSGTYPE msgtype,
  165. BOOL bUnicode,
  166. HWND hwnd,
  167. UINT uMsg,
  168. WPARAM wParam,
  169. LPARAM lParam,
  170. LRESULT lRet = 0,
  171. WNDPROC pfnDefProc = NULL )
  172. {
  173. #ifdef DEBUG
  174. if( MSGTYPE_DEFWNDPROC == msgtype )
  175. {
  176. ASSERT( pfnDefProc != NULL ); // DWP, handlers require default processing
  177. }
  178. else
  179. {
  180. ASSERT( NULL == pfnDefProc ); // no default processing for pre/post OWP, DDP callbacks
  181. }
  182. #endif DEBUG
  183. ptm->hwnd = hwnd;
  184. ptm->uMsg = uMsg;
  185. ptm->uCodePage = bUnicode ? CP_WINUNICODE : GetACP();
  186. ptm->wParam = wParam;
  187. ptm->lParam = lParam;
  188. ptm->type = msgtype;
  189. ptm->lRet = lRet;
  190. ptm->pfnDefProc = pfnDefProc;
  191. ptm->fHandled = FALSE;
  192. }
  193. //---------------------------------------------------------------------------
  194. #ifdef UNICODE
  195. const BOOL _fUnicode = TRUE;
  196. #else // UNICODE
  197. const BOOL _fUnicode = FALSE;
  198. #endif // UNICODE
  199. //---------------------------------------------------------------------------
  200. void _PreprocessThemeChanged(HWND hwnd, WPARAM wParam, LPARAM lParam, ePROCTYPE eCallType,
  201. UINT *puDisposition)
  202. {
  203. //---- is this msg meant for this process? ----
  204. if (IS_THEME_CHANGE_TARGET(lParam))
  205. {
  206. BOOL fActive = ((lParam & WTC_THEMEACTIVE) != 0);
  207. if (eCallType == PRE) // only do this on the Pre (once is enough)
  208. {
  209. //Log(LOG_TMCHANGE, L"hwnd=0x%x received WM_THEMECHANGED, changenum=0x%x",
  210. // hwnd, wParam);
  211. ClearExStyleBits(hwnd);
  212. }
  213. //---- this part still needs to be done in both cases ----
  214. if(! (fActive))
  215. *puDisposition |= HMD_THEMEDETACH;
  216. else
  217. *puDisposition |= HMD_CHANGETHEME;
  218. }
  219. }
  220. //---------------------------------------------------------------------------
  221. BOOL CALLBACK TriggerCallback(HWND hwnd, LPARAM lParam)
  222. {
  223. LPARAM *plParams = (LPARAM *)lParam;
  224. SafeSendMessage(hwnd, WM_THEMECHANGED, plParams[0], plParams[1]);
  225. return TRUE;
  226. }
  227. //---------------------------------------------------------------------------
  228. void _PreprocessThemeChangedTrigger(HWND hwnd, WPARAM wParam, LPARAM lParamMixed)
  229. {
  230. int iLoadId = (int(lParamMixed) >> 4);
  231. LPARAM lParamBits = (int(lParamMixed) & 0xf);
  232. BOOL fFirstMsg = NewThemeCheck((int)wParam, TRUE);
  233. if (fFirstMsg)
  234. {
  235. //Log(LOG_TMLOAD, L"hwnd=0x%x received NEW WM_THEMECHANGED_TRIGGER, loadid=%d", hwnd,
  236. // iLoadId);
  237. //---- send WM_THEMECHANGED to all windows in this process ----
  238. //---- so they let go of previous theme now ----
  239. LPARAM lParams[2] = {wParam, lParamBits};
  240. EnumProcessWindows(TriggerCallback, (LPARAM)&lParams);
  241. if (iLoadId) // there was a previous theme
  242. {
  243. g_pRenderList->FreeRenderObjects(iLoadId);
  244. }
  245. }
  246. }
  247. //---------------------------------------------------------------------------
  248. inline UINT _PreprocessHookedMsg(
  249. HWND hwnd,
  250. UINT uMsg,
  251. WPARAM wParam,
  252. LPARAM lParam,
  253. ePROCTYPE eCallType )
  254. {
  255. UINT uDisposition = HMD_NIL;
  256. static bool s_fTriggerDone = false; // For some USER-owned windows, we don't get PRE, only DEF.
  257. switch( uMsg )
  258. {
  259. case WM_THEMECHANGED:
  260. {
  261. _PreprocessThemeChanged(hwnd, wParam, lParam, eCallType, &uDisposition);
  262. break;
  263. }
  264. case WM_NCDESTROY:
  265. uDisposition |= HMD_WINDOWDESTROY;
  266. break;
  267. case WM_STYLECHANGED:
  268. uDisposition |= HMD_REATTACH;
  269. break;
  270. case WM_THEMECHANGED_TRIGGER:
  271. //---- NULL WPARAM means this is really a normal WM_UAHINIT msgs (shared msg num) ----
  272. if (wParam)
  273. {
  274. if (eCallType == PRE // This is the normal case
  275. || (eCallType == DEF && !s_fTriggerDone)) // USER server-side window, we missed the PRE
  276. {
  277. Log(LOG_TMCHANGE, L"Recv'd: WM_THEMECHANGED_TRIGGER, Change Num=%d", wParam);
  278. _PreprocessThemeChangedTrigger(hwnd, wParam, lParam);
  279. }
  280. if (eCallType == PRE) // Mark it done for the incoming DEF call
  281. {
  282. s_fTriggerDone = true;
  283. }
  284. else // After we're done, reset the flag for the next theme change
  285. {
  286. s_fTriggerDone = false;
  287. }
  288. }
  289. break;
  290. }
  291. return uDisposition;
  292. }
  293. //---------------------------------------------------------------------------
  294. // Pre-CallWndProc hook procedure
  295. BOOL CALLBACK ThemePreWndProc(
  296. HWND hwnd,
  297. UINT uMsg,
  298. WPARAM wParam,
  299. LPARAM lParam,
  300. LRESULT* plRes,
  301. VOID** ppvParam )
  302. {
  303. // Note: From this point until the point we invoke a message handler,
  304. // We need to take care that we don't do anything (including DEBUG-only code)
  305. // that causes a message to be sent to the window.
  306. BOOL fHandled = FALSE;
  307. //----------//
  308. LogEntryMsg(L"ThemePreWndProc", hwnd, uMsg);
  309. if( IsTargetProcess(hwnd) )
  310. {
  311. // Retrieve window object from handle
  312. CThemeWnd *pwnd = CThemeWnd::FromHwnd(hwnd);
  313. // #443100 InstallShield installs a global CBT hook. Their hook handler
  314. // generates messages prior to the window receiving WM_NCCREATE which
  315. // causes us to exile the window prematurely because the window is temporarily
  316. // parented by HWND_MESSAGE
  317. BOOL fPrematureExile = (EXILED_THEMEWND(pwnd) && WM_NCCREATE == uMsg);
  318. if ( (uMsg != WM_NCCREATE) || fPrematureExile )
  319. {
  320. // Pre-process WM_THEMECHANGE message.
  321. // Note: Pre-OWP does a detach only on theme removal. Post-OWP takes care
  322. // of window death.
  323. UINT uDisp = _PreprocessHookedMsg( hwnd, uMsg, wParam, lParam, PRE );
  324. BOOL fLifeIsShort = TESTFLAG( uDisp, HMD_THEMEDETACH|HMD_WINDOWDESTROY );
  325. BOOL fDetach = TESTFLAG( uDisp, HMD_THEMEDETACH );
  326. if( _WindowHasTheme(hwnd) || fLifeIsShort )
  327. {
  328. // On STYLECHANGED or WM_THEMECHANGE,
  329. // try reattaching window that was previously rejected or failed, resp.
  330. if( (REJECTED_THEMEWND(pwnd) && TESTFLAG(uDisp, HMD_REATTACH)) ||
  331. (FAILED_THEMEWND(pwnd) && WM_THEMECHANGED == uMsg) ||
  332. fPrematureExile )
  333. {
  334. CThemeWnd::Detach(hwnd, FALSE); // remove rejection tag.
  335. pwnd = NULL;
  336. }
  337. // Attach window object if applicable.
  338. if( pwnd == THEMEWND_NIL && !(fLifeIsShort || _fUnhooking) )
  339. {
  340. pwnd = CThemeWnd::Attach(hwnd); // NOTE: Handle -1 ThemeWnd
  341. }
  342. if( VALID_THEMEWND(pwnd) )
  343. {
  344. // protect our themewnd pointer
  345. pwnd->AddRef();
  346. // set up a theme message block
  347. THEME_MSG tm;
  348. _InitThemeMsg( &tm, MSGTYPE_PRE_WNDPROC, _fUnicode, hwnd, uMsg, wParam, lParam );
  349. // is this a message we want to handle?
  350. HOOKEDMSGHANDLER pfnPre;
  351. if( FindOwpHandler( uMsg, &pfnPre, NULL ) )
  352. {
  353. // call the message handler
  354. LRESULT lRetHandler = pfnPre( pwnd, &tm );
  355. fHandled = tm.fHandled;
  356. if( fHandled )
  357. {
  358. *plRes = lRetHandler;
  359. }
  360. }
  361. // decrement themewnd ref
  362. pwnd->Release();
  363. }
  364. }
  365. if( fDetach )
  366. {
  367. CThemeWnd::Detach( hwnd, uDisp );
  368. pwnd = NULL;
  369. }
  370. }
  371. }
  372. LogExitMsg(L"ThemePreWndProc");
  373. return fHandled;
  374. }
  375. //---------------------------------------------------------------------------
  376. // Post-CallWndProc hook procedure
  377. BOOL CALLBACK ThemePostWndProc(
  378. HWND hwnd,
  379. UINT uMsg,
  380. WPARAM wParam,
  381. LPARAM lParam,
  382. LRESULT* plRes,
  383. VOID** ppvParam )
  384. {
  385. // Note: From this point until the point we invoke a message handler,
  386. // We need to take care that we don't do anything (including DEBUG-only code)
  387. // that causes a message to be sent to the window.
  388. LogEntryMsg(L"ThemePostWndProc", hwnd, uMsg);
  389. BOOL fHandled = FALSE;
  390. if( IsTargetProcess(hwnd) && WM_NCCREATE != uMsg )
  391. {
  392. UINT uDisp = _PreprocessHookedMsg( hwnd, uMsg, wParam, lParam, POST );
  393. BOOL fDetach = TESTFLAG(uDisp, HMD_WINDOWDESTROY);
  394. BOOL fRevoked = FALSE;
  395. CThemeWnd* pwnd = CThemeWnd::FromHwnd(hwnd);
  396. if( _WindowHasTheme(hwnd) && VALID_THEMEWND(pwnd) )
  397. {
  398. // protect our themewnd pointer
  399. pwnd->AddRef();
  400. // is this a message we want to handle?
  401. HOOKEDMSGHANDLER pfnPost = NULL;
  402. if( FindOwpHandler( uMsg, NULL, &pfnPost ) )
  403. {
  404. // set up a theme message block
  405. THEME_MSG tm;
  406. _InitThemeMsg( &tm, MSGTYPE_POST_WNDPROC, _fUnicode, hwnd, uMsg, wParam, lParam, *plRes );
  407. // call the message handler
  408. LRESULT lRetHandler = pfnPost( pwnd, &tm );
  409. fHandled = tm.fHandled;
  410. if( fHandled )
  411. {
  412. *plRes = lRetHandler;
  413. }
  414. }
  415. fRevoked = (pwnd->IsRevoked() && !pwnd->IsRevoked(RF_DEFER));
  416. // decrement themewnd ref
  417. pwnd->Release();
  418. }
  419. else
  420. {
  421. // special back-end processing for non-themed windows.
  422. fHandled = CThemeWnd::_PostWndProc( hwnd, uMsg, wParam, lParam, plRes );
  423. }
  424. if( fDetach )
  425. {
  426. CThemeWnd::Detach( hwnd, uDisp );
  427. pwnd = NULL; // don't touch
  428. }
  429. else if( fRevoked )
  430. {
  431. pwnd = CThemeWnd::FromHwnd(hwnd);
  432. if( VALID_THEMEWND(pwnd) )
  433. {
  434. pwnd->Revoke();
  435. pwnd = NULL; // don't touch
  436. }
  437. }
  438. }
  439. LogExitMsg(L"ThemePostWndProc");
  440. return fHandled;
  441. }
  442. //---------------------------------------------------------------------------
  443. BOOL CALLBACK ThemePreDefDlgProc(
  444. HWND hwnd,
  445. UINT uMsg,
  446. WPARAM wParam,
  447. LPARAM lParam,
  448. LRESULT* plRes,
  449. VOID** ppvData)
  450. {
  451. LogEntryMsg(L"ThemePreDefDlgProc", hwnd, uMsg);
  452. // Note: From this point until the point we invoke a message handler,
  453. // We need to take care that we don't do anything (including DEBUG-only code)
  454. // that causes a message to be sent to the window.
  455. BOOL fHandled = FALSE;
  456. CThemeWnd* pwnd = CThemeWnd::FromHwnd(hwnd);
  457. if( IsTargetProcess(hwnd) && g_pAppInfo->AppIsThemed() )
  458. {
  459. if( VALID_THEMEWND(pwnd) )
  460. {
  461. // protect our themewnd pointer
  462. pwnd->AddRef();
  463. // is this a message we want to handle?
  464. HOOKEDMSGHANDLER pfnPre = NULL;
  465. if( FindDdpHandler( uMsg, &pfnPre, NULL ) )
  466. {
  467. // set up a theme message block
  468. THEME_MSG tm;
  469. _InitThemeMsg( &tm, MSGTYPE_PRE_DEFDLGPROC, _fUnicode,
  470. hwnd, uMsg, wParam, lParam, *plRes );
  471. // call the message handler
  472. LRESULT lRetHandler = pfnPre( pwnd, &tm );
  473. fHandled = tm.fHandled;
  474. if( fHandled )
  475. {
  476. *plRes = lRetHandler;
  477. }
  478. }
  479. // decrement themewnd ref
  480. pwnd->Release();
  481. }
  482. }
  483. LogExitMsg(L"ThemePreDefDlgProc");
  484. return fHandled;
  485. }
  486. //---------------------------------------------------------------------------
  487. BOOL CALLBACK ThemePostDefDlgProc(
  488. HWND hwnd,
  489. UINT uMsg,
  490. WPARAM wParam,
  491. LPARAM lParam,
  492. LRESULT* plRes,
  493. VOID** ppvData)
  494. {
  495. LogEntryMsg(L"ThemePostDefDlgProc", hwnd, uMsg);
  496. // Note: From this point until the point we invoke a message handler,
  497. // We need to take care that we don't do anything (including DEBUG-only code)
  498. // that causes a message to be sent to the window.
  499. BOOL fHandled = FALSE;
  500. if( IsTargetProcess(hwnd) )
  501. {
  502. CThemeWnd* pwnd = CThemeWnd::FromHwnd(hwnd);
  503. if( _WindowHasTheme(hwnd) && VALID_THEMEWND(pwnd) )
  504. {
  505. // protect our themewnd pointer
  506. pwnd->AddRef();
  507. // is this a message we want to handle?
  508. HOOKEDMSGHANDLER pfnPost = NULL;
  509. if( FindDdpHandler( uMsg, NULL, &pfnPost ) )
  510. {
  511. // set up a theme message block
  512. THEME_MSG tm;
  513. _InitThemeMsg( &tm, MSGTYPE_POST_DEFDLGPROC, _fUnicode,
  514. hwnd, uMsg, wParam, lParam, *plRes );
  515. // call the message handler
  516. LRESULT lRetHandler = pfnPost( pwnd, &tm );
  517. fHandled = tm.fHandled;
  518. if( fHandled )
  519. {
  520. *plRes = lRetHandler;
  521. }
  522. }
  523. // decrement themewnd ref
  524. pwnd->Release();
  525. }
  526. else
  527. {
  528. // special back-end processing for non-themed windows.
  529. fHandled = CThemeWnd::_PostDlgProc( hwnd, uMsg, wParam, lParam, plRes );
  530. }
  531. }
  532. LogExitMsg(L"ThemePostDefDlgProc");
  533. return fHandled;
  534. }
  535. //---------------------------------------------------------------------------
  536. BOOL _ShouldInitApiHook( DWORD dwCmd, void* pvData )
  537. {
  538. if( -1 == _fShouldEnableApiHooks )
  539. {
  540. _fShouldEnableApiHooks = TRUE;
  541. if( IsDebuggerPresent() )
  542. {
  543. BOOL fHookDebuggees = TRUE;
  544. HRESULT hr = GetCurrentUserThemeInt( L"ThemeDebuggees", TRUE, &fHookDebuggees );
  545. if( SUCCEEDED(hr) && !fHookDebuggees )
  546. {
  547. _fShouldEnableApiHooks = FALSE;
  548. }
  549. }
  550. }
  551. return _fShouldEnableApiHooks;
  552. }
  553. //---------------------------------------------------------------------------
  554. // ThemeInitApiHook() - USER API subclassing initialization callback.
  555. // This is called by USER asynchronously after we call RegisterDefWindowProc().
  556. BOOL CALLBACK ThemeInitApiHook( DWORD dwCmd, void * pvData )
  557. {
  558. //Log(LOG_TMCHANGE, L"ThemeInitApiHook called with dwCmd=%d, ApiCallCount=%d", dwCmd, _cInitUAH);
  559. BOOL fRetVal = FALSE;
  560. //---- if wierd loading order has called us before DllMain(), deny hooking ----
  561. if (! g_fUxthemeInitialized)
  562. {
  563. g_fEarlyHookRequest = TRUE; // remember that we denied at least one hook request
  564. }
  565. else if( _ShouldInitApiHook( dwCmd, pvData ) )
  566. {
  567. switch (dwCmd)
  568. {
  569. case UIAH_INITIALIZE:
  570. {
  571. if( !UNHOOKING() )
  572. {
  573. int cInit = InterlockedIncrement(&_cInitUAH);
  574. if (cInit != 1) // another thread is taking (has taken) care of this
  575. {
  576. //Log(LOG_TMCHANGE, L"ThemeInitApiHook already called - will just exit");
  577. InterlockedDecrement(&_cInitUAH);
  578. }
  579. else
  580. {
  581. PUSERAPIHOOK puah = (PUSERAPIHOOK)pvData;
  582. // stash 'real' defwindowproc functions
  583. _hookinf.uahReal = *puah;
  584. puah->pfnGetScrollInfo = ThemeGetScrollInfoProc;
  585. puah->pfnSetScrollInfo = ThemeSetScrollInfoProc;
  586. puah->pfnEnableScrollBar = ThemeEnableScrollInfoProc;
  587. puah->pfnSetWindowRgn = ThemeSetWindowRgn;
  588. // DefWindowProc override hooks
  589. puah->pfnDefWindowProcW = ThemeDefWindowProcW;
  590. puah->pfnDefWindowProcA = ThemeDefWindowProcA;
  591. puah->mmDWP.cb = GetDwpMsgMask( &puah->mmDWP.rgb );
  592. // WndProc override hooks
  593. puah->uoiWnd.pfnBeforeOWP = ThemePreWndProc;
  594. puah->uoiWnd.pfnAfterOWP = ThemePostWndProc;
  595. puah->uoiWnd.mm.cb = GetOwpMsgMask( &puah->uoiWnd.mm.rgb ); // OWP message bitmask
  596. // DefDlgProc override hooks
  597. puah->uoiDlg.pfnBeforeOWP = ThemePreDefDlgProc;
  598. puah->uoiDlg.pfnAfterOWP = ThemePostDefDlgProc;
  599. puah->uoiDlg.mm.cb = GetDdpMsgMask( &puah->uoiDlg.mm.rgb ); // OWP message bitmask
  600. // System metrics hooks
  601. puah->pfnGetSystemMetrics = ThemeGetSystemMetrics;
  602. puah->pfnSystemParametersInfoA = ThemeSystemParametersInfoA;
  603. puah->pfnSystemParametersInfoW = ThemeSystemParametersInfoW;
  604. // Drawing hooks
  605. puah->pfnDrawFrameControl = ThemeDrawFrameControl;
  606. puah->pfnDrawCaption = ThemeDrawCaption;
  607. // MDI sysmenu hooks
  608. puah->pfnMDIRedrawFrame = ThemeMDIRedrawFrame;
  609. BOOL fNcThemed = g_pAppInfo ? TESTFLAG( g_pAppInfo->GetAppFlags(), STAP_ALLOW_NONCLIENT ) : FALSE;
  610. if( !fNcThemed || !LoadHookInstance() || !ApiHandlerInit( g_szProcessName, puah, &_hookinf.uahReal ) )
  611. {
  612. // restore 'Real' function table:
  613. *puah = _hookinf.uahReal;
  614. }
  615. else
  616. {
  617. InterlockedExchange( (LONG*)&g_eThemeHookState, HS_INITIALIZED );
  618. CThemeServices::ReestablishServerConnection();
  619. OnHooksEnabled();
  620. }
  621. fRetVal = TRUE; // acknowledge out args
  622. }
  623. }
  624. break;
  625. }
  626. case UIAH_UNINITIALIZE:
  627. case UIAH_UNHOOK:
  628. // It is possible to be called on UIAH_INITIALIZED and UIAH_UNHOOK
  629. // simultaneously on two separate threads.
  630. // Here we allow only one thread to transition from INITIALIZED to UNHOOKING state, and racing threads
  631. // will no-op. [scotthan]
  632. if( HS_INITIALIZED == InterlockedCompareExchange( (LONG*)&g_eThemeHookState, HS_UNHOOKING, HS_INITIALIZED ) )
  633. {
  634. //---- now that we are completely done, decrement the count ----
  635. //Log(LOG_TMCHANGE, L"ThemeInitApiHook is now decrementing the CallCount");
  636. int cInit;
  637. cInit = InterlockedDecrement(&_cInitUAH);
  638. ASSERT(0 == cInit);
  639. //---- detach themed windows, revert global state, etc
  640. OnHooksDisabled(FALSE);
  641. // one thread transitions to UNITIALIZED state:
  642. InterlockedExchange( (LONG*)&g_eThemeHookState, HS_UNINITIALIZED );
  643. break;
  644. }
  645. fRetVal = TRUE; // allow the hook/unhook
  646. break;
  647. }
  648. }
  649. //Log(LOG_TMCHANGE, L"ThemeInitApiHook exiting with fRetVal=%d, ApiCallCount=%d",
  650. // fRetVal, _cInitUAH);
  651. return fRetVal;
  652. }
  653. //---------------------------------------------------------------------------
  654. BOOL NewThemeCheck(int iChangeNum, BOOL fMsgCheck)
  655. {
  656. //---- return TRUE if this is the first WM_THEMECHANGEDTRIGGER msg of ----
  657. //---- current theme change ----
  658. Log(LOG_TMCHANGE, L"NewThemeCheck, iChangeNum=%d, fMsgCheck=%d",
  659. iChangeNum, fMsgCheck);
  660. BOOL fFirstMsg = FALSE;
  661. //---- update thememgr info now (don't wait for first WM_THEMECHANGED msg) ----
  662. if (! g_pAppInfo->CustomAppTheme())
  663. {
  664. //---- get real changenum to minimize redundant theme changes ----
  665. if (iChangeNum == -1)
  666. {
  667. CThemeServices::GetCurrentChangeNumber(&iChangeNum);
  668. }
  669. //---- fThemeChanged is TRUE if this is the first time we have seen this ----
  670. //---- change number or we recently found a new theme handle ----
  671. BOOL fThemeChanged;
  672. g_pAppInfo->ResetAppTheme(iChangeNum, fMsgCheck, &fThemeChanged, &fFirstMsg);
  673. if (fThemeChanged)
  674. {
  675. //---- see if theme services has died and been reborn ----
  676. if( S_FALSE == CThemeServices::ReestablishServerConnection() )
  677. {
  678. //---- services are back up - simulate a reset ----
  679. Log(LOG_ALWAYS, L"Recovering from Themes service restart");
  680. }
  681. //---- refresh theme metrics cache ----
  682. AcquireNcThemeMetrics();
  683. }
  684. }
  685. return fFirstMsg;
  686. }
  687. //---------------------------------------------------------------------------
  688. void OnHooksEnabled()
  689. {
  690. WindowDump(L"OnHooksEnabled");
  691. //---- hooking is turned on now ----
  692. Log(LOG_TMCHANGE, L"*** LOCAL Hooks installed ***");
  693. //---- load app's custom theme file, if one is registered ----
  694. //---- for now, comment this out since its not needed & causes problems if advapi32.dll not yet init-ed ----
  695. // g_pAppInfo->LoadCustomAppThemeIfFound();
  696. //---- we may have started this process with themes already on; in this case, we ----
  697. //---- don't get a WM_THEMECHANGED msg, so we better check for a theme now ----
  698. NewThemeCheck(-1, FALSE);
  699. }
  700. //---------------------------------------------------------------------------
  701. void OnHooksDisabled(BOOL fShutDown)
  702. {
  703. DWORD dwStartTime = StartTimer();
  704. WindowDump(L"OnHooksDisabled");
  705. //---- reset the AppTheme info to OFF ----
  706. g_pAppInfo->ResetAppTheme(-1, FALSE, NULL, NULL);
  707. g_pAppInfo->SetPreviewThemeFile(NULL, NULL);
  708. //---- keep the static theme info in sync ----
  709. AcquireNcThemeMetrics();
  710. // NOTE: this function called from ThemeInitApiHook()( & ThemeHookShutdown()
  711. // We need to release all nctheme state objects from windows in this process
  712. // in two cases:
  713. // (1) normal process shutdown.
  714. // (2) Themes being turned off (this case). Here, we're relying on notification
  715. // from USER that hooks are coming off this process.
  716. if (fShutDown)
  717. CThemeWnd::DetachAll( HMD_PROCESSDETACH );
  718. else
  719. CThemeWnd::DetachAll( HMD_THEMEDETACH );
  720. #ifdef DEBUG
  721. //---- all nonclient & client code should have closed their HTHEME's by now ----
  722. g_pAppInfo->DumpFileHolders();
  723. g_pRenderList->DumpFileHolders();
  724. #endif
  725. //---- force this process to remove its refcount on the global theme ----
  726. //---- this is allowed because hTheme's are no longer directly connected ----
  727. //---- to a CRenderObj ----
  728. g_pRenderList->FreeRenderObjects(-1);
  729. // free hook instance
  730. if( _hookinf.hInst )
  731. {
  732. FreeLibrary( _hookinf.hInst );
  733. _hookinf.hInst = NULL;
  734. }
  735. if (LogOptionOn(LO_TMLOAD))
  736. {
  737. DWORD dwTicks;
  738. dwTicks = StopTimer(dwStartTime);
  739. WCHAR buff[100];
  740. TimeToStr(dwTicks, buff);
  741. Log(LOG_TMLOAD, L"OnHooksDisabled took: %s", buff);
  742. }
  743. Log(LOG_TMCHANGE, L"*** LOCAL Hooks removed ***");
  744. }
  745. //---------------------------------------------------------------------------
  746. // _ThemeDefWindowProc() - defwindowproc worker
  747. LRESULT CALLBACK _ThemeDefWindowProc(
  748. HWND hwnd,
  749. UINT uMsg,
  750. WPARAM wParam,
  751. LPARAM lParam,
  752. BOOL bUnicode )
  753. {
  754. // Note: From this point until the point we invoke a message handler,
  755. // We need to take care that we don't do anything that causes
  756. // a message to be sent to the window.
  757. LRESULT lRet = 0L;
  758. LogEntryMsg(L"_ThemeDefWindowProc", hwnd, uMsg);
  759. BOOL fHandled = FALSE;
  760. WNDPROC pfnDefault = bUnicode ? _hookinf.uahReal.pfnDefWindowProcW :
  761. _hookinf.uahReal.pfnDefWindowProcA;
  762. // Pre-process WM_THEMECHANGE message
  763. if( IsTargetProcess(hwnd) )
  764. {
  765. UINT uDisp = _PreprocessHookedMsg( hwnd, uMsg, wParam, lParam, DEF );
  766. BOOL fLifeIsShort = TESTFLAG(uDisp, HMD_THEMEDETACH|HMD_WINDOWDESTROY);
  767. BOOL fDetach = TESTFLAG(uDisp, HMD_WINDOWDESTROY) && IsServerSideWindow(hwnd);
  768. // Try handling message
  769. CThemeWnd* pwnd = CThemeWnd::FromHwnd(hwnd);
  770. // special back-end processing for non-themed windows.
  771. fHandled = CThemeWnd::_PreDefWindowProc( hwnd, uMsg, wParam, lParam, &lRet );
  772. if(fHandled == FALSE &&
  773. (_WindowHasTheme(hwnd) || fLifeIsShort))
  774. {
  775. // On STYLECHANGED or WM_THEMECHANGE,
  776. // try reattaching window that was previously rejected or failed, resp.
  777. if( (REJECTED_THEMEWND(pwnd) && TESTFLAG(uDisp, HMD_REATTACH)) ||
  778. (FAILED_THEMEWND(pwnd) && WM_THEMECHANGED == uMsg) )
  779. {
  780. CThemeWnd::Detach(hwnd, FALSE); // remove rejection tag.
  781. pwnd = NULL;
  782. }
  783. // Attach window object if applicable.
  784. if( pwnd == NULL && !(fLifeIsShort || _fUnhooking) )
  785. {
  786. pwnd = CThemeWnd::Attach(hwnd);
  787. }
  788. if( VALID_THEMEWND(pwnd) )
  789. {
  790. // protect our themewnd pointer:
  791. pwnd->AddRef();
  792. // set up a theme message block
  793. THEME_MSG tm;
  794. _InitThemeMsg( &tm, MSGTYPE_DEFWNDPROC, bUnicode, hwnd, uMsg,
  795. wParam, lParam, 0, pfnDefault );
  796. // is this a message we want to handle?
  797. HOOKEDMSGHANDLER pfnHandler = NULL;
  798. if( FindDwpHandler( uMsg, &pfnHandler ))
  799. {
  800. // call the message handler
  801. LRESULT lRetHandler = pfnHandler( pwnd, &tm );
  802. fHandled = tm.fHandled;
  803. if( fHandled )
  804. {
  805. lRet = lRetHandler;
  806. }
  807. }
  808. // decrement themewnd ref
  809. pwnd->Release();
  810. }
  811. }
  812. if( fDetach )
  813. {
  814. CThemeWnd::Detach( hwnd, uDisp );
  815. pwnd = NULL; // don't touch
  816. }
  817. }
  818. if( !fHandled )
  819. lRet = pfnDefault( hwnd, uMsg, wParam, lParam );
  820. LogExitMsg(L"_ThemeDefWindowProc");
  821. return lRet;
  822. }
  823. //---------------------------------------------------------------------------
  824. // ThemeDefWindowProcA() - Themed ansi defwindowproc
  825. LRESULT CALLBACK ThemeDefWindowProcA( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  826. {
  827. return _ThemeDefWindowProc( hwnd, uMsg, wParam, lParam, FALSE );
  828. }
  829. //---------------------------------------------------------------------------
  830. // ThemeDefWindowProcW() - Themed widechar defwindowproc
  831. LRESULT CALLBACK ThemeDefWindowProcW( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam )
  832. {
  833. return _ThemeDefWindowProc( hwnd, uMsg, wParam, lParam, TRUE );
  834. }
  835. //---------------------------------------------------------------------------
  836. BOOL IsEqualScrollInfo( LPCSCROLLINFO psi1, LPCSCROLLINFO psi2 )
  837. {
  838. if( psi1->fMask != psi2->fMask )
  839. return FALSE;
  840. if( psi1->fMask & SIF_RANGE )
  841. {
  842. if( (psi1->nMin != psi2->nMin) ||
  843. (psi1->nMax != psi2->nMax) )
  844. {
  845. return FALSE;
  846. }
  847. }
  848. if( psi1->fMask & SIF_POS )
  849. {
  850. if( psi1->nPos != psi2->nPos )
  851. return FALSE;
  852. }
  853. if( psi1->fMask & SIF_PAGE )
  854. {
  855. if( psi1->nPage != psi2->nPage )
  856. return FALSE;
  857. }
  858. if( psi1->fMask & SIF_TRACKPOS )
  859. {
  860. if( psi1->nTrackPos != psi2->nTrackPos )
  861. return FALSE;
  862. }
  863. return TRUE;
  864. }
  865. //---------------------------------------------------------------------------
  866. int CALLBACK ThemeSetScrollInfoProc(
  867. HWND hwnd,
  868. int nBar,
  869. IN LPCSCROLLINFO psi,
  870. BOOL fRedraw )
  871. {
  872. int nRet = 0;
  873. if ( psi != NULL )
  874. {
  875. LogEntryMsg(L"ThemeSetScrollInfoProc", hwnd, nBar);
  876. BOOL fHandled = FALSE;
  877. if ( IsTargetProcess(hwnd) && _WindowHasTheme(hwnd) && (nBar != SB_CTL) )
  878. {
  879. DWORD dwStyle;
  880. BOOL fStyleChanged;
  881. CThemeWnd* pwnd = CThemeWnd::FromHwnd(hwnd);
  882. //
  883. // Call the real SetScrollInfo first to give user
  884. // a chance to update their internal state. They can
  885. // potentially set WS_VSCROLL/WS_HSCROLL without notifying
  886. // anyone at all (eg. defview's listview)
  887. //
  888. // If they do, we'll need to redraw the entire
  889. // scroll bar.
  890. //
  891. dwStyle = GetWindowLong(hwnd, GWL_STYLE);
  892. nRet = _hookinf.uahReal.pfnSetScrollInfo( hwnd, nBar, psi, FALSE );
  893. fStyleChanged = (((dwStyle ^ GetWindowLong(hwnd, GWL_STYLE)) & (WS_VSCROLL|WS_HSCROLL)) != 0) ? TRUE : FALSE;
  894. // If we previously rejected the host window, it's possible that it
  895. // didn't have the WS_H/VSCROLL bits. Now it will, so we can re-attach.
  896. if ( REJECTED_THEMEWND(pwnd) )
  897. {
  898. CThemeWnd::Detach(hwnd, FALSE);
  899. pwnd = CThemeWnd::Attach(hwnd);
  900. }
  901. if ( VALID_THEMEWND(pwnd) )
  902. {
  903. // SetScrollInfo can potentially change WS_VSCROLL/WS_HSCROLL but
  904. // no style change message gets send. User does this by directly changing
  905. // the wnd struct. We do this by calling SetWindowLong which will generated
  906. // stylchanging and stylechanged. For compatability, we'll need to suppress
  907. // these messages.
  908. pwnd->SuppressStyleMsgs();
  909. fHandled = TRUE;
  910. #ifdef _ENABLE_SCROLL_SPEW_
  911. SpewScrollInfo( "ThemeSetScrollInfoProc to RealSetScrollInfo:", hwnd, psi );
  912. #endif // _ENABLE_SCROLL_SPEW_
  913. SCROLLINFO si;
  914. si.cbSize = sizeof(si);
  915. si.fMask = psi->fMask | SIF_DISABLENOSCROLL;
  916. if ( _hookinf.uahReal.pfnGetScrollInfo( hwnd, nBar, &si ) )
  917. {
  918. ThemeSetScrollInfo( hwnd, nBar, &si, fRedraw );
  919. }
  920. else
  921. {
  922. ThemeSetScrollInfo( hwnd, nBar, psi, fRedraw );
  923. }
  924. if ( fRedraw && fStyleChanged )
  925. {
  926. HDC hdc = GetWindowDC(hwnd);
  927. if ( hdc )
  928. {
  929. DrawScrollBar(hwnd, hdc, NULL, (nBar != SB_HORZ));
  930. ReleaseDC(hwnd, hdc);
  931. }
  932. }
  933. pwnd->AllowStyleMsgs();
  934. }
  935. }
  936. if( !fHandled )
  937. {
  938. nRet = _hookinf.uahReal.pfnSetScrollInfo( hwnd, nBar, psi, fRedraw );
  939. }
  940. LogExitMsg(L"ThemeSetScrollInfoProc");
  941. }
  942. return nRet;
  943. }
  944. //---------------------------------------------------------------------------
  945. BOOL CALLBACK ThemeGetScrollInfoProc(
  946. HWND hwnd,
  947. int nBar,
  948. IN OUT LPSCROLLINFO psi )
  949. {
  950. BOOL fRet = FALSE;
  951. if ( psi != NULL )
  952. {
  953. LogEntryMsg(L"ThemeGetScrollInfoProc", hwnd, nBar);
  954. if( IsTargetProcess(hwnd) && _WindowHasTheme(hwnd) )
  955. {
  956. CThemeWnd* pwnd = CThemeWnd::FromHwnd(hwnd);
  957. if( VALID_THEMEWND(pwnd) )
  958. {
  959. fRet = ThemeGetScrollInfo( hwnd, nBar, psi );
  960. }
  961. }
  962. if( !fRet )
  963. {
  964. fRet = _hookinf.uahReal.pfnGetScrollInfo( hwnd, nBar, psi );
  965. }
  966. LogExitMsg(L"ThemeGetScrollInfoProc");
  967. }
  968. else
  969. {
  970. SetLastError(ERROR_INVALID_PARAMETER);
  971. }
  972. return fRet;
  973. }
  974. //---------------------------------------------------------------------------
  975. BOOL CALLBACK ThemeEnableScrollInfoProc( HWND hwnd, UINT nSBFlags, UINT nArrows )
  976. {
  977. LogEntryMsg(L"ThemeEnableScrollInfoProc", 0, 0);
  978. BOOL fRet = _hookinf.uahReal.pfnEnableScrollBar( hwnd, nSBFlags, nArrows );
  979. if( fRet )
  980. {
  981. if( IsTargetProcess(hwnd) && _WindowHasTheme(hwnd))
  982. {
  983. CThemeWnd* pwnd = CThemeWnd::FromHwnd(hwnd);
  984. if( VALID_THEMEWND(pwnd) )
  985. {
  986. ThemeEnableScrollBar( hwnd, nSBFlags, nArrows );
  987. }
  988. }
  989. }
  990. LogExitMsg(L"ThemeEnableScrollInfoProc");
  991. return fRet;
  992. }
  993. //---------------------------------------------------------------------------
  994. int CALLBACK ThemeGetSystemMetrics( int iMetric )
  995. {
  996. LogEntryMsg(L"ThemeGetSystemMetrics", 0, 0);
  997. int iRet;
  998. if( IsTargetProcess() && g_pAppInfo->AppIsThemed() && !IN_CLASSICSYSMETCALL() )
  999. {
  1000. BOOL fHandled = FALSE;
  1001. iRet = _InternalGetSystemMetrics( iMetric, fHandled );
  1002. if( fHandled )
  1003. return iRet;
  1004. }
  1005. iRet = _hookinf.uahReal.pfnGetSystemMetrics(iMetric);
  1006. LogExitMsg(L"ThemeGetSystemMetrics");
  1007. return iRet;
  1008. }
  1009. //---------------------------------------------------------------------------
  1010. THEMEAPI_(int) ClassicGetSystemMetrics( int iMetric )
  1011. {
  1012. LogEntryMsg(L"ThemeGetSystemMetrics", 0, 0);
  1013. if( HOOKSACTIVE() && _hookinf.uahReal.pfnGetSystemMetrics != NULL )
  1014. {
  1015. return _hookinf.uahReal.pfnGetSystemMetrics( iMetric );
  1016. }
  1017. ENTER_CLASSICSYSMETCALL();
  1018. int nRet = GetSystemMetrics( iMetric );
  1019. LEAVE_CLASSICSYSMETCALL();
  1020. LogExitMsg(L"ThemeGetSystemMetrics");
  1021. return nRet;
  1022. }
  1023. //---------------------------------------------------------------------------
  1024. BOOL CALLBACK ThemeSystemParametersInfoA(
  1025. IN UINT uiAction,
  1026. IN UINT uiParam,
  1027. IN OUT PVOID pvParam,
  1028. IN UINT fWinIni)
  1029. {
  1030. LogEntryMsg(L"ThemeSystemParametersInfoA", 0, 0);
  1031. BOOL fRet = FALSE;
  1032. if( IsTargetProcess() && g_pAppInfo->AppIsThemed() && !IN_CLASSICSYSMETCALL() )
  1033. {
  1034. BOOL fHandled = FALSE;
  1035. fRet = _InternalSystemParametersInfo( uiAction, uiParam, pvParam, fWinIni, FALSE, fHandled );
  1036. if( fHandled )
  1037. return fRet;
  1038. }
  1039. fRet = _hookinf.uahReal.pfnSystemParametersInfoA( uiAction, uiParam, pvParam, fWinIni );
  1040. LogExitMsg(L"ThemeSystemParametersInfoA");
  1041. return fRet;
  1042. }
  1043. //---------------------------------------------------------------------------
  1044. BOOL CALLBACK ThemeSystemParametersInfoW( IN UINT uiAction, IN UINT uiParam, IN OUT PVOID pvParam, IN UINT fWinIni)
  1045. {
  1046. LogEntryMsg(L"ThemeSystemParametersInfoA", 0, 0);
  1047. BOOL fRet = FALSE;
  1048. if( IsTargetProcess() && g_pAppInfo->AppIsThemed() && !IN_CLASSICSYSMETCALL() )
  1049. {
  1050. BOOL fHandled = FALSE;
  1051. fRet = _InternalSystemParametersInfo( uiAction, uiParam, pvParam, fWinIni, TRUE, fHandled );
  1052. if( fHandled )
  1053. return fRet;
  1054. }
  1055. fRet = _hookinf.uahReal.pfnSystemParametersInfoW( uiAction, uiParam, pvParam, fWinIni );
  1056. LogExitMsg(L"ThemeSystemParametersInfoA");
  1057. return fRet;
  1058. }
  1059. //---------------------------------------------------------------------------
  1060. THEMEAPI_(BOOL) ClassicSystemParametersInfoA( IN UINT uiAction, IN UINT uiParam, IN OUT PVOID pvParam, IN UINT fWinIni)
  1061. {
  1062. if( HOOKSACTIVE() && _hookinf.uahReal.pfnSystemParametersInfoA )
  1063. {
  1064. return _hookinf.uahReal.pfnSystemParametersInfoA( uiAction, uiParam, pvParam, fWinIni );
  1065. }
  1066. ENTER_CLASSICSYSMETCALL();
  1067. BOOL fRet = SystemParametersInfoA( uiAction, uiParam, pvParam, fWinIni );
  1068. LEAVE_CLASSICSYSMETCALL();
  1069. return fRet;
  1070. }
  1071. //---------------------------------------------------------------------------
  1072. THEMEAPI_(BOOL) ClassicSystemParametersInfoW( IN UINT uiAction, IN UINT uiParam, IN OUT PVOID pvParam, IN UINT fWinIni)
  1073. {
  1074. if( HOOKSACTIVE() && _hookinf.uahReal.pfnSystemParametersInfoW )
  1075. {
  1076. return _hookinf.uahReal.pfnSystemParametersInfoW( uiAction, uiParam, pvParam, fWinIni );
  1077. }
  1078. ENTER_CLASSICSYSMETCALL();
  1079. BOOL fRet = SystemParametersInfoW( uiAction, uiParam, pvParam, fWinIni );
  1080. LEAVE_CLASSICSYSMETCALL();
  1081. return fRet;
  1082. }
  1083. //---------------------------------------------------------------------------
  1084. THEMEAPI_(BOOL) ClassicAdjustWindowRectEx( LPRECT prcWnd, DWORD dwStyle, BOOL fMenu, DWORD dwExStyle )
  1085. {
  1086. // If hooks are active, simply call user32!RealAdjustWindowRectEx.
  1087. if( HOOKSACTIVE() && _hookinf.uahReal.pfnAdjustWindowRectEx )
  1088. {
  1089. return _hookinf.uahReal.pfnAdjustWindowRectEx( prcWnd, dwStyle, fMenu, dwExStyle );
  1090. }
  1091. ENTER_CLASSICSYSMETCALL();
  1092. BOOL fRet = AdjustWindowRectEx( prcWnd, dwStyle, fMenu, dwExStyle );
  1093. LEAVE_CLASSICSYSMETCALL();
  1094. return fRet;
  1095. }
  1096. //---------------------------------------------------------------------------
  1097. BOOL CALLBACK ThemeSetWindowRgn( HWND hwnd, HRGN hrgn, BOOL fRedraw)
  1098. {
  1099. LogEntryMsg(L"ThemeSetWindowRgn", hwnd, 0);
  1100. BOOL fHandled = FALSE;
  1101. if( IsTargetProcess(hwnd) )
  1102. {
  1103. CThemeWnd* pwnd = CThemeWnd::FromHwnd(hwnd);
  1104. if( VALID_THEMEWND(pwnd) )
  1105. {
  1106. if( _WindowHasTheme(hwnd) )
  1107. {
  1108. if( hrgn != NULL &&
  1109. pwnd->IsFrameThemed() && !pwnd->AssigningFrameRgn() /* don't hook our own call */ )
  1110. {
  1111. // If we're executing here, the window is being assigned a
  1112. // region externally or by the app. We'll want to revoke theming
  1113. // of this window from this point forward.
  1114. pwnd->AddRef();
  1115. // Disown our theme window region without directly removing it;
  1116. // we'll simply fall through and let the theme region get stomped.
  1117. if( pwnd->AssignedFrameRgn() )
  1118. pwnd->AssignFrameRgn( FALSE, FTF_NOMODIFYRGN );
  1119. // Exile the window.
  1120. pwnd->Revoke();
  1121. pwnd->Release();
  1122. }
  1123. }
  1124. }
  1125. else if( NULL == hrgn && !IsWindowInDestroy(hwnd) )
  1126. {
  1127. if( TESTFLAG( CThemeWnd::EvaluateWindowStyle( hwnd ), TWCF_FRAME|TWCF_TOOLFRAME ) )
  1128. {
  1129. if( pwnd )
  1130. RemoveProp( hwnd, MAKEINTATOM(GetThemeAtom(THEMEATOM_NONCLIENT)) );
  1131. NCEVALUATE nce = {0};
  1132. nce.fIgnoreWndRgn = TRUE;
  1133. pwnd = CThemeWnd::Attach(hwnd, &nce);
  1134. if( VALID_THEMEWND(pwnd) )
  1135. {
  1136. ASSERT(pwnd->TestCF(TWCF_FRAME|TWCF_TOOLFRAME));
  1137. fHandled = TRUE;
  1138. pwnd->SetFrameTheme( FTF_REDRAW, NULL );
  1139. }
  1140. }
  1141. }
  1142. }
  1143. BOOL fRet = TRUE;
  1144. if( !fHandled )
  1145. {
  1146. ASSERT(_hookinf.uahReal.pfnSetWindowRgn);
  1147. fRet = _hookinf.uahReal.pfnSetWindowRgn( hwnd, hrgn, fRedraw );
  1148. }
  1149. LogExitMsg(L"ThemeSetWindowRgn");
  1150. return fRet;
  1151. }
  1152. //---------------------------------------------------------------------------
  1153. BOOL CALLBACK ThemeDrawFrameControl(
  1154. IN HDC hdc, IN OUT LPRECT prc, IN UINT uType, IN UINT uState )
  1155. {
  1156. LogEntryMsg(L"ThemeDrawFrameControl", NULL, 0);
  1157. if( IsTargetProcess() )
  1158. {
  1159. CThemeWnd* pwnd = CThemeWnd::FromHdc(hdc);
  1160. if( NULL == pwnd) // HDC is a memory DC
  1161. {
  1162. // Find the window in this thread that is processing WM_NCPAINT
  1163. HWND hwnd = NcPaintWindow_Find();
  1164. if( hwnd )
  1165. {
  1166. pwnd = CThemeWnd::FromHwnd(hwnd);
  1167. }
  1168. }
  1169. if( VALID_THEMEWND(pwnd) && _WindowHasTheme(*pwnd) )
  1170. {
  1171. if( pwnd->IsFrameThemed() && pwnd->InNcPaint() && !pwnd->InNcThemePaint() )
  1172. {
  1173. DWORD dwFlags = RF_NORMAL|RF_DEFER;
  1174. if( pwnd->AssignedFrameRgn() )
  1175. {
  1176. dwFlags |= RF_REGION;
  1177. }
  1178. pwnd->SetRevokeFlags(dwFlags);
  1179. }
  1180. }
  1181. }
  1182. ASSERT(_hookinf.uahReal.pfnDrawFrameControl);
  1183. BOOL fRet = _hookinf.uahReal.pfnDrawFrameControl( hdc, prc, uType, uState );
  1184. LogExitMsg(L"ThemeDrawFrameControl");
  1185. return fRet;
  1186. }
  1187. //---------------------------------------------------------------------------
  1188. BOOL CALLBACK ThemeDrawCaption( IN HWND hwnd, IN HDC hdc, IN CONST RECT *prc, IN UINT uType)
  1189. {
  1190. LogEntryMsg(L"ThemeDrawFrameControl", NULL, 0);
  1191. if( IsTargetProcess() )
  1192. {
  1193. CThemeWnd* pwnd = CThemeWnd::FromHwnd(hwnd);
  1194. if( VALID_THEMEWND(pwnd) && _WindowHasTheme(*pwnd) )
  1195. {
  1196. if( pwnd->IsFrameThemed() && pwnd->InNcPaint() && !pwnd->InNcThemePaint() )
  1197. {
  1198. DWORD dwFlags = RF_NORMAL|RF_DEFER;
  1199. if( pwnd->AssignedFrameRgn() )
  1200. {
  1201. dwFlags |= RF_REGION;
  1202. }
  1203. pwnd->SetRevokeFlags(dwFlags);
  1204. }
  1205. }
  1206. }
  1207. ASSERT(_hookinf.uahReal.pfnDrawCaption);
  1208. BOOL fRet = _hookinf.uahReal.pfnDrawCaption( hwnd, hdc, prc, uType );
  1209. LogExitMsg(L"ThemeDrawFrameControl");
  1210. return fRet;
  1211. }
  1212. //---------------------------------------------------------------------------
  1213. VOID CALLBACK ThemeMDIRedrawFrame( IN HWND hwndChild, BOOL fAdd )
  1214. {
  1215. LogEntryMsg(L"ThemeMDIRedrawFrame", NULL, 0);
  1216. if( IsTargetProcess() )
  1217. {
  1218. HWND hwndClient = GetParent(hwndChild);
  1219. HWND hwndFrame = GetParent(hwndClient);
  1220. if( hwndFrame )
  1221. {
  1222. CThemeWnd* pwnd = CThemeWnd::FromHwnd(hwndFrame);
  1223. if( VALID_THEMEWND(pwnd) )
  1224. {
  1225. pwnd->ModifyMDIMenubar( fAdd, FALSE );
  1226. }
  1227. }
  1228. }
  1229. ASSERT(_hookinf.uahReal.pfnMDIRedrawFrame);
  1230. _hookinf.uahReal.pfnMDIRedrawFrame( hwndChild, fAdd );
  1231. LogExitMsg(L"ThemeMDIRedrawFrame");
  1232. }