25

我需要捕获 DirectX 窗口的视觉输出(如屏幕截图)。目前,我使用这种方法
但是,当窗口在后台时,它会捕获它前面的任何内容。

我看到 DirectX 窗口即使在最小化或在后台呈现,所以这应该是可能的。
但是,怎么做?(它还需要速度快,而且它也需要在 Windows XP 上运行,不幸的是......)

编辑:这些天我很忙......别担心,如果它到期,我会把赏金退回。

4

3 回答 3

25

要捕获在后台(或移出屏幕)的 Direct3D 窗口,我相信您有以下选择:

  1. 通过您已经发布的链接或这个更新的示例(EasyHook 可能很难设置,但它确实工作得很好)在目标应用程序中注入和挂钩 Direct3D - 您可以随时寻求帮助以使其正常工作. 我已经使用该技术在许多游戏中毫无问题地捕获(最近用于流光溢彩克隆项目)。这种方法的问题是您担心游戏保护会导致禁令,但是 FRAPs 也使用挂钩来实现这一点,所以您的担心可能被夸大了?我猜游戏玩家因屏幕截图而被禁止是一种昂贵的发现方式。

  2. 对于 Vista/Win 7 上的窗口应用程序 - 您可以注入和挂钩 DWM 并通过其共享表面发出捕获请求。我已经在 Vista 上运行了这个,但还没有完成它在 Windows 7 上的运行,这是一个适用于 Windows 7 http://www.youtube.com/watch?v=G75WKeXqXkc的示例。这种方法的主要问题是使用了未记录的 API,这可能意味着您的应用程序在 Windows 补丁发布时没有任何警告就中断了 - 您还必须为每个新的主要 Windows 风格重做该技术。这也不能解决您在 Windows XP 中捕获的需要。

  3. 同样在 DWM 中,还有一个缩略图 API。这取决于您尝试执行的操作。有一些关于这个 API 的信息以及其他 DWM API 在这里http://blogs.msdn.com/b/greg_schechter/archive/2006/09/14/753605.aspx

  4. 还有其他技术可以在不使用 EasyHook 的情况下拦截 Direct3D 调用,例如用包装器替换各种 DLL。您可以在这里找到各种其他游戏挂钩/拦截技术:http: //www.gamedeception.net/

  5. 只需将 Direct3D 应用程序带到前台(我猜这在您的情况下是不受欢迎的) - 这对屏幕外窗口不起作用,除非您也移动窗口。

  6. 不幸的是,我能想到的 Windows XP 的唯一解决方案是以某种形式拦截 Direct3D API。

只是在最小化时对 Direct3D 渲染进行说明。在我对这个问题的相当有限的测试中,我发现这取决于应用程序;通常不建议在应用程序最小化时进行渲染(也是此参考),但它确实会在后台继续渲染。

更新:为第 1 点提供了更多最新注入示例的附加链接。

于 2012-04-11T10:47:24.863 回答
6

一个快速的谷歌,我发现了这个与 Windows XP 相关的代码项目。我不知道您是否可以将这些知识应用到 Windows Vista 和 7 中?

http://www.codeproject.com/Articles/5051/Various-methods-for-capturing-the-screen

编辑:

我也找到了这篇文章:

http://www.codeproject.com/Articles/20651/Capturing-Minimized-Window-A-Kid-s-Trick

此链接来自评论中的 Justins 博客文章。看来他正在和某人一起做这个(我看到那是你的链接)。

http://spazzarama.com/2009/02/07/screencapture-with-direct3d/

于 2012-04-10T15:58:31.137 回答
2

您说您在项目中使用的链接到的代码(来自 spazzarama)捕获 DirectX 设备的前端缓冲区。您是否尝试过捕获后台缓冲区?从链接站点上的代码开始,您将第 90 行从

device.GetFrontBufferData(0, surface);

Surface backbuffer = device.GetBackBuffer(0, 0, BackBufferType.Mono);
SurfaceLoader.Save("Screenshot.bmp", ImageFileFormat.Bmp, backbuffer);

这还涉及删除链接示例中的第 96-98 行。后缓冲区可能会在没有阻碍窗口的情况下生成。

编辑

没关系这一切。我刚刚意识到您链接的示例代码正在使用窗口句柄来定义屏幕区域,而实际上并没有对 DirectX 窗口进行任何操作。您的示例代码无法解决障碍,因为在您访问区域时,您的区域已经在其前面的另一个窗口中绘制。

挽救应用程序的最佳选择可能是在运行代码以捕获图像之前将 DirectX 窗口置于屏幕顶部。您可以使用该Wind32API BringWindowToTop功能来做到这一点(http://msdn.microsoft.com/en-us/library/ms632673%28VS.85%29.aspx)。

于 2012-04-10T21:56:11.193 回答