common dependencies

This commit is contained in:
seraphima
2024-06-12 19:31:43 +02:00
parent ae6cb122c8
commit 71c7241fe1
15 changed files with 43 additions and 412 deletions

View File

@@ -600,7 +600,6 @@ 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\json.h = src\modules\Projects\projects-common\json.h
src\modules\Projects\projects-common\MonitorEnumerator.h = src\modules\Projects\projects-common\MonitorEnumerator.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

View File

@@ -6,50 +6,17 @@
#include <iostream>
#include "../projects-common/AppUtils.h"
#include "../projects-common/MonitorEnumerator.h"
#include "../projects-common/WindowEnumerator.h"
#include "../projects-common/WindowFilter.h"
#include <projects-common/AppUtils.h>
#include <projects-common/MonitorEnumerator.h>
#include <projects-common/WindowEnumerator.h>
#include <projects-common/WindowFilter.h>
#include <common/Display/dpi_aware.h>
using namespace winrt;
using namespace Windows::Foundation;
using namespace Windows::Management::Deployment;
namespace Common
{
namespace Display
{
namespace DPIAware
{
enum AwarenessLevel
{
UNAWARE,
SYSTEM_AWARE,
PER_MONITOR_AWARE,
PER_MONITOR_AWARE_V2,
UNAWARE_GDISCALED
};
AwarenessLevel GetAwarenessLevel(DPI_AWARENESS_CONTEXT system_returned_value)
{
const std::array levels{ DPI_AWARENESS_CONTEXT_UNAWARE,
DPI_AWARENESS_CONTEXT_SYSTEM_AWARE,
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE,
DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2,
DPI_AWARENESS_CONTEXT_UNAWARE_GDISCALED };
for (size_t i = 0; i < size(levels); ++i)
{
if (AreDpiAwarenessContextsEqual(levels[i], system_returned_value))
{
return static_cast<DPIAware::AwarenessLevel>(i);
}
}
return AwarenessLevel::UNAWARE;
}
}
}
}
namespace FancyZones
{
inline bool allMonitorsHaveSameDpiScaling()
@@ -114,8 +81,8 @@ namespace FancyZones
rect.top -= yOffset;
rect.bottom -= yOffset;
const auto level = Common::Display::DPIAware::GetAwarenessLevel(GetWindowDpiAwarenessContext(window));
const bool accountForUnawareness = level < Common::Display::DPIAware::PER_MONITOR_AWARE;
const auto level = DPIAware::GetAwarenessLevel(GetWindowDpiAwarenessContext(window));
const bool accountForUnawareness = level < DPIAware::PER_MONITOR_AWARE;
if (accountForUnawareness && !allMonitorsHaveSameDpiScaling())
{

View File

@@ -1,6 +1,6 @@
#pragma once
#include "../projects-common/Data.h"
#include <projects-common/Data.h>
bool Launch(const Project::Application& app);
void Launch(const Project& project);

View File

@@ -137,6 +137,9 @@
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\Display\Display.vcxproj">
<Project>{caba8dfb-823b-4bf2-93ac-3f31984150d9}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
</ProjectReference>

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">

View File

@@ -2,9 +2,9 @@
#include <iostream>
#include "../projects-common/Data.h"
#include <projects-common/Data.h>
#include "AppLauncher.h"
#include <AppLauncher.h>
int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, PSTR cmdline, int cmdshow)
{

View File

@@ -3,49 +3,10 @@
#include <ShellScalingApi.h>
#include "../projects-common/MonitorEnumerator.h"
#include "OnThreadExecutor.h"
#include <projects-common/MonitorEnumerator.h>
#include <OnThreadExecutor.h>
namespace Common
{
namespace Display
{
namespace DPIAware
{
constexpr inline int DEFAULT_DPI = 96;
void Convert(HMONITOR monitor_handle, float& width, float& height)
{
if (monitor_handle == NULL)
{
const POINT ptZero = { 0, 0 };
monitor_handle = MonitorFromPoint(ptZero, MONITOR_DEFAULTTOPRIMARY);
}
UINT dpi_x, dpi_y;
if (GetDpiForMonitor(monitor_handle, MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y) == S_OK)
{
width = width * dpi_x / DEFAULT_DPI;
height = height * dpi_y / DEFAULT_DPI;
}
}
HRESULT GetScreenDPIForMonitor(HMONITOR targetMonitor, UINT& dpi)
{
if (targetMonitor != nullptr)
{
UINT dummy = 0;
return GetDpiForMonitor(targetMonitor, MDT_EFFECTIVE_DPI, &dpi, &dummy);
}
else
{
dpi = DPIAware::DEFAULT_DPI;
return E_FAIL;
}
}
}
}
}
#include <common/Display/dpi_aware.h>
namespace MonitorUtils
{
@@ -93,7 +54,7 @@ namespace MonitorUtils
float dpiUnawareHeight = static_cast<float>(dpiUnawareMonitorInfo.rcMonitor.bottom - dpiUnawareMonitorInfo.rcMonitor.top);
UINT dpi = 0;
if (Common::Display::DPIAware::GetScreenDPIForMonitor(monitorData.first, dpi) != S_OK)
if (DPIAware::GetScreenDPIForMonitor(monitorData.first, dpi) != S_OK)
{
continue;
}

View File

@@ -2,7 +2,7 @@
#include <vector>
#include "../projects-common/Data.h"
#include <projects-common/Data.h>
// FancyZones: MonitorUtils.h
namespace MonitorUtils

View File

@@ -139,6 +139,9 @@
<None Include="packages.config" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\common\Display\Display.vcxproj">
<Project>{caba8dfb-823b-4bf2-93ac-3f31984150d9}</Project>
</ProjectReference>
<ProjectReference Include="..\..\..\common\logger\logger.vcxproj">
<Project>{d9b8fc84-322a-4f9f-bbb9-20915c47ddfd}</Project>
</ProjectReference>

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup>
<Filter Include="Source Files">

View File

@@ -3,13 +3,13 @@
#include <chrono>
#include <iostream>
#include "../projects-common/AppUtils.h"
#include "../projects-common/Data.h"
#include "../projects-common/GuidUtils.h"
#include "../projects-common/WindowEnumerator.h"
#include "../projects-common/WindowFilter.h"
#include <projects-common/AppUtils.h>
#include <projects-common/Data.h>
#include <projects-common/GuidUtils.h>
#include <projects-common/WindowEnumerator.h>
#include <projects-common/WindowFilter.h>
#include "MonitorUtils.h"
#include <MonitorUtils.h>
int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, PSTR cmdline, int cmdshow)
{
@@ -99,7 +99,7 @@ int APIENTRY WinMain(HINSTANCE hInst, HINSTANCE hInstPrev, PSTR cmdline, int cmd
}
// filter by app path
std::wstring processPath = Common::Utils::ProcessPath::get_process_path_waiting_uwp(window);
std::wstring processPath = get_process_path_waiting_uwp(window);
if (processPath.empty() || WindowUtils::IsExcludedByDefault(window, processPath, title))
{
continue;

View File

@@ -7,7 +7,7 @@
#include <filesystem>
#include "../projects-common/WindowUtils.h"
#include <common/utils/process_path.h>
namespace Utils
{
@@ -174,7 +174,7 @@ namespace Utils
inline std::optional<AppData> GetApp(HWND window, const AppList& apps)
{
std::wstring processPath = Common::Utils::ProcessPath::get_process_path_waiting_uwp(window);
std::wstring processPath = get_process_path_waiting_uwp(window);
return Utils::Apps::GetApp(processPath, apps);
}
}

View File

@@ -4,7 +4,8 @@
#include <optional>
#include <shlobj.h>
#include "json.h"
#include <common/SettingsAPI/settings_helpers.h>
#include <common/utils/json.h>
struct Project
{

View File

@@ -5,202 +5,9 @@
#include <algorithm>
namespace Common
{
namespace Display
{
namespace DPIAware
{
constexpr inline int DEFAULT_DPI = 96;
inline void InverseConvert(HMONITOR monitor_handle, float& width, float& height)
{
if (monitor_handle == NULL)
{
const POINT ptZero = { 0, 0 };
monitor_handle = MonitorFromPoint(ptZero, MONITOR_DEFAULTTOPRIMARY);
}
UINT dpi_x, dpi_y;
if (GetDpiForMonitor(monitor_handle, MDT_EFFECTIVE_DPI, &dpi_x, &dpi_y) == S_OK)
{
width = width * DPIAware::DEFAULT_DPI / dpi_x;
height = height * DPIAware::DEFAULT_DPI / dpi_y;
}
}
}
}
namespace Utils
{
namespace ProcessPath
{
// Get the executable path or module name for modern apps
inline std::wstring get_process_path(DWORD pid) noexcept
{
auto process = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, TRUE, pid);
std::wstring name;
if (process != INVALID_HANDLE_VALUE)
{
name.resize(MAX_PATH);
DWORD name_length = static_cast<DWORD>(name.length());
if (QueryFullProcessImageNameW(process, 0, name.data(), &name_length) == 0)
{
name_length = 0;
}
name.resize(name_length);
CloseHandle(process);
}
return name;
}
// Get the executable path or module name for modern apps
inline std::wstring get_process_path(HWND window) noexcept
{
const static std::wstring app_frame_host = L"ApplicationFrameHost.exe";
DWORD pid{};
GetWindowThreadProcessId(window, &pid);
auto name = get_process_path(pid);
if (name.length() >= app_frame_host.length() &&
name.compare(name.length() - app_frame_host.length(), app_frame_host.length(), app_frame_host) == 0)
{
// It is a UWP app. We will enumerate the windows and look for one created
// by something with a different PID
DWORD new_pid = pid;
EnumChildWindows(
window, [](HWND hwnd, LPARAM param) -> BOOL {
auto new_pid_ptr = reinterpret_cast<DWORD*>(param);
DWORD pid;
GetWindowThreadProcessId(hwnd, &pid);
if (pid != *new_pid_ptr)
{
*new_pid_ptr = pid;
return FALSE;
}
else
{
return TRUE;
}
},
reinterpret_cast<LPARAM>(&new_pid));
// If we have a new pid, get the new name.
if (new_pid != pid)
{
return get_process_path(new_pid);
}
}
return name;
}
inline std::wstring get_process_path_waiting_uwp(HWND window)
{
const static std::wstring appFrameHost = L"ApplicationFrameHost.exe";
int attempt = 0;
auto processPath = get_process_path(window);
while (++attempt < 30 && processPath.length() >= appFrameHost.length() &&
processPath.compare(processPath.length() - appFrameHost.length(), appFrameHost.length(), appFrameHost) == 0)
{
std::this_thread::sleep_for(std::chrono::milliseconds(5));
processPath = get_process_path(window);
}
return processPath;
}
}
namespace ExcludedApps
{
inline bool find_folder_in_path(const std::wstring& where, const std::vector<std::wstring>& what)
{
for (const auto& row : what)
{
const auto pos = where.rfind(row);
if (pos != std::wstring::npos)
{
return true;
}
}
return false;
}
// Checks if a process path is included in a list of strings.
inline bool find_app_name_in_path(const std::wstring& where, const std::vector<std::wstring>& what)
{
for (const auto& row : what)
{
const auto pos = where.rfind(row);
const auto last_slash = where.rfind('\\');
//Check that row occurs in where, and its last occurrence contains in itself the first character after the last backslash.
if (pos != std::wstring::npos && pos <= last_slash + 1 && pos + row.length() > last_slash)
{
return true;
}
}
return false;
}
inline bool check_excluded_app_with_title(const std::vector<std::wstring>& excludedApps, std::wstring title)
{
CharUpperBuffW(title.data(), static_cast<DWORD>(title.length()));
for (const auto& app : excludedApps)
{
if (title.contains(app))
{
return true;
}
}
return false;
}
inline bool check_excluded_app(const std::wstring& processPath, const std::wstring& title, const std::vector<std::wstring>& excludedApps)
{
bool res = find_app_name_in_path(processPath, excludedApps);
if (!res)
{
res = check_excluded_app_with_title(excludedApps, title);
}
return res;
}
}
namespace Window
{
// Check if window is part of the shell or the taskbar.
inline bool is_system_window(HWND hwnd, const char* class_name)
{
// We compare the HWND against HWND of the desktop and shell windows,
// we also filter out some window class names know to belong to the taskbar.
constexpr std::array system_classes = { "SysListView32", "WorkerW", "Shell_TrayWnd", "Shell_SecondaryTrayWnd", "Progman" };
const std::array system_hwnds = { GetDesktopWindow(), GetShellWindow() };
for (auto system_hwnd : system_hwnds)
{
if (hwnd == system_hwnd)
{
return true;
}
}
for (const auto system_class : system_classes)
{
if (!strcmp(system_class, class_name))
{
return true;
}
}
return false;
}
}
}
}
#include <common/Display/dpi_aware.h>
#include <common/utils/excluded_apps.h>
#include <common/utils/window.h>
// FancyZones WindowUtils
namespace WindowUtils
@@ -247,14 +54,14 @@ namespace WindowUtils
CharUpperBuffW(processPathUpper.data(), static_cast<DWORD>(processPathUpper.length()));
static std::vector<std::wstring> defaultExcludedFolders = { NonLocalizable::SystemAppsFolder, NonLocalizable::System, NonLocalizable::System32, NonLocalizable::SystemWOW64 };
if (Common::Utils::ExcludedApps::find_folder_in_path(processPathUpper, defaultExcludedFolders))
if (find_folder_in_path(processPathUpper, defaultExcludedFolders))
{
return true;
}
std::array<char, 256> className;
GetClassNameA(window, className.data(), static_cast<int>(className.size()));
if (Common::Utils::Window::is_system_window(window, className.data()))
if (is_system_window(window, className.data()))
{
return true;
}
@@ -265,7 +72,7 @@ namespace WindowUtils
}
static std::vector<std::wstring> defaultExcludedApps = { NonLocalizable::CoreWindow, NonLocalizable::SearchUI, NonLocalizable::ProjectsEditor, NonLocalizable::ProjectsLauncher, NonLocalizable::ProjectsSnapshotTool };
return (Common::Utils::ExcludedApps::check_excluded_app(processPathUpper, title, defaultExcludedApps));
return (check_excluded_app(window, processPathUpper, defaultExcludedApps));
}
inline RECT GetWindowRect(HWND window)
@@ -278,8 +85,8 @@ namespace WindowUtils
float originX = static_cast<float>(rect.left);
float originY = static_cast<float>(rect.top);
Common::Display::DPIAware::InverseConvert(MonitorFromWindow(window, MONITOR_DEFAULTTONULL), width, height);
Common::Display::DPIAware::InverseConvert(MonitorFromWindow(window, MONITOR_DEFAULTTONULL), originX, originY);
DPIAware::InverseConvert(MonitorFromWindow(window, MONITOR_DEFAULTTONULL), width, height);
DPIAware::InverseConvert(MonitorFromWindow(window, MONITOR_DEFAULTTONULL), originX, originY);
return RECT(static_cast<LONG>(std::roundf(originX)),
static_cast<LONG>(std::roundf(originY)),

View File

@@ -1,110 +0,0 @@
#pragma once
#include <winrt/Windows.Foundation.h>
#include <winrt/Windows.Foundation.Collections.h>
#include <winrt/Windows.Data.Json.h>
#include <optional>
#include <fstream>
// common/utils/json.h
namespace json
{
using namespace winrt::Windows::Data::Json;
inline std::optional<JsonObject> from_file(std::wstring_view file_name)
{
try
{
std::ifstream file(file_name.data(), std::ios::binary);
if (file.is_open())
{
using isbi = std::istreambuf_iterator<char>;
std::string obj_str{ isbi{ file }, isbi{} };
return JsonValue::Parse(winrt::to_hstring(obj_str)).GetObjectW();
}
return std::nullopt;
}
catch (...)
{
return std::nullopt;
}
}
inline void to_file(std::wstring_view file_name, const JsonObject& obj)
{
std::wstring obj_str{ obj.Stringify().c_str() };
std::ofstream{ file_name.data(), std::ios::binary } << winrt::to_string(obj_str);
}
inline bool has(
const json::JsonObject& o,
std::wstring_view name,
const json::JsonValueType type = JsonValueType::Object)
{
return o.HasKey(name) && o.GetNamedValue(name).ValueType() == type;
}
template<typename T>
inline std::enable_if_t<std::is_arithmetic_v<T>, JsonValue> value(const T arithmetic)
{
return json::JsonValue::CreateNumberValue(arithmetic);
}
template<typename T>
inline std::enable_if_t<!std::is_arithmetic_v<T>, JsonValue> value(T s)
{
return json::JsonValue::CreateStringValue(s);
}
inline JsonValue value(const bool boolean)
{
return json::JsonValue::CreateBooleanValue(boolean);
}
inline JsonValue value(JsonObject value)
{
return value.as<JsonValue>();
}
inline JsonValue value(JsonValue value)
{
return value; // identity function overload for convenience
}
template<typename T, typename D = std::optional<T>>
requires std::constructible_from<std::optional<T>, D>
void get(const json::JsonObject& o, const wchar_t* name, T& destination, D default_value = std::nullopt)
{
try
{
if constexpr (std::is_same_v<T, bool>)
{
destination = o.GetNamedBoolean(name);
}
else if constexpr (std::is_arithmetic_v<T>)
{
destination = static_cast<T>(o.GetNamedNumber(name));
}
else if constexpr (std::is_same_v<T, std::wstring>)
{
destination = o.GetNamedString(name);
}
else if constexpr (std::is_same_v<T, json::JsonObject>)
{
destination = o.GetNamedObject(name);
}
else
{
static_assert(std::bool_constant<std::is_same_v<T, T&>>::value, "Unsupported type");
}
}
catch (...)
{
std::optional<T> maybe_default{ std::move(default_value) };
if (maybe_default.has_value())
destination = std::move(*maybe_default);
}
}
}