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.

234 lines
5.2 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. Commandos.cpp
  5. Abstract:
  6. A hack for Commandos (EIDOS). The game caches a pointer to the ddraw
  7. primary surface. On NT, after a mode change, the memory can be mapped
  8. into a different location - so when they try to write to it, it access
  9. violates.
  10. We know from debugging the app where they keep the cached pointer, so
  11. when they restore the surface, we relock it, and patch the new pointer
  12. into their store.
  13. Notes:
  14. This is an app specific hack.
  15. History:
  16. 10/29/1999 linstev Created
  17. --*/
  18. #include "precomp.h"
  19. IMPLEMENT_SHIM_BEGIN(Commandos)
  20. #include "ShimHookMacro.h"
  21. APIHOOK_ENUM_BEGIN
  22. APIHOOK_ENUM_ENTRY_DIRECTX_COMSERVER()
  23. APIHOOK_ENUM_END
  24. IMPLEMENT_DIRECTX_COMSERVER_HOOKS()
  25. static LPVOID pLastPrimary = NULL;
  26. static LPDWORD pAppPrimary = NULL;
  27. /*++
  28. Hook create surface so we can be sure we're being called.
  29. --*/
  30. HRESULT
  31. COMHOOK(IDirectDraw, CreateSurface)(
  32. PVOID pThis,
  33. LPDDSURFACEDESC lpDDSurfaceDesc,
  34. LPDIRECTDRAWSURFACE* lplpDDSurface,
  35. IUnknown* pUnkOuter
  36. )
  37. {
  38. HRESULT hReturn;
  39. _pfn_IDirectDraw_CreateSurface pfnOld = ORIGINAL_COM(IDirectDraw, CreateSurface, pThis);
  40. if (SUCCEEDED(hReturn = (*pfnOld)(
  41. pThis,
  42. lpDDSurfaceDesc,
  43. lplpDDSurface,
  44. pUnkOuter)))
  45. {
  46. HookObject(
  47. NULL,
  48. IID_IDirectDrawSurface,
  49. (PVOID*)lplpDDSurface,
  50. NULL,
  51. FALSE);
  52. }
  53. return hReturn;
  54. }
  55. /*++
  56. Find out where they store the pointer.
  57. --*/
  58. HRESULT
  59. COMHOOK(IDirectDrawSurface, Lock)(
  60. LPDIRECTDRAWSURFACE lpDDSurface,
  61. LPRECT lpDestRect,
  62. LPDDSURFACEDESC lpDDSurfaceDesc,
  63. DWORD dwFlags,
  64. HANDLE hEvent
  65. )
  66. {
  67. DDSURFACEDESC ddsd = {sizeof(ddsd)};
  68. HRESULT hReturn, hr;
  69. // Retrieve the old function
  70. _pfn_IDirectDrawSurface_Lock pfnOld = ORIGINAL_COM(IDirectDrawSurface, Lock, lpDDSurface);
  71. // Call the old API
  72. if (FAILED(hReturn = (*pfnOld)(
  73. lpDDSurface,
  74. lpDestRect,
  75. lpDDSurfaceDesc,
  76. dwFlags,
  77. hEvent)))
  78. {
  79. return hReturn;
  80. }
  81. // Make sure it's a primary
  82. hr = lpDDSurface->GetSurfaceDesc(&ddsd);
  83. if (SUCCEEDED(hr) &&
  84. (ddsd.ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | DDSCAPS_VISIBLE)))
  85. {
  86. // We know:
  87. // 1. They cache the primary address in [esi+0x20]
  88. // 2. They lock the primary more than once
  89. //
  90. // We assume:
  91. // 1. When they lock the primary, esi+0x20 is a valid pointer
  92. if ((pLastPrimary) && (!pAppPrimary))
  93. {
  94. __asm
  95. {
  96. pop edi
  97. pop esi
  98. mov eax,pLastPrimary
  99. cmp [esi+0x20],eax
  100. jne WrongESI
  101. // [esi+0x20] does contain the cached pointer
  102. lea eax,[esi+0x20]
  103. mov pAppPrimary,eax
  104. WrongESI:
  105. push esi
  106. push edi
  107. }
  108. }
  109. pLastPrimary = lpDDSurfaceDesc->lpSurface;
  110. }
  111. return hReturn;
  112. }
  113. /*++
  114. Patch the new pointer directly into their data segment.
  115. --*/
  116. HRESULT
  117. COMHOOK(IDirectDrawSurface, Restore)(
  118. LPDIRECTDRAWSURFACE lpDDSurface
  119. )
  120. {
  121. DDSURFACEDESC ddsd = {sizeof(ddsd)};
  122. HRESULT hReturn, hr, hrt;
  123. // Retrieve the old function
  124. _pfn_IDirectDrawSurface_Restore pfnOld = ORIGINAL_COM(IDirectDrawSurface, Restore, lpDDSurface);
  125. // Call the old API
  126. if (FAILED(hReturn = (*pfnOld)(lpDDSurface)))
  127. {
  128. return hReturn;
  129. }
  130. // Make sure it's a primary
  131. hr = lpDDSurface->GetSurfaceDesc(&ddsd);
  132. if (SUCCEEDED(hr) &&
  133. (ddsd.ddsCaps.dwCaps & (DDSCAPS_PRIMARYSURFACE | DDSCAPS_VISIBLE)))
  134. {
  135. // Check if we've been set up
  136. if (!((pLastPrimary) && (pAppPrimary)))
  137. {
  138. return hReturn;
  139. }
  140. // We must get a pointer here, so keep trying
  141. do
  142. {
  143. hr = lpDDSurface->Lock(
  144. NULL,
  145. &ddsd,
  146. DDLOCK_SURFACEMEMORYPTR | DDLOCK_WAIT,
  147. NULL);
  148. if (hr == DDERR_SURFACELOST)
  149. {
  150. // Don't care about result
  151. (*pfnOld)(lpDDSurface);
  152. }
  153. } while (hr == DDERR_SURFACELOST);
  154. // Patch the new pointer into their memory
  155. pLastPrimary = ddsd.lpSurface;
  156. if ((pLastPrimary) && (pAppPrimary))
  157. {
  158. *pAppPrimary = (DWORD_PTR)pLastPrimary;
  159. }
  160. // Unlock the surface
  161. lpDDSurface->Unlock(NULL);
  162. }
  163. return hReturn;
  164. }
  165. /*++
  166. Register hooked functions
  167. --*/
  168. HOOK_BEGIN
  169. APIHOOK_ENTRY_DIRECTX_COMSERVER()
  170. COMHOOK_ENTRY(DirectDraw, IDirectDraw, CreateSurface, 6)
  171. COMHOOK_ENTRY(DirectDraw, IDirectDrawSurface, Lock, 25)
  172. COMHOOK_ENTRY(DirectDraw, IDirectDrawSurface, Restore, 27)
  173. HOOK_END
  174. IMPLEMENT_SHIM_END