令我难以置信。 DirectX绕过所有内容并直接与设备驱动程序对话,因此GDI和其他常用方法将无法工作 - 除非Aero被禁用(或不可用),所有出现的内容都是屏幕左上方的黑色矩形。我已经尝试过其他人在几个论坛上提出的建议,使用DirectX来获取后台缓冲区并保存它,但我得到了相同的结果:
device-> GetFrontBufferData(0,surface); D3DXSaveSurfaceToFile(“fileName”,D3DXIFF_BMP,surface,NULL,NULL);
启用Aero后,有没有办法获取另一个全屏DirectX应用程序的屏幕截图?
答案 0 :(得分:22)
查看Detours。
使用Detours,您可以调整Direct3DCreate9
,IDirect3D9::CreateDevice
和IDirect3D9::Present
之类的调用,您可以在其中执行设置所需的操作,然后执行帧捕获。
答案 1 :(得分:8)
这是a C# example of hooking IDirect3DDevice9对象通过DLL注入和使用EasyHook挂钩的功能(如Microsoft Detours)。这与FRAPS的工作方式类似。
这允许您以窗口/全屏模式捕获屏幕并使用后台缓冲区,这比尝试从前台缓冲区中检索数据要快得多。
一个小的C ++助手DLL用于确定在运行时挂钩的IDirect3DDevice9对象的方法。
对于DirectX 10/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