截取DirectX全屏应用程序
这让我难以置信。 DirectX绕过了一切,并直接与设备驱动程序对话,因此GDI和其他常用方法将无法工作 – 除非Aero被禁用(或不可用),否则屏幕左上angular会出现一个黑色矩形。 我已经尝试了其他几个论坛上提出的build议,使用DirectX获取后台缓冲区并保存它,但是我得到了相同的结果:
device-> GetFrontBufferData(0,surface); D3DXSaveSurfaceToFile(“fileName”,D3DXIFF_BMP,surface,NULL,NULL);
启用Aero后,有没有办法获得另一个全屏DirectX应用程序的屏幕截图?
看看Detours 。
使用Detours,您可以调用Direct3DCreate9
, IDirect3D9::CreateDevice
和IDirect3D9::Present
等调用,您可以在其中执行设置所需的操作,然后执行帧捕获。
这里是一个C#示例,通过使用EasyHook(如Microsoft Detours)通过DLL注入和函数挂钩来挂钩IDirect3DDevice9对象。 这与FRAPS的工作原理类似。
这使您可以以窗口/全屏模式捕获屏幕,并使用后台缓冲区,这比从前台缓冲区检索数据要快得多。
一个小的C ++帮助程序DLL用于确定IDirect3DDevice9对象在运行时挂钩的方法。
更新:对于DirectX 10/11,请参阅D3D 9,10和11的屏幕截图和覆盖图
这是我刚刚用作testing的代码片段,它似乎工作。
宽度和高度是窗口模式下的屏幕大小,而不是窗口大小。 所以对我来说,他们被设置为1280 x 1024,而不是我渲染的窗口大小。
你需要用一些获取你的IDirect3DDevice9的方法来replacemEngine-> getDevice()。 我只是插入这个代码到一个随机的d3d应用程序,我不得不使它更容易testing。 但是我可以确认它同时捕获了该应用程序的输出和另一个正在运行的d3d应用程序。
哦,我认为这是D3D9,因为你没有说,我不知道d3d10或11
IDirect3DSurface9* surface; mEngine->getDevice()->CreateOffscreenPlainSurface(width, height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &surface, NULL); mEngine->getDevice()->GetFrontBufferData(0, surface); D3DXSaveSurfaceToFile("c:\\tmp\\output.jpg", D3DXIFF_JPG, surface, NULL, NULL); surface->Release();
有一个像fraps: taksi开源程序,但看起来过时了
以下是关于Fraps如何工作的一些讨论。 这并不简单。
http://www.woodmann.com/forum/archive/index.php/t-11023.html
任何试图从不同的DirectX设备读取前端缓冲区的技巧,我怀疑可能只是偶然的工作,因为未初始化的内存的运气。
按照J99的回答,我使代码适用于窗口模式和全屏模式。 这也是在D3D9中完成的。
IDirect3DSurface9* surface; D3DDISPLAYMODE mode; pDev->GetDisplayMode(0, &mode); // pDev is my *IDirect3DDevice // we can capture only the entire screen, // so width and height must match current display mode pDev->CreateOffscreenPlainSurface(mode.Width, mode.Height, D3DFMT_A8R8G8B8, D3DPOOL_SCRATCH, &surface, NULL); if(pDev->GetFrontBufferData(0, surface)==D3D_OK) { if(bWindowed) // a global config variable { // get client area in desktop coordinates // this might need to be changed to support multiple screens RECT r; GetClientRect(hWnd, &r); // hWnd is our window handle POINT p = {0, 0}; ClientToScreen(hWnd, &p); SetRect(&r, px, py, p.x+r.right, p.y+r.bottom); D3DXSaveSurfaceToFile(szFilename, D3DXIFF_JPG, surface, NULL, &r); } else D3DXSaveSurfaceToFile(szFilename, D3DXIFF_JPG, surface, NULL, NULL); } surface->Release();
它看起来像CreateOffscreenPlainSurface的格式和池参数必须完全相同。
你可能想看看我的Investigo项目。
它使用DirectX代理DLL来拦截DirectX API函数。
在Present中调用的时候已经有代码了。 虽然它还不能从UI访问。 你应该可以很容易地启用代码。
http://www.codeproject.com/Articles/448756/Introducing-Investigo-Using-a-Proxy-DLL-and-embedd