1 /*
2 * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved.
3 *
4 * Use of this source code is governed by a BSD-style license
5 * that can be found in the LICENSE file in the root of the source
6 * tree. An additional intellectual property rights grant can be found
7 * in the file PATENTS. All contributing project authors may
8 * be found in the AUTHORS file in the root of the source tree.
9 */
10
11 #include "modules/desktop_capture/win/screen_capture_utils.h"
12
13 #include <windows.h>
14
15 #include <string>
16 #include <vector>
17
18 #include "modules/desktop_capture/desktop_capturer.h"
19 #include "rtc_base/checks.h"
20 #include "rtc_base/string_utils.h"
21 #include "rtc_base/win32.h"
22
23 namespace webrtc {
24 namespace {
25
GetMonitorListHandler(HMONITOR monitor,HDC hdc,LPRECT rect,LPARAM data)26 BOOL CALLBACK GetMonitorListHandler(HMONITOR monitor,
27 HDC hdc,
28 LPRECT rect,
29 LPARAM data) {
30 auto monitor_list = reinterpret_cast<DesktopCapturer::SourceList*>(data);
31
32 // Get the name of the monitor.
33 MONITORINFOEXA monitor_info;
34 monitor_info.cbSize = sizeof(MONITORINFOEXA);
35 if (!GetMonitorInfoA(monitor, &monitor_info)) {
36 // Continue the enumeration, but don't add this monitor to |monitor_list|.
37 return TRUE;
38 }
39
40 DesktopCapturer::Source monitor_source;
41 monitor_source.id = reinterpret_cast<intptr_t>(monitor);
42 monitor_source.title = monitor_info.szDevice;
43 monitor_list->push_back(monitor_source);
44 return TRUE;
45 }
46
47 } // namespace
48
49 // |monitors| is populated with HMONITOR values for each display monitor found.
50 // This is in contrast to |GetScreenList| which returns the display indices.
GetMonitorList(DesktopCapturer::SourceList * monitors)51 bool GetMonitorList(DesktopCapturer::SourceList* monitors) {
52 RTC_DCHECK_EQ(monitors->size(), 0U);
53 // |EnumDisplayMonitors| accepts a display context and a rectangle, which
54 // allows us to specify a certain region and return only the monitors that
55 // intersect that region. We, however, want all the monitors, so we pass in
56 // NULL parameters.
57 return EnumDisplayMonitors(/*hdc=*/NULL, /*clip_rect=*/NULL,
58 GetMonitorListHandler,
59 reinterpret_cast<LPARAM>(monitors));
60 }
61
GetScreenList(DesktopCapturer::SourceList * screens,std::vector<std::string> * device_names)62 bool GetScreenList(DesktopCapturer::SourceList* screens,
63 std::vector<std::string>* device_names /* = nullptr */) {
64 RTC_DCHECK_EQ(screens->size(), 0U);
65 if (device_names) {
66 RTC_DCHECK_EQ(device_names->size(), 0U);
67 }
68
69 BOOL enum_result = TRUE;
70 for (int device_index = 0;; ++device_index) {
71 DISPLAY_DEVICEW device;
72 device.cb = sizeof(device);
73 enum_result = EnumDisplayDevicesW(NULL, device_index, &device, 0);
74
75 // |enum_result| is 0 if we have enumerated all devices.
76 if (!enum_result)
77 break;
78
79 // We only care about active displays.
80 if (!(device.StateFlags & DISPLAY_DEVICE_ACTIVE))
81 continue;
82
83 screens->push_back({device_index, std::string()});
84 if (device_names) {
85 device_names->push_back(rtc::ToUtf8(device.DeviceName));
86 }
87 }
88 return true;
89 }
90
IsMonitorValid(DesktopCapturer::SourceId monitor)91 bool IsMonitorValid(DesktopCapturer::SourceId monitor) {
92 MONITORINFO monitor_info;
93 monitor_info.cbSize = sizeof(MONITORINFO);
94 return GetMonitorInfoA(reinterpret_cast<HMONITOR>(monitor), &monitor_info);
95 }
96
IsScreenValid(DesktopCapturer::SourceId screen,std::wstring * device_key)97 bool IsScreenValid(DesktopCapturer::SourceId screen, std::wstring* device_key) {
98 if (screen == kFullDesktopScreenId) {
99 *device_key = L"";
100 return true;
101 }
102
103 DISPLAY_DEVICEW device;
104 device.cb = sizeof(device);
105 BOOL enum_result = EnumDisplayDevicesW(NULL, screen, &device, 0);
106 if (enum_result)
107 *device_key = device.DeviceKey;
108
109 return !!enum_result;
110 }
111
GetFullscreenRect()112 DesktopRect GetFullscreenRect() {
113 return DesktopRect::MakeXYWH(GetSystemMetrics(SM_XVIRTUALSCREEN),
114 GetSystemMetrics(SM_YVIRTUALSCREEN),
115 GetSystemMetrics(SM_CXVIRTUALSCREEN),
116 GetSystemMetrics(SM_CYVIRTUALSCREEN));
117 }
118
GetScreenRect(DesktopCapturer::SourceId screen,const std::wstring & device_key)119 DesktopRect GetScreenRect(DesktopCapturer::SourceId screen,
120 const std::wstring& device_key) {
121 if (screen == kFullDesktopScreenId) {
122 return GetFullscreenRect();
123 }
124
125 DISPLAY_DEVICEW device;
126 device.cb = sizeof(device);
127 BOOL result = EnumDisplayDevicesW(NULL, screen, &device, 0);
128 if (!result)
129 return DesktopRect();
130
131 // Verifies the device index still maps to the same display device, to make
132 // sure we are capturing the same device when devices are added or removed.
133 // DeviceKey is documented as reserved, but it actually contains the registry
134 // key for the device and is unique for each monitor, while DeviceID is not.
135 if (device_key != device.DeviceKey)
136 return DesktopRect();
137
138 DEVMODEW device_mode;
139 device_mode.dmSize = sizeof(device_mode);
140 device_mode.dmDriverExtra = 0;
141 result = EnumDisplaySettingsExW(device.DeviceName, ENUM_CURRENT_SETTINGS,
142 &device_mode, 0);
143 if (!result)
144 return DesktopRect();
145
146 return DesktopRect::MakeXYWH(
147 device_mode.dmPosition.x, device_mode.dmPosition.y,
148 device_mode.dmPelsWidth, device_mode.dmPelsHeight);
149 }
150
151 } // namespace webrtc
152