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.

517 lines
12 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. TurkeyHunter.cpp
  5. Abstract:
  6. In Win9x, IDirectDraw::GetDC simply locks the surface and creates a DC
  7. around it via internal GDI calls. On NT, GDI supports DCs obtained from
  8. DirectDraw surfaces.
  9. Some games, like Turkey Hunter, use Surface::Unlock to get usage of the
  10. surface back, instead of Surface::ReleaseDC. Ordinarily we could simply
  11. make the unlock call the DirectDraw ReleaseDC, except that they continue
  12. using the DC after they've unlocked the surface.
  13. Notes:
  14. This is a general purpose hack.
  15. History:
  16. 01/20/2000 linstev Created
  17. --*/
  18. #include "precomp.h"
  19. IMPLEMENT_SHIM_BEGIN(TurkeyHunter)
  20. #include "ShimHookMacro.h"
  21. APIHOOK_ENUM_BEGIN
  22. APIHOOK_ENUM_ENTRY_DIRECTX_COMSERVER()
  23. APIHOOK_ENUM_END
  24. IMPLEMENT_DIRECTX_COMSERVER_HOOKS()
  25. // Link list of open DCs
  26. struct DC
  27. {
  28. DC *next;
  29. HDC hdc;
  30. HBITMAP hbmp;
  31. DWORD dwWidth, dwHeight;
  32. LPDIRECTDRAWSURFACE lpDDSurface;
  33. BOOL bBad;
  34. };
  35. DC *g_DCList = NULL;
  36. HRESULT
  37. COMHOOK(IDirectDrawSurface, ReleaseDC)(
  38. LPDIRECTDRAWSURFACE lpDDSurface,
  39. HDC hDC);
  40. /*++
  41. Hook create surface so we can be sure we're being called.
  42. --*/
  43. HRESULT
  44. COMHOOK(IDirectDraw, CreateSurface)(
  45. PVOID pThis,
  46. LPDDSURFACEDESC lpDDSurfaceDesc,
  47. LPDIRECTDRAWSURFACE* lplpDDSurface,
  48. IUnknown* pUnkOuter
  49. )
  50. {
  51. HRESULT hReturn;
  52. _pfn_IDirectDraw_CreateSurface pfnOld =
  53. ORIGINAL_COM(IDirectDraw, CreateSurface, pThis);
  54. if (SUCCEEDED(hReturn = (*pfnOld)(
  55. pThis,
  56. lpDDSurfaceDesc,
  57. lplpDDSurface,
  58. pUnkOuter)))
  59. {
  60. HookObject(
  61. NULL,
  62. IID_IDirectDrawSurface,
  63. (PVOID*)lplpDDSurface,
  64. NULL,
  65. FALSE);
  66. }
  67. return hReturn;
  68. }
  69. /*++
  70. Hook create surface so we can be sure we're being called.
  71. --*/
  72. HRESULT
  73. COMHOOK(IDirectDraw2, CreateSurface)(
  74. PVOID pThis,
  75. LPDDSURFACEDESC lpDDSurfaceDesc,
  76. LPDIRECTDRAWSURFACE* lplpDDSurface,
  77. IUnknown* pUnkOuter
  78. )
  79. {
  80. HRESULT hReturn;
  81. _pfn_IDirectDraw2_CreateSurface pfnOld =
  82. ORIGINAL_COM(IDirectDraw2, CreateSurface, pThis);
  83. if (SUCCEEDED(hReturn = (*pfnOld)(
  84. pThis,
  85. lpDDSurfaceDesc,
  86. lplpDDSurface,
  87. pUnkOuter)))
  88. {
  89. HookObject(
  90. NULL,
  91. IID_IDirectDrawSurface,
  92. (PVOID*)lplpDDSurface,
  93. NULL,
  94. FALSE);
  95. }
  96. return hReturn;
  97. }
  98. /*++
  99. Fake a DC - or rather produce a normal GDI DC that doesn't have the surface
  100. memory backing it.
  101. --*/
  102. HRESULT
  103. COMHOOK(IDirectDrawSurface, GetDC)(
  104. LPDIRECTDRAWSURFACE lpDDSurface,
  105. HDC FAR *lphDC
  106. )
  107. {
  108. HRESULT hReturn = DDERR_GENERIC;
  109. _pfn_IDirectDrawSurface_ReleaseDC pfnOldReleaseDC = NULL;
  110. _pfn_IDirectDrawSurface_GetDC pfnOld = NULL;
  111. DDSURFACEDESC ddsd = {sizeof(DDSURFACEDESC)};
  112. HDC hdc = 0;
  113. HBITMAP hbmp = 0;
  114. HGDIOBJ hOld = 0;
  115. DC *pdc = NULL;
  116. if (!lphDC || !lpDDSurface)
  117. {
  118. DPFN( eDbgLevelError, "Invalid parameters");
  119. goto Exit;
  120. }
  121. // Original GetDC
  122. pfnOld = ORIGINAL_COM(IDirectDrawSurface, GetDC, (LPVOID) lpDDSurface);
  123. if (!pfnOld)
  124. {
  125. DPFN( eDbgLevelError, "Old GetDC not found");
  126. goto Exit;
  127. }
  128. if (FAILED(hReturn = (*pfnOld)(
  129. lpDDSurface,
  130. lphDC)))
  131. {
  132. DPFN( eDbgLevelError, "IDirectDraw::GetDC Failed");
  133. goto Exit;
  134. }
  135. // We need the surface desc for the surface width and height
  136. lpDDSurface->GetSurfaceDesc(&ddsd);
  137. // Create a DC to be used by the app
  138. hdc = CreateCompatibleDC(0);
  139. if (!hdc)
  140. {
  141. DPFN( eDbgLevelError, "CreateDC failed");
  142. goto Exit;
  143. }
  144. // Create the DIB Section
  145. BITMAPINFO bmi;
  146. ZeroMemory(&bmi, sizeof(bmi));
  147. bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  148. bmi.bmiHeader.biPlanes = 1;
  149. bmi.bmiHeader.biBitCount = 24;
  150. bmi.bmiHeader.biCompression = BI_RGB;
  151. bmi.bmiHeader.biWidth = ddsd.dwWidth;
  152. bmi.bmiHeader.biHeight = ddsd.dwHeight;
  153. hbmp = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, NULL, NULL, 0);
  154. if (!hbmp)
  155. {
  156. DPFN( eDbgLevelError, "CreateDIBSection failed");
  157. goto Exit;
  158. }
  159. // Select the DIB Section into the DC
  160. hOld = SelectObject(hdc, hbmp);
  161. BitBlt(hdc, 0, 0, ddsd.dwWidth, ddsd.dwHeight, *lphDC, 0, 0, SRCCOPY);
  162. // Original ReleaseDC
  163. pfnOldReleaseDC =
  164. ORIGINAL_COM(IDirectDrawSurface, ReleaseDC, (LPVOID) lpDDSurface);
  165. if (!pfnOldReleaseDC)
  166. {
  167. DPFN( eDbgLevelError, "Old ReleaseDC not found");
  168. goto Exit;
  169. }
  170. // Release the DirectDraw DC
  171. (*pfnOldReleaseDC)(lpDDSurface, *lphDC);
  172. // Return the DC we just created
  173. *lphDC = hdc;
  174. // Add this to our DC list
  175. pdc = (DC *) malloc(sizeof DC);
  176. if (pdc)
  177. {
  178. pdc->next = g_DCList;
  179. g_DCList = pdc;
  180. pdc->hdc = hdc;
  181. pdc->lpDDSurface = lpDDSurface;
  182. pdc->hbmp = hbmp;
  183. pdc->dwHeight = ddsd.dwHeight;
  184. pdc->dwWidth = ddsd.dwWidth;
  185. pdc->bBad = FALSE;
  186. }
  187. else
  188. {
  189. DPFN( eDbgLevelError, "Out of memory");
  190. goto Exit;
  191. }
  192. hReturn = DD_OK;
  193. Exit:
  194. if (hReturn != DD_OK)
  195. {
  196. if (hOld && hdc)
  197. {
  198. SelectObject(hdc, hOld);
  199. }
  200. if (hbmp)
  201. {
  202. DeleteObject(hbmp);
  203. }
  204. if (hdc)
  205. {
  206. DeleteDC(hdc);
  207. }
  208. }
  209. return DD_OK;
  210. }
  211. /*++
  212. ReleaseDC has to copy the data back into the surface.
  213. --*/
  214. HRESULT
  215. COMHOOK(IDirectDrawSurface, ReleaseDC)(
  216. LPDIRECTDRAWSURFACE lpDDSurface,
  217. HDC hDC
  218. )
  219. {
  220. HRESULT hReturn = DDERR_GENERIC;
  221. // Original ReleaseDC
  222. _pfn_IDirectDrawSurface_ReleaseDC pfnOld =
  223. ORIGINAL_COM(IDirectDrawSurface, ReleaseDC, (LPVOID) lpDDSurface);
  224. // Run the list to see if we need to do anything
  225. DC *pdc = g_DCList, *last = NULL;
  226. while (pdc)
  227. {
  228. if ((pdc->lpDDSurface == lpDDSurface) &&
  229. (pdc->hdc == hDC))
  230. {
  231. // Remove it from the list
  232. if (last)
  233. {
  234. last->next = pdc->next;
  235. }
  236. else
  237. {
  238. g_DCList = pdc->next;
  239. }
  240. break;
  241. }
  242. last = pdc;
  243. pdc = pdc->next;
  244. }
  245. // We were in the list and someone used Unlock.
  246. if (pdc && (pdc->bBad))
  247. {
  248. // Original GetDC
  249. _pfn_IDirectDrawSurface_GetDC pfnOldGetDC =
  250. ORIGINAL_COM(IDirectDrawSurface, GetDC, (LPVOID)pdc->lpDDSurface);
  251. // Original ReleaseDC
  252. _pfn_IDirectDrawSurface_ReleaseDC pfnOldReleaseDC =
  253. ORIGINAL_COM(IDirectDrawSurface, ReleaseDC, (LPVOID)pdc->lpDDSurface);
  254. if (pfnOldGetDC && pfnOldReleaseDC)
  255. {
  256. // Copy everything back onto the surface
  257. HDC hTempDC;
  258. HGDIOBJ hOld = SelectObject(hDC, pdc->hbmp);
  259. if (SUCCEEDED((*pfnOldGetDC)(pdc->lpDDSurface, &hTempDC)))
  260. {
  261. BitBlt(hTempDC, 0, 0, pdc->dwWidth, pdc->dwHeight, hDC, 0, 0, SRCCOPY);
  262. (*pfnOldReleaseDC)(pdc->lpDDSurface, hTempDC);
  263. }
  264. SelectObject(hDC, hOld);
  265. // Delete the DIB Section
  266. DeleteObject(pdc->hbmp);
  267. // Delete the DC
  268. DeleteDC(hDC);
  269. hReturn = DD_OK;
  270. }
  271. }
  272. else
  273. {
  274. if (pfnOld)
  275. {
  276. // Didn't need to fake
  277. hReturn = (*pfnOld)(lpDDSurface, hDC);
  278. }
  279. }
  280. // Free the list item
  281. if (pdc)
  282. {
  283. free(pdc);
  284. }
  285. return hReturn;
  286. }
  287. /*++
  288. This is where we detect if Surface::Unlock was called after a Surface::GetDC.
  289. --*/
  290. HRESULT
  291. COMHOOK(IDirectDrawSurface, Unlock)(
  292. LPDIRECTDRAWSURFACE lpDDSurface,
  293. LPVOID lpSurfaceData
  294. )
  295. {
  296. HRESULT hRet = DDERR_GENERIC;
  297. // Walk the list to see if we're in it.
  298. DC *pdc = g_DCList;
  299. while (pdc)
  300. {
  301. if (pdc->lpDDSurface == lpDDSurface)
  302. {
  303. pdc->bBad = TRUE;
  304. break;
  305. }
  306. pdc = pdc->next;
  307. }
  308. if (!pdc)
  309. {
  310. // Original Unlock
  311. _pfn_IDirectDrawSurface_Unlock pfnOld =
  312. ORIGINAL_COM(IDirectDrawSurface, Unlock, (LPVOID)lpDDSurface);
  313. if (pfnOld)
  314. {
  315. // This is just a normal unlock
  316. hRet = (*pfnOld)(lpDDSurface, lpSurfaceData);
  317. }
  318. }
  319. else
  320. {
  321. // We never really locked in the first place, so no harm done.
  322. hRet = DD_OK;
  323. }
  324. return hRet;
  325. }
  326. /*++
  327. This is a problem case where they Blt after the Surface::Unlock, but before
  328. the Surface::ReleaseDC.
  329. --*/
  330. HRESULT
  331. COMHOOK(IDirectDrawSurface, Blt)(
  332. LPDIRECTDRAWSURFACE lpDDDestSurface,
  333. LPRECT lpDestRect,
  334. LPDIRECTDRAWSURFACE lpDDSrcSurface,
  335. LPRECT lpSrcRect,
  336. DWORD dwFlags,
  337. LPDDBLTFX lpDDBltFX
  338. )
  339. {
  340. HRESULT hRet = DDERR_GENERIC;
  341. // Original Blt
  342. _pfn_IDirectDrawSurface_Blt pfnOld =
  343. ORIGINAL_COM(IDirectDrawSurface, Blt, (LPVOID) lpDDDestSurface);
  344. if (!pfnOld)
  345. {
  346. return hRet;
  347. }
  348. // Are we in the bad state
  349. DC *pdc = g_DCList;
  350. while (pdc)
  351. {
  352. if (pdc->lpDDSurface == lpDDDestSurface)
  353. {
  354. break;
  355. }
  356. pdc = pdc->next;
  357. }
  358. if (!pdc)
  359. {
  360. return (*pfnOld)(
  361. lpDDDestSurface,
  362. lpDestRect,
  363. lpDDSrcSurface,
  364. lpSrcRect,
  365. dwFlags,
  366. lpDDBltFX);
  367. }
  368. // To get here, there must be an outstanding DC on this surface
  369. // Original GetDC
  370. _pfn_IDirectDrawSurface_GetDC pfnOldGetDC =
  371. ORIGINAL_COM(IDirectDrawSurface, GetDC, (LPVOID) lpDDDestSurface);
  372. // Original ReleaseDC
  373. _pfn_IDirectDrawSurface_ReleaseDC pfnOldReleaseDC =
  374. ORIGINAL_COM(IDirectDrawSurface, ReleaseDC, (LPVOID) lpDDDestSurface);
  375. if (!pfnOldGetDC || !pfnOldReleaseDC)
  376. {
  377. return hRet;
  378. }
  379. // Copy the DC contents to the surface
  380. HDC hTempDC;
  381. HGDIOBJ hOld = SelectObject(pdc->hdc, pdc->hbmp);
  382. if (SUCCEEDED((*pfnOldGetDC)(lpDDDestSurface, &hTempDC)))
  383. {
  384. BitBlt(hTempDC, 0, 0, pdc->dwWidth, pdc->dwHeight, pdc->hdc, 0, 0, SRCCOPY);
  385. (*pfnOldReleaseDC)(lpDDDestSurface, hTempDC);
  386. }
  387. // Do the ddraw Blt
  388. hRet = (*pfnOld)(
  389. lpDDDestSurface,
  390. lpDestRect,
  391. lpDDSrcSurface,
  392. lpSrcRect,
  393. dwFlags,
  394. lpDDBltFX);
  395. // Copy stuff back to the DC
  396. if (SUCCEEDED((*pfnOldGetDC)(lpDDDestSurface, &hTempDC)))
  397. {
  398. BitBlt(pdc->hdc, 0, 0, pdc->dwWidth, pdc->dwHeight, hTempDC, 0, 0, SRCCOPY);
  399. (*pfnOldReleaseDC)(lpDDDestSurface, hTempDC);
  400. }
  401. SelectObject(pdc->hdc, hOld);
  402. return hRet;
  403. }
  404. /*++
  405. Register hooked functions
  406. --*/
  407. HOOK_BEGIN
  408. APIHOOK_ENTRY_DIRECTX_COMSERVER()
  409. COMHOOK_ENTRY(DirectDraw, IDirectDraw, CreateSurface, 6)
  410. COMHOOK_ENTRY(DirectDraw, IDirectDraw2, CreateSurface, 6)
  411. COMHOOK_ENTRY(DirectDraw, IDirectDrawSurface, GetDC, 17)
  412. COMHOOK_ENTRY(DirectDraw, IDirectDrawSurface, ReleaseDC, 26)
  413. COMHOOK_ENTRY(DirectDraw, IDirectDrawSurface, Unlock, 32)
  414. COMHOOK_ENTRY(DirectDraw, IDirectDrawSurface, Blt, 5)
  415. HOOK_END
  416. IMPLEMENT_SHIM_END