diff --git a/modules/desktop_capture/win/test_support/test_window.cc b/modules/desktop_capture/win/test_support/test_window.cc index d5fa9ed24e..bcbadecfaf 100644 --- a/modules/desktop_capture/win/test_support/test_window.cc +++ b/modules/desktop_capture/win/test_support/test_window.cc @@ -41,7 +41,8 @@ LRESULT CALLBACK WindowProc(HWND hwnd, WindowInfo CreateTestWindow(const WCHAR* window_title, const int height, - const int width) { + const int width, + const LONG extended_styles) { WindowInfo info; ::GetModuleHandleExW(GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, @@ -61,11 +62,12 @@ WindowInfo CreateTestWindow(const WCHAR* window_title, // height and width parameters, or if they supplied invalid values. int window_height = height <= 0 ? kWindowHeight : height; int window_width = width <= 0 ? kWindowWidth : width; - info.hwnd = ::CreateWindowW(kWindowClass, window_title, WS_OVERLAPPEDWINDOW, - CW_USEDEFAULT, CW_USEDEFAULT, window_width, - window_height, /*parent_window=*/nullptr, - /*menu_bar=*/nullptr, info.window_instance, - /*additional_params=*/nullptr); + info.hwnd = + ::CreateWindowExW(extended_styles, kWindowClass, window_title, + WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, + window_width, window_height, /*parent_window=*/nullptr, + /*menu_bar=*/nullptr, info.window_instance, + /*additional_params=*/nullptr); ::ShowWindow(info.hwnd, SW_SHOWNORMAL); ::UpdateWindow(info.hwnd); diff --git a/modules/desktop_capture/win/test_support/test_window.h b/modules/desktop_capture/win/test_support/test_window.h index 7c7676c194..05727684ea 100644 --- a/modules/desktop_capture/win/test_support/test_window.h +++ b/modules/desktop_capture/win/test_support/test_window.h @@ -33,7 +33,8 @@ struct WindowInfo { WindowInfo CreateTestWindow(const WCHAR* window_title, const int height = 0, - const int width = 0); + const int width = 0, + const LONG extended_styles = 0); void ResizeTestWindow(const HWND hwnd, const int width, const int height); diff --git a/modules/desktop_capture/win/wgc_capturer_win.h b/modules/desktop_capture/win/wgc_capturer_win.h index aae2304263..1171d15fad 100644 --- a/modules/desktop_capture/win/wgc_capturer_win.h +++ b/modules/desktop_capture/win/wgc_capturer_win.h @@ -46,7 +46,10 @@ class WindowEnumerator final : public SourceEnumerator { ~WindowEnumerator() override = default; bool FindAllSources(DesktopCapturer::SourceList* sources) override { - return window_capture_helper_.EnumerateCapturableWindows(sources); + // WGC fails to capture windows with the WS_EX_TOOLWINDOW style, so we + // provide it as a filter to ensure windows with the style are not returned. + return window_capture_helper_.EnumerateCapturableWindows(sources, + WS_EX_TOOLWINDOW); } private: diff --git a/modules/desktop_capture/win/wgc_capturer_win_unittest.cc b/modules/desktop_capture/win/wgc_capturer_win_unittest.cc index 732de7db20..1056c821c3 100644 --- a/modules/desktop_capture/win/wgc_capturer_win_unittest.cc +++ b/modules/desktop_capture/win/wgc_capturer_win_unittest.cc @@ -364,6 +364,25 @@ TEST_F(WgcCapturerWinTest, SelectClosedWindow) { EXPECT_FALSE(capturer_->SelectSource(source_id_)); } +TEST_F(WgcCapturerWinTest, UnsupportedWindowStyle) { + // Create a window with the WS_EX_TOOLWINDOW style, which WGC does not + // support. + window_info_ = CreateTestWindow(kWindowTitle, kMediumWindowWidth, + kMediumWindowHeight, WS_EX_TOOLWINDOW); + capturer_ = WgcCapturerWin::CreateRawWindowCapturer( + DesktopCaptureOptions::CreateDefault()); + DesktopCapturer::SourceList sources; + EXPECT_TRUE(capturer_->GetSourceList(&sources)); + auto it = std::find_if( + sources.begin(), sources.end(), [&](const DesktopCapturer::Source& src) { + return src.id == reinterpret_cast(window_info_.hwnd); + }); + + // We should not find the window, since we filter for unsupported styles. + EXPECT_EQ(it, sources.end()); + DestroyTestWindow(window_info_); +} + TEST_F(WgcCapturerWinTest, IncreaseWindowSizeMidCapture) { SetUpForWindowCapture(kSmallWindowWidth, kSmallWindowHeight); EXPECT_TRUE(capturer_->SelectSource(source_id_)); diff --git a/modules/desktop_capture/win/window_capture_utils.cc b/modules/desktop_capture/win/window_capture_utils.cc index 9e33e56c2d..7c5cc70087 100644 --- a/modules/desktop_capture/win/window_capture_utils.cc +++ b/modules/desktop_capture/win/window_capture_utils.cc @@ -27,12 +27,16 @@ namespace webrtc { namespace { struct GetWindowListParams { - GetWindowListParams(int flags, DesktopCapturer::SourceList* result) - : ignoreUntitled(flags & GetWindowListFlags::kIgnoreUntitled), - ignoreUnresponsive(flags & GetWindowListFlags::kIgnoreUnresponsive), + GetWindowListParams(int flags, + LONG ex_style_filters, + DesktopCapturer::SourceList* result) + : ignore_untitled(flags & GetWindowListFlags::kIgnoreUntitled), + ignore_unresponsive(flags & GetWindowListFlags::kIgnoreUnresponsive), + ex_style_filters(ex_style_filters), result(result) {} - const bool ignoreUntitled; - const bool ignoreUnresponsive; + const bool ignore_untitled; + const bool ignore_unresponsive; + const LONG ex_style_filters; DesktopCapturer::SourceList* const result; }; @@ -67,7 +71,13 @@ BOOL CALLBACK GetWindowListHandler(HWND hwnd, LPARAM param) { return TRUE; } - if (params->ignoreUnresponsive && !IsWindowResponding(hwnd)) { + // Filter out windows that match the extended styles the caller has specified, + // e.g. WS_EX_TOOLWINDOW for capturers that don't support overlay windows. + if (exstyle & params->ex_style_filters) { + return TRUE; + } + + if (params->ignore_unresponsive && !IsWindowResponding(hwnd)) { return TRUE; } @@ -79,7 +89,7 @@ BOOL CALLBACK GetWindowListHandler(HWND hwnd, LPARAM param) { // pump is waiting on this thread. If we've filtered out unresponsive // windows, this is not a concern, but otherwise we need to check if we can // safely make blocking calls. - if (params->ignoreUnresponsive || CanSafelyMakeBlockingCalls(hwnd)) { + if (params->ignore_unresponsive || CanSafelyMakeBlockingCalls(hwnd)) { const size_t kTitleLength = 500; WCHAR window_title[kTitleLength] = L""; if (GetWindowTextLength(hwnd) != 0 && @@ -89,7 +99,7 @@ BOOL CALLBACK GetWindowListHandler(HWND hwnd, LPARAM param) { } // Skip windows when we failed to convert the title or it is empty. - if (params->ignoreUntitled && window.title.empty()) + if (params->ignore_untitled && window.title.empty()) return TRUE; // Capture the window class name, to allow specific window classes to be @@ -271,8 +281,10 @@ bool IsWindowResponding(HWND window) { nullptr); } -bool GetWindowList(int flags, DesktopCapturer::SourceList* windows) { - GetWindowListParams params(flags, windows); +bool GetWindowList(int flags, + DesktopCapturer::SourceList* windows, + LONG ex_style_filters) { + GetWindowListParams params(flags, ex_style_filters, windows); return ::EnumWindows(&GetWindowListHandler, reinterpret_cast(¶ms)) != 0; } @@ -432,10 +444,11 @@ bool WindowCaptureHelperWin::IsWindowCloaked(HWND hwnd) { } bool WindowCaptureHelperWin::EnumerateCapturableWindows( - DesktopCapturer::SourceList* results) { + DesktopCapturer::SourceList* results, + LONG ex_style_filters) { if (!webrtc::GetWindowList((GetWindowListFlags::kIgnoreUntitled | GetWindowListFlags::kIgnoreUnresponsive), - results)) { + results, ex_style_filters)) { return false; } diff --git a/modules/desktop_capture/win/window_capture_utils.h b/modules/desktop_capture/win/window_capture_utils.h index f636a312f5..11b2c2c1b5 100644 --- a/modules/desktop_capture/win/window_capture_utils.h +++ b/modules/desktop_capture/win/window_capture_utils.h @@ -86,8 +86,11 @@ enum GetWindowListFlags { // - Program Manager & Start menu. // - [with kIgnoreUntitled] windows with no title. // - [with kIgnoreUnresponsive] windows that unresponsive. +// - Any windows with extended styles that match |ex_style_filters|. // Returns false if native APIs failed. -bool GetWindowList(int flags, DesktopCapturer::SourceList* windows); +bool GetWindowList(int flags, + DesktopCapturer::SourceList* windows, + LONG ex_style_filters = 0); typedef HRESULT(WINAPI* DwmIsCompositionEnabledFunc)(BOOL* enabled); typedef HRESULT(WINAPI* DwmGetWindowAttributeFunc)(HWND hwnd, @@ -107,7 +110,12 @@ class WindowCaptureHelperWin { bool IsWindowOnCurrentDesktop(HWND hwnd); bool IsWindowVisibleOnCurrentDesktop(HWND hwnd); bool IsWindowCloaked(HWND hwnd); - bool EnumerateCapturableWindows(DesktopCapturer::SourceList* results); + + // The optional |ex_style_filters| parameter allows callers to provide + // extended window styles (e.g. WS_EX_TOOLWINDOW) and prevent windows that + // match from being included in |results|. + bool EnumerateCapturableWindows(DesktopCapturer::SourceList* results, + LONG ex_style_filters = 0); private: HMODULE dwmapi_library_ = nullptr;