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.

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