1. 特定の AppMode 切り替えの場合,正常に AppMode が切り替わらない。
これは RS6 1903 以降の環境に有効な内容です。
enum PreferredAppMode { APPMODE_DEFAULT = 0, APPMODE_ALLOWDARK = 1, APPMODE_FORCEDARK = 2, APPMODE_FORCELIGHT = 3, APPMODE_MAX = 4 } [DllImport("uxtheme.dll", EntryPoint = "#104")] static extern void RefreshImmersiveColorPolicyState(); [DllImport("uxtheme.dll", EntryPoint = "#135")] static extern PreferredAppMode SetPreferredAppMode(PreferredAppMode appMode); // RS6 1903
という関数があるのですが,これの挙動がおかしいという話。
なお,RS5 1809 では同じエントリーポイントで Allow Dark
のみが使える感じです。
[DllImport("uxtheme.dll", EntryPoint = "#135")] static extern bool AllowDarkModeForApp(bool bAllowDarkMode); // RS5 1809
テーマの切り替えをアプリ側でしたいケースが存在すると思うのですが,その場合,FORCEDARK や FORCELIGHT を使うことになると思うんですが,
- (OS: Light) FORCEDARK (2) → DEFAULT (0), FORCELIGHT (3)
- (OS: Dark) ALLOWDARK (1), FORCEDARK (2) → DEFAULT (0), FORCELIGHT (3)
のケースのみ,AppMode が正常に変わらないという問題を抱えています。
ちなみに,SetPreferredAppMode
のあと RefreshImmersiveColorPolicyState
を呼ばないと正常にテーマ変更されないのでご注意を。
この不具合は 1909 と 20H1 で発生しています(1909 以前のバージョンは調べていません。そもそも 1909 と 20H1 以外手元に持ち合わせていないのですが……)。
7/27追記: 回避策は FORCELIGHT をセットしたいときに事前にテキトーなものをセット,リロードすれば良さげです。
if (appMode == PreferredAppMode.APPMODE_DEFAULT || appMode == PreferredAppMode.APPMODE_FORCELIGHT) { SetPreferredAppMode(PreferredAppMode.APPMODE_ALLOWDARK); RefreshImmersiveColorPolicyState(); } var ret = SetPreferredAppMode(appMode) == appMode; RefreshImmersiveColorPolicyState(); return ret;
2. Win32 の Dark Mode 実装の参考に
こういうものが GitHub で公開されています。
実はまだこの Win32 のテーマ切り替えの全容理解していなくて,ハイコントラストのときどのように動作するとかいまいちよくわかっていません…… 非公開 API な上,API が洗練されていないっぽいし,上記に書いた通り不具合もあるようですし……
ちなみに,MetroRadiance で動作させた場合こんな感じです。
System Menu とか使っている人少なさそうなので,完全に趣味の領域ですけどね(CaptionIcon クリック or タイトルバー領域の右クリック)。
まとめ
Dark Theme も Acrylic Blur も WinUI でやれ! 感すごいですね。WinUI 3 preview 2 だとまだ実用アプリ組むのには条件的にしんどいと思っていて……
preview 3 になったら実用的なアプリ作れるのかなぁ🤔 って感じですね。