windows 叠加在 3D 全屏应用程序上

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/925981/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-09 06:26:06  来源:igfitidea点击:

Overlaying on a 3D fullscreen application

windowsopengldirectxoverlayfullscreen

提问by aib

I want to display some custom graphics on top of a 3rd party fullscreen Windows application.

我想在第 3 方全屏 Windows 应用程序之上显示一些自定义图形。

Have you played any Steam games? It has an executable, GameOverlayUI.exe that lets you access Steam windows from within a game. (The GUI elements look custom-drawn, I don't know if that is a necessity; but they look exactly the same inside a game as they do on the desktop.) It even goes as far to 'dim' the game graphics in the background.

你玩过steam游戏吗?它有一个可执行文件 GameOverlayUI.exe,可让您从游戏中访问 Steam 窗口。(GUI 元素看起来是自定义绘制的,我不知道这是否必要;但它们在游戏中的外观与在桌面上的完全相同。)它甚至可以将游戏图形“变暗”背景。

I'm wondering how one could go about writing such an application.

我想知道如何编写这样的应用程序。

I'm also wondering how broad the scope of solutions would be. Could you use one method for all OpenGL applications? For all Direct3D minus DirectDraw applications? For all fullscreen Windows applications?

我还想知道解决方案的范围有多大。您可以对所有 OpenGL 应用程序使用一种方法吗?对于所有 Direct3D 减去 DirectDraw 应用程序?对于所有全屏 Windows 应用程序?

I'm looking for more 'modern' and generic solutions - overlaying a command prompt or a 320x240 indexed color application isn't a concern.

我正在寻找更“现代”和通用的解决方案 - 覆盖命令提示符或 320x240 索引颜色应用程序不是问题。

Edit: Some clarification: The fullscreen application isn't mine. It can be anything. Most probably, it will be a 3D game. I want to display, say a digital clock in the bottom right corner of the screen, on top of the game graphics. I would like to avoid tricks such as injecting code or debugging the process, if possible.

编辑:一些澄清:全屏应用程序不是我的。它可以是任何东西。最有可能的是,这将是一个 3D 游戏。我想在游戏图形的顶部显示,比如屏幕右下角的数字时钟。如果可能的话,我想避免诸如注入代码或调试过程之类的技巧。

采纳答案by Shaun Lebron

Well, here's another example. Xfire is a chat program that overlays its interface into games so you can receive messages while playing. The way they do this is by editing the d3d/opengl DLL at the process memory level, like injecting assembly jumps. I know this because their method was causing my mod to crash, and I actually saw the strange assembly code they were injecting into the d3d9.dll.

好吧,这是另一个例子。Xfire 是一个聊天程序,它将其界面叠加到游戏中,因此您可以在玩游戏时接收消息。他们这样做的方法是在进程内存级别编辑 d3d/opengl DLL,例如注入程序集跳转。我知道这是因为他们的方法导致我的 mod 崩溃,我实际上看到了他们注入 d3d9.dll 的奇怪汇编代码。

So here's how Xfire does this:

因此,Xfire 是如何做到这一点的:

  1. target the process of the game
  2. search its process memory for d3d.dll/opengl.dll
  3. inject into the process a DLL containing the custom interface logic
  4. connect interface's functions to the program flow by manually writing assembly jumps in the d3d/opengl functions found in the process memory
  1. 瞄准游戏进程
  2. 在其进程内存中搜索 d3d.dll/opengl.dll
  3. 将包含自定义接口逻辑的 DLL 注入进程
  4. 通过在进程内存中的 d3d/opengl 函数中手动编写程序集跳转,将接口的函数连接到程序流

There's no other conceivable way since you need to hiHyman the graphics device that belongs to that game. I'm willing to bet that Steam does it the same way as Xfire. So yeah, no easy way to do this unless someone created a helpful library to do everything you need to do at the low level.

没有其他可以想象的方法,因为您需要劫持属于该游戏的图形设备。我敢打赌 Steam 的做法与 Xfire 相同。所以,是的,除非有人创建了一个有用的库来完成您在低级别需要做的所有事情,否则没有简单的方法可以做到这一点。

You also asked about dimming the game graphics under your overlay. This is just a simple DrawPrimitivecall to draw a filled transparent rectangle over the screen.

您还询问了如何将叠加层下的游戏图形调暗。这只是DrawPrimitive在屏幕上绘制一个填充的透明矩形的简单调用。

回答by Shaun Lebron

Created a Gist with full code here

在此处创建了包含完整代码的 Gist

This is a pretty esoteric art, and there are several ways to do this. I prefer what's called a Direct3D Wrapper. It's been years since I've done this, but I did it with a game once. I may have left out some details, but I just hope to illustrate the idea.

这是一门非常深奥的艺术,有几种方法可以做到这一点。我更喜欢所谓的Direct3D Wrapper。自从我这样做已经好几年了,但我曾经用游戏做过一次。我可能遗漏了一些细节,但我只是希望能说明这个想法。

All Direct3D9 games need to call IDirect3DDevice9::EndSceneafter the screen is rendered and ready to be drawn. So in theory, we can put custom code inside EndScenethat draws what we want over the game. We do this by creating a class that looks like IDirect3DDevice9 to the game, but it's really just a wrapper that forwards all function calls to the real class. So now, in our custom class, our wrapper function for EndScenelooks like this:

所有 Direct3D9 游戏都需要在屏幕呈现并准备好绘制后调用IDirect3DDevice9::EndScene。所以理论上,我们可以在里面放置自定义代码EndScene,在游戏中绘制我们想要的东西。我们通过为游戏创建一个看起来像 IDirect3DDevice9 的类来实现这一点,但它实际上只是一个将所有函数调用转发到真实类的包装器。所以现在,在我们的自定义类中,我们的包装函数 forEndScene看起来像这样:

HRESULT IDirect3DDevice9::EndScene()
{
   // draw overlays here

   realDevice.EndScene();
}

Then we compile it into a DLL called d3d9.dll, and drop it in the game executable's directory. The real d3d9.dll should be in the /system32 folder, but the game first looks in the current directory, and instead loads ours. Once the game loads, it uses our DLL to create an instance of our wrapper class. And now each time EndSceneis called, our code is executed to draw what we want to the screen.

然后我们将它编译成一个名为 d3d9.dll 的 DLL,并将它放到游戏可执行文件的目录中。真正的 d3d9.dll 应该在 /system32 文件夹中,但游戏首先在当前目录中查找,然后加载我们的。游戏加载后,它会使用我们的 DLL 创建包装类的实例。现在每次EndScene被调用时,我们的代码都会被执行以在屏幕上绘制我们想要的东西。

I think you can try the same principle with OpenGL. But to prevent tampering, I think some modern games try to prevent this.

我想你可以用 OpenGL 尝试同样的原理。但是为了防止篡改,我认为一些现代游戏试图防止这种情况发生。

回答by Shaun Lebron

I've been thinking about this. For OpenGL, I'd hook WGL's SwapBuffers with Detours, drawing my stuff after the game and then swapping buffers myself.

我一直在思考这个问题。对于 OpenGL,我会将 WGL 的 SwapBuffers 与 Detours 挂钩,在游戏结束后绘制我的东西,然后自己交换缓冲区。

回答by moobaa

I've done overlays with both DirectX & WPF viewports (same thing, really), using the overlay to paint some nice 2D GDI+ stuff on top of 3D visualisations.

我已经使用 DirectX 和 WPF 视口进行了叠加(实际上是相同的),使用叠加在 3D 可视化之上绘制了一些不错的 2D GDI+ 内容。

I managed by using a panel on top of the "actual" visualisation, setting the colour to transparent except for the bits I wanted overlaid. Worked pretty well, but it was a bit of a pain passing click, drag, and other events through the "drawing" layer to the 3D control.

我通过在“实际”可视化顶部使用面板进行管理,将颜色设置为透明,除了我想要覆盖的位。工作得很好,但是将单击、拖动和其他事件通过“绘图”层传递到 3D 控件有点麻烦。