/*++ Copyright (c) 2000 Microsoft Corporation Module Name: IgnoreHungAppPaint.cpp Abstract: Setup the hollow brush to prevent user from trashing peoples windows. Notes: This is a general purpose shim. History: 12/04/2000 linstev Created --*/ #include "precomp.h" #include "LegalStr.h" IMPLEMENT_SHIM_BEGIN(IgnoreHungAppPaint) #include "ShimHookMacro.h" APIHOOK_ENUM_BEGIN APIHOOK_ENUM_ENTRY(RegisterClassA) APIHOOK_ENUM_ENTRY(RegisterClassW) APIHOOK_ENUM_ENTRY(RegisterClassExA) APIHOOK_ENUM_ENTRY(RegisterClassExW) APIHOOK_ENUM_END struct HUNGCLASS { char szClass[MAX_PATH]; HUNGCLASS *next; }; HUNGCLASS *g_lHungList = NULL; BOOL g_bAll = FALSE; /*++ Check if a class needs a hollow brush. --*/ BOOL IsHungClassA(LPCSTR szClass) { BOOL bRet = FALSE; if (szClass) { HUNGCLASS *h = g_lHungList; while (h) { if (_stricmp(szClass, h->szClass) == 0) { LOGN(eDbgLevelWarning, "Matched hung class: forcing HOLLOW_BRUSH"); bRet = TRUE; break; } h = h->next; } } return bRet; } /*++ Check if a class needs a hollow brush. --*/ BOOL IsHungClassW(LPCWSTR wszClass) { CHAR szClass[MAX_PATH]; WideCharToMultiByte( CP_ACP, 0, (LPWSTR) wszClass, MAX_PATH, (LPSTR) szClass, MAX_PATH, 0, 0); return IsHungClassA(szClass); } /*++ Hook all possible calls that can initialize or change a window's WindowProc (or DialogProc) --*/ ATOM APIHOOK(RegisterClassA)( WNDCLASSA *lpWndClass ) { if (lpWndClass && (g_bAll || IsHungClassA(lpWndClass->lpszClassName))) { lpWndClass->hbrBackground = (HBRUSH) GetStockObject(HOLLOW_BRUSH); } return ORIGINAL_API(RegisterClassA)(lpWndClass); } ATOM APIHOOK(RegisterClassW)( WNDCLASSW *lpWndClass ) { if (lpWndClass && IsHungClassW(lpWndClass->lpszClassName)) { lpWndClass->hbrBackground = (HBRUSH) GetStockObject(HOLLOW_BRUSH); } return ORIGINAL_API(RegisterClassW)(lpWndClass); } ATOM APIHOOK(RegisterClassExA)( WNDCLASSEXA *lpWndClass ) { if (lpWndClass && IsHungClassA(lpWndClass->lpszClassName)) { lpWndClass->hbrBackground = (HBRUSH) GetStockObject(HOLLOW_BRUSH); } return ORIGINAL_API(RegisterClassExA)(lpWndClass); } ATOM APIHOOK(RegisterClassExW)( WNDCLASSEXW *lpWndClass ) { if (lpWndClass && IsHungClassW(lpWndClass->lpszClassName)) { lpWndClass->hbrBackground = (HBRUSH) GetStockObject(HOLLOW_BRUSH); } return ORIGINAL_API(RegisterClassExW)(lpWndClass); } /*++ Parse the command line for fixes: CLASS1; CLASS2; CLASS3 ... --*/ VOID ParseCommandLineA( LPCSTR lpCommandLine ) { // Add all the defaults if no command line is specified if (!lpCommandLine || (lpCommandLine[0] == '\0')) { g_bAll = TRUE; DPFN(eDbgLevelInfo, "All classes will use HOLLOW_BRUSH"); return; } char seps[] = " ,\t;"; char *token = NULL; // Since strtok modifies the string, we need to copy it LPSTR szCommandLine = (LPSTR) malloc(strlen(lpCommandLine) + 1); if (!szCommandLine) goto Exit; strcpy(szCommandLine, lpCommandLine); // // Run the string, looking for fix names // token = _strtok(szCommandLine, seps); while (token) { HUNGCLASS *h; h = (HUNGCLASS *) malloc(sizeof(HUNGCLASS)); if (h) { h->next = g_lHungList; g_lHungList = h; strncpy(h->szClass, token, MAX_PATH); DPFN(eDbgLevelInfo, "Adding %s", token); } else { DPFN(eDbgLevelError, "Out of memory"); } // Get the next token token = _strtok(NULL, seps); } Exit: if (szCommandLine) { free(szCommandLine); } } /*++ Register hooked functions --*/ BOOL NOTIFY_FUNCTION( DWORD fdwReason ) { if (fdwReason == DLL_PROCESS_ATTACH) { ParseCommandLineA(COMMAND_LINE); } return TRUE; } HOOK_BEGIN CALL_NOTIFY_FUNCTION APIHOOK_ENTRY(USER32.DLL, RegisterClassA) APIHOOK_ENTRY(USER32.DLL, RegisterClassW); APIHOOK_ENTRY(USER32.DLL, RegisterClassExA); APIHOOK_ENTRY(USER32.DLL, RegisterClassExW); HOOK_END IMPLEMENT_SHIM_END