C++ - How to screen-capture, except for some windows
Asked Answered
C

5

11

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.
Clause answered 4/5, 2012 at 8:48 Comment(12)
I do know MSFT's my meeting is a good example, although don't know how is that done.Alethaalethea
Thank you - there are similar products that do this (JoinMe or GTM), I will also try to investigate this, but I was hoping for a quicker answer.Clause
Screen capturing normally captures the "screen area above the window" rather than the drawn contents of the window itself. You could try capturing all visible top level windows and recompositing them.Alarise
Actually you would still need to draw the windows that are partially visible, not just the top-level windows. Also, NON-SHARING-WINDOWS could also be top-level.Clause
@Alarise edit Actually you would still need to draw the windows that are partially visible, not just the top-level windows. Also, NON-SHARING-WINDOWS could also be top-level, so I would need to get the content of the windows that are underneath these NON-SHARING-WINDOWS.Clause
I forgot to mention a starting point for this functionality: link The code in this link works well for layered windows, but not by default in Windows 7 (you can use DwmEnableComposition to programmatically bypass this "inconvenience", but in Windows 8 the DwmEnableComposition method is deprecated)Clause
@SucataMihnea: Yes, I was suggesting getting each window (excluding the non shared ones) and recompisiting into a final image instead of the full screenshotAlarise
does anyone here know how WebEx or GootoMeeting like services manages to do the same?Spirograph
@SucataMihnea did you get any solution? I am also looking answer for the same question.Vergos
@Vergos no, no solutions yet (at least none that doesn't require composing the image, which is too slow for real time streaming). Looking into the Magnification API, but that has downsides as wellClause
If you are still looking refer to Media this project contains a class called ScreenCapture, within this class you can set screen co-ordinates of what portion of all your screens you wish to capture. All your screens are treated as one large image and all you have to do is set co-ordinates of where you wish to start and finish.Micronutrient
There is still no solution for topic?Balduin
A
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.

Ambsace answered 19/2, 2016 at 8:31 Comment(2)
I have tried that 4 months ago. This method will create problem for capturing some desktop elements like start menu and tool bar. These will be printed as black on the DC and there is no transparency created.Vergos
There is PaintDesktop for capturing the wallpaper onlySingspiel
C
0

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://learn.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

Celesta answered 26/12, 2018 at 10:26 Comment(0)
D
0

I'm aware this question is pretty old, but I ran into the same problem and it was very, very hard to find any information at all regarding this.

Since Windows 10 version 2004 (build 10.0.19041), the SetWindowDisplayAffinity API has been expanded to include a flag called WDA_EXCLUDEFROMCAPTURE (0x00000011). This will remove the window from images captured with BitBlt

The window is displayed only on a monitor. Everywhere else, the window does not appear at all. One use for this affinity is for windows that show video recording controls, so that the controls are not included in the capture.

Introduced in Windows 10 Version 2004. See remarks about compatibility regarding previous versions of Windows.

For versions before 2004, it will use the existing WDA_MONITOR flag.

I have tested this with a screen capture of the desktop and I am unsure what would happen if you were to use a window DC.

So I guess a possible solution would be:

// get window handle
hWnd = (...)

BOOL result = SetWindowDisplayAffinity(m_hWnd, WDA_EXCLUDEFROMCAPTURE);

// do bitblt stuff

Dareen answered 17/6, 2022 at 12:19 Comment(0)
T
0

mabye you can use Magnification API, even Microsoft said The MagImageScalingCallback function is deprecated in Windows 7 and later, and should not be used in new applications. There is no alternate functionality., but it still work on Windows 10;

Here is the overview of this API : https://learn.microsoft.com/en-us/previous-versions/windows/desktop/magapi/magapi-intro

The sample code of Microsoft is here : https://github.com/microsoft/Windows-classic-samples/tree/main/Samples/Magnification

If you want to get the screenshot rgb data, you can use this api MagSetImageScalingCallback to set callback of Magnifier window, every time you use MagSetWindowSource or InvalidRect of magnifer window, this callback function MagImageScalingCallback will be called, so you can get screenshot rgb data here.

Thoroughfare answered 18/1, 2023 at 8:24 Comment(0)
I
-1

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.

Illuviation answered 4/5, 2012 at 19:40 Comment(2)
Thank you, but since it is a screen sharing application (again, s/w such as JoinMe and GoToMeeting already do this), it is not user friendly (or business wise) to force the user to choose only one window :)Clause
Anyway, my question was more on the technical side - does anyone know which C/C++ instructions I can use to capture screens in Windows 7 and/or 8, and not render some of the visible windows? I am looking for the equivalent of layered windows (see the following MSDN link for an example of using layered windows)Clause

© 2022 - 2025 — McMap. All rights reserved.