diff --git a/PowerToys.sln b/PowerToys.sln
index eb70eaf85f..6cb2700098 100644
--- a/PowerToys.sln
+++ b/PowerToys.sln
@@ -596,7 +596,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "projects-common", "projects
src\modules\Projects\projects-common\AppUtils.h = src\modules\Projects\projects-common\AppUtils.h
src\modules\Projects\projects-common\Data.h = src\modules\Projects\projects-common\Data.h
src\modules\Projects\projects-common\GuidUtils.h = src\modules\Projects\projects-common\GuidUtils.h
- src\modules\Projects\projects-common\MonitorEnumerator.h = src\modules\Projects\projects-common\MonitorEnumerator.h
+ src\modules\Projects\projects-common\MonitorUtils.h = src\modules\Projects\projects-common\MonitorUtils.h
src\modules\Projects\projects-common\VirtualDesktop.h = src\modules\Projects\projects-common\VirtualDesktop.h
src\modules\Projects\projects-common\WindowEnumerator.h = src\modules\Projects\projects-common\WindowEnumerator.h
src\modules\Projects\projects-common\WindowFilter.h = src\modules\Projects\projects-common\WindowFilter.h
diff --git a/src/common/Display/Display.vcxproj b/src/common/Display/Display.vcxproj
index e69a2ada2d..87b74ba534 100644
--- a/src/common/Display/Display.vcxproj
+++ b/src/common/Display/Display.vcxproj
@@ -24,15 +24,18 @@
NotUsing
- ..\..\..\;%(AdditionalIncludeDirectories)
+ ..\..\..\;..\..\common;.\;%(AdditionalIncludeDirectories)
_LIB;%(PreprocessorDefinitions)
+
+
+
diff --git a/src/common/Display/DisplayUtils.cpp b/src/common/Display/DisplayUtils.cpp
new file mode 100644
index 0000000000..43baef908c
--- /dev/null
+++ b/src/common/Display/DisplayUtils.cpp
@@ -0,0 +1,147 @@
+#include "DisplayUtils.h"
+
+#include
+#include
+
+#include
+#include
+
+#include
+
+namespace DisplayUtils
+{
+ constexpr bool not_digit(wchar_t ch)
+ {
+ return '0' <= ch && ch <= '9';
+ }
+
+ std::wstring remove_non_digits(const std::wstring& input)
+ {
+ std::wstring result;
+ std::copy_if(input.begin(), input.end(), std::back_inserter(result), not_digit);
+ return result;
+ }
+
+ std::pair SplitDisplayDeviceId(const std::wstring& str) noexcept
+ {
+ // format: \\?\DISPLAY#{device id}#{instance id}#{some other id}
+ // example: \\?\DISPLAY#GSM1388#4&125707d6&0&UID8388688#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}
+ // output: { GSM1388, 4&125707d6&0&UID8388688 }
+
+ size_t nameStartPos = str.find_first_of('#');
+ size_t uidStartPos = str.find('#', nameStartPos + 1);
+ size_t uidEndPos = str.find('#', uidStartPos + 1);
+
+ if (nameStartPos == std::string::npos || uidStartPos == std::string::npos || uidEndPos == std::string::npos)
+ {
+ return { str, L"" };
+ }
+
+ return { str.substr(nameStartPos + 1, uidStartPos - nameStartPos - 1), str.substr(uidStartPos + 1, uidEndPos - uidStartPos - 1) };
+ }
+
+ std::pair> GetDisplays()
+ {
+ bool success = true;
+ std::vector result{};
+ auto allMonitors = MonitorEnumerator::Enumerate();
+
+ OnThreadExecutor dpiUnawareThread;
+ dpiUnawareThread.submit(OnThreadExecutor::task_t{ [&] {
+ SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE);
+ SetThreadDpiHostingBehavior(DPI_HOSTING_BEHAVIOR_MIXED);
+ } }).wait();
+
+ for (auto& monitorData : allMonitors)
+ {
+ MONITORINFOEX monitorInfo = monitorData.second;
+ MONITORINFOEX dpiUnawareMonitorInfo{};
+
+ dpiUnawareThread.submit(OnThreadExecutor::task_t{ [&] {
+ dpiUnawareMonitorInfo.cbSize = sizeof(dpiUnawareMonitorInfo);
+ if (!GetMonitorInfo(monitorData.first, &dpiUnawareMonitorInfo))
+ {
+ return;
+ }
+ } }).wait();
+
+ UINT dpi = 0;
+ if (DPIAware::GetScreenDPIForMonitor(monitorData.first, dpi) != S_OK)
+ {
+ success = false;
+ break;
+ }
+
+ DisplayUtils::DisplayData data{
+ .monitor = monitorData.first,
+ .dpi = dpi,
+ .monitorRectDpiAware = monitorInfo.rcMonitor,
+ .monitorRectDpiUnaware = dpiUnawareMonitorInfo.rcMonitor,
+ };
+
+ bool foundActiveMonitor = false;
+ DISPLAY_DEVICE displayDevice{ .cb = sizeof(displayDevice) };
+ DWORD displayDeviceIndex = 0;
+ while (EnumDisplayDevicesW(monitorInfo.szDevice, displayDeviceIndex, &displayDevice, EDD_GET_DEVICE_INTERFACE_NAME))
+ {
+ /*
+ * if (WI_IsFlagSet(displayDevice.StateFlags, DISPLAY_DEVICE_ACTIVE) &&
+ WI_IsFlagClear(displayDevice.StateFlags, DISPLAY_DEVICE_MIRRORING_DRIVER))
+ */
+ if (((displayDevice.StateFlags & DISPLAY_DEVICE_ACTIVE) == DISPLAY_DEVICE_ACTIVE) &&
+ (displayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) == 0)
+ {
+ // Find display devices associated with the display.
+ foundActiveMonitor = true;
+ break;
+ }
+
+ displayDeviceIndex++;
+ }
+
+ if (foundActiveMonitor)
+ {
+ auto deviceId = SplitDisplayDeviceId(displayDevice.DeviceID);
+ data.id = deviceId.first;
+ data.instanceId = deviceId.second;
+ try
+ {
+ std::wstring numberStr = displayDevice.DeviceName; // \\.\DISPLAY1\Monitor0
+ numberStr = numberStr.substr(0, numberStr.find_last_of('\\')); // \\.\DISPLAY1
+ numberStr = remove_non_digits(numberStr);
+ data.number = std::stoi(numberStr);
+ }
+ catch (...)
+ {
+ success = false;
+ break;
+ }
+ }
+ else
+ {
+ success = false;
+
+ // Use the display name as a fallback value when no proper device was found.
+ data.id = monitorInfo.szDevice;
+ data.instanceId = L"";
+
+ try
+ {
+ std::wstring numberStr = monitorInfo.szDevice; // \\.\DISPLAY1
+ numberStr = remove_non_digits(numberStr);
+ data.number = std::stoi(numberStr);
+ }
+ catch (...)
+ {
+ success = false;
+ break;
+ }
+ }
+
+ result.push_back(data);
+ }
+
+ return { success, result };
+ }
+
+}
diff --git a/src/common/Display/DisplayUtils.h b/src/common/Display/DisplayUtils.h
new file mode 100644
index 0000000000..0b0e86e227
--- /dev/null
+++ b/src/common/Display/DisplayUtils.h
@@ -0,0 +1,21 @@
+#pragma once
+
+#include
+#include
+#include
+
+namespace DisplayUtils
+{
+ struct DisplayData
+ {
+ HMONITOR monitor{};
+ std::wstring id;
+ std::wstring instanceId;
+ unsigned int number{};
+ unsigned int dpi{};
+ RECT monitorRectDpiAware{};
+ RECT monitorRectDpiUnaware{};
+ };
+
+ std::pair> GetDisplays();
+};
diff --git a/src/common/Display/MonitorEnumerator.h b/src/common/Display/MonitorEnumerator.h
new file mode 100644
index 0000000000..c603bfee6d
--- /dev/null
+++ b/src/common/Display/MonitorEnumerator.h
@@ -0,0 +1,35 @@
+#pragma once
+
+#include
+#include
+#include
+
+class MonitorEnumerator
+{
+public:
+ static std::vector> Enumerate()
+ {
+ MonitorEnumerator inst;
+ EnumDisplayMonitors(NULL, NULL, Callback, reinterpret_cast(&inst));
+ return inst.m_monitors;
+ }
+
+private:
+ MonitorEnumerator() = default;
+ ~MonitorEnumerator() = default;
+
+ static BOOL CALLBACK Callback(HMONITOR monitor, HDC /*hdc*/, LPRECT /*pRect*/, LPARAM param)
+ {
+ MonitorEnumerator* inst = reinterpret_cast(param);
+ MONITORINFOEX mi;
+ mi.cbSize = sizeof(mi);
+ if (GetMonitorInfo(monitor, &mi))
+ {
+ inst->m_monitors.push_back({monitor, mi});
+ }
+
+ return TRUE;
+ }
+
+ std::vector> m_monitors;
+};
\ No newline at end of file
diff --git a/src/modules/Projects/ProjectsSnapshotTool/MonitorUtils.cpp b/src/modules/Projects/ProjectsSnapshotTool/MonitorUtils.cpp
deleted file mode 100644
index 3ae47ee592..0000000000
--- a/src/modules/Projects/ProjectsSnapshotTool/MonitorUtils.cpp
+++ /dev/null
@@ -1,176 +0,0 @@
-#include "pch.h"
-#include "MonitorUtils.h"
-
-#include
-
-#include
-#include
-
-#include
-
-namespace MonitorUtils
-{
- namespace Display
- {
- constexpr inline bool not_digit(wchar_t ch)
- {
- return '0' <= ch && ch <= '9';
- }
-
- std::wstring remove_non_digits(const std::wstring& input)
- {
- std::wstring result;
- std::copy_if(input.begin(), input.end(), std::back_inserter(result), not_digit);
- return result;
- }
-
- std::pair> GetDisplays()
- {
- bool success = true;
- std::vector result{};
-
- auto allMonitors = MonitorEnumerator::Enumerate();
- for (auto& monitorData : allMonitors)
- {
- MONITORINFOEX monitorInfo = monitorData.second;
- MONITORINFOEX dpiUnawareMonitorInfo{};
-
- OnThreadExecutor dpiUnawareThread;
- dpiUnawareThread.submit(OnThreadExecutor::task_t{ [&] {
- SetThreadDpiAwarenessContext(DPI_AWARENESS_CONTEXT_UNAWARE);
- SetThreadDpiHostingBehavior(DPI_HOSTING_BEHAVIOR_MIXED);
-
- dpiUnawareMonitorInfo.cbSize = sizeof(dpiUnawareMonitorInfo);
- if (!GetMonitorInfo(monitorData.first, &dpiUnawareMonitorInfo))
- {
- return;
- }
- } }).wait();
-
- float width = static_cast(monitorInfo.rcMonitor.right - monitorInfo.rcMonitor.left);
- float height = static_cast(monitorInfo.rcMonitor.bottom - monitorInfo.rcMonitor.top);
-
- float dpiUnawareWidth = static_cast(dpiUnawareMonitorInfo.rcMonitor.right - dpiUnawareMonitorInfo.rcMonitor.left);
- float dpiUnawareHeight = static_cast(dpiUnawareMonitorInfo.rcMonitor.bottom - dpiUnawareMonitorInfo.rcMonitor.top);
-
- UINT dpi = 0;
- if (DPIAware::GetScreenDPIForMonitor(monitorData.first, dpi) != S_OK)
- {
- continue;
- }
-
- Project::Monitor monitorId{
- .monitor = monitorData.first,
- .dpi = dpi,
- .monitorRectDpiAware = Project::Monitor::MonitorRect {
- .top = monitorInfo.rcMonitor.top,
- .left = monitorInfo.rcMonitor.left,
- .width = static_cast(std::roundf(width)),
- .height = static_cast(std::roundf(height)),
- },
- .monitorRectDpiUnaware = Project::Monitor::MonitorRect {
- .top = dpiUnawareMonitorInfo.rcMonitor.top,
- .left = dpiUnawareMonitorInfo.rcMonitor.left,
- .width = static_cast(std::roundf(dpiUnawareWidth)),
- .height = static_cast(std::roundf(dpiUnawareHeight)),
- },
- };
-
- bool foundActiveMonitor = false;
- DISPLAY_DEVICE displayDevice{ .cb = sizeof(displayDevice) };
- DWORD displayDeviceIndex = 0;
- while (EnumDisplayDevicesW(monitorInfo.szDevice, displayDeviceIndex, &displayDevice, EDD_GET_DEVICE_INTERFACE_NAME))
- {
- /*
- * if (WI_IsFlagSet(displayDevice.StateFlags, DISPLAY_DEVICE_ACTIVE) &&
- WI_IsFlagClear(displayDevice.StateFlags, DISPLAY_DEVICE_MIRRORING_DRIVER))
- */
- if (((displayDevice.StateFlags & DISPLAY_DEVICE_ACTIVE) == DISPLAY_DEVICE_ACTIVE) &&
- (displayDevice.StateFlags & DISPLAY_DEVICE_MIRRORING_DRIVER) == 0)
- {
- // Find display devices associated with the display.
- foundActiveMonitor = true;
- break;
- }
-
- displayDeviceIndex++;
- }
-
- if (foundActiveMonitor)
- {
- auto deviceId = SplitDisplayDeviceId(displayDevice.DeviceID);
- monitorId.id = deviceId.first;
- monitorId.instanceId = deviceId.second;
- try
- {
- std::wstring numberStr = displayDevice.DeviceName; // \\.\DISPLAY1\Monitor0
- numberStr = numberStr.substr(0, numberStr.find_last_of('\\')); // \\.\DISPLAY1
- numberStr = remove_non_digits(numberStr);
- monitorId.number = std::stoi(numberStr);
- }
- catch (...)
- {
- monitorId.number = 0;
- }
- }
- else
- {
- success = false;
-
- // Use the display name as a fallback value when no proper device was found.
- monitorId.id = monitorInfo.szDevice;
- monitorId.instanceId = L"";
-
- try
- {
- std::wstring numberStr = monitorInfo.szDevice; // \\.\DISPLAY1
- numberStr = remove_non_digits(numberStr);
- monitorId.number = std::stoi(numberStr);
- }
- catch (...)
- {
- monitorId.number = 0;
- }
- }
-
- result.push_back(std::move(monitorId));
- }
-
- return { success, result };
- }
-
- std::pair SplitDisplayDeviceId(const std::wstring& str) noexcept
- {
- // format: \\?\DISPLAY#{device id}#{instance id}#{some other id}
- // example: \\?\DISPLAY#GSM1388#4&125707d6&0&UID8388688#{e6f07b5f-ee97-4a90-b076-33f57bf4eaa7}
- // output: { GSM1388, 4&125707d6&0&UID8388688 }
-
- size_t nameStartPos = str.find_first_of('#');
- size_t uidStartPos = str.find('#', nameStartPos + 1);
- size_t uidEndPos = str.find('#', uidStartPos + 1);
-
- if (nameStartPos == std::string::npos || uidStartPos == std::string::npos || uidEndPos == std::string::npos)
- {
- return { str, L"" };
- }
-
- return { str.substr(nameStartPos + 1, uidStartPos - nameStartPos - 1), str.substr(uidStartPos + 1, uidEndPos - uidStartPos - 1) };
- }
- }
-
- std::vector IdentifyMonitors() noexcept
- {
- auto displaysResult = Display::GetDisplays();
-
- // retry
- int retryCounter = 0;
- while (!displaysResult.first && retryCounter < 100)
- {
- std::this_thread::sleep_for(std::chrono::milliseconds(30));
- displaysResult = Display::GetDisplays();
- retryCounter++;
- }
-
- return displaysResult.second;
- }
-}
\ No newline at end of file
diff --git a/src/modules/Projects/ProjectsSnapshotTool/MonitorUtils.h b/src/modules/Projects/ProjectsSnapshotTool/MonitorUtils.h
deleted file mode 100644
index 3942255016..0000000000
--- a/src/modules/Projects/ProjectsSnapshotTool/MonitorUtils.h
+++ /dev/null
@@ -1,17 +0,0 @@
-#pragma once
-
-#include
-
-#include
-
-// FancyZones: MonitorUtils.h
-namespace MonitorUtils
-{
- namespace Display
- {
- std::pair> GetDisplays();
- std::pair SplitDisplayDeviceId(const std::wstring& str) noexcept;
- }
-
- std::vector IdentifyMonitors() noexcept;
-}
\ No newline at end of file
diff --git a/src/modules/Projects/ProjectsSnapshotTool/ProjectsSnapshotTool.vcxproj b/src/modules/Projects/ProjectsSnapshotTool/ProjectsSnapshotTool.vcxproj
index 03074170de..6917ff39fc 100644
--- a/src/modules/Projects/ProjectsSnapshotTool/ProjectsSnapshotTool.vcxproj
+++ b/src/modules/Projects/ProjectsSnapshotTool/ProjectsSnapshotTool.vcxproj
@@ -123,14 +123,12 @@
-
Create
-
diff --git a/src/modules/Projects/ProjectsSnapshotTool/ProjectsSnapshotTool.vcxproj.filters b/src/modules/Projects/ProjectsSnapshotTool/ProjectsSnapshotTool.vcxproj.filters
index d182bcfb57..bb9fecde08 100644
--- a/src/modules/Projects/ProjectsSnapshotTool/ProjectsSnapshotTool.vcxproj.filters
+++ b/src/modules/Projects/ProjectsSnapshotTool/ProjectsSnapshotTool.vcxproj.filters
@@ -18,9 +18,6 @@
Header Files
-
- Header Files
-
Header Files
@@ -32,9 +29,6 @@
Source Files
-
- Source Files
-
diff --git a/src/modules/Projects/ProjectsSnapshotTool/main.cpp b/src/modules/Projects/ProjectsSnapshotTool/main.cpp
index 854a12973e..10bb24295c 100644
--- a/src/modules/Projects/ProjectsSnapshotTool/main.cpp
+++ b/src/modules/Projects/ProjectsSnapshotTool/main.cpp
@@ -6,11 +6,10 @@
#include
#include
#include
+#include
#include
#include
-#include
-
#include
#include
#include
diff --git a/src/modules/Projects/projects-common/MonitorUtils.h b/src/modules/Projects/projects-common/MonitorUtils.h
new file mode 100644
index 0000000000..7119d48b33
--- /dev/null
+++ b/src/modules/Projects/projects-common/MonitorUtils.h
@@ -0,0 +1,46 @@
+#pragma once
+
+#include
+#include
+
+namespace MonitorUtils
+{
+ inline std::vector IdentifyMonitors() noexcept
+ {
+ auto displaysResult = DisplayUtils::GetDisplays();
+
+ int retryCounter = 0;
+ while (!displaysResult.first && retryCounter < 100)
+ {
+ std::this_thread::sleep_for(std::chrono::milliseconds(30));
+ displaysResult = DisplayUtils::GetDisplays();
+ retryCounter++;
+ }
+
+ std::vector result{};
+ for (const auto& data : displaysResult.second)
+ {
+ result.emplace_back(Project::Monitor{
+ .monitor = data.monitor,
+ .id = data.id,
+ .instanceId = data.instanceId,
+ .number = data.number,
+ .dpi = data.dpi,
+ .monitorRectDpiAware = Project::Monitor::MonitorRect{
+ .top = data.monitorRectDpiAware.top,
+ .left = data.monitorRectDpiAware.left,
+ .width = data.monitorRectDpiAware.right - data.monitorRectDpiAware.left,
+ .height = data.monitorRectDpiAware.bottom - data.monitorRectDpiAware.top,
+ },
+ .monitorRectDpiUnaware = Project::Monitor::MonitorRect{
+ .top = data.monitorRectDpiUnaware.top,
+ .left = data.monitorRectDpiUnaware.left,
+ .width = data.monitorRectDpiUnaware.right - data.monitorRectDpiUnaware.left,
+ .height = data.monitorRectDpiUnaware.bottom - data.monitorRectDpiUnaware.top,
+ },
+ });
+ }
+
+ return result;
+ }
+}
\ No newline at end of file