C++ - How to screen-capture, except for some windo

2020-06-04 02:39发布

问题:

Situation: I have a software that performs screen sharing over the Internet, where one user acts as a presenter, and other users act as viewers/attendees.

Besides the presentation windows, the presenter also has a set of NON-SHARING-WINDOWS that appear on the screen (a button bar for start sharing/stop sharing/etc., a Skype window etc.).

The presenter can configure from the setup of the screen sharing software to make these NON-SHARING-WINDOWS invisible (i.e. they will not appear in the screen sharing that is being sent to the attendees, but the window content behind them will appear in the screenshot).

The screenshots are sent at approximately 10 frames-per-second, or faster.

Question: how can I programmatically capture the screen, except for these NON-SHARING-WINDOWS windows?

Notes:

  • Because of the higher frames-per-second value, I cannot minimize/maximize/set alpha for these windows, because then the windows will flicker. The application is written in Win32 C++.
  • I would use layered windows, but because of the Windows 7 Desktop Composition feature, this is not usable out-of-the-box (and in Windows 8, you cannot use DwmEnableComposition anymore to temporarily and programmatically disable composition)
  • I could use the layered window approach for Windows XP/2000/7 etc., and a different approach for Windows 8 (if there is one), though I would prefer a single process that works on all systems
  • I could also try to "compose" the screenshots by capturing individual images (of the desktop, the windows that need to be captured) and using their z-index to create the final image, but because of the required frames-per-second value, this process would be too slow.

回答1:

In windows even the desktop is considered a window and has its own HWND. It seems however, not easily possible to only copy the "wallpaper" on its own.

So i basically see two ways to do that. 1. Copy the entire desktop e.g. BitBlt(GetWindowDC(GetDesktopWindow()),...)

OR

  1. Use GetWindow and traverse the window list in backward direction starting from the Desktop-Window whose HWND you just can determine with GetDesktopWindow(), Like this:

    // paint on a black DC hwnd=GetDesktopWindow() while (hwnd = GetWindow(hwnd, GW_HWNDPREV)) { // is this window not shared? continue // else bitblt it into our dc }

Hope i gave some inspiration :-) If someone knows a way how to copy ONLY the desktop without its child windows please let me know.



回答2:

You can use Magnifier API.

There is a function in magnifier API that allows you to exclude specific windows from your target window (your window with 1x magnification where magnifier renders).

You can set this window to full screen and make it transparent and then use PrintWindow function.

The function: https://docs.microsoft.com/en-us/windows/desktop/api/magnification/nf-magnification-magsetwindowfilterlist

Sample projects:

https://www.codeproject.com/Articles/607288/Screenshot-using-the-Magnification-library

https://code.msdn.microsoft.com/windowsdesktop/Magnification-API-Sample-14269fd2



回答3:

I think that to limit the capture content within a big window will be more simple. otherwise you will need to cut some windows from the screen capture.