OpenGL/D3D: How do I get a screen grab of a game running full screen in Windows?

不打扰是莪最后的温柔 提交于 2019-11-27 20:47:29

There are a few approaches to this problem. Most of them are icky, and it totally depends on what kind of graphics API you want to target, and which functions the target application uses. Most DirectX, GDI+ and OpenGL applications are double or tripple-buffered, so they all call:

void SwapBuffers(HDC hdc)

at some point. They also generate WM_PAINT messages in their message queue whenever the window should be drawn. This gives you two options.

  • You can install a global hook or thread-local hook into the target process and capture WM_PAINT messages. This allows you to copy the contents from the device context just before the painting happens. The process can be found by enumerating all the processes on the system and look for a known window name, or a known module handle.

  • You can inject code into the target process's local copy of SwapBuffers. On Linux this would be easy to do via the LD_PRELOAD environmental variable, or by calling ld-linux.so.2 explicitly, but there is no equivalient on Windows. Luckily there is a framework from Microsoft Research which can do this for you called Detours. You can find this here: link.

The demoscene group Farbrausch made a demo-capturing tool named kkapture which makes use of the Detours library. Their tool targets applications that require no user input however, so they basically run the demos at a fixed framerate by hooking into all the possible time functions, like timeGetTime(), GetTickCount() and QueryPerformanceCounter(). It's totally rad. A presentation written by ryg (I think?) regarding kkapture's internals can be found here. I think that's of interest to you.

For more information about Windows hooks, see here and here.

EDIT:

This idea intrigued me, so I used Detours to hook into OpenGL applications and mess with the graphics. Here is Quake 2 with green fog added:

Some more information about how Detours works, since I've used it first hand now:

Detours works on two levels. The actual hooking only works in the same process space as the target process. So Detours has a function for injecting a DLL into a process and force its DLLMain to run too, as well as functions that are supposed to be used in that DLL. When DLLMain is run, the DLL should call DetourAttach() to specify the functions to hook, as well as the "detour" function, which is the code you want to override with.

So it basically works like this:

  • You have a launcher application who's only task is to call DetourCreateProcessWithDll(). It works the same way as CreateProcessW, only with a few extra parameters. This injects a DLL into a process and calls its DllMain().
  • You implement a DLL that calls the Detour functions and sets up trampoline functions. That means calling DetourTransactionBegin(), DetourUpdateThread(), DetourAttach() followed by DetourTransactionEnd().
  • Use the launcher to inject the DLL you implemented into a process.

There are some caveats though. When DllMain is run, libraries that are imported later with LoadLibrary() aren't visible yet. So you can't necessarily set up everything during the DLL attachment event. A workaround is to keep track of all the functions that are overridden so far, and try to initialize the others inside these functions that you can already call. This way you will discover new functions as soon as LoadLibrary have mapped them into the memory space of the process. I'm not quite sure how well this would work for wglGetProcAddress though. (Perhaps someone else here has ideas regarding this?)

Some LoadLibrary() calls seem to fail. I tested with Quake 2, and DirectSound and the waveOut API failed to initalize for some reason. I'm still investigating this.

I found a sourceforge'd project called taksi:

http://taksi.sourceforge.net/

Taksi does not provide audio capture, though.

I've written screen grabbers in the past (DirectX7-9 era). I found good old DirectDraw worked remarkably well and would reliably grab bits of hardware-accelerated/video screen content which other methods (D3D, GDI, OpenGL) seemed to leave blank or scrambled. It was very fast too.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!