

WPFには[テーマ](https://docs.microsoft.com/en-us/archive/blogs/wpfsdk/using-themes-
with-custom-
controls)というものがあることを知りました（ここでいうテーマというのは、リンク先のような`Aero.NormalColor.xaml`などのことを呼ぶこととします）。これらのテーマは、たぶん[Github](https://github.com/dotnet/wpf/tree/master/src/Microsoft.DotNet.Wpf/src/Themes)にて公開されているものと思われます。  
テーマに関して、参照先の記事は古いので現在は状況が異なるのかもしれませんが、質問です。

**Q1.** WPFの既定のテーマはどれですか？（リンク先にあるもの？それとも異なるもの？オープンソースではない？）  
**Q2.**
任意のWPFアプリケーションについて、機械的な手段で現在適用されているテーマを調べることは可能ですか？（たとえば、.exeや.dllから、使われているテーマ(.xamlファイル）を取得する、などをやれたらうれしい。[dnSpy](https://github.com/dnSpy/dnSpy)が使える？？）

環境はWindows 10, .NET Core 3.0としておきますが、回答するためにさらに仮定が必要ならば追記可能です。

以上、よろしくお願いいたします。


CC BY-SA 4.0
2020-11-15T06:02:28.390
71964
2020-11-17T15:21:20.707
question
c# .net wpf
WPFの既定のテーマ？


とりあえず達成する方法をみつけたので回答として報告しておきます。

**A1.** A2により調査した結果、結論としては、今回の環境では`Aero2.NormalColor.xaml`でした。  
**A2.** いくつかの方法を試しました。

  1. 手動でテーマを適用して、既定と同じ見た目のものが今のテーマである、と考えて、`Aero`,`Aero2`,`AeroLite`,`Classic`,`Luna`,`Royale`を全通り試しました。  
`App.xaml`に次のような記述を追加してアプリを起動します（[参考](https://qiita.com/norimatsu_yusuke/items/3a7a22f0d852d99e18cc)）:

[code]    <Application.Resources>

      <ResourceDictionary Source="/PresentationFramework.<ThemeAssembly>;component/themes/<ThemeFile>.xaml" />
    </Application.Resources>
    
[/code]

この結果、`Aero2`のとき、見た目の変化がおきず、おそらくこれが既定のテーマであると予想できます。

  2. [dnSpy](https://github.com/dnSpy/dnSpy)を用いる方法:  
実際にロードされているDLLやリソース(.xamlなど)を具体的に知ることができれば、適用されているテーマを知ることができると考えました。  
完全な調査をするためにブレークポイントを設置するべき箇所は実際にはもっとあるかもしれませんが、今回は次の箇所に設置して調査しました（[export](https://pastebin.com/i7EfzLSE)）:

    1. `RuntimeAssembly.InternalLoadAssemblyName`メソッド: 
      * [`Assembly.Load`](https://docs.microsoft.com/en-us/dotnet/api/system.reflection.assembly.load?view=net-5.0)などDLLを読み込むときに呼び出されるメソッドです。
      * このメソッドの呼び出しを記録した結果、今回の環境では`PresentationFramework.Aero2.dll`がロードされていて、それ以外のテーマらしいDLLはロードされていませんでした。
      * このメソッドの呼び出しのコールスタックに基づいて調べたところ、このDLLが選択されるのは、最終的にはWinAPIの[GetCurrentThemeName](https://docs.microsoft.com/en-us/windows/win32/api/uxtheme/nf-uxtheme-getcurrentthemename)が返す値によるようです（cf. `UxThemeWrapper.GetThemeNameAndColor`）。より深く調査したい方はこのあたりの呼び出しを調べるとよいと思われます。
    2. `Baml2006Reader.Initialize`メソッド: 
      * XAMLファイルをロードするときに内部的に呼び出されるメソッドです。
      * このメソッドの引数`settings`の`LocalAssembly`でそのXAMLリソースが格納されたDLL、`BaseUri`プロパティでロードしようとしているXAMLファイルの情報が取得できるようです。
      * ただし、肝心のテーマファイル（`Aero2.NormalColor.xaml`）の読み込み時には、`LocalAssembly`は`PresentationFramework.Aero2`となっていたものの、`BaseUri`が`null`でした。これはUriからではなくリソースに対応するStreamから直接ロードしようとしているためだと思われます。
      * ドキュメントが未整備なサードパーティライブラリなどの調査には使えるかもしれません。
    3. `ResourceManager.GetObject(string, CultureInfo, bool)`メソッド: 
      * DLLからリソース（.xaml,.bamlなど）を取得するときに呼び出されるメソッドです。[public](https://docs.microsoft.com/en-us/dotnet/api/system.resources.resourcemanager.getobject?view=net-5.0)なメソッドの内部で呼ばれます。
      * 引数`name`によりリソース名、インスタンスの`MainAssembly`プロパティからは対応するDLLの情報が取得できるようです。
      * `name`から`themes/aero2.normalcolor.baml`を見つけることができました。

これらの調査ではロードされているDLLやXAMLがわかるだけで、実際の[WPFのTree](https://docs.microsoft.com/en-
us/dotnet/desktop/wpf/advanced/trees-in-
wpf?view=netframeworkdesktop-4.8)でどう適用されているかまでは確信を持てませんが、当初の目的は達成できたのでここまでとしました。

技術的な興味として、以上のような調査をReflection的に（つまりコードで）実施する方法について、引き続き回答を募りたいと思います。  
なにか知見をお持ちの方がいらっしゃれば、ぜひお教えください。


CC BY-SA 4.0
2020-11-17T15:08:47.327
72017
2020-11-17T15:21:20.707
2020-11-17T15:21:20.707
71964
answer