截取DirectX全屏应用程序的屏幕截图

时间:2009-12-25 22:50:26

标签: directx screenshot fullscreen

令我难以置信。 DirectX绕过所有内容并直接与设备驱动程序对话,因此GDI和其他常用方法将无法工作 - 除非Aero被禁用(或不可用),所有出现的内容都是屏幕左上方的黑色矩形。我已经尝试过其他人在几个论坛上提出的建议,使用DirectX来获取后台缓冲区并保存它,但我得到了相同的结果:

device-> GetFrontBufferData(0,surface); D3DXSaveSurfaceToFile(“fileName”,D3DXIFF_BMP,surface,NULL,NULL);

启用Aero后,有没有办法获取另一个全屏DirectX应用程序的屏幕截图?

7 个答案:

答案 0 :(得分:22)

查看Detours

使用Detours,您可以调整Direct3DCreate9IDirect3D9::CreateDeviceIDirect3D9::Present之类的调用,您可以在其中执行设置所需的操作,然后执行帧捕获。

答案 1 :(得分:8)

这是a C# example of hooking IDirect3DDevice9对象通过DLL注入和使用EasyHook挂钩的功能(如Microsoft Detours)。这与FRAPS的工作方式类似。

这允许您以窗口/全屏模式捕获屏幕并使用后台缓冲区,这比尝试从前台缓冲区中检索数据要快得多。

一个小的C ++助手DLL用于确定在运行时挂钩的IDirect3DDevice9对象的方法。

对于DirectX 10/11的

更新,请参阅Screen capture and overlays for D3D 9, 10 and 11

答案 2 :(得分:3)

这是我刚才用作测试的代码片段,它似乎有效。

宽度和高度是窗口模式下SCREEN的大小,而不是窗口的大小。所以对我来说它们被设置为1280 x 1024而不是我正在渲染的窗口。

你需要用某种方式获取你的IDirect3DDevice9替换mEngine-> getDevice()。我刚把这个代码插入一个随机的d3d应用程序,我不得不让它更容易测试。但我可以确认它捕获了该应用程序的输出和同时运行的另一个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();

答案 3 :(得分:2)

有像fraps这样的开源程序:taksi但看起来过时了

答案 4 :(得分:2)

以下是有关Fraps如何工作的一些讨论。这并不简单。

http://www.woodmann.com/forum/archive/index.php/t-11023.html

尝试从不同的DirectX设备读取前端缓冲区的任何技巧,我怀疑由于未初始化的内存的运气可能偶尔会工作。

答案 5 :(得分:2)

根据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, p.x, p.y, 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的格式和池参数必须完全相同。

答案 6 :(得分:1)

您可能想看看我的Investigo项目。

它使用DirectX代理DLL拦截DirectX API函数。

在调用Present时,已有代码可以截取屏幕截图。虽然它尚未从UI访问。您应该能够轻松地启用代码。

http://www.codeproject.com/Articles/448756/Introducing-Investigo-Using-a-Proxy-DLL-and-embedd