Skip to content

Commit

Permalink
Add hmon support (#3)
Browse files Browse the repository at this point in the history
* renames in prep of adding second combobox

* add hmon capture helpers

* basic hmon capture

* layout adjustments

* add stop capture

* add stop capture button

* add item name to title

* check hresults
  • Loading branch information
robmikh authored Jun 26, 2019
1 parent bba2f84 commit d853df5
Show file tree
Hide file tree
Showing 9 changed files with 207 additions and 22 deletions.
29 changes: 27 additions & 2 deletions Win32CaptureSample/App.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,21 +42,35 @@ App::App(
m_device = CreateDirect3DDevice(dxgiDevice.get());
}

void App::StartCapture(HWND hwnd)
GraphicsCaptureItem App::StartCaptureFromWindowHandle(HWND hwnd)
{
auto item = CreateCaptureItemForWindow(hwnd);

StartCaptureFromItem(item);

return item;
}

GraphicsCaptureItem App::StartCaptureFromMonitorHandle(HMONITOR hmon)
{
auto item = CreateCaptureItemForMonitor(hmon);

StartCaptureFromItem(item);

return item;
}

IAsyncAction App::StartCaptureWithPickerAsync()
IAsyncOperation<GraphicsCaptureItem> App::StartCaptureWithPickerAsync()
{
auto result = false;
auto item = co_await m_picker.PickSingleItemAsync();

if (item != nullptr)
{
StartCaptureFromItem(item);
}

co_return item;
}

void App::StartCaptureFromItem(
Expand All @@ -68,4 +82,15 @@ void App::StartCaptureFromItem(
m_brush.Surface(surface);

m_capture->StartCapture();
}

void App::StopCapture()
{
if (m_capture != nullptr)
{
m_capture->Close();
m_capture = nullptr;

m_brush.Surface(nullptr);
}
}
7 changes: 5 additions & 2 deletions Win32CaptureSample/App.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,11 @@ class App
winrt::Windows::Graphics::Capture::GraphicsCapturePicker picker);
~App() {}

void StartCapture(HWND hwnd);
winrt::Windows::Foundation::IAsyncAction StartCaptureWithPickerAsync();
winrt::Windows::Graphics::Capture::GraphicsCaptureItem StartCaptureFromWindowHandle(HWND hwnd);
winrt::Windows::Graphics::Capture::GraphicsCaptureItem StartCaptureFromMonitorHandle(HMONITOR hmon);
winrt::Windows::Foundation::IAsyncOperation<winrt::Windows::Graphics::Capture::GraphicsCaptureItem> StartCaptureWithPickerAsync();

void StopCapture();

private:
void StartCaptureFromItem(winrt::Windows::Graphics::Capture::GraphicsCaptureItem item);
Expand Down
31 changes: 31 additions & 0 deletions Win32CaptureSample/EnumerationMonitor.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
#include "pch.h"
#include "EnumerationMonitor.h"

BOOL CALLBACK EnumDisplayMonitorsProc(HMONITOR hmon, HDC, LPRECT, LPARAM lparam)
{
MONITORINFOEX monitorInfo = {};
monitorInfo.cbSize = sizeof(MONITORINFOEX);
if (!GetMonitorInfo(hmon, &monitorInfo))
{
winrt::check_hresult(GetLastError());
}

std::wstring displayName(monitorInfo.szDevice);

std::vector<EnumerationMonitor>& monitors = *reinterpret_cast<std::vector<EnumerationMonitor>*>(lparam);
monitors.push_back(EnumerationMonitor(hmon, displayName));

return TRUE;
}

const std::vector<EnumerationMonitor> EnumerateMonitors()
{
std::vector<EnumerationMonitor> monitors;
EnumDisplayMonitors(NULL, NULL, EnumDisplayMonitorsProc, reinterpret_cast<LPARAM>(&monitors));
return monitors;
}

std::vector<EnumerationMonitor> EnumerationMonitor::EnumerateAllMonitors()
{
return EnumerateMonitors();
}
21 changes: 21 additions & 0 deletions Win32CaptureSample/EnumerationMonitor.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

struct EnumerationMonitor
{
public:
EnumerationMonitor(nullptr_t) {}
EnumerationMonitor(HMONITOR hmon, std::wstring& displayName)
{
m_hmon = hmon;
m_displayName = displayName;
}

HMONITOR Hmon() const noexcept { return m_hmon; }
std::wstring DisplayName() const noexcept { return m_displayName; }

static std::vector<EnumerationMonitor> EnumerateAllMonitors();

private:
HMONITOR m_hmon;
std::wstring m_displayName;
};
116 changes: 101 additions & 15 deletions Win32CaptureSample/SampleWindow.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

using namespace winrt;
using namespace Windows::Graphics::Capture;
using namespace Windows::System;
using namespace Windows::UI;
using namespace Windows::UI::Composition;
using namespace Windows::UI::Composition::Desktop;
Expand Down Expand Up @@ -51,6 +52,7 @@ SampleWindow::SampleWindow(

m_app = app;
m_windows = EnumerationWindow::EnumerateAllWindows();
m_monitors = EnumerationMonitor::EnumerateAllMonitors();

CreateControls(instance);
}
Expand All @@ -62,18 +64,43 @@ LRESULT SampleWindow::MessageHandler(UINT const message, WPARAM const wparam, LP
case WM_COMMAND:
{
auto command = HIWORD(wparam);
auto hwnd = (HWND)lparam;
switch (command)
{
case CBN_SELCHANGE:
{
auto index = SendMessage((HWND)lparam, CB_GETCURSEL, 0, 0);
auto window = m_windows[index];
m_app->StartCapture(window.Hwnd());
auto index = SendMessage(hwnd, CB_GETCURSEL, 0, 0);
if (hwnd == m_windowComboBoxHwnd)
{
auto window = m_windows[index];
auto item = m_app->StartCaptureFromWindowHandle(window.Hwnd());

SetSubTitle(std::wstring(item.DisplayName()));
SendMessage(m_monitorComboBoxHwnd, CB_SETCURSEL, -1, 0);
}
else if (hwnd == m_monitorComboBoxHwnd)
{
auto monitor = m_monitors[index];
auto item = m_app->StartCaptureFromMonitorHandle(monitor.Hmon());

SetSubTitle(std::wstring(item.DisplayName()));
SendMessage(m_windowComboBoxHwnd, CB_SETCURSEL, -1, 0);
}
}
break;
case BN_CLICKED:
{
auto ignored = m_app->StartCaptureWithPickerAsync();
if (hwnd == m_pickerButtonHwnd)
{
OnPickerButtonClicked();
}
else if (hwnd == m_stopButtonHwnd)
{
m_app->StopCapture();
SetSubTitle(L"");
SendMessage(m_monitorComboBoxHwnd, CB_SETCURSEL, -1, 0);
SendMessage(m_windowComboBoxHwnd, CB_SETCURSEL, -1, 0);
}
}
break;
}
Expand All @@ -87,10 +114,22 @@ LRESULT SampleWindow::MessageHandler(UINT const message, WPARAM const wparam, LP
return 0;
}

fire_and_forget SampleWindow::OnPickerButtonClicked()
{
auto selectedItem = co_await m_app->StartCaptureWithPickerAsync();

if (selectedItem)
{
SetSubTitle(std::wstring(selectedItem.DisplayName()));
SendMessage(m_monitorComboBoxHwnd, CB_SETCURSEL, -1, 0);
SendMessage(m_windowComboBoxHwnd, CB_SETCURSEL, -1, 0);
}
}

void SampleWindow::CreateControls(HINSTANCE instance)
{
// Create combo box
HWND comboBoxHwnd = CreateWindow(
// Create window combo box
HWND windowComboBoxHwnd = CreateWindow(
WC_COMBOBOX,
L"",
CBS_DROPDOWNLIST | CBS_HASSTRINGS | WS_VSCROLL | WS_CHILD | WS_OVERLAPPED | WS_VISIBLE,
Expand All @@ -102,30 +141,77 @@ void SampleWindow::CreateControls(HINSTANCE instance)
NULL,
instance,
NULL);
WINRT_VERIFY(comboBoxHwnd);
WINRT_VERIFY(windowComboBoxHwnd);

// Populate combo box
// Populate window combo box
for (auto& window : m_windows)
{
SendMessage(comboBoxHwnd, CB_ADDSTRING, 0, (LPARAM)window.Title().c_str());
SendMessage(windowComboBoxHwnd, CB_ADDSTRING, 0, (LPARAM)window.Title().c_str());
}

// Create monitor combo box
HWND monitorComboBoxHwnd = CreateWindow(
WC_COMBOBOX,
L"",
CBS_DROPDOWNLIST | CBS_HASSTRINGS | WS_VSCROLL | WS_CHILD | WS_OVERLAPPED | WS_VISIBLE,
10,
45,
200,
200,
m_window,
NULL,
instance,
NULL);
WINRT_VERIFY(monitorComboBoxHwnd);

// Populate monitor combo box
for (auto& monitor : m_monitors)
{
SendMessage(monitorComboBoxHwnd, CB_ADDSTRING, 0, (LPARAM)monitor.DisplayName().c_str());
}

// Create button
HWND buttonHwnd = CreateWindow(
// Create picker button
HWND pickerButtonHwnd = CreateWindow(
WC_BUTTON,
L"Use Picker",
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
10,
40,
80,
200,
30,
m_window,
NULL,
instance,
NULL);
WINRT_VERIFY(pickerButtonHwnd);

// Create picker button
HWND stopButtonHwnd = CreateWindow(
WC_BUTTON,
L"Stop Capture",
WS_TABSTOP | WS_VISIBLE | WS_CHILD | BS_DEFPUSHBUTTON,
10,
120,
200,
30,
m_window,
NULL,
instance,
NULL);
WINRT_VERIFY(buttonHwnd);
WINRT_VERIFY(stopButtonHwnd);

m_comboBoxHwnd = comboBoxHwnd;
m_buttonHwnd = buttonHwnd;
m_windowComboBoxHwnd = windowComboBoxHwnd;
m_monitorComboBoxHwnd = monitorComboBoxHwnd;
m_pickerButtonHwnd = pickerButtonHwnd;
m_stopButtonHwnd = stopButtonHwnd;
}

void SampleWindow::SetSubTitle(std::wstring text)
{
std::wstring titleText(L"Win32CaptureSample");
if (!text.empty())
{
titleText += (L" - " + text);
}
SetWindowText(m_window, titleText.c_str());
}
10 changes: 8 additions & 2 deletions Win32CaptureSample/SampleWindow.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once
#include "DesktopWindow.h"
#include "EnumerationWindow.h"
#include "EnumerationMonitor.h"

class App;

Expand All @@ -23,10 +24,15 @@ struct SampleWindow : DesktopWindow<SampleWindow>

private:
void CreateControls(HINSTANCE instance);
void SetSubTitle(std::wstring text);
winrt::fire_and_forget OnPickerButtonClicked();

private:
HWND m_comboBoxHwnd = NULL;
HWND m_buttonHwnd = NULL;
HWND m_windowComboBoxHwnd = NULL;
HWND m_monitorComboBoxHwnd = NULL;
HWND m_pickerButtonHwnd = NULL;
HWND m_stopButtonHwnd = NULL;
std::vector<EnumerationWindow> m_windows;
std::vector<EnumerationMonitor> m_monitors;
std::shared_ptr<App> m_app;
};
2 changes: 2 additions & 0 deletions Win32CaptureSample/Win32CaptureSample.vcxproj
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,7 @@
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="App.cpp" />
<ClCompile Include="EnumerationMonitor.cpp" />
<ClCompile Include="EnumerationWindow.cpp" />
<ClCompile Include="main.cpp" />
<ClCompile Include="pch.cpp" />
Expand All @@ -151,6 +152,7 @@
<ClInclude Include="dispatcherqueue.interop.h" />
<ClInclude Include="d3dHelpers.h" />
<ClInclude Include="direct3d11.interop.h" />
<ClInclude Include="EnumerationMonitor.h" />
<ClInclude Include="EnumerationWindow.h" />
<ClInclude Include="pch.h" />
<ClInclude Include="SampleWindow.h" />
Expand Down
2 changes: 2 additions & 0 deletions Win32CaptureSample/Win32CaptureSample.vcxproj.filters
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
<ClCompile Include="SimpleCapture.cpp" />
<ClCompile Include="SampleWindow.cpp" />
<ClCompile Include="EnumerationWindow.cpp" />
<ClCompile Include="EnumerationMonitor.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="pch.h" />
Expand All @@ -20,6 +21,7 @@
<ClInclude Include="DesktopWindow.h" />
<ClInclude Include="SampleWindow.h" />
<ClInclude Include="EnumerationWindow.h" />
<ClInclude Include="EnumerationMonitor.h" />
</ItemGroup>
<ItemGroup>
<None Include="packages.config" />
Expand Down
11 changes: 10 additions & 1 deletion Win32CaptureSample/capture.interop.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,16 @@ inline auto CreateCaptureItemForWindow(HWND hwnd)
auto activation_factory = winrt::get_activation_factory<winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
auto interop_factory = activation_factory.as<IGraphicsCaptureItemInterop>();
winrt::Windows::Graphics::Capture::GraphicsCaptureItem item = { nullptr };
interop_factory->CreateForWindow(hwnd, winrt::guid_of<ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>(), reinterpret_cast<void**>(winrt::put_abi(item)));
winrt::check_hresult(interop_factory->CreateForWindow(hwnd, winrt::guid_of<ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>(), reinterpret_cast<void**>(winrt::put_abi(item))));
return item;
}

inline auto CreateCaptureItemForMonitor(HMONITOR hmon)
{
auto activation_factory = winrt::get_activation_factory<winrt::Windows::Graphics::Capture::GraphicsCaptureItem>();
auto interop_factory = activation_factory.as<IGraphicsCaptureItemInterop>();
winrt::Windows::Graphics::Capture::GraphicsCaptureItem item = { nullptr };
winrt::check_hresult(interop_factory->CreateForMonitor(hmon, winrt::guid_of<ABI::Windows::Graphics::Capture::IGraphicsCaptureItem>(), reinterpret_cast<void**>(winrt::put_abi(item))));
return item;
}

Expand Down

0 comments on commit d853df5

Please sign in to comment.