【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を起点にカスタマイズする
目次