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.
Sucata Mihnea
  • 349
  • 1
  • 5
  • 15
  • I do know MSFT's my meeting is a good example, although don't know how is that done. – zinking May 04 '12 at 08:57
  • 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. – Sucata Mihnea May 04 '12 at 09:19
  • 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. – Deanna May 04 '12 at 14:04
  • 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. – Sucata Mihnea May 04 '12 at 15:01
  • @Deanna [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. – Sucata Mihnea May 04 '12 at 15:07
  • I forgot to mention a starting point for this functionality: [link](http://social.msdn.microsoft.com/Forums/zh/vcgeneral/thread/6f1e9f74-ae6e-4df1-92b8-72e7a98bf58f) 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) – Sucata Mihnea May 04 '12 at 15:07
  • @SucataMihnea: Yes, I was suggesting getting each window (excluding the non shared ones) and recompisiting into a final image instead of the full screenshot – Deanna May 04 '12 at 16:00
  • does anyone here know how WebEx or GootoMeeting like services manages to do the same? – rohitvk May 22 '14 at 11:54
  • @SucataMihnea did you get any solution? I am also looking answer for the same question. – Vishnu Jul 10 '15 at 08:51
  • @Vishnu 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](https://msdn.microsoft.com/en-us/library/windows/desktop/ms692162%28v=vs.85%29.aspx), but that has downsides as well – Sucata Mihnea Jul 13 '15 at 12:05
  • If you are still looking refer to [Media](https://github.com/nequeo/media/tree/master/NequeoMediaFoundation) 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. – D.Zadravec Feb 20 '17 at 05:00
  • There is still no solution for topic? – user869217 Jul 30 '20 at 13:24

5 Answers5

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.

Felix M.
  • 246
  • 1
  • 6
  • 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. – Vishnu Feb 19 '16 at 10:07
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

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

AsPas
  • 359
  • 5
  • 22
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.

Grey
  • 5
  • 3
-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.

getfile1
  • 143
  • 1
  • 7
  • 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 :) – Sucata Mihnea May 07 '12 at 06:22
  • 4
    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](http://social.msdn.microsoft.com/Forums/zh/vcgeneral/thread/6f1e9f74-ae6e-4df1-92b8-72e7a98bf58f) for an example of using layered windows) – Sucata Mihnea May 07 '12 at 06:27