少し前にブラウザ上で動作する.NETデコンパイラ Kani を作成したのでその紹介です。
ブラウザさえあれば簡単に試すことができます。
PWAに対応しているのでメニューからインストールすることでローカルで動作させることも可能です。
ソース:yaegaki/Kani
解説
KaniではBlazorとdnSpyを内部で使用しています。
これらを使用することで簡単にブラウザ上で動作する.NETデコンパイラを作成することができました。
Blazorについて
Blazorはブラウザ上で.NETアプリを動作するためのフレームワークです。
以下の記事がqiitaでも人気になっていたので知っている人も多いのではないでしょうか。
C# で Single Page Web Application が書ける Blazor が凄かった件
Blazorの完成度は結構高く特に意識することなくC#で書いたコードが動作しました。
dnSpyについて
dnSpyはWindows向けの.NETデコンパイラでとにかく完成度が高いです。
凄すぎて大草原不可避な.NET デコンパイラdnSpyを使ってみる
dnSpy自体はWindows向けのアプリケーションですがすべてがC#で書かれています。
なのでGUIなどのWindowsに依存する部分を除けばBlazorで動かすことができるようになります。
幸いなことにdnSpyは機能ごとにプロジェクトが分かれており簡単に再利用できました。
苦労したポイント
2019/7/9時点での情報です
Blazorアプリのビルドに失敗する
Windows上でBlazorアプリをビルドすると特におかしいところがなくてもエラーになる場合がありました。
エラーログは以下のようなものでした。
Unhandled Exception: Mono.Cecil.AssemblyResolutionException: Failed to resolve assembly: 'C:\Users\xx\.nuget\packaes\system.threading.tasks.parallel\4.3.0\lib\netstandard1.3\System.Threading.Tasks.Parallel.dll, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' ---> Mono.Cecil.AssemblyResolutionException: Failed to resolve assembly: 'C:\Users\xx\.nuget\packaes\system.threading.tasks.parallel\4.3.0\lib\netstandard1.3\System.Threading.Tasks.Parallel.dll, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'
at Mono.Linker.DirectoryAssemblyResolver.Resolve(AssemblyNameReference name, ReaderParameters parameters)
at Mono.Linker.AssemblyResolver.Resolve(AssemblyNameReference name, ReaderParameters parameters)
at Mono.Linker.LinkContext.Resolve(IMetadataScope scope)
at Mono.Linker.LinkContext.Resolve(IMetadataScope scope)
at Mono.Linker.LinkContext.Resolve(String name)
at Mono.Linker.Steps.ResolveFromAssemblyStep.Process()
at Mono.Linker.Steps.BaseStep.Process(LinkContext context)
at Mono.Linker.Pipeline.ProcessStep(LinkContext context, IStep step)
at Mono.Linker.Pipeline.Process(LinkContext context)
at Mono.Linker.Driver.Run(ILogger customLogger)
at Mono.Linker.Driver.Execute(String[] args, ILogger customLogger)
at Mono.Linker.Driver.Main(String[] args)
内容的にはアセンブリの解決ができなかったというものですがパスをよく見たら何かおかしいです。
本来ならばnugetのパッケージのパスはC:\Users\xx\.nuget\packages\...
というものですがC:\Users\xx\.nuget\packaes\...
となっています。
(packages
がpackaes
になっている)
詳細はわかりませんがおそらく引数が長くなりすぎて限界を超えてしまったため、一部の情報が欠落してしまったのだと思います。
コマンド プロンプト (Cmd.exe) へ 8192 文字以上の引数を渡した場合に発生する現象
根本的にはどうやって解決するべきかわからなかったため参照するアセンブリの数を減らすという対策をとりました。
dnSpyは多言語に対応しておりリソースファイルが多かったのでその数を減らしました。
ファイルのドラッグドロップについて
Kaniは.NETアセンブリをドラッグドロップすることでデコンパイルを行います。
このドラッグドロップを実装するために少し苦労しました。
ブラウザ上にファイルをドラッグドロップしてそのバイナリを得るためにはdragover
とdrop
で発生するイベントについてpreventDefault
を呼び出す必要があります。
Blazorのバインド機能でイベントを設定した場合、どうやってもpreventDefault
を呼ぶことができずページ遷移が発生してしまいました。
これを回避するためにはjsで処理を書く必要があり、C#だけで完結できずに少し残念でした。
また、jsからUint8Array
をC#に渡す方法がよくわからず最終的には**blob
にしてblobURL
を発行しC#側でHTTP.GETを行う**という回りくどい方法をとりました。
これについてはもう少しまともな方法があるかもしれません。
最後に
BlazorとdnSpyが凄すぎて感動しました。
特にBlazorは色々可能性を感じました。
適当なC#アプリをブラウザに移植してみるのも楽しいと思いますのでぜひやってみてください。