恍兮惚兮 f7384a43aa w732
2024-06-05 21:53:12 +08:00

209 lines
6.5 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#include "define.h"
// https://github.com/Blinue/Xaml-Islands-Cpp/blob/main/src/XamlIslandsCpp/XamlWindow.h
static uint32_t GetOSversion() noexcept
{
HMODULE hNtDll = GetModuleHandle(L"ntdll.dll");
if (!hNtDll)
{
return 0;
}
auto rtlGetVersion = (LONG(WINAPI *)(PRTL_OSVERSIONINFOW))GetProcAddress(hNtDll, "RtlGetVersion");
if (rtlGetVersion == nullptr)
{
// assert(false);
return 0;
}
RTL_OSVERSIONINFOW version{};
version.dwOSVersionInfoSize = sizeof(version);
rtlGetVersion(&version);
return version.dwMajorVersion;
}
static uint32_t GetOSBuild() noexcept
{
HMODULE hNtDll = GetModuleHandle(L"ntdll.dll");
if (!hNtDll)
{
return 0;
}
auto rtlGetVersion = (LONG(WINAPI *)(PRTL_OSVERSIONINFOW))GetProcAddress(hNtDll, "RtlGetVersion");
if (rtlGetVersion == nullptr)
{
// assert(false);
return 0;
}
RTL_OSVERSIONINFOW version{};
version.dwOSVersionInfoSize = sizeof(version);
rtlGetVersion(&version);
return version.dwBuildNumber;
}
struct Win32Helper
{
struct OSVersion
{
constexpr OSVersion(uint32_t build) : _build(build) {}
bool Is20H1OrNewer() const noexcept
{
return _build >= 19041;
}
// 下面为 Win11
// 不考虑代号相同的 Win10
bool IsWin11() const noexcept
{
return Is21H2OrNewer();
}
bool Is21H2OrNewer() const noexcept
{
return _build >= 22000;
}
bool Is22H2OrNewer() const noexcept
{
return _build >= 22621;
}
private:
uint32_t _build = 0;
};
static OSVersion GetOSVersion() noexcept;
};
Win32Helper::OSVersion Win32Helper::GetOSVersion() noexcept
{
static OSVersion version = GetOSBuild();
return version;
}
enum class PreferredAppMode
{
Default,
AllowDark,
ForceDark,
ForceLight,
Max
};
using fnSetPreferredAppMode = PreferredAppMode(WINAPI *)(PreferredAppMode appMode);
using fnAllowDarkModeForWindow = bool(WINAPI *)(HWND hWnd, bool allow);
using fnRefreshImmersiveColorPolicyState = void(WINAPI *)();
using fnFlushMenuThemes = void(WINAPI *)();
// using fnDwmSetWindowAttribute=HRESULT (WINAPI*)(HWND,DWORD,LPCVOID,DWORD);
static fnSetPreferredAppMode SetPreferredAppMode = nullptr;
static fnAllowDarkModeForWindow AllowDarkModeForWindow = nullptr;
static fnRefreshImmersiveColorPolicyState RefreshImmersiveColorPolicyState = nullptr;
static fnFlushMenuThemes FlushMenuThemes = nullptr;
// static fnDwmSetWindowAttribute DwmSetWindowAttribute=nullptr;
static bool initok()
{
return SetPreferredAppMode && AllowDarkModeForWindow && RefreshImmersiveColorPolicyState && FlushMenuThemes; //&&DwmSetWindowAttribute;
}
static bool InitApis() noexcept
{
if (initok())
return true;
HMODULE hUxtheme = LoadLibrary(L"uxtheme.dll");
// assert(hUxtheme);
SetPreferredAppMode = (fnSetPreferredAppMode)GetProcAddress(hUxtheme, MAKEINTRESOURCEA(135));
AllowDarkModeForWindow = (fnAllowDarkModeForWindow)GetProcAddress(hUxtheme, MAKEINTRESOURCEA(133));
RefreshImmersiveColorPolicyState = (fnRefreshImmersiveColorPolicyState)GetProcAddress(hUxtheme, MAKEINTRESOURCEA(104));
FlushMenuThemes = (fnFlushMenuThemes)GetProcAddress(hUxtheme, MAKEINTRESOURCEA(136));
// HMODULE hdwmapi = LoadLibrary(L"dwmapi.dll");
// DwmSetWindowAttribute = (fnDwmSetWindowAttribute)GetProcAddress(hdwmapi, "DwmSetWindowAttribute");
return initok();
}
static void SetWindowTheme(HWND hWnd, bool darkBorder, bool darkMenu) noexcept
{
if (!InitApis())
return;
SetPreferredAppMode(darkMenu ? PreferredAppMode::ForceDark : PreferredAppMode::ForceLight);
AllowDarkModeForWindow(hWnd, darkMenu);
// 使标题栏适应黑暗模式
// build 18985 之前 DWMWA_USE_IMMERSIVE_DARK_MODE 的值不同
// https://github.com/MicrosoftDocs/sdk-api/pull/966/files
constexpr const DWORD DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1 = 19;
BOOL value = darkBorder;
DwmSetWindowAttribute(
hWnd,
Win32Helper::GetOSVersion().Is20H1OrNewer() ? DWMWA_USE_IMMERSIVE_DARK_MODE : DWMWA_USE_IMMERSIVE_DARK_MODE_BEFORE_20H1,
&value,
sizeof(value));
RefreshImmersiveColorPolicyState();
FlushMenuThemes();
}
DECLARE void _SetTheme(
HWND _hWnd,
bool dark,
int backdrop)
{
// printf("%d %d\n",GetOSversion(),GetOSBuild());
if (GetOSversion() <= 6)//win7 x32 DwmSetWindowAttribute会崩直接禁了反正没用。不知道win8怎么样。
return;
// auto _isBackgroundSolidColor = backdrop == WindowBackdrop::SolidColor;
// if (Win32Helper::GetOSVersion().Is22H2OrNewer() &&
// _isBackgroundSolidColor != (backdrop == WindowBackdrop::SolidColor))
// {
// return true;
// }
// Win10 中即使在亮色主题下我们也使用暗色边框,这也是 UWP 窗口的行为
SetWindowTheme(
_hWnd,
Win32Helper::GetOSVersion().IsWin11() ? dark : true,
dark);
// if (!Win32Helper::GetOSVersion().Is22H2OrNewer())
// {
// return false;
// }
// 非常诡异这里marBACKDROP_MAPvalue的声明顺序会导致在win7-32位上崩溃原因未知。
MARGINS mar{-1, -1, -1, -1};
// 这个最重要不可以跳过否则transaprent会黑。win7无效仍然是黑的所以win7不可以使用QTWIN11主题。
DwmExtendFrameIntoClientArea(_hWnd, &mar);
// https://learn.microsoft.com/zh-cn/windows/win32/api/dwmapi/ne-dwmapi-dwm_systembackdrop_type
// 设置背景
static const DWM_SYSTEMBACKDROP_TYPE BACKDROP_MAP[] = {
DWMSBT_AUTO, DWMSBT_TRANSIENTWINDOW, DWMSBT_MAINWINDOW, DWMSBT_TABBEDWINDOW};
DWM_SYSTEMBACKDROP_TYPE value = BACKDROP_MAP[backdrop];
// 不管操作系统版本了,硬设置就行,测试不会崩溃,让系统自己处理。
DwmSetWindowAttribute(_hWnd, DWMWA_SYSTEMBACKDROP_TYPE, &value, sizeof(value));
}
DECLARE bool isDark()
{
HKEY hKey;
const char *subKey = "Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
if (RegOpenKeyExA(HKEY_CURRENT_USER, subKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
{
DWORD value;
DWORD dataSize = sizeof(DWORD);
if (RegQueryValueExA(hKey, "AppsUseLightTheme", 0, NULL, (LPBYTE)&value, &dataSize) == ERROR_SUCCESS)
{
RegCloseKey(hKey);
return 1 - value;
}
RegCloseKey(hKey);
}
return false;
}