171 lines
3.6 KiB
C++
171 lines
3.6 KiB
C++
/*++
|
|
|
|
Copyright (c) 1999 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
UltimateSoccerManager.cpp
|
|
|
|
Abstract:
|
|
|
|
A hack for Ultimate Soccer Manager (Sierra Sports). The game caches a
|
|
pointer to a ddraw system memory surface. It later uses that pointer even
|
|
after the surface has been freed.
|
|
|
|
This worked on Win9x by blind luck: when they re-create a new surface, it
|
|
happened to end up in the same system memory as before.
|
|
|
|
Notes:
|
|
|
|
This is an app specific shim.
|
|
|
|
History:
|
|
|
|
01/07/2000 linstev Created
|
|
|
|
--*/
|
|
|
|
#include "precomp.h"
|
|
|
|
IMPLEMENT_SHIM_BEGIN(UltimateSoccerManager)
|
|
#include "ShimHookMacro.h"
|
|
|
|
APIHOOK_ENUM_BEGIN
|
|
APIHOOK_ENUM_ENTRY_DIRECTX_COMSERVER()
|
|
APIHOOK_ENUM_END
|
|
|
|
IMPLEMENT_DIRECTX_COMSERVER_HOOKS()
|
|
|
|
// Keep a list of cached surfaces
|
|
struct SLIST
|
|
{
|
|
struct SLIST *next;
|
|
DDSURFACEDESC ddsd;
|
|
LPDIRECTDRAWSURFACE lpDDSurface;
|
|
};
|
|
SLIST *g_SList = NULL;
|
|
|
|
/*++
|
|
|
|
Hook create surface so we can return the cached surface if possible.
|
|
|
|
--*/
|
|
|
|
HRESULT
|
|
COMHOOK(IDirectDraw, CreateSurface)(
|
|
PVOID pThis,
|
|
LPDDSURFACEDESC lpDDSurfaceDesc,
|
|
LPDIRECTDRAWSURFACE* lplpDDSurface,
|
|
IUnknown* pUnkOuter
|
|
)
|
|
{
|
|
HRESULT hReturn;
|
|
|
|
// Retrieve the old function
|
|
_pfn_IDirectDraw_CreateSurface pfnOld =
|
|
ORIGINAL_COM(IDirectDraw, CreateSurface, pThis);
|
|
|
|
SLIST *surf = g_SList, *last = NULL;
|
|
while (surf)
|
|
{
|
|
// Check for the same kind of surface.
|
|
if ((lpDDSurfaceDesc->ddsCaps.dwCaps == surf->ddsd.ddsCaps.dwCaps) &&
|
|
(lpDDSurfaceDesc->dwWidth == surf->ddsd.dwWidth) &&
|
|
(lpDDSurfaceDesc->dwHeight == surf->ddsd.dwHeight))
|
|
{
|
|
*lplpDDSurface = surf->lpDDSurface;
|
|
|
|
if (last)
|
|
{
|
|
last->next = surf->next;
|
|
}
|
|
else
|
|
{
|
|
g_SList = surf->next;
|
|
}
|
|
free(surf);
|
|
|
|
DPFN( eDbgLevelInfo, "Returning cached surface %08lx\n", *lplpDDSurface);
|
|
|
|
return DD_OK;
|
|
}
|
|
surf = surf->next;
|
|
}
|
|
|
|
if (SUCCEEDED(hReturn = (*pfnOld)(
|
|
pThis,
|
|
lpDDSurfaceDesc,
|
|
lplpDDSurface,
|
|
pUnkOuter)))
|
|
{
|
|
HookObject(
|
|
NULL,
|
|
IID_IDirectDrawSurface,
|
|
(PVOID*)lplpDDSurface,
|
|
NULL,
|
|
FALSE);
|
|
}
|
|
|
|
return hReturn;
|
|
}
|
|
|
|
/*++
|
|
|
|
If it's a system memory surface, go ahead and cache it if we're about to
|
|
release it anyway.
|
|
|
|
--*/
|
|
|
|
ULONG
|
|
COMHOOK(IDirectDrawSurface, Release)(
|
|
LPDIRECTDRAWSURFACE lpDDSurface
|
|
)
|
|
{
|
|
lpDDSurface->AddRef();
|
|
|
|
// Retrieve the old function
|
|
_pfn_IDirectDrawSurface_Release pfnOld = ORIGINAL_COM(IDirectDrawSurface, Release, (LPVOID) lpDDSurface);
|
|
|
|
ULONG uRet = (*pfnOld)(lpDDSurface);
|
|
|
|
if (uRet == 1)
|
|
{
|
|
DDSURFACEDESC ddsd = {sizeof(ddsd)};
|
|
|
|
if (SUCCEEDED(lpDDSurface->GetSurfaceDesc(&ddsd)) &&
|
|
(ddsd.ddsCaps.dwCaps ==
|
|
(DDSCAPS_OFFSCREENPLAIN | DDSCAPS_SYSTEMMEMORY)))
|
|
{
|
|
SLIST *surf = (SLIST *) malloc(sizeof(SLIST));
|
|
surf->next = g_SList;
|
|
MoveMemory(&surf->ddsd, &ddsd, sizeof(ddsd));
|
|
surf->lpDDSurface = lpDDSurface;
|
|
g_SList = surf;
|
|
|
|
DPFN( eDbgLevelInfo, "Surface %08lx is being cached\n", lpDDSurface);
|
|
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return (*pfnOld)(lpDDSurface);
|
|
}
|
|
|
|
/*++
|
|
|
|
Register hooked functions
|
|
|
|
--*/
|
|
|
|
|
|
HOOK_BEGIN
|
|
|
|
APIHOOK_ENTRY_DIRECTX_COMSERVER()
|
|
COMHOOK_ENTRY(DirectDraw, IDirectDraw, CreateSurface, 6)
|
|
COMHOOK_ENTRY(DirectDraw, IDirectDrawSurface, Release, 2)
|
|
|
|
HOOK_END
|
|
|
|
IMPLEMENT_SHIM_END
|
|
|