218 lines
6.3 KiB
C++
Raw Normal View History

2024-11-05 15:46:45 +08:00

2024-04-14 20:55:06 +08:00
// https://github.com/Blinue/Xaml-Islands-Cpp/blob/main/src/XamlIslandsCpp/XamlWindow.h
2024-06-05 21:53:12 +08:00
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;
}
2024-04-14 20:55:06 +08:00
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
{
2024-11-15 03:25:43 +08:00
#ifndef WINXP
2024-04-14 20:55:06 +08:00
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();
2024-11-15 03:25:43 +08:00
#endif
2024-04-14 20:55:06 +08:00
}
2024-11-04 23:10:41 +08:00
DECLARE_API void setdwmextendframe(HWND hwnd)
2024-08-13 23:07:35 +08:00
{
2024-11-15 03:25:43 +08:00
#ifndef WINXP
2024-08-13 23:07:35 +08:00
MARGINS mar{-1, -1, -1, -1};
DwmExtendFrameIntoClientArea(hwnd, &mar);
2024-11-15 03:25:43 +08:00
#endif
2024-08-13 23:07:35 +08:00
}
2024-11-04 23:10:41 +08:00
DECLARE_API void _SetTheme(
2024-04-14 20:55:06 +08:00
HWND _hWnd,
bool dark,
int backdrop)
{
2024-11-15 03:25:43 +08:00
#ifndef WINXP
2024-06-05 21:53:12 +08:00
// printf("%d %d\n",GetOSversion(),GetOSBuild());
2024-08-13 23:07:35 +08:00
if (GetOSversion() <= 6) // win7 x32 DwmSetWindowAttribute会崩直接禁了反正没用。不知道win8怎么样。
2024-06-05 21:53:12 +08:00
return;
2024-05-29 09:37:43 +08:00
// auto _isBackgroundSolidColor = backdrop == WindowBackdrop::SolidColor;
// if (Win32Helper::GetOSVersion().Is22H2OrNewer() &&
// _isBackgroundSolidColor != (backdrop == WindowBackdrop::SolidColor))
// {
// return true;
// }
// Win10 中即使在亮色主题下我们也使用暗色边框,这也是 UWP 窗口的行为
2024-04-14 20:55:06 +08:00
SetWindowTheme(
_hWnd,
Win32Helper::GetOSVersion().IsWin11() ? dark : true,
dark);
2024-05-29 09:37:43 +08:00
// if (!Win32Helper::GetOSVersion().Is22H2OrNewer())
// {
// return false;
// }
2024-04-14 20:55:06 +08:00
2024-05-30 08:32:21 +08:00
// 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];
2024-05-29 10:16:49 +08:00
// 不管操作系统版本了,硬设置就行,测试不会崩溃,让系统自己处理。
2024-04-14 20:55:06 +08:00
DwmSetWindowAttribute(_hWnd, DWMWA_SYSTEMBACKDROP_TYPE, &value, sizeof(value));
2024-11-15 03:25:43 +08:00
#endif
2024-04-16 20:16:24 +08:00
}
2024-11-04 23:10:41 +08:00
DECLARE_API bool isDark()
2024-04-16 20:16:24 +08:00
{
2024-11-15 03:25:43 +08:00
#ifndef WINXP
2024-04-16 20:16:24 +08:00
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);
}
2024-11-15 03:25:43 +08:00
#endif
2024-04-14 20:55:06 +08:00
return false;
}