|
|
#include "stdafx.h"
#include "handlers.h"
//-------------------------------------------------------------------------//
// Declare registered message vars **here**
//-------------------------------------------------------------------------//
#define __NO_APPHACKS__
//-------------------------------------------------------------------------//
// Message Handlers
//-------------------------------------------------------------------------//
// Rules for message handlers [scotthan]:
//
// (1) Use DECL_ macros to declare message handler prototype and
// table entries for message handlers below.
// (2) A message handler implementation should NOT:
// 1. call DefWindowProc or CallWindowProc directly,
// but rather use DoMsgDefault().
// 2. delete the incoming CThemeWnd* object,
// (3) A message handler SHOULD:
// 1. Honor the codepage value in the message block when
// handling messages that carry string args.
// If the codepage member is CP_WINUNICODE, the widechar
// string processing should be assumed; otherwise, multibyte
// string processing should be assumed.
// 2. If a message should not be forwarded for default processing,
// mark the message as handled using MsgHandled().
// (4) Handlers should be listed in the BEGIN/ENDMSG() block
// below in decreasing order of expected frequency.
//---------------------//
// WndProc overrides
//---------------------//
// msg handler decls:
DECL_MSGHANDLER( OnOwpPostCreate ); DECL_MSGHANDLER( OnOwpPreStyleChange ); DECL_MSGHANDLER( OnOwpPreWindowPosChanging ); DECL_MSGHANDLER( OnOwpPreWindowPosChanged ); DECL_MSGHANDLER( OnOwpPostWindowPosChanged ); DECL_MSGHANDLER( OnOwpPostSettingChange ); DECL_MSGHANDLER( OnOwpPreMeasureItem ); DECL_MSGHANDLER( OnOwpPreDrawItem ); DECL_MSGHANDLER( OnOwpPreMenuChar ); DECL_MSGHANDLER( OnOwpPostThemeChanged ); DECL_MSGHANDLER( OnOwpPreNcPaint ); DECL_MSGHANDLER( OnOwpPostNcPaint );
// handler table:
BEGIN_HANDLER_TABLE(_rgOwpHandlers) // frequent messages
DECL_MSGENTRY( WM_NCPAINT, OnOwpPreNcPaint, OnOwpPostNcPaint ) DECL_MSGENTRY( WM_WINDOWPOSCHANGING, OnOwpPreWindowPosChanging, NULL ) DECL_MSGENTRY( WM_WINDOWPOSCHANGED, OnOwpPreWindowPosChanged, OnOwpPostWindowPosChanged ) DECL_MSGENTRY( WM_SETTINGCHANGE, NULL, OnOwpPostSettingChange ) DECL_MSGENTRY( WM_MEASUREITEM, OnOwpPreMeasureItem, NULL ) DECL_MSGENTRY( WM_DRAWITEM, OnOwpPreDrawItem, NULL ) DECL_MSGENTRY( WM_MDISETMENU, NULL, NULL )
// rare messages:
DECL_MSGENTRY( WM_MENUCHAR, OnOwpPreMenuChar, NULL ) DECL_MSGENTRY( WM_STYLECHANGING, OnOwpPreStyleChange, NULL ) DECL_MSGENTRY( WM_STYLECHANGED, OnOwpPreStyleChange, NULL ) DECL_MSGENTRY( WM_NCCREATE, NULL, NULL ) DECL_MSGENTRY( WM_CREATE, NULL, OnOwpPostCreate ) DECL_MSGENTRY( WM_NCDESTROY, NULL, NULL ) DECL_MSGENTRY( WM_THEMECHANGED, NULL, OnOwpPostThemeChanged ) // we handle in line in ThemePreWndProc()
DECL_MSGENTRY( WM_THEMECHANGED_TRIGGER, NULL, NULL ) // we handle in line in ThemePreWndProc()
END_HANDLER_TABLE()
// Note: values of high owp message must be in sync w/ table.
#define WNDPROC_MSG_LAST WM_THEMECHANGED_TRIGGER // 0x031B (alias for WM_UAHINIT)
//------------------------//
// DefDlgProc overrides
//------------------------//
// msg handler decls:
DECL_MSGHANDLER( OnDdpPostCtlColor ); DECL_MSGHANDLER( OnDdpCtlColor ); DECL_MSGHANDLER( OnDdpPrint ); DECL_MSGHANDLER( OnDdpPostInitDialog );
// handler table:
BEGIN_HANDLER_TABLE(_rgDdpHandlers) // frequent messages:
DECL_MSGENTRY( WM_CTLCOLORDLG, NULL, OnDdpPostCtlColor ) DECL_MSGENTRY( WM_CTLCOLORSTATIC, NULL, OnDdpCtlColor) DECL_MSGENTRY( WM_CTLCOLORBTN, NULL, OnDdpCtlColor) DECL_MSGENTRY( WM_CTLCOLORMSGBOX, NULL, OnDdpPostCtlColor ) DECL_MSGENTRY( WM_PRINTCLIENT, NULL, OnDdpPrint ) // rare messages:
DECL_MSGENTRY( WM_INITDIALOG, NULL, OnDdpPostInitDialog ) END_HANDLER_TABLE()
// Note: values of high ddp message must be in sync w/ table.
#define DEFDLGPROC_MSG_LAST WM_PRINTCLIENT // 0x0318
//--------------------------//
// DefWindowProc override
//--------------------------//
// msg handler decls:
DECL_MSGHANDLER( OnDwpNcPaint ); DECL_MSGHANDLER( OnDwpNcHitTest ); DECL_MSGHANDLER( OnDwpNcActivate ); DECL_MSGHANDLER( OnDwpNcLButtonDown ); DECL_MSGHANDLER( OnDwpNcThemeDrawCaption ); DECL_MSGHANDLER( OnDwpNcThemeDrawFrame ); DECL_MSGHANDLER( OnDwpNcMouseMove ); DECL_MSGHANDLER( OnDwpNcMouseLeave ); DECL_MSGHANDLER( OnDwpWindowPosChanged ); DECL_MSGHANDLER( OnDwpSysCommand ); DECL_MSGHANDLER( OnDwpSetText ); DECL_MSGHANDLER( OnDwpSetIcon ); DECL_MSGHANDLER( OnDwpStyleChanged ); DECL_MSGHANDLER( OnDwpPrint ); DECL_MSGHANDLER( OnDwpPrintClient ); DECL_MSGHANDLER( OnDwpContextMenu );
// handler table:
BEGIN_HANDLER_TABLE(_rgDwpHandlers) // frequent messages:
DECL_MSGENTRY( WM_NCHITTEST, OnDwpNcHitTest, NULL ) DECL_MSGENTRY( WM_NCPAINT, OnDwpNcPaint, NULL ) DECL_MSGENTRY( WM_NCACTIVATE, OnDwpNcActivate, NULL ) DECL_MSGENTRY( WM_NCMOUSEMOVE, OnDwpNcMouseMove, NULL ) DECL_MSGENTRY( WM_NCMOUSELEAVE, OnDwpNcMouseLeave, NULL ) DECL_MSGENTRY( WM_WINDOWPOSCHANGED, OnDwpWindowPosChanged, NULL ) DECL_MSGENTRY( WM_SYSCOMMAND, OnDwpSysCommand, NULL ) DECL_MSGENTRY( WM_NCLBUTTONDOWN, OnDwpNcLButtonDown, NULL ) DECL_MSGENTRY( WM_NCUAHDRAWCAPTION, OnDwpNcThemeDrawCaption, NULL ) DECL_MSGENTRY( WM_NCUAHDRAWFRAME, OnDwpNcThemeDrawFrame, NULL ) DECL_MSGENTRY( WM_PRINT, OnDwpPrint, NULL ) DECL_MSGENTRY( WM_PRINTCLIENT, OnDwpPrintClient, NULL ) DECL_MSGENTRY( WM_CTLCOLORMSGBOX, OnDdpPostCtlColor, NULL) // Strange: Sent to DefWindowProc, but is a Dialog message
DECL_MSGENTRY( WM_CTLCOLORSTATIC, OnDdpCtlColor, NULL) DECL_MSGENTRY( WM_CTLCOLORBTN, OnDdpCtlColor, NULL) // rare messages:
DECL_MSGENTRY( WM_SETTEXT, OnDwpSetText, NULL ) DECL_MSGENTRY( WM_SETICON, OnDwpSetIcon, NULL ) DECL_MSGENTRY( WM_STYLECHANGED, OnDwpStyleChanged, NULL ) DECL_MSGENTRY( WM_CONTEXTMENU, OnDwpContextMenu, NULL ) DECL_MSGENTRY( WM_THEMECHANGED_TRIGGER, NULL, NULL ) DECL_MSGENTRY( WM_NCDESTROY, NULL, NULL ) END_HANDLER_TABLE()
// Note: values of high dwp message must be in sync w/ handler table.
#define DEFWNDPROC_MSG_LAST WM_THEMECHANGED_TRIGGER // 0x031B
//---------------------------------------------------------------------------
BOOL _FindMsgHandler( UINT, MSGENTRY [], int, IN HOOKEDMSGHANDLER*, IN HOOKEDMSGHANDLER* ); BOOL _SetMsgHandler( UINT, MSGENTRY [], int, IN HOOKEDMSGHANDLER, BOOL );
//---------------------------------------------------------------------------
// Special case hook handling
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
BOOL _IsExcludedSystemProcess( LPCWSTR pszProcess ) { static const WCHAR* _rgszSystemProcessList[] = { L"lsass", // Local Security Authority sub-system
L"services", // Service Control Manager
L"svchost", // Service Host
L"mstask", // Microsoft Task Scheduler
L"dfssvc", // Distributed File System Service
L"winmgmt", // Windows Management Instrumentation
L"spoolsv", // Print Spool Service
L"msdtc", // Microsoft Distributed Transaction Co-ordinator
L"regsvc", // Remote Registry Service
L"webclnt", // Web Client
L"mspmspsv", // WMDM PMSP Service (what is this?)
L"ntvdm" // NT virtual DOS machine
};
return AsciiScanStringList( pszProcess, _rgszSystemProcessList, ARRAYSIZE(_rgszSystemProcessList), TRUE ); }
//---------------------------------------------------------------------------
BOOL _IsProcessOnInteractiveWindowStation() // check if we're on winsta0.
{ BOOL fRet = FALSE; HWINSTA hWinSta = GetProcessWindowStation(); if( hWinSta != NULL ) { DWORD cbLength = 0; WCHAR wszName[32];
if (GetUserObjectInformationW(hWinSta, UOI_NAME, wszName, sizeof(wszName), &cbLength)) { fRet = (0 == AsciiStrCmpI(wszName, L"winsta0")); } else { // Problem! It's either:
// - our buffer was too small (in which case it can't be winsta0)
// - or some other failure we cannot overcome anyhow
} } return(fRet); }
//---------------------------------------------------------------------------
BOOL _IsWin16App() // check if this is a 16-bit process
{ GUITHREADINFO gti; gti.cbSize = sizeof(gti); gti.flags = GUI_16BITTASK;
return GetGUIThreadInfo( GetCurrentThreadId(), >i ) && TESTFLAG(gti.flags, GUI_16BITTASK ); }
//---------------------------------------------------------------------------
BOOL ApiHandlerInit( const LPCTSTR pszProcess, USERAPIHOOK* puahTheme, const USERAPIHOOK* puahReal ) { // exclude known non-UI system processes
if( _IsExcludedSystemProcess( pszProcess ) ) return FALSE;
// exclude any process not hosted on winsta0.
if( !_IsProcessOnInteractiveWindowStation() ) return FALSE;
if( _IsWin16App() ) return FALSE; // SHIMSHIM [scotthan]:
#ifdef _DEBUG
//---- temp patch against msvcmon ----
if( 0 == AsciiStrCmpI(pszProcess, L"msvcmon") ) { return FALSE; }
//---- temp patch against msdev ----
if( 0 == AsciiStrCmpI(pszProcess, L"msdev") ) { return FALSE; }
//---- Aid in debugging classic/themed differences: ---
if( 0 == AsciiStrCmpI( pszProcess, L"mditest1" ) ) { return FALSE; } #endif
#ifndef __NO_APPHACKS__
static const WCHAR* _rgszExcludeAppList[] = { #ifdef THEME_CALCSIZE
// Invoking SetWindowPos from CThemeWnd::SetFrameTheme on our Post-WM_CREATE handler
// causes emacs to divide by zero after receiving meaningless rects from two
// successive calls to AdjustWindowRectEx from his WM_WINDOWPOSCHANGING handler.
// I don't believe it is related to the fact that AdjustWindowRectEx has yet
// to be implemented for themed windows (raid# 140989), but rather that the wndproc
// is not ready for a WM_WINDOWPOSCHANGING message on the abrubtly on the
// heels of a WM_CREATE handler.
L"emacs",
L"neoplanet", // 247283: We rush in to theme neoplanet's dialogs, which we almost
L"np", // immediately revoke, but not before sizing the dialog to theme-compatible
// client rect. When we withdraw, we leave it clipped. No good way to deal
// with this for beta2.
// HTML Editor++ v.8: 286676:
// This guy recomputes his nonclient area, and then AVs dereferencing a
// WM_WINDOWPOSCHANGING message under themes.
L"coffee", #endif THEME_CALCSIZE
L"refcntr", // 205059: Corel Reference Center; lower 10% of window is clipped.
L"KeyFramerPro", // 336456: Regardless of whether themes are enabled, Boris KeyFramer Pro v.5
// does two SetWindowRgn() calls for every WM_PAINT, the first with a region,
// the next with NULL, Is the app trying to clip his painting?
// If so, this is not what SetWindowRgn was intended for, and explains why this
// app is so clunky at window resizing. Rather, SelectClipRgn is the
// correct API.
// When themes are enabled, we keep revoking and re-attatching with each
// SetWindowRgn call, so we get substantial flicker.
// The ISV should be notified of this bug.
// Applications that do custom non-client painting and hence look broken when
// themed. Our only recourse at the moment it to exclude them from non-client
// themeing so that we don't stomp whatever they are trying to do.
L"RealJBox", // 273370: Real JukeBox
L"RealPlay", // 285368: Real AudioPlayer
L"TeamMgr", // 286654: Microsoft Team Manager97
L"TrpMaker", // 307107: Rand McNally TripMaker 2000
L"StrFindr", // 307535: Rand McNally StreetFinder 2000
L"Exceed", // 276244: Hummingbird Exceed 6.2/7.0
L"VP30", // 328676: Intel Video Phone
// 313407: Groove, build 760
// Calls DefWindowProc for NCPAINT, then paints his own caption over it.
// Note: this just might work correctly if we had a DrawFrameControl hook.
L"groove", // filever 1.1.0.760, 1/22/2001 tested.
// 303756: Exclude all Lotus SmartSuite apps to provide consistency among their
// apps. All of them draw into the caption bar.
L"WordPro", // 285065: Lotus WordPro, a particularly poorly implemented app.
L"SmartCtr", // It's WordPerfect compat menu is the elephant man of modern software.
L"123w", L"Approach", L"FastSite", L"F32Main", L"Org5",
// 358337: Best Technology - GCC Developer Lite. Custom caption bar fights with Luna.
L"GCCDevL", // install point: http://www.besttechnology.co.jp/download/GDL1_0_3_6.EXE
// 360422: J Zenrin The Real Digital Map Z3(T1):Max/Min/Close buttons are overlapped on classic buttons in title bar.
L"emZmain",
// 364337: Encarta World English Dictionary: Luna system buttons are overlaid on top of app's custom ones when mousing over
L"ewed.exe",
// 343171: Reaktor Realtime Instrument: pressing the close button while themed causes this app to
// spin in a tight loop running at realtime priority, effectively hanging the machine.
// The message loop for this app is extremely timing sensitive, the additional overhead
// introduced by theming alters the timing enough to break this app.
L"Reaktor", };
if( AsciiScanStringList( pszProcess, _rgszExcludeAppList, ARRAYSIZE(_rgszExcludeAppList), TRUE ) ) { return FALSE; }
#ifdef THEME_CALCSIZE
// Winstone 99 needs modified NC_CALCSIZE behavior for Netscape or it will hang.
if ( 0 == AsciiStrCmpI( pszProcess, L"Netscape" )) { if (FindWindowEx(NULL, NULL, L"ZDBench32Frame", NULL) != NULL) { _SetMsgHandler( WM_NCCALCSIZE, _rgDwpHandlers, ARRAYSIZE(_rgDwpHandlers), OnDwpNcCalcSize2, FALSE ); return TRUE; } } #endif THEME_CALCSIZE
//-------------------------
// This AppHack was once fixed, but got broke again with
// addition of logic for partial-screen maximized windows.
//
// Something in our answer to NCCALCSIZE causes quick time player
// to continously flood its 'control' frame window's winproc with
// WM_PAINTS by repeatedly calling InvalidateRgn + UpdateWindow. My
// suspicion is that he looks at what DefWindowProc returns from
// NCCALCSIZE to determine the area he needs to manage, and when
// this doesn't hash with other SYSMET values and/or AdjustWindowRect,
// he redundantly invalidates himself,
//
// This only repros if qtp is launched w/ .mov file, works fine if
// launched without a file and then a file is loaded.
#ifdef THEME_CALCSIZE
if( 0 == AsciiStrCmpI( pszProcess, L"QuickTimePlayer" )) { _SetMsgHandler( WM_NCCALCSIZE, _rgDwpHandlers, ARRAYSIZE(_rgDwpHandlers), OnDwpNcCalcSize2, FALSE ); return TRUE; }
// SEANHI DID NOT RECEIVE THE S/W FROM APPLIB AND SO WAS UNABLE TO VERIFY THIS
// NO LONGER REPROS W/ ELIMINATION OF THEMED SYSMETS
//-------------------------
// Paradox 9 appHack for nonclient button sizes:
//
// Paradox table schema view uses DrawFrameControl to render both
// a classic toolframe (small) caption and buttons, but uses the
// themed values of SM_CYSIZE instead of SM_CYSMSIZE to size the buttons.
// This apphack redirects requests in this process for SM_CX/YSIZE to SM_CX/YSMSIZE.
if( 0 == AsciiStrCmpI( pszProcess, L"pdxwin32" ) ) { _SetGsmHandler( SM_CXSIZE, OnGsmCxSmBtnSize ); _SetGsmHandler( SM_CYSIZE, OnGsmCySmBtnSize ); return TRUE; } #endif THEME_CALCSIZE
//-------------------------
#else
# pragma message("App hacks disabled")
#endif __NO_APPHACKS__
return TRUE; }
//---------------------------------------------------------------------------
// Handler table utility functions
//---------------------------------------------------------------------------
//---------------------------------------------------------------------------
void HandlerTableInit() {}
//---------------------------------------------------------------------------
BOOL _InitMsgMask( LPBYTE prgMsgMask, DWORD dwMaskBytes, MSGENTRY* prgEntries, int cEntries, IN OUT BOOL& fInit ) { if( !fInit ) { for( int i = 0; i < cEntries; i++ ) { if( -1 == prgEntries[i].nMsg ) { ASSERT(prgEntries[i].pnRegMsg); // Initialize registered message entry
prgEntries[i].nMsg = *prgEntries[i].pnRegMsg;
Log(LOG_TMHANDLE, L"InitMsgMsg corrected registered msg: 0x%x", prgEntries[i].nMsg); }
//---- ensure we set up limit on table correctly ----
ASSERT((prgEntries[i].nMsg)/8 < dwMaskBytes); SET_MSGMASK( prgMsgMask, prgEntries[i].nMsg ); } fInit = TRUE; }
return fInit; }
//---------------------------------------------------------------------------
// Scan of MSG table as linear array:
inline int _FindMsgHandler( UINT nMsg, MSGENTRY rgEntries[], int cEntries, OUT OPTIONAL HOOKEDMSGHANDLER* ppfnHandler, OUT OPTIONAL HOOKEDMSGHANDLER* ppfnHandler2 ) { ASSERT( nMsg ); ASSERT( nMsg != (UINT)-1 );
if( ppfnHandler ) *ppfnHandler = NULL; if( ppfnHandler2 ) *ppfnHandler2 = NULL;
for( int i = 0; i < cEntries; i++ ) { if( rgEntries[i].nMsg == nMsg ) { // If no handler requested, return success
if( NULL == ppfnHandler && NULL == ppfnHandler2 ) return i;
// Assign outbound handler values
if( ppfnHandler ) *ppfnHandler = rgEntries[i].pfnHandler; if( ppfnHandler2 ) *ppfnHandler2 = rgEntries[i].pfnHandler2;
// return TRUE iif caller got what he asked for.
return ((ppfnHandler && *ppfnHandler) || (ppfnHandler2 && *ppfnHandler2)) ? i : -1; } } return -1; }
//---------------------------------------------------------------------------
// Modify existing handler
inline BOOL _SetMsgHandler( UINT nMsg, MSGENTRY rgEntries[], int cEntries, IN HOOKEDMSGHANDLER pfnHandler, BOOL fHandler2 ) { int i = _FindMsgHandler( nMsg, rgEntries, cEntries, NULL, NULL ); if( i >= 0 ) { if( fHandler2 ) rgEntries[i].pfnHandler2 = pfnHandler; else rgEntries[i].pfnHandler = pfnHandler; return TRUE; } return FALSE; }
#define CBMSGMASK(msgHigh) (((msgHigh)+1)/8 + ((((msgHigh)+1) % 8) ? 1: 0))
//---------------------------------------------------------------------------
DWORD GetOwpMsgMask( LPBYTE* prgMsgMask ) { static BOOL _fOwpMask = FALSE; // initialized?
static BYTE _rgOwpMask[CBMSGMASK(WNDPROC_MSG_LAST)] = {0};
if( _InitMsgMask( _rgOwpMask, ARRAYSIZE(_rgOwpMask), _rgOwpHandlers, ARRAYSIZE(_rgOwpHandlers), _fOwpMask ) ) { *prgMsgMask = _rgOwpMask; return ARRAYSIZE(_rgOwpMask); } return 0; }
//---------------------------------------------------------------------------
DWORD GetDdpMsgMask( LPBYTE* prgMsgMask ) { static BOOL _fDdpMask = FALSE; // initialized?
static BYTE _rgDdpMask[CBMSGMASK(DEFDLGPROC_MSG_LAST)] = {0};
if( _InitMsgMask( _rgDdpMask, ARRAYSIZE(_rgDdpMask), _rgDdpHandlers, ARRAYSIZE(_rgDdpHandlers), _fDdpMask ) ) { *prgMsgMask = _rgDdpMask; return ARRAYSIZE(_rgDdpMask); } return 0; }
//---------------------------------------------------------------------------
DWORD GetDwpMsgMask( LPBYTE* prgMsgMask ) { static BOOL _fDwpMask = FALSE; // initialized?
static BYTE _rgDwpMask[CBMSGMASK(DEFWNDPROC_MSG_LAST)] = {0};
if( _InitMsgMask( _rgDwpMask, ARRAYSIZE(_rgDwpMask), _rgDwpHandlers, ARRAYSIZE(_rgDwpHandlers), _fDwpMask ) ) { *prgMsgMask = _rgDwpMask; return ARRAYSIZE(_rgDwpMask); } return 0; }
//---------------------------------------------------------------------------
BOOL FindOwpHandler( UINT nMsg, HOOKEDMSGHANDLER* ppfnPre, HOOKEDMSGHANDLER* ppfnPost ) { return _FindMsgHandler( nMsg, _rgOwpHandlers, ARRAYSIZE(_rgOwpHandlers), ppfnPre, ppfnPost ) >= 0; }
//---------------------------------------------------------------------------
BOOL FindDdpHandler( UINT nMsg, HOOKEDMSGHANDLER* ppfnPre, HOOKEDMSGHANDLER* ppfnPost ) { return _FindMsgHandler( nMsg, _rgDdpHandlers, ARRAYSIZE(_rgDdpHandlers), ppfnPre, ppfnPost ) >= 0; }
//---------------------------------------------------------------------------
BOOL FindDwpHandler( UINT nMsg, HOOKEDMSGHANDLER* ppfnPre ) { HOOKEDMSGHANDLER pfnPost; return _FindMsgHandler( nMsg, _rgDwpHandlers, ARRAYSIZE(_rgDwpHandlers), ppfnPre, &pfnPost ) >= 0; }
//---------------------------------------------------------------------------
// Performs default message processing.
LRESULT WINAPI DoMsgDefault( const THEME_MSG *ptm ) { ASSERT( ptm ); if( ptm->pfnDefProc ) { MsgHandled( ptm ); if( MSGTYPE_DEFWNDPROC == ptm->type ) return ptm->pfnDefProc( ptm->hwnd, ptm->uMsg, ptm->wParam, ptm->lParam ); else { ASSERT( NULL == ptm->pfnDefProc ); // bad initialization (_InitThemeMsg)
} } return 0L; }
|