/*++ Copyright (c) 2001 Microsoft Corporation Module Name: CorrectCreateSurface.cpp Abstract: Clean up bad ddraw CreateSurface caps. Command Line FIX;CHK:Flags;DEL:Flags;ADD=Flags e.g., - FIX;CHK:DDSCAPS_TEXTURE;DEL:DDSCAPS_3DDEVICE FIX - Sets the flags which indicate whether to fix the flags and call the interface or to make a call and retry after fixing caps if the call fails. The default is to call the interface with passed in parameters and if the call fails then the flags are fixed and a retry is made. CHK - Check for flags (condition) ADD - Add flags DEL - Delete flags Notes: This is a general purpose shim. History: 02/16/2001 a-leelat Created 02/13/2002 astritz Security Review --*/ #include "precomp.h" IMPLEMENT_SHIM_BEGIN(CorrectCreateSurface) #include "ShimHookMacro.h" APIHOOK_ENUM_BEGIN APIHOOK_ENUM_ENTRY_DIRECTX_COMSERVER() APIHOOK_ENUM_END IMPLEMENT_DIRECTX_COMSERVER_HOOKS() DWORD g_dwFlagsChk = 0; DWORD g_dwFlagsAdd = 0; DWORD g_dwFlagsDel = 0; BOOL g_bTryAndFix = TRUE; struct DDFLAGS { WCHAR * lpszFlagName; DWORD dwFlag; }; //Hold the falg entries //add any undefined flags to this array static DDFLAGS g_DDFlags[] = { {L"DDSCAPS_3DDEVICE", DDSCAPS_3DDEVICE}, {L"DDSCAPS_ALLOCONLOAD", DDSCAPS_ALLOCONLOAD}, {L"DDSCAPS_ALPHA", DDSCAPS_ALPHA}, {L"DDSCAPS_BACKBUFFER", DDSCAPS_BACKBUFFER}, {L"DDSCAPS_COMPLEX", DDSCAPS_COMPLEX}, {L"DDSCAPS_FLIP", DDSCAPS_FLIP}, {L"DDSCAPS_FRONTBUFFER", DDSCAPS_FRONTBUFFER}, {L"DDSCAPS_HWCODEC", DDSCAPS_HWCODEC}, {L"DDSCAPS_LIVEVIDEO", DDSCAPS_LIVEVIDEO}, {L"DDSCAPS_LOCALVIDMEM", DDSCAPS_LOCALVIDMEM}, {L"DDSCAPS_MIPMAP", DDSCAPS_MIPMAP}, {L"DDSCAPS_MODEX", DDSCAPS_MODEX}, {L"DDSCAPS_NONLOCALVIDMEM", DDSCAPS_NONLOCALVIDMEM}, {L"DDSCAPS_OFFSCREENPLAIN", DDSCAPS_OFFSCREENPLAIN}, {L"DDSCAPS_OPTIMIZED", DDSCAPS_OPTIMIZED}, {L"DDSCAPS_OVERLAY", DDSCAPS_OVERLAY}, {L"DDSCAPS_OWNDC", DDSCAPS_OWNDC}, {L"DDSCAPS_PALETTE", DDSCAPS_PALETTE}, {L"DDSCAPS_PRIMARYSURFACE", DDSCAPS_PRIMARYSURFACE}, {L"DDSCAPS_STANDARDVGAMODE", DDSCAPS_STANDARDVGAMODE}, {L"DDSCAPS_SYSTEMMEMORY", DDSCAPS_SYSTEMMEMORY}, {L"DDSCAPS_TEXTURE", DDSCAPS_TEXTURE}, {L"DDSCAPS_VIDEOMEMORY", DDSCAPS_VIDEOMEMORY}, {L"DDSCAPS_VIDEOPORT", DDSCAPS_VIDEOPORT}, {L"DDSCAPS_VISIBLE", DDSCAPS_VISIBLE}, {L"DDSCAPS_WRITEONLY", DDSCAPS_WRITEONLY}, {L"DDSCAPS_ZBUFFER", DDSCAPS_ZBUFFER}, }; #define DDFLAGSSIZE sizeof(g_DDFlags) / sizeof(g_DDFlags[0]) DWORD GetDWord(const CString & lpFlag) { for ( int i = 0; i < DDFLAGSSIZE; i++ ) { if (lpFlag.CompareNoCase(g_DDFlags[i].lpszFlagName) == 0) { return g_DDFlags[i].dwFlag; } } return 0; } const WCHAR * GetName(DWORD dwDDSCAPS) { for ( int i = 0; i < DDFLAGSSIZE; i++ ) { if (g_DDFlags[i].dwFlag == dwDDSCAPS) { return g_DDFlags[i].lpszFlagName; } } return NULL; } VOID FixCaps(LPDDSURFACEDESC lpDDSurfaceDesc) { if ( lpDDSurfaceDesc->dwFlags & DDSD_CAPS ) { //To Check if( !lpDDSurfaceDesc->ddsCaps.dwCaps || lpDDSurfaceDesc->ddsCaps.dwCaps & g_dwFlagsChk ) { //To remove lpDDSurfaceDesc->ddsCaps.dwCaps &= ~g_dwFlagsDel; //To add lpDDSurfaceDesc->ddsCaps.dwCaps |= g_dwFlagsAdd; } } } VOID FixCaps2(LPDDSURFACEDESC2 lpDDSurfaceDesc) { if ( lpDDSurfaceDesc->dwFlags & DDSD_CAPS ) { //To Check if ( !lpDDSurfaceDesc->ddsCaps.dwCaps || lpDDSurfaceDesc->ddsCaps.dwCaps & g_dwFlagsChk ) { //To remove lpDDSurfaceDesc->ddsCaps.dwCaps &= ~g_dwFlagsDel; //To add lpDDSurfaceDesc->ddsCaps.dwCaps |= g_dwFlagsAdd; } } } HRESULT COMHOOK(IDirectDraw, CreateSurface)( PVOID pThis, LPDDSURFACEDESC lpDDSurfaceDesc, LPDIRECTDRAWSURFACE* lplpDDSurface, IUnknown* pUnkOuter ) { _pfn_IDirectDraw_CreateSurface pfnOld = ORIGINAL_COM(IDirectDraw, CreateSurface, pThis); //Fix it anyway if ( !g_bTryAndFix ) FixCaps(lpDDSurfaceDesc); HRESULT hRet = (*pfnOld)( pThis, lpDDSurfaceDesc, lplpDDSurface, pUnkOuter); if ( (hRet == DDERR_INVALIDCAPS) || (hRet == DDERR_INVALIDPIXELFORMAT)|| (hRet == DDERR_UNSUPPORTED) || (hRet == DDERR_OUTOFVIDEOMEMORY ) || (hRet == DDERR_INVALIDPARAMS) ) { FixCaps(lpDDSurfaceDesc); hRet = (*pfnOld)( pThis, lpDDSurfaceDesc, lplpDDSurface, pUnkOuter); } return hRet; } /*++ Hook create surface and fix parameters --*/ HRESULT COMHOOK(IDirectDraw2, CreateSurface)( PVOID pThis, LPDDSURFACEDESC lpDDSurfaceDesc, LPDIRECTDRAWSURFACE* lplpDDSurface, IUnknown* pUnkOuter ) { _pfn_IDirectDraw2_CreateSurface pfnOld = ORIGINAL_COM(IDirectDraw2, CreateSurface, pThis); //Fix it anyway if ( !g_bTryAndFix ) FixCaps(lpDDSurfaceDesc); HRESULT hRet = (*pfnOld)( pThis, lpDDSurfaceDesc, lplpDDSurface, pUnkOuter); if ( (hRet == DDERR_INVALIDCAPS) || (hRet == DDERR_INVALIDPIXELFORMAT) || (hRet == DDERR_UNSUPPORTED) || (hRet == DDERR_OUTOFVIDEOMEMORY ) || (hRet == DDERR_INVALIDPARAMS) ) { FixCaps(lpDDSurfaceDesc); hRet = (*pfnOld)( pThis, lpDDSurfaceDesc, lplpDDSurface, pUnkOuter); } return hRet; } /*++ Hook create surface and fix parameters --*/ HRESULT COMHOOK(IDirectDraw4, CreateSurface)( PVOID pThis, LPDDSURFACEDESC2 lpDDSurfaceDesc, LPDIRECTDRAWSURFACE* lplpDDSurface, IUnknown* pUnkOuter ) { _pfn_IDirectDraw4_CreateSurface pfnOld = ORIGINAL_COM(IDirectDraw4, CreateSurface, pThis); //Fix it anyway if ( !g_bTryAndFix ) FixCaps2(lpDDSurfaceDesc); HRESULT hRet = (*pfnOld)( pThis, lpDDSurfaceDesc, lplpDDSurface, pUnkOuter); if ( (hRet == DDERR_INVALIDCAPS) || (hRet == DDERR_INVALIDPIXELFORMAT) || (hRet == DDERR_UNSUPPORTED) || (hRet == DDERR_OUTOFVIDEOMEMORY ) || (hRet == DDERR_INVALIDPARAMS) ) { FixCaps2(lpDDSurfaceDesc); hRet = (*pfnOld)( pThis, lpDDSurfaceDesc, lplpDDSurface, pUnkOuter); } return hRet; } /*++ Hook create surface and fix parameters --*/ HRESULT COMHOOK(IDirectDraw7, CreateSurface)( PVOID pThis, LPDDSURFACEDESC2 lpDDSurfaceDesc, LPDIRECTDRAWSURFACE* lplpDDSurface, IUnknown* pUnkOuter ) { _pfn_IDirectDraw7_CreateSurface pfnOld = ORIGINAL_COM(IDirectDraw7, CreateSurface, pThis); if ( !g_bTryAndFix ) FixCaps2(lpDDSurfaceDesc); HRESULT hRet = (*pfnOld)( pThis, lpDDSurfaceDesc, lplpDDSurface, pUnkOuter); if ( (hRet == DDERR_INVALIDCAPS) || (hRet == DDERR_INVALIDPIXELFORMAT) || (hRet == DDERR_UNSUPPORTED) || (hRet == DDERR_OUTOFVIDEOMEMORY) || (hRet == DDERR_INVALIDPARAMS ) ) { FixCaps2(lpDDSurfaceDesc); hRet = (*pfnOld)( pThis, lpDDSurfaceDesc, lplpDDSurface, pUnkOuter); } return hRet; } BOOL ParseCommandLine(const char * lpszCommandLine) { CSTRING_TRY { DPFN( eDbgLevelInfo, "[ParseCommandLine] CommandLine(%s)\n", lpszCommandLine); CStringToken csCommandLine(lpszCommandLine, ";|:="); CString csOperator; while (csCommandLine.GetToken(csOperator)) { if (csOperator.CompareNoCase(L"Fix") == 0) { //Go ahead and fix the caps //before we make the call. g_bTryAndFix = FALSE; DPFN( eDbgLevelInfo, "[ParseCommandLine] Do not fix\n", lpszCommandLine); } else { // The next token is the caps to add CString csDDSCAPS; csCommandLine.GetToken(csDDSCAPS); DWORD dwDDSCAPS = GetDWord(csDDSCAPS); // returns 0 for unknown DDSCAPS if (dwDDSCAPS) { if (csOperator.CompareNoCase(L"Add") == 0) { DPFN( eDbgLevelInfo, "[ParseCommandLine] Add(%S)\n", GetName(dwDDSCAPS)); g_dwFlagsAdd |= dwDDSCAPS; } else if (csOperator.CompareNoCase(L"Del") == 0) { DPFN( eDbgLevelInfo, "[ParseCommandLine] Del(%S)\n", GetName(dwDDSCAPS)); g_dwFlagsDel |= dwDDSCAPS; } else if (csOperator.CompareNoCase(L"Chk") == 0) { DPFN( eDbgLevelInfo, "[ParseCommandLine] Chk(%S)\n", GetName(dwDDSCAPS)); g_dwFlagsChk |= dwDDSCAPS; } } } } } CSTRING_CATCH { return FALSE; } return TRUE; } BOOL NOTIFY_FUNCTION( DWORD fdwReason) { BOOL bSuccess = TRUE; if (fdwReason == DLL_PROCESS_ATTACH) { // Run the command line to check for adjustments to defaults bSuccess = ParseCommandLine(COMMAND_LINE); } return bSuccess; } /*++ Register hooked functions --*/ HOOK_BEGIN CALL_NOTIFY_FUNCTION APIHOOK_ENTRY_DIRECTX_COMSERVER() COMHOOK_ENTRY(DirectDraw, IDirectDraw, CreateSurface, 6) COMHOOK_ENTRY(DirectDraw, IDirectDraw2, CreateSurface, 6) COMHOOK_ENTRY(DirectDraw, IDirectDraw4, CreateSurface, 6) COMHOOK_ENTRY(DirectDraw, IDirectDraw7, CreateSurface, 6) HOOK_END IMPLEMENT_SHIM_END