Getting screenshot of a child window running OpenG

2019-01-26 19:32发布

问题:

I have a main window with children. I need to take screenshots programmatically to crop and draw them back on my main window. The way I do this is:

HDC hDC = GetWindowDC(hWnd);
HDC memDC = CreateCompatibleDC(hDC);
HBITMAP memBM = CreateCompatibleBitmap(hDC, Width, Height);
HBITMAP OldBM = (HBITMAP)::SelectObject(memDC, memBM );
BitBlt(memDC, 0, 0, Width, Height , hDC, BEGINX, BEGINY, SRCCOPY);
int Bpp = GetDeviceCaps(hDC,BITSPIXEL);
int size = Bpp/8 * ( Width * Height );
BYTE *lpBits = new BYTE[size];
GetBitmapBits(memBM, size, lpBits);

But this doesn't capture the OpenGL section of the child windows, instead it just draws blank white in the area where OGL render is supposed to be.

回答1:

I remember having similar problems a few years back when I was attempting to screen grab a video and just getting a black region where the video had been. Got around it at the time by reducing the hardware accelaration setting on the video driver (on XP: right click desktop > properties > settings > advanced > troubleshoot).

As for a code-based solution, you might want to refer to the following previous posts:

Blank Screenshots In Vista and Win7 when gaming

Saving a screenshot of a window using C#, WPF, and DWM



回答2:

Possibly NQR, but you could render your scene to a bitmap and BLT it into the blank space.



回答3:

OpenGL might be rendering into a layered context; try

BitBlt(memDC, 0, 0, Width, Height , hDC, BEGINX, BEGINY, SRCCOPY | CAPTUREBLT);

instead.



回答4:

I assume you are on win platform.

I thing you can render to bitmap even if you do not have the source code for child window.

  1. First obtain correct Handle to the child window
    • correct handle search is very tricky because almost everything in win is a window (so there are hundreds handles...)
  2. create bitmap
  3. change handle of rendering/device context of screenshoted window to your bitmap.
    • not all windows can do that!!!
  4. force repaint
    • minimize/restore win or something
  5. store your new bitmap
  6. restore render/device contexts of your screenshoted window.

Beware this is not very stable process (OpenGL can make conflicts during context handles change) and in some cases you even cannot change handles to contexts

More safe is to screenshot desktop it self.

TCanvas *scr=new TCanvas();
scr->Handle=GetDC(GetDesktopWindow());
// copy scr to your bitmap (do not forget to resize bitmap)

Warning do not obtain/create/release contexts or win handles too often because its a little buggy (sometimes winapi functions stops returning correct handler values) better way is obtain handle once and hope that no one closes window ... for your child wins you know exactly when to get new handler) That is true also for IsWindow() function.

For more info take a look at:

  • How can I access a graphics card's output directly?