【MFC】ダークモード対応: 課題と実装アプローチ

【MFC】ダークモード対応: 課題と実装アプローチ

Windows 10 以降でダークモードが標準機能となり、ユーザーからの対応要望が増えています。しかし MFC にはダークモードを直接サポートする API がなく、実装には工夫が必要です。
この記事では、MFC アプリへのダークモード対応の課題と実装方法を解説します。


目次

なぜ MFC では難しいのか

  • 標準コントロール(ボタン、エディット、リストボックス等)の背景色は Windows が描画する
  • MFC のコモンコントロールは GDI ベースで、テーマ変更の仕組みが限定的
  • タイトルバーや一部のコントロールは、Windows のバージョンや標準テーマ描画の影響を受ける

特に注意したいのは、「背景だけ黒くすれば終わり」ではない点です。Static、Edit、ListBox は OnCtlColor である程度合わせられますが、Button のように標準テーマ描画の影響が強い部品は、見た目を完全に揃えるにはオーナードローや別コントロール化が必要になります。

MFC ダークモード対応サンプルで、Static、Edit、ListBox、Button の色の変化と標準描画の制約を比較している画面

ダークモードの検出

bool IsWindowsDarkMode()
{
    DWORD dwValue = 0;
    DWORD dwSize = sizeof(dwValue);
    LSTATUS status = RegGetValue(
        HKEY_CURRENT_USER,
        _T("Software\\Microsoft\\Windows\\CurrentVersion\\Themes\\Personalize"),
        _T("AppsUseLightTheme"),
        RRF_RT_DWORD, nullptr, &dwValue, &dwSize);

    return (status == ERROR_SUCCESS && dwValue == 0);
}

WM_SETTINGCHANGE メッセージを監視すると、ユーザーがテーマを変更したタイミングを検出できます。

void CMainFrame::OnSettingChange(UINT, LPCTSTR lpszSection)
{
    if (lpszSection && CString(lpszSection) == _T("ImmersiveColorSet"))
    {
        ApplyDarkMode();
    }
}

背景色のカスタマイズ

// Static / Edit / ListBox などの色を変更
HBRUSH CMyFrame::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    if (m_bDarkMode)
    {
        pDC->SetTextColor(RGB(240, 240, 240));
        pDC->SetBkColor(RGB(48, 48, 48));

        if (nCtlColor == CTLCOLOR_STATIC ||
            nCtlColor == CTLCOLOR_EDIT ||
            nCtlColor == CTLCOLOR_LISTBOX)
        {
            return m_brControlDark;
        }
    }
    return __super::OnCtlColor(pDC, pWnd, nCtlColor);
}

この方法で塗り替えやすい部品もありますが、ボタンやタブなどは標準テーマ描画の都合で一部だけ明るく残ることがあります。そこが MFC ダークモード対応の難所です。


タイトルバーのダーク化

タイトルバーは DwmSetWindowAttribute でダーク表示を指定できます。ただし、DWMWA_USE_IMMERSIVE_DARK_MODE の扱いは Windows のバージョンによって差があります。アプリ全体のダークモード対応とは分けて、補助的な見た目調整として扱うのが安全です。

#include <dwmapi.h>
#pragma comment(lib, "dwmapi.lib")

void SetDarkTitleBar(HWND hWnd, BOOL bDark)
{
    BOOL bValue = bDark;
    DwmSetWindowAttribute(hWnd,
        DWMWA_USE_IMMERSIVE_DARK_MODE,
        &bValue,
        sizeof(bValue));
}

現実的なアプローチ

  1. タイトルバーのダーク化は、対応環境で使える補助的な見た目調整として扱う
  2. メインエリアの背景色は OnCtlColor / OnEraseBkgnd で対応
  3. 標準コントロールの完全なダーク化はオーナードローが必要になる場合がある
  4. 完璧を目指すよりも、主要な背景色とテキスト色の対応から始めるのが現実的

まとめ

  • MFC にはダークモードの直接サポートはないが、段階的に対応可能
  • レジストリと WM_SETTINGCHANGE でダークモードを検出する
  • タイトルバーのダーク化は、対応環境で使える補助的な調整として扱う
  • コントロールの色変更は OnCtlColor を起点にカスタマイズする
目次