2023 年です。私たちが作成するプログラムがダーク モードをサポートしていなければ、それは正当化されません。
ダークモードかどうかを判断する
Windows では、現在のシステムのカラー モードがダークかどうかを判断するには、レジストリ キーを照会することで実現できます。
C++ のサンプル コードは次のとおりです。
HKEY hKey;
const wchar_t* subKey = L"SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize";
const wchar_t* valueName = L"AppsUseLightTheme";
DWORD value = -1;
DWORD valueSize = sizeof(DWORD);
if (RegOpenKeyEx(HKEY_CURRENT_USER, subKey, 0, KEY_READ, &hKey) == ERROR_SUCCESS)
{
HRESULT hr = RegGetValue(hKey, nullptr, valueName, RRF_RT_REG_DWORD, nullptr, &value, &valueSize);
if (hr != S_OK)
{
value = -1; // 不要假定该键必须存在,如果找不到将返回默认值
}
RegCloseKey(hKey);
}
if (value == 0)
{
// 当前使用暗色主题
}
else if (value == 1)
{
// 当前使用亮色主题
}
else
{
// 无法确定当前主题
}
C# のサンプル コードは次のとおりです。
using Microsoft.Win32;
RegistryKey key = Registry.CurrentUser.OpenSubKey(@"SOFTWARE\Microsoft\Windows\CurrentVersion\Themes\Personalize");
if (key != null)
{
int appsUseLightTheme = (int)key.GetValue("AppsUseLightTheme", -1);
if (appsUseLightTheme == 0)
{
// 当前使用暗色主题
}
else if (appsUseLightTheme == 1)
{
// 当前使用亮色主题
}
else
{
// 无法确定当前主题
}
key.Close();
}
ウィンドウをダークモードに設定する
Windows にはダーク モード WinAPI が付属しており、これを直接呼び出してウィンドウのタイトル バーを暗い色に変えることができます。
C++ のサンプル コードは次のとおりです。
#include <windows.h>
#include <dwmapi.h>
int main() {
HWND hWnd = GetMainWindowHandle(); // 获取主窗口句柄
DWORD dwAttribute = DWMWA_USE_IMMERSIVE_DARK_MODE; // 设置暗色模式属性
BOOL bValue = TRUE; // 启用暗色模式
DwmSetWindowAttribute(hWnd, dwAttribute, &bValue, sizeof(bValue)); // 设置窗口属性
return 0;
}
C# のサンプル コードは次のとおりです。
[DllImport("dwmapi.dll", PreserveSig = true)]
public static extern int DwmSetWindowAttribute(IntPtr hwnd, DwmWindowAttribute attr, ref int attrValue, int attrSize);
public static bool EnableDarkModeForWindow(IntPtr hWnd, bool enable)
{
int darkMode = enable ? 1 : 0;
int hr = DwmSetWindowAttribute(hWnd, DwmWindowAttribute.UseImmersiveDarkMode, ref darkMode, sizeof(int));
return hr >= 0;
}
public enum DwmWindowAttribute : uint
{
NCRenderingEnabled = 1,
NCRenderingPolicy,
TransitionsForceDisabled,
AllowNCPaint,
CaptionButtonBounds,
NonClientRtlLayout,
ForceIconicRepresentation,
Flip3DPolicy,
ExtendedFrameBounds,
HasIconicBitmap,
DisallowPeek,
ExcludedFromPeek,
Cloak,
Cloaked,
FreezeRepresentation,
PassiveUpdateMode,
UseHostBackdropBrush,
UseImmersiveDarkMode = 20,
WindowCornerPreference = 33,
BorderColor,
CaptionColor,
TextColor,
VisibleFrameBorderThickness,
SystemBackdropType,
Last
}
色の変化に対応する
システムの色が変わると、THEMECHANGED
すべてのウィンドウにメッセージが送信されます。
C++ では、このメッセージを WndProc でキャプチャし、特定の操作を実行できます (たとえば、前述したように、ウィンドウをダーク モードに設定します)。
#include <Windows.h>
#include <iostream>
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int main() {
// 注册窗口类
WNDCLASS wc = {
};
wc.lpfnWndProc = WndProc;
wc.hInstance = GetModuleHandle(NULL);
wc.lpszClassName = L"MyWindowClass";
if (!RegisterClass(&wc)) {
std::cerr << "Failed to register window class" << std::endl;
return 1;
}
// 创建窗口
HWND hwnd = CreateWindow(
L"MyWindowClass",
L"My Window",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
NULL, NULL, GetModuleHandle(NULL), NULL
);
if (!hwnd) {
std::cerr << "Failed to create window" << std::endl;
return 1;
}
// 显示窗口
ShowWindow(hwnd, SW_SHOWDEFAULT);
// 消息循环
MSG msg;
while (GetMessage(&msg, NULL, 0, 0)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return 0;
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
switch (uMsg) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_THEMECHANGED:
std::cout << "Theme changed" << std::endl;
return 0;
default:
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
}
C# の場合、WinForm または WPF を使用している場合は、このイベントをサブスクライブし、特定のカテゴリを判断して、最終的に操作を実行することで、イベントを持つC# のカプセル化されたSystemEvents
クラスを直接使用できます。UserPreferenceChanged
SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged;
private void SystemEvents_UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e)
{
if (e.Category == UserPreferenceCategory.General)
{
// 更新颜色主题
}
}