From b820b77c79afbc2b2b939e7c73c98c9ed407ec80 Mon Sep 17 00:00:00 2001 From: Robert Mikhayelyan Date: Fri, 27 Sep 2019 23:27:24 -0700 Subject: [PATCH 1/8] seperate window class --- Win32CaptureSample/SampleWindow.cpp | 16 +++++++++++----- Win32CaptureSample/SampleWindow.h | 3 +++ Win32CaptureSample/main.cpp | 2 ++ 3 files changed, 16 insertions(+), 5 deletions(-) diff --git a/Win32CaptureSample/SampleWindow.cpp b/Win32CaptureSample/SampleWindow.cpp index d656d5c..52d2d5e 100644 --- a/Win32CaptureSample/SampleWindow.cpp +++ b/Win32CaptureSample/SampleWindow.cpp @@ -10,8 +10,11 @@ using namespace Windows::UI; using namespace Windows::UI::Composition; using namespace Windows::UI::Composition::Desktop; -SampleWindow::SampleWindow(HINSTANCE instance, int cmdShow, std::shared_ptr app) +const std::wstring SampleWindow::ClassName = L"Win32CaptureSample"; + +void SampleWindow::RegisterWindowClass() { + auto instance = winrt::check_pointer(GetModuleHandleW(nullptr)); WNDCLASSEX wcex = { sizeof(wcex) }; wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; @@ -19,12 +22,15 @@ SampleWindow::SampleWindow(HINSTANCE instance, int cmdShow, std::shared_ptr wcex.hIcon = LoadIconW(instance, IDI_APPLICATION); wcex.hCursor = LoadCursorW(nullptr, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1); - wcex.lpszClassName = L"Win32CaptureSample"; + wcex.lpszClassName = ClassName.c_str(); wcex.hIconSm = LoadIconW(wcex.hInstance, IDI_APPLICATION); - WINRT_VERIFY(RegisterClassExW(&wcex)); - WINRT_ASSERT(!m_window); + winrt::check_bool(RegisterClassExW(&wcex)); +} - WINRT_VERIFY(CreateWindowW(L"Win32CaptureSample", L"Win32CaptureSample", WS_OVERLAPPEDWINDOW, +SampleWindow::SampleWindow(HINSTANCE instance, int cmdShow, std::shared_ptr app) +{ + WINRT_ASSERT(!m_window); + WINRT_VERIFY(CreateWindowW(ClassName.c_str(), L"Win32CaptureSample", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600, nullptr, nullptr, instance, this)); WINRT_ASSERT(m_window); diff --git a/Win32CaptureSample/SampleWindow.h b/Win32CaptureSample/SampleWindow.h index f353578..1359e55 100644 --- a/Win32CaptureSample/SampleWindow.h +++ b/Win32CaptureSample/SampleWindow.h @@ -7,6 +7,9 @@ class App; struct SampleWindow : DesktopWindow { + static const std::wstring ClassName; + static void RegisterWindowClass(); + SampleWindow(HINSTANCE instance, int cmdShow, std::shared_ptr app); winrt::Windows::UI::Composition::Desktop::DesktopWindowTarget CreateWindowTarget(winrt::Windows::UI::Composition::Compositor const& compositor) diff --git a/Win32CaptureSample/main.cpp b/Win32CaptureSample/main.cpp index 84293e0..83f8f9a 100644 --- a/Win32CaptureSample/main.cpp +++ b/Win32CaptureSample/main.cpp @@ -27,6 +27,8 @@ int __stdcall WinMain(HINSTANCE instance, HINSTANCE, PSTR cmdLine, int cmdShow) return 1; } + SampleWindow::RegisterWindowClass(); + // Create the DispatcherQueue that the compositor needs to run auto controller = CreateDispatcherQueueControllerForCurrentThread(); From 9f170a42a7c4679422f64bbabb1000c286eecd96 Mon Sep 17 00:00:00 2001 From: Robert Mikhayelyan Date: Sat, 28 Sep 2019 03:47:45 -0700 Subject: [PATCH 2/8] Basic self refreshing window list --- Win32CaptureSample/App.cpp | 1 - Win32CaptureSample/EnumerationWindow.cpp | 90 ---------- Win32CaptureSample/EnumerationWindow.h | 20 --- Win32CaptureSample/SampleWindow.cpp | 19 ++- Win32CaptureSample/SampleWindow.h | 5 +- Win32CaptureSample/Win32CaptureSample.vcxproj | 18 +- .../Win32CaptureSample.vcxproj.filters | 4 +- Win32CaptureSample/WindowList.cpp | 156 ++++++++++++++++++ Win32CaptureSample/WindowList.h | 45 +++++ Win32CaptureSample/packages.config | 5 +- Win32CaptureSample/pch.h | 8 + 11 files changed, 238 insertions(+), 133 deletions(-) delete mode 100644 Win32CaptureSample/EnumerationWindow.cpp delete mode 100644 Win32CaptureSample/EnumerationWindow.h create mode 100644 Win32CaptureSample/WindowList.cpp create mode 100644 Win32CaptureSample/WindowList.h diff --git a/Win32CaptureSample/App.cpp b/Win32CaptureSample/App.cpp index a0ce42f..b552fcb 100644 --- a/Win32CaptureSample/App.cpp +++ b/Win32CaptureSample/App.cpp @@ -1,5 +1,4 @@ #include "pch.h" -#include "EnumerationWindow.h" #include "App.h" #include "SimpleCapture.h" #include "CaptureSnapshot.h" diff --git a/Win32CaptureSample/EnumerationWindow.cpp b/Win32CaptureSample/EnumerationWindow.cpp deleted file mode 100644 index aea7585..0000000 --- a/Win32CaptureSample/EnumerationWindow.cpp +++ /dev/null @@ -1,90 +0,0 @@ -#include "pch.h" -#include "EnumerationWindow.h" -#include - -std::wstring GetClassName(HWND hwnd) -{ - const DWORD TITLE_SIZE = 1024; - wchar_t windowTitle[TITLE_SIZE]; - - ::GetClassNameW(hwnd, windowTitle, TITLE_SIZE); - - std::wstring title(&windowTitle[0]); - return title; -} - -std::wstring GetWindowTextW(HWND hwnd) -{ - const DWORD TITLE_SIZE = 1024; - wchar_t windowTitle[TITLE_SIZE]; - - ::GetWindowTextW(hwnd, windowTitle, TITLE_SIZE); - return std::wstring(windowTitle); -} - -bool IsCapturableWindow(EnumerationWindow const& window) -{ - HWND hwnd = window.Hwnd(); - HWND shellWindow = GetShellWindow(); - - auto title = window.Title(); - auto className = window.ClassName(); - - if (hwnd == shellWindow) - { - return false; - } - - if (title.length() == 0) - { - return false; - } - - if (!IsWindowVisible(hwnd)) - { - return false; - } - - if (GetAncestor(hwnd, GA_ROOT) != hwnd) - { - return false; - } - - LONG style = GetWindowLongW(hwnd, GWL_STYLE); - if (!((style & WS_DISABLED) != WS_DISABLED)) - { - return false; - } - - DWORD cloaked = FALSE; - if (SUCCEEDED(DwmGetWindowAttribute(hwnd, DWMWA_CLOAKED, &cloaked, sizeof(cloaked))) && (cloaked == DWM_CLOAKED_SHELL)) - { - return false; - } - - return true; -} - -std::vector EnumerationWindow::EnumerateAllWindows() -{ - std::vector windows; - EnumWindows([](HWND hwnd, LPARAM lParam) - { - auto class_name = GetClassNameW(hwnd); - auto title = GetWindowTextW(hwnd); - - auto window = EnumerationWindow(hwnd, title, class_name); - - if (!IsCapturableWindow(window)) - { - return TRUE; - } - - auto& windows = *reinterpret_cast*>(lParam); - windows.push_back(window); - - return TRUE; - }, reinterpret_cast(&windows)); - - return windows; -} \ No newline at end of file diff --git a/Win32CaptureSample/EnumerationWindow.h b/Win32CaptureSample/EnumerationWindow.h deleted file mode 100644 index 1386f27..0000000 --- a/Win32CaptureSample/EnumerationWindow.h +++ /dev/null @@ -1,20 +0,0 @@ -#pragma once - -struct EnumerationWindow -{ -public: - static std::vector EnumerateAllWindows(); - - HWND Hwnd() const noexcept { return m_hwnd; } - std::wstring Title() const noexcept { return m_title; } - std::wstring ClassName() const noexcept { return m_className; } - -private: - EnumerationWindow(HWND hwnd, const std::wstring& title, const std::wstring& className) : - m_hwnd(hwnd), m_title(title), m_className(className) - { - } - const HWND m_hwnd; - const std::wstring m_title; - const std::wstring m_className; -}; \ No newline at end of file diff --git a/Win32CaptureSample/SampleWindow.cpp b/Win32CaptureSample/SampleWindow.cpp index 52d2d5e..01e9422 100644 --- a/Win32CaptureSample/SampleWindow.cpp +++ b/Win32CaptureSample/SampleWindow.cpp @@ -1,6 +1,7 @@ #include "pch.h" #include "App.h" #include "SampleWindow.h" +#include "WindowList.h" #include using namespace winrt; @@ -38,12 +39,17 @@ SampleWindow::SampleWindow(HINSTANCE instance, int cmdShow, std::shared_ptr UpdateWindow(m_window); m_app = app; - m_windows = EnumerationWindow::EnumerateAllWindows(); + m_windowList = std::make_unique(); m_monitors = EnumerationMonitor::EnumerateAllMonitors(); CreateControls(instance); } +SampleWindow::~SampleWindow() +{ + m_windowList.reset(); +} + LRESULT SampleWindow::MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) { switch (message) @@ -59,8 +65,8 @@ LRESULT SampleWindow::MessageHandler(UINT const message, WPARAM const wparam, LP auto index = SendMessageW(hwnd, CB_GETCURSEL, 0, 0); if (hwnd == m_windowComboBoxHwnd) { - auto window = m_windows[index]; - auto item = m_app->StartCaptureFromWindowHandle(window.Hwnd()); + auto window = m_windowList->GetCurrentWindows()[index]; + auto item = m_app->StartCaptureFromWindowHandle(window.WindowHandle); SetSubTitle(std::wstring(item.DisplayName())); SendMessageW(m_monitorComboBoxHwnd, CB_SETCURSEL, -1, 0); @@ -142,11 +148,8 @@ void SampleWindow::CreateControls(HINSTANCE instance) 10, 10, 200, 200, m_window, nullptr, instance, nullptr); WINRT_VERIFY(windowComboBoxHwnd); - // Populate window combo box - for (auto& window : m_windows) - { - SendMessageW(windowComboBoxHwnd, CB_ADDSTRING, 0, (LPARAM)window.Title().c_str()); - } + // Populate window combo box and register for updates + m_windowList->RegisterComboBoxForUpdates(windowComboBoxHwnd); // Create monitor combo box HWND monitorComboBoxHwnd = CreateWindowW(WC_COMBOBOX, L"", diff --git a/Win32CaptureSample/SampleWindow.h b/Win32CaptureSample/SampleWindow.h index 1359e55..7ad71be 100644 --- a/Win32CaptureSample/SampleWindow.h +++ b/Win32CaptureSample/SampleWindow.h @@ -1,9 +1,9 @@ #pragma once #include "DesktopWindow.h" -#include "EnumerationWindow.h" #include "EnumerationMonitor.h" class App; +class WindowList; struct SampleWindow : DesktopWindow { @@ -11,6 +11,7 @@ struct SampleWindow : DesktopWindow static void RegisterWindowClass(); SampleWindow(HINSTANCE instance, int cmdShow, std::shared_ptr app); + ~SampleWindow(); winrt::Windows::UI::Composition::Desktop::DesktopWindowTarget CreateWindowTarget(winrt::Windows::UI::Composition::Compositor const& compositor) { @@ -38,7 +39,7 @@ struct SampleWindow : DesktopWindow HWND m_stopButtonHwnd = nullptr; HWND m_currentSnapshotHwnd = nullptr; HWND m_snapshotButtonHwnd = nullptr; - std::vector m_windows; + std::unique_ptr m_windowList; std::vector m_monitors; std::shared_ptr m_app; }; \ No newline at end of file diff --git a/Win32CaptureSample/Win32CaptureSample.vcxproj b/Win32CaptureSample/Win32CaptureSample.vcxproj index 19ec11e..9d2e9c2 100644 --- a/Win32CaptureSample/Win32CaptureSample.vcxproj +++ b/Win32CaptureSample/Win32CaptureSample.vcxproj @@ -1,6 +1,6 @@ - + Debug @@ -139,11 +139,11 @@ - + @@ -156,26 +156,28 @@ - + - - + + + This project references NuGet package(s) that are missing on this computer. Use NuGet Package Restore to download them. For more information, see http://go.microsoft.com/fwlink/?LinkID=322105. The missing file is {0}. - - - + + + + \ No newline at end of file diff --git a/Win32CaptureSample/Win32CaptureSample.vcxproj.filters b/Win32CaptureSample/Win32CaptureSample.vcxproj.filters index ea770e9..436c25e 100644 --- a/Win32CaptureSample/Win32CaptureSample.vcxproj.filters +++ b/Win32CaptureSample/Win32CaptureSample.vcxproj.filters @@ -6,9 +6,9 @@ - + @@ -21,11 +21,11 @@ - + diff --git a/Win32CaptureSample/WindowList.cpp b/Win32CaptureSample/WindowList.cpp new file mode 100644 index 0000000..dd315c7 --- /dev/null +++ b/Win32CaptureSample/WindowList.cpp @@ -0,0 +1,156 @@ +#include "pch.h" +#include "WindowList.h" +#include + +bool IsCapturableWindow(const WindowInfo const& window) +{ + auto hwnd = window.WindowHandle; + auto shellWindow = GetShellWindow(); + + auto title = window.Title; + + if (hwnd == shellWindow) + { + return false; + } + + if (title.length() == 0) + { + return false; + } + + if (!IsWindowVisible(hwnd)) + { + return false; + } + + if (GetAncestor(hwnd, GA_ROOT) != hwnd) + { + return false; + } + + LONG style = GetWindowLongW(hwnd, GWL_STYLE); + if (!((style & WS_DISABLED) != WS_DISABLED)) + { + return false; + } + + DWORD cloaked = FALSE; + if (SUCCEEDED(DwmGetWindowAttribute(hwnd, DWMWA_CLOAKED, &cloaked, sizeof(cloaked))) && (cloaked == DWM_CLOAKED_SHELL)) + { + return false; + } + + // Unfortunate work-around. Not sure how to avoid this. + if (wcscmp(title.c_str(), L"Task View") == 0) + { + return false; + } + + return true; +} + +static thread_local WindowList* WindowListForThread; + +WindowList::WindowList() +{ + if (WindowListForThread) + { + throw std::exception("WindowList already exists for this thread!"); + } + WindowListForThread = this; + + EnumWindows([](HWND hwnd, LPARAM lParam) + { + if (GetWindowTextLengthW(hwnd) > 0) + { + auto window = WindowInfo(hwnd); + + if (!IsCapturableWindow(window)) + { + return TRUE; + } + + auto windowList = reinterpret_cast(lParam); + windowList->AddWindow(window); + } + + return TRUE; + }, reinterpret_cast(this)); + + // TODO: Handle desktop switching (new windows) + m_eventHook.reset(SetWinEventHook(EVENT_OBJECT_DESTROY, /*EVENT_OBJECT_SHOW*/EVENT_OBJECT_UNCLOAKED, nullptr, + [](HWINEVENTHOOK eventHook, DWORD event, HWND hwnd, LONG objectId, LONG childId, DWORD eventThreadId, DWORD eventTimeInMilliseconds) + { + if (event == EVENT_OBJECT_DESTROY && childId == CHILDID_SELF) + { + WindowListForThread->RemoveWindow(WindowInfo(hwnd)); + return; + } + + if (objectId == OBJID_WINDOW && childId == CHILDID_SELF && hwnd != nullptr && GetAncestor(hwnd, GA_ROOT) == hwnd && + GetWindowTextLengthW(hwnd) > 0 && (event == EVENT_OBJECT_SHOW || event == EVENT_OBJECT_UNCLOAKED)) + { + auto window = WindowInfo(hwnd); + + if (IsCapturableWindow(window)) + { + WindowListForThread->AddWindow(window); + } + } + }, 0, 0, WINEVENT_OUTOFCONTEXT)); +} + +WindowList::~WindowList() +{ + m_eventHook.reset(); + WindowListForThread = nullptr; +} + +void WindowList::AddWindow(WindowInfo const& info) +{ + auto search = m_seenWindows.find(info.WindowHandle); + if (search == m_seenWindows.end()) + { + m_windows.push_back(info); + m_seenWindows.insert(info.WindowHandle); + for (auto& comboBox : m_comboBoxes) + { + winrt::check_hresult(SendMessageW(comboBox, CB_ADDSTRING, 0, (LPARAM)info.Title.c_str())); + } + } +} + +bool WindowList::RemoveWindow(WindowInfo const& info) +{ + auto search = m_seenWindows.find(info.WindowHandle); + if (search != m_seenWindows.end()) + { + m_seenWindows.erase(search); + auto index = 0; + for (auto& window : m_windows) + { + if (window.WindowHandle == info.WindowHandle) + { + break; + } + index++; + } + m_windows.erase(m_windows.begin() + index); + for (auto& comboBox : m_comboBoxes) + { + winrt::check_hresult(SendMessageW(comboBox, CB_DELETESTRING, index, 0)); + } + return index >= 0; + } + return false; +} + +void WindowList::ForceUpdateComboBox(HWND comboBoxHandle) +{ + winrt::check_hresult(SendMessageW(comboBoxHandle, CB_RESETCONTENT, 0, 0)); + for (auto& window : m_windows) + { + winrt::check_hresult(SendMessageW(comboBoxHandle, CB_ADDSTRING, 0, (LPARAM)window.Title.c_str())); + } +} \ No newline at end of file diff --git a/Win32CaptureSample/WindowList.h b/Win32CaptureSample/WindowList.h new file mode 100644 index 0000000..b1156a3 --- /dev/null +++ b/Win32CaptureSample/WindowList.h @@ -0,0 +1,45 @@ +#pragma once + +struct WindowInfo +{ + WindowInfo(HWND windowHandle) + { + WindowHandle = windowHandle; + auto titleLength = GetWindowTextLengthW(WindowHandle); + if (titleLength > 0) + { + titleLength++; + } + std::wstring title(titleLength, 0); + GetWindowTextW(WindowHandle, title.data(), titleLength); + Title = title; + } + + HWND WindowHandle; + std::wstring Title; + + bool operator==(const WindowInfo& info) { return WindowHandle == info.WindowHandle; } + bool operator!=(const WindowInfo& info) { return !(*this == info); } +}; + +class WindowList +{ +public: + WindowList(); + ~WindowList(); + + void RegisterComboBoxForUpdates(HWND comboBoxHandle) { m_comboBoxes.push_back(comboBoxHandle); ForceUpdateComboBox(comboBoxHandle); } + void UnregisterComboBox(HWND comboBoxHandle) { m_comboBoxes.erase(std::remove(m_comboBoxes.begin(), m_comboBoxes.end(), comboBoxHandle), m_comboBoxes.end()); } + const std::vector GetCurrentWindows() { return m_windows; } + +private: + void AddWindow(WindowInfo const& info); + bool RemoveWindow(WindowInfo const& info); + void ForceUpdateComboBox(HWND comboBoxHandle); + +private: + std::vector m_comboBoxes; + std::vector m_windows; + std::unordered_set m_seenWindows; + wil::unique_hwineventhook m_eventHook; +}; \ No newline at end of file diff --git a/Win32CaptureSample/packages.config b/Win32CaptureSample/packages.config index 436c36d..b6fd47d 100644 --- a/Win32CaptureSample/packages.config +++ b/Win32CaptureSample/packages.config @@ -1,5 +1,6 @@  - - + + + \ No newline at end of file diff --git a/Win32CaptureSample/pch.h b/Win32CaptureSample/pch.h index 0506c07..27365d3 100644 --- a/Win32CaptureSample/pch.h +++ b/Win32CaptureSample/pch.h @@ -3,6 +3,8 @@ #include #include +#include + // WinRT #include #include @@ -25,6 +27,9 @@ // STL #include #include +#include +#include +#include // D3D #include @@ -32,6 +37,9 @@ #include #include +// WIL +#include + // Helpers #include "composition.interop.h" #include "d3dHelpers.h" From df8455e81b1d921b28e7c1bfbeb874570c9e956b Mon Sep 17 00:00:00 2001 From: Robert Mikhayelyan Date: Sat, 28 Sep 2019 13:42:30 -0700 Subject: [PATCH 3/8] more robust window filtering --- Win32CaptureSample/WindowList.cpp | 41 ++++++++++--------------------- Win32CaptureSample/WindowList.h | 5 ++++ 2 files changed, 18 insertions(+), 28 deletions(-) diff --git a/Win32CaptureSample/WindowList.cpp b/Win32CaptureSample/WindowList.cpp index dd315c7..39b0dfe 100644 --- a/Win32CaptureSample/WindowList.cpp +++ b/Win32CaptureSample/WindowList.cpp @@ -4,45 +4,31 @@ bool IsCapturableWindow(const WindowInfo const& window) { - auto hwnd = window.WindowHandle; - auto shellWindow = GetShellWindow(); - - auto title = window.Title; - - if (hwnd == shellWindow) + if (window.Title.empty() || window.WindowHandle == GetShellWindow() || + !IsWindowVisible(window.WindowHandle) || GetAncestor(window.WindowHandle, GA_ROOT) != window.WindowHandle) { return false; } - if (title.length() == 0) - { - return false; - } - - if (!IsWindowVisible(hwnd)) - { - return false; - } - - if (GetAncestor(hwnd, GA_ROOT) != hwnd) - { - return false; - } - - LONG style = GetWindowLongW(hwnd, GWL_STYLE); + LONG style = GetWindowLongW(window.WindowHandle, GWL_STYLE); if (!((style & WS_DISABLED) != WS_DISABLED)) { return false; } - DWORD cloaked = FALSE; - if (SUCCEEDED(DwmGetWindowAttribute(hwnd, DWMWA_CLOAKED, &cloaked, sizeof(cloaked))) && (cloaked == DWM_CLOAKED_SHELL)) + // Check to see if the window is cloaked if it's a UWP + if (wcscmp(window.ClassName.c_str(), L"Windows.UI.Core.CoreWindow") == 0 || + wcscmp(window.ClassName.c_str(), L"ApplicationFrameWindow") == 0) { - return false; + DWORD cloaked = FALSE; + if (SUCCEEDED(DwmGetWindowAttribute(window.WindowHandle, DWMWA_CLOAKED, &cloaked, sizeof(cloaked))) && (cloaked == DWM_CLOAKED_SHELL)) + { + return false; + } } // Unfortunate work-around. Not sure how to avoid this. - if (wcscmp(title.c_str(), L"Task View") == 0) + if (wcscmp(window.Title.c_str(), L"Task View") == 0) { return false; } @@ -78,7 +64,6 @@ WindowList::WindowList() return TRUE; }, reinterpret_cast(this)); - // TODO: Handle desktop switching (new windows) m_eventHook.reset(SetWinEventHook(EVENT_OBJECT_DESTROY, /*EVENT_OBJECT_SHOW*/EVENT_OBJECT_UNCLOAKED, nullptr, [](HWINEVENTHOOK eventHook, DWORD event, HWND hwnd, LONG objectId, LONG childId, DWORD eventThreadId, DWORD eventTimeInMilliseconds) { @@ -141,7 +126,7 @@ bool WindowList::RemoveWindow(WindowInfo const& info) { winrt::check_hresult(SendMessageW(comboBox, CB_DELETESTRING, index, 0)); } - return index >= 0; + return true; } return false; } diff --git a/Win32CaptureSample/WindowList.h b/Win32CaptureSample/WindowList.h index b1156a3..495c1d1 100644 --- a/Win32CaptureSample/WindowList.h +++ b/Win32CaptureSample/WindowList.h @@ -13,10 +13,15 @@ struct WindowInfo std::wstring title(titleLength, 0); GetWindowTextW(WindowHandle, title.data(), titleLength); Title = title; + auto classNameLength = 256; + std::wstring className(classNameLength, 0); + GetClassNameW(WindowHandle, className.data(), classNameLength); + ClassName = className; } HWND WindowHandle; std::wstring Title; + std::wstring ClassName; bool operator==(const WindowInfo& info) { return WindowHandle == info.WindowHandle; } bool operator!=(const WindowInfo& info) { return !(*this == info); } From 41f479101491a2e87ce971aba6b310e360349938 Mon Sep 17 00:00:00 2001 From: Robert Mikhayelyan Date: Sat, 28 Sep 2019 14:07:27 -0700 Subject: [PATCH 4/8] stop capture on item close --- Win32CaptureSample/SampleWindow.cpp | 24 ++++++++++++++++++++---- Win32CaptureSample/SampleWindow.h | 3 +++ 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/Win32CaptureSample/SampleWindow.cpp b/Win32CaptureSample/SampleWindow.cpp index 01e9422..934f640 100644 --- a/Win32CaptureSample/SampleWindow.cpp +++ b/Win32CaptureSample/SampleWindow.cpp @@ -66,7 +66,9 @@ LRESULT SampleWindow::MessageHandler(UINT const message, WPARAM const wparam, LP if (hwnd == m_windowComboBoxHwnd) { auto window = m_windowList->GetCurrentWindows()[index]; + m_itemClosedRevoker.revoke(); auto item = m_app->StartCaptureFromWindowHandle(window.WindowHandle); + m_itemClosedRevoker = item.Closed(auto_revoke, { this, &SampleWindow::OnCaptureItemClosed }); SetSubTitle(std::wstring(item.DisplayName())); SendMessageW(m_monitorComboBoxHwnd, CB_SETCURSEL, -1, 0); @@ -74,7 +76,9 @@ LRESULT SampleWindow::MessageHandler(UINT const message, WPARAM const wparam, LP else if (hwnd == m_monitorComboBoxHwnd) { auto monitor = m_monitors[index]; + m_itemClosedRevoker.revoke(); auto item = m_app->StartCaptureFromMonitorHandle(monitor.Hmon()); + m_itemClosedRevoker = item.Closed(auto_revoke, { this, &SampleWindow::OnCaptureItemClosed }); SetSubTitle(std::wstring(item.DisplayName())); SendMessageW(m_windowComboBoxHwnd, CB_SETCURSEL, -1, 0); @@ -89,10 +93,7 @@ LRESULT SampleWindow::MessageHandler(UINT const message, WPARAM const wparam, LP } else if (hwnd == m_stopButtonHwnd) { - m_app->StopCapture(); - SetSubTitle(L""); - SendMessageW(m_monitorComboBoxHwnd, CB_SETCURSEL, -1, 0); - SendMessageW(m_windowComboBoxHwnd, CB_SETCURSEL, -1, 0); + StopCapture(); } else if (hwnd == m_currentSnapshotHwnd) { @@ -121,6 +122,8 @@ fire_and_forget SampleWindow::OnPickerButtonClicked() if (selectedItem) { + m_itemClosedRevoker.revoke(); + m_itemClosedRevoker = selectedItem.Closed(auto_revoke, { this, &SampleWindow::OnCaptureItemClosed }); SetSubTitle(std::wstring(selectedItem.DisplayName())); SendMessageW(m_monitorComboBoxHwnd, CB_SETCURSEL, -1, 0); SendMessageW(m_windowComboBoxHwnd, CB_SETCURSEL, -1, 0); @@ -204,3 +207,16 @@ void SampleWindow::SetSubTitle(std::wstring const& text) } SetWindowTextW(m_window, titleText.c_str()); } + +void SampleWindow::StopCapture() +{ + m_app->StopCapture(); + SetSubTitle(L""); + SendMessageW(m_monitorComboBoxHwnd, CB_SETCURSEL, -1, 0); + SendMessageW(m_windowComboBoxHwnd, CB_SETCURSEL, -1, 0); +} + +void SampleWindow::OnCaptureItemClosed(GraphicsCaptureItem const&, winrt::Windows::Foundation::IInspectable const&) +{ + StopCapture(); +} \ No newline at end of file diff --git a/Win32CaptureSample/SampleWindow.h b/Win32CaptureSample/SampleWindow.h index 7ad71be..75d1a35 100644 --- a/Win32CaptureSample/SampleWindow.h +++ b/Win32CaptureSample/SampleWindow.h @@ -31,6 +31,8 @@ struct SampleWindow : DesktopWindow void SetSubTitle(std::wstring const& text); winrt::fire_and_forget OnPickerButtonClicked(); winrt::fire_and_forget OnSnapshotButtonClicked(); + void StopCapture(); + void OnCaptureItemClosed(winrt::Windows::Graphics::Capture::GraphicsCaptureItem const&, winrt::Windows::Foundation::IInspectable const&); private: HWND m_windowComboBoxHwnd = nullptr; @@ -42,4 +44,5 @@ struct SampleWindow : DesktopWindow std::unique_ptr m_windowList; std::vector m_monitors; std::shared_ptr m_app; + winrt::Windows::Graphics::Capture::GraphicsCaptureItem::Closed_revoker m_itemClosedRevoker; }; \ No newline at end of file From d26dc1985ab0c8a59876a40eda880e164c625da8 Mon Sep 17 00:00:00 2001 From: Robert Mikhayelyan Date: Sat, 28 Sep 2019 15:03:55 -0700 Subject: [PATCH 5/8] starting monitor list refresh --- Win32CaptureSample/EnumerationMonitor.cpp | 6 +- Win32CaptureSample/SampleWindow.cpp | 102 ++++++++++++---------- 2 files changed, 58 insertions(+), 50 deletions(-) diff --git a/Win32CaptureSample/EnumerationMonitor.cpp b/Win32CaptureSample/EnumerationMonitor.cpp index ff45a6d..a59a446 100644 --- a/Win32CaptureSample/EnumerationMonitor.cpp +++ b/Win32CaptureSample/EnumerationMonitor.cpp @@ -7,11 +7,7 @@ std::vector EnumerationMonitor::EnumerateAllMonitors() EnumDisplayMonitors(nullptr, nullptr, [](HMONITOR hmon, HDC, LPRECT, LPARAM lparam) { MONITORINFOEX monitorInfo = { sizeof(monitorInfo) }; - if (!GetMonitorInfoW(hmon, &monitorInfo)) - { - winrt::check_hresult(GetLastError()); - } - + winrt::check_bool(GetMonitorInfo(hmon, &monitorInfo)); std::wstring displayName(monitorInfo.szDevice); auto& monitors = *reinterpret_cast*>(lparam); diff --git a/Win32CaptureSample/SampleWindow.cpp b/Win32CaptureSample/SampleWindow.cpp index 934f640..6efed87 100644 --- a/Win32CaptureSample/SampleWindow.cpp +++ b/Win32CaptureSample/SampleWindow.cpp @@ -55,59 +55,71 @@ LRESULT SampleWindow::MessageHandler(UINT const message, WPARAM const wparam, LP switch (message) { case WM_COMMAND: + { + auto command = HIWORD(wparam); + auto hwnd = (HWND)lparam; + switch (command) { - auto command = HIWORD(wparam); - auto hwnd = (HWND)lparam; - switch (command) + case CBN_SELCHANGE: { - case CBN_SELCHANGE: + auto index = SendMessageW(hwnd, CB_GETCURSEL, 0, 0); + if (hwnd == m_windowComboBoxHwnd) { - auto index = SendMessageW(hwnd, CB_GETCURSEL, 0, 0); - if (hwnd == m_windowComboBoxHwnd) - { - auto window = m_windowList->GetCurrentWindows()[index]; - m_itemClosedRevoker.revoke(); - auto item = m_app->StartCaptureFromWindowHandle(window.WindowHandle); - m_itemClosedRevoker = item.Closed(auto_revoke, { this, &SampleWindow::OnCaptureItemClosed }); - - SetSubTitle(std::wstring(item.DisplayName())); - SendMessageW(m_monitorComboBoxHwnd, CB_SETCURSEL, -1, 0); - } - else if (hwnd == m_monitorComboBoxHwnd) - { - auto monitor = m_monitors[index]; - m_itemClosedRevoker.revoke(); - auto item = m_app->StartCaptureFromMonitorHandle(monitor.Hmon()); - m_itemClosedRevoker = item.Closed(auto_revoke, { this, &SampleWindow::OnCaptureItemClosed }); - - SetSubTitle(std::wstring(item.DisplayName())); - SendMessageW(m_windowComboBoxHwnd, CB_SETCURSEL, -1, 0); - } + auto window = m_windowList->GetCurrentWindows()[index]; + m_itemClosedRevoker.revoke(); + auto item = m_app->StartCaptureFromWindowHandle(window.WindowHandle); + m_itemClosedRevoker = item.Closed(auto_revoke, { this, &SampleWindow::OnCaptureItemClosed }); + + SetSubTitle(std::wstring(item.DisplayName())); + SendMessageW(m_monitorComboBoxHwnd, CB_SETCURSEL, -1, 0); } - break; - case BN_CLICKED: + else if (hwnd == m_monitorComboBoxHwnd) { - if (hwnd == m_pickerButtonHwnd) - { - OnPickerButtonClicked(); - } - else if (hwnd == m_stopButtonHwnd) - { - StopCapture(); - } - else if (hwnd == m_currentSnapshotHwnd) - { - m_app->SnapshotCurrentCapture(); - } - else if (hwnd == m_snapshotButtonHwnd) - { - OnSnapshotButtonClicked(); - } + auto monitor = m_monitors[index]; + m_itemClosedRevoker.revoke(); + auto item = m_app->StartCaptureFromMonitorHandle(monitor.Hmon()); + m_itemClosedRevoker = item.Closed(auto_revoke, { this, &SampleWindow::OnCaptureItemClosed }); + + SetSubTitle(std::wstring(item.DisplayName())); + SendMessageW(m_windowComboBoxHwnd, CB_SETCURSEL, -1, 0); } - break; } + break; + case BN_CLICKED: + { + if (hwnd == m_pickerButtonHwnd) + { + OnPickerButtonClicked(); + } + else if (hwnd == m_stopButtonHwnd) + { + StopCapture(); + } + else if (hwnd == m_currentSnapshotHwnd) + { + m_app->SnapshotCurrentCapture(); + } + else if (hwnd == m_snapshotButtonHwnd) + { + OnSnapshotButtonClicked(); + } + } + break; } - break; + } + break; + case WM_DISPLAYCHANGE: + { + // TODO: Preserve selected index if still valid + winrt::check_hresult(SendMessageW(m_monitorComboBoxHwnd, CB_RESETCONTENT, 0, 0)); + m_monitors = EnumerationMonitor::EnumerateAllMonitors(); + // Populate monitor combo box + for (auto& monitor : m_monitors) + { + SendMessageW(m_monitorComboBoxHwnd, CB_ADDSTRING, 0, (LPARAM)monitor.DisplayName().c_str()); + } + } + break; default: return base_type::MessageHandler(message, wparam, lparam); break; From 91e535b24e478e24e64fb617be185dd8385c88c9 Mon Sep 17 00:00:00 2001 From: Robert Mikhayelyan Date: Sat, 28 Sep 2019 15:43:47 -0700 Subject: [PATCH 6/8] more robust monitor enumeration --- Win32CaptureSample/EnumerationMonitor.cpp | 19 ----- Win32CaptureSample/EnumerationMonitor.h | 18 ----- Win32CaptureSample/MonitorList.cpp | 77 +++++++++++++++++++ Win32CaptureSample/MonitorList.h | 37 +++++++++ Win32CaptureSample/SampleWindow.cpp | 29 +++---- Win32CaptureSample/SampleWindow.h | 6 +- Win32CaptureSample/Win32CaptureSample.vcxproj | 4 +- .../Win32CaptureSample.vcxproj.filters | 4 +- 8 files changed, 131 insertions(+), 63 deletions(-) delete mode 100644 Win32CaptureSample/EnumerationMonitor.cpp delete mode 100644 Win32CaptureSample/EnumerationMonitor.h create mode 100644 Win32CaptureSample/MonitorList.cpp create mode 100644 Win32CaptureSample/MonitorList.h diff --git a/Win32CaptureSample/EnumerationMonitor.cpp b/Win32CaptureSample/EnumerationMonitor.cpp deleted file mode 100644 index a59a446..0000000 --- a/Win32CaptureSample/EnumerationMonitor.cpp +++ /dev/null @@ -1,19 +0,0 @@ -#include "pch.h" -#include "EnumerationMonitor.h" - -std::vector EnumerationMonitor::EnumerateAllMonitors() -{ - std::vector monitors; - EnumDisplayMonitors(nullptr, nullptr, [](HMONITOR hmon, HDC, LPRECT, LPARAM lparam) - { - MONITORINFOEX monitorInfo = { sizeof(monitorInfo) }; - winrt::check_bool(GetMonitorInfo(hmon, &monitorInfo)); - std::wstring displayName(monitorInfo.szDevice); - - auto& monitors = *reinterpret_cast*>(lparam); - monitors.push_back({ hmon, displayName }); - - return TRUE; - }, reinterpret_cast(&monitors)); - return monitors; -} \ No newline at end of file diff --git a/Win32CaptureSample/EnumerationMonitor.h b/Win32CaptureSample/EnumerationMonitor.h deleted file mode 100644 index efdcb15..0000000 --- a/Win32CaptureSample/EnumerationMonitor.h +++ /dev/null @@ -1,18 +0,0 @@ -#pragma once - -struct EnumerationMonitor -{ -public: - static std::vector EnumerateAllMonitors(); - - HMONITOR Hmon() const noexcept { return m_hmon; } - std::wstring DisplayName() const noexcept { return m_displayName; } - -private: - EnumerationMonitor(HMONITOR hmon, const std::wstring& displayName) : m_hmon(hmon), m_displayName(displayName) - { - } - - const HMONITOR m_hmon; - const std::wstring m_displayName; -}; \ No newline at end of file diff --git a/Win32CaptureSample/MonitorList.cpp b/Win32CaptureSample/MonitorList.cpp new file mode 100644 index 0000000..c3d3d36 --- /dev/null +++ b/Win32CaptureSample/MonitorList.cpp @@ -0,0 +1,77 @@ +#include "pch.h" +#include "MonitorList.h" + +std::vector EnumerateAllMonitors() +{ + std::vector monitors; + EnumDisplayMonitors(nullptr, nullptr, [](HMONITOR hmon, HDC, LPRECT, LPARAM lparam) + { + auto& monitors = *reinterpret_cast*>(lparam); + monitors.push_back(MonitorInfo(hmon)); + + return TRUE; + }, reinterpret_cast(&monitors)); + return monitors; +} + +MonitorList::MonitorList() +{ + m_monitors = EnumerateAllMonitors(); +} + +void MonitorList::Update() +{ + OutputDebugStringW(L"\nUpdate called:\n"); + auto monitors = EnumerateAllMonitors(); + std::map newMonitors; + for (auto& monitor : monitors) + { + newMonitors.insert({ monitor.MonitorHandle, monitor }); + } + + std::vector monitorIndexesToRemove; + auto index = 0; + for (auto& monitor : m_monitors) + { + auto search = newMonitors.find(monitor.MonitorHandle); + if (search == newMonitors.end()) + { + monitorIndexesToRemove.push_back(index); + } + else + { + newMonitors.erase(search); + } + index++; + } + + // Remove old monitors + for (auto& removalIndex : monitorIndexesToRemove) + { + m_monitors.erase(m_monitors.begin() + removalIndex); + for (auto& comboBox : m_comboBoxes) + { + winrt::check_hresult(SendMessageW(comboBox, CB_DELETESTRING, removalIndex, 0)); + } + } + + // Add new monitors + for (auto& pair : newMonitors) + { + auto monitor = pair.second; + m_monitors.push_back(monitor); + for (auto& comboBox : m_comboBoxes) + { + winrt::check_hresult(SendMessageW(comboBox, CB_ADDSTRING, 0, (LPARAM)monitor.DisplayName.c_str())); + } + } +} + +void MonitorList::ForceUpdateComboBox(HWND comboBoxHandle) +{ + winrt::check_hresult(SendMessageW(comboBoxHandle, CB_RESETCONTENT, 0, 0)); + for (auto& monitor : m_monitors) + { + winrt::check_hresult(SendMessageW(comboBoxHandle, CB_ADDSTRING, 0, (LPARAM)monitor.DisplayName.c_str())); + } +} \ No newline at end of file diff --git a/Win32CaptureSample/MonitorList.h b/Win32CaptureSample/MonitorList.h new file mode 100644 index 0000000..dd3f701 --- /dev/null +++ b/Win32CaptureSample/MonitorList.h @@ -0,0 +1,37 @@ +#pragma once + +struct MonitorInfo +{ + MonitorInfo(HMONITOR monitorHandle) + { + MonitorHandle = monitorHandle; + MONITORINFOEX monitorInfo = { sizeof(monitorInfo) }; + winrt::check_bool(GetMonitorInfo(MonitorHandle, &monitorInfo)); + std::wstring displayName(monitorInfo.szDevice); + DisplayName = displayName; + } + + HMONITOR MonitorHandle; + std::wstring DisplayName; + + bool operator==(const MonitorInfo& monitor) { return MonitorHandle == monitor.MonitorHandle; } + bool operator!=(const MonitorInfo& monitor) { return !(*this == monitor); } +}; + +class MonitorList +{ +public: + MonitorList(); + + void Update(); + void RegisterComboBoxForUpdates(HWND comboBoxHandle) { m_comboBoxes.push_back(comboBoxHandle); ForceUpdateComboBox(comboBoxHandle); } + void UnregisterComboBox(HWND comboBoxHandle) { m_comboBoxes.erase(std::remove(m_comboBoxes.begin(), m_comboBoxes.end(), comboBoxHandle), m_comboBoxes.end()); } + const std::vector GetCurrentMonitors() { return m_monitors; } + +private: + void ForceUpdateComboBox(HWND comboBoxHandle); + +private: + std::vector m_comboBoxes; + std::vector m_monitors; +}; \ No newline at end of file diff --git a/Win32CaptureSample/SampleWindow.cpp b/Win32CaptureSample/SampleWindow.cpp index 6efed87..d58a4ed 100644 --- a/Win32CaptureSample/SampleWindow.cpp +++ b/Win32CaptureSample/SampleWindow.cpp @@ -2,6 +2,7 @@ #include "App.h" #include "SampleWindow.h" #include "WindowList.h" +#include "MonitorList.h" #include using namespace winrt; @@ -39,15 +40,15 @@ SampleWindow::SampleWindow(HINSTANCE instance, int cmdShow, std::shared_ptr UpdateWindow(m_window); m_app = app; - m_windowList = std::make_unique(); - m_monitors = EnumerationMonitor::EnumerateAllMonitors(); + m_windows = std::make_unique(); + m_monitors = std::make_unique(); CreateControls(instance); } SampleWindow::~SampleWindow() { - m_windowList.reset(); + m_windows.reset(); } LRESULT SampleWindow::MessageHandler(UINT const message, WPARAM const wparam, LPARAM const lparam) @@ -65,7 +66,7 @@ LRESULT SampleWindow::MessageHandler(UINT const message, WPARAM const wparam, LP auto index = SendMessageW(hwnd, CB_GETCURSEL, 0, 0); if (hwnd == m_windowComboBoxHwnd) { - auto window = m_windowList->GetCurrentWindows()[index]; + auto window = m_windows->GetCurrentWindows()[index]; m_itemClosedRevoker.revoke(); auto item = m_app->StartCaptureFromWindowHandle(window.WindowHandle); m_itemClosedRevoker = item.Closed(auto_revoke, { this, &SampleWindow::OnCaptureItemClosed }); @@ -75,9 +76,9 @@ LRESULT SampleWindow::MessageHandler(UINT const message, WPARAM const wparam, LP } else if (hwnd == m_monitorComboBoxHwnd) { - auto monitor = m_monitors[index]; + auto monitor = m_monitors->GetCurrentMonitors()[index]; m_itemClosedRevoker.revoke(); - auto item = m_app->StartCaptureFromMonitorHandle(monitor.Hmon()); + auto item = m_app->StartCaptureFromMonitorHandle(monitor.MonitorHandle); m_itemClosedRevoker = item.Closed(auto_revoke, { this, &SampleWindow::OnCaptureItemClosed }); SetSubTitle(std::wstring(item.DisplayName())); @@ -110,14 +111,7 @@ LRESULT SampleWindow::MessageHandler(UINT const message, WPARAM const wparam, LP break; case WM_DISPLAYCHANGE: { - // TODO: Preserve selected index if still valid - winrt::check_hresult(SendMessageW(m_monitorComboBoxHwnd, CB_RESETCONTENT, 0, 0)); - m_monitors = EnumerationMonitor::EnumerateAllMonitors(); - // Populate monitor combo box - for (auto& monitor : m_monitors) - { - SendMessageW(m_monitorComboBoxHwnd, CB_ADDSTRING, 0, (LPARAM)monitor.DisplayName().c_str()); - } + m_monitors->Update(); } break; default: @@ -164,7 +158,7 @@ void SampleWindow::CreateControls(HINSTANCE instance) WINRT_VERIFY(windowComboBoxHwnd); // Populate window combo box and register for updates - m_windowList->RegisterComboBoxForUpdates(windowComboBoxHwnd); + m_windows->RegisterComboBoxForUpdates(windowComboBoxHwnd); // Create monitor combo box HWND monitorComboBoxHwnd = CreateWindowW(WC_COMBOBOX, L"", @@ -173,10 +167,7 @@ void SampleWindow::CreateControls(HINSTANCE instance) WINRT_VERIFY(monitorComboBoxHwnd); // Populate monitor combo box - for (auto& monitor : m_monitors) - { - SendMessageW(monitorComboBoxHwnd, CB_ADDSTRING, 0, (LPARAM)monitor.DisplayName().c_str()); - } + m_monitors->RegisterComboBoxForUpdates(monitorComboBoxHwnd); // Create picker button HWND pickerButtonHwnd = CreateWindowW(WC_BUTTON, L"Use Picker", diff --git a/Win32CaptureSample/SampleWindow.h b/Win32CaptureSample/SampleWindow.h index 75d1a35..0c8189d 100644 --- a/Win32CaptureSample/SampleWindow.h +++ b/Win32CaptureSample/SampleWindow.h @@ -1,9 +1,9 @@ #pragma once #include "DesktopWindow.h" -#include "EnumerationMonitor.h" class App; class WindowList; +class MonitorList; struct SampleWindow : DesktopWindow { @@ -41,8 +41,8 @@ struct SampleWindow : DesktopWindow HWND m_stopButtonHwnd = nullptr; HWND m_currentSnapshotHwnd = nullptr; HWND m_snapshotButtonHwnd = nullptr; - std::unique_ptr m_windowList; - std::vector m_monitors; + std::unique_ptr m_windows; + std::unique_ptr m_monitors; std::shared_ptr m_app; winrt::Windows::Graphics::Capture::GraphicsCaptureItem::Closed_revoker m_itemClosedRevoker; }; \ No newline at end of file diff --git a/Win32CaptureSample/Win32CaptureSample.vcxproj b/Win32CaptureSample/Win32CaptureSample.vcxproj index 9d2e9c2..22235d4 100644 --- a/Win32CaptureSample/Win32CaptureSample.vcxproj +++ b/Win32CaptureSample/Win32CaptureSample.vcxproj @@ -138,8 +138,8 @@ - + @@ -155,7 +155,7 @@ - + diff --git a/Win32CaptureSample/Win32CaptureSample.vcxproj.filters b/Win32CaptureSample/Win32CaptureSample.vcxproj.filters index 436c25e..a49bc5c 100644 --- a/Win32CaptureSample/Win32CaptureSample.vcxproj.filters +++ b/Win32CaptureSample/Win32CaptureSample.vcxproj.filters @@ -6,9 +6,9 @@ - + @@ -21,11 +21,11 @@ - + From b615a58e7f40f4bfa619431c77f767b0c193c3a7 Mon Sep 17 00:00:00 2001 From: Robert Mikhayelyan Date: Sat, 28 Sep 2019 15:44:11 -0700 Subject: [PATCH 7/8] remove debug string --- Win32CaptureSample/MonitorList.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/Win32CaptureSample/MonitorList.cpp b/Win32CaptureSample/MonitorList.cpp index c3d3d36..9eed1d9 100644 --- a/Win32CaptureSample/MonitorList.cpp +++ b/Win32CaptureSample/MonitorList.cpp @@ -21,7 +21,6 @@ MonitorList::MonitorList() void MonitorList::Update() { - OutputDebugStringW(L"\nUpdate called:\n"); auto monitors = EnumerateAllMonitors(); std::map newMonitors; for (auto& monitor : monitors) From 3f012d01b49724d131fa60c99f7ffa3d3f2affcb Mon Sep 17 00:00:00 2001 From: Robert Mikhayelyan Date: Sat, 28 Sep 2019 15:49:11 -0700 Subject: [PATCH 8/8] move dwmapi into pch --- Win32CaptureSample/WindowList.cpp | 1 - Win32CaptureSample/pch.h | 3 +++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/Win32CaptureSample/WindowList.cpp b/Win32CaptureSample/WindowList.cpp index 39b0dfe..bea0b5a 100644 --- a/Win32CaptureSample/WindowList.cpp +++ b/Win32CaptureSample/WindowList.cpp @@ -1,6 +1,5 @@ #include "pch.h" #include "WindowList.h" -#include bool IsCapturableWindow(const WindowInfo const& window) { diff --git a/Win32CaptureSample/pch.h b/Win32CaptureSample/pch.h index 27365d3..097076f 100644 --- a/Win32CaptureSample/pch.h +++ b/Win32CaptureSample/pch.h @@ -37,6 +37,9 @@ #include #include +// DWM +#include + // WIL #include