| /* |
| * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. |
| * |
| * Use of this source code is governed by a BSD-style license |
| * that can be found in the LICENSE file in the root of the source |
| * tree. An additional intellectual property rights grant can be found |
| * in the file PATENTS. All contributing project authors may |
| * be found in the AUTHORS file in the root of the source tree. |
| */ |
| |
| #include "modules/desktop_capture/win/screen_capture_utils.h" |
| |
| #include <windows.h> |
| |
| #include <string> |
| #include <vector> |
| |
| #include "modules/desktop_capture/desktop_capturer.h" |
| #include "rtc_base/checks.h" |
| #include "rtc_base/string_utils.h" |
| #include "rtc_base/win32.h" |
| |
| namespace webrtc { |
| namespace { |
| |
| BOOL CALLBACK GetMonitorListHandler(HMONITOR monitor, |
| HDC hdc, |
| LPRECT rect, |
| LPARAM data) { |
| auto monitor_list = reinterpret_cast<DesktopCapturer::SourceList*>(data); |
| |
| // Get the name of the monitor. |
| MONITORINFOEXA monitor_info; |
| monitor_info.cbSize = sizeof(MONITORINFOEXA); |
| if (!GetMonitorInfoA(monitor, &monitor_info)) { |
| // Continue the enumeration, but don't add this monitor to |monitor_list|. |
| return TRUE; |
| } |
| |
| DesktopCapturer::Source monitor_source; |
| monitor_source.id = reinterpret_cast<intptr_t>(monitor); |
| monitor_source.title = monitor_info.szDevice; |
| monitor_list->push_back(monitor_source); |
| return TRUE; |
| } |
| |
| } // namespace |
| |
| // |monitors| is populated with HMONITOR values for each display monitor found. |
| // This is in contrast to |GetScreenList| which returns the display indices. |
| bool GetMonitorList(DesktopCapturer::SourceList* monitors) { |
| RTC_DCHECK_EQ(monitors->size(), 0U); |
| // |EnumDisplayMonitors| accepts a display context and a rectangle, which |
| // allows us to specify a certain region and return only the monitors that |
| // intersect that region. We, however, want all the monitors, so we pass in |
| // NULL parameters. |
| return EnumDisplayMonitors(/*hdc=*/NULL, /*clip_rect=*/NULL, |
| GetMonitorListHandler, |
| reinterpret_cast<LPARAM>(monitors)); |
| } |
| |
| bool GetScreenList(DesktopCapturer::SourceList* screens, |
| std::vector<std::string>* device_names /* = nullptr */) { |
| RTC_DCHECK_EQ(screens->size(), 0U); |
| if (device_names) { |
| RTC_DCHECK_EQ(device_names->size(), 0U); |
| } |
| |
| BOOL enum_result = TRUE; |
| for (int device_index = 0;; ++device_index) { |
| DISPLAY_DEVICEW device; |
| device.cb = sizeof(device); |
| enum_result = EnumDisplayDevicesW(NULL, device_index, &device, 0); |
| |
| // |enum_result| is 0 if we have enumerated all devices. |
| if (!enum_result) |
| break; |
| |
| // We only care about active displays. |
| if (!(device.StateFlags & DISPLAY_DEVICE_ACTIVE)) |
| continue; |
| |
| screens->push_back({device_index, std::string()}); |
| if (device_names) { |
| device_names->push_back(rtc::ToUtf8(device.DeviceName)); |
| } |
| } |
| return true; |
| } |
| |
| bool IsMonitorValid(DesktopCapturer::SourceId monitor) { |
| MONITORINFO monitor_info; |
| monitor_info.cbSize = sizeof(MONITORINFO); |
| return GetMonitorInfoA(reinterpret_cast<HMONITOR>(monitor), &monitor_info); |
| } |
| |
| bool IsScreenValid(DesktopCapturer::SourceId screen, std::wstring* device_key) { |
| if (screen == kFullDesktopScreenId) { |
| *device_key = L""; |
| return true; |
| } |
| |
| DISPLAY_DEVICEW device; |
| device.cb = sizeof(device); |
| BOOL enum_result = EnumDisplayDevicesW(NULL, screen, &device, 0); |
| if (enum_result) |
| *device_key = device.DeviceKey; |
| |
| return !!enum_result; |
| } |
| |
| DesktopRect GetFullscreenRect() { |
| return DesktopRect::MakeXYWH(GetSystemMetrics(SM_XVIRTUALSCREEN), |
| GetSystemMetrics(SM_YVIRTUALSCREEN), |
| GetSystemMetrics(SM_CXVIRTUALSCREEN), |
| GetSystemMetrics(SM_CYVIRTUALSCREEN)); |
| } |
| |
| DesktopRect GetScreenRect(DesktopCapturer::SourceId screen, |
| const std::wstring& device_key) { |
| if (screen == kFullDesktopScreenId) { |
| return GetFullscreenRect(); |
| } |
| |
| DISPLAY_DEVICEW device; |
| device.cb = sizeof(device); |
| BOOL result = EnumDisplayDevicesW(NULL, screen, &device, 0); |
| if (!result) |
| return DesktopRect(); |
| |
| // Verifies the device index still maps to the same display device, to make |
| // sure we are capturing the same device when devices are added or removed. |
| // DeviceKey is documented as reserved, but it actually contains the registry |
| // key for the device and is unique for each monitor, while DeviceID is not. |
| if (device_key != device.DeviceKey) |
| return DesktopRect(); |
| |
| DEVMODEW device_mode; |
| device_mode.dmSize = sizeof(device_mode); |
| device_mode.dmDriverExtra = 0; |
| result = EnumDisplaySettingsExW(device.DeviceName, ENUM_CURRENT_SETTINGS, |
| &device_mode, 0); |
| if (!result) |
| return DesktopRect(); |
| |
| return DesktopRect::MakeXYWH( |
| device_mode.dmPosition.x, device_mode.dmPosition.y, |
| device_mode.dmPelsWidth, device_mode.dmPelsHeight); |
| } |
| |
| } // namespace webrtc |