Exclude WS_EX_TOOLWINDOWs for WgcCapturerWin.

This changes modifies EnumerateCapturableWindows to accept an optional
parameter consisting of extended window styles that will prevent windows
with the specified styles from being returned. This allows us to filter
out windows with the WS_EX_TOOLWINDOW style for the WgcCapturerWin,
which does not support capture of such windows.

Bug: webrtc:12679
Change-Id: Id9ac28afd331ba20fcb7f9e7be54ea5eee2e022e
Reviewed-on: https://webrtc-review.googlesource.com/c/src/+/215161
Reviewed-by: Jamie Walch <jamiewalch@chromium.org>
Commit-Queue: Austin Orion <auorion@microsoft.com>
Cr-Commit-Position: refs/heads/master@{#33779}
This commit is contained in:
Austin Orion 2021-04-14 10:14:01 -07:00 committed by Commit Bot
parent 516e284351
commit 688235d330
6 changed files with 68 additions and 22 deletions

View File

@ -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);

View File

@ -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);

View File

@ -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:

View File

@ -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<intptr_t>(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_));

View File

@ -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<LPARAM>(&params)) != 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;
}

View File

@ -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;