見出し画像

C++/CLIからWPFアプリケーションを呼び出すスマートな方法

こんにちは。
今回は、あまり使う場面がない(?)かもしれない、マニアックなプログラミングの話をしていきたいと思います。

今回の話をするにあたり、以下のような簡単なアプリケーションを作成してみました。
このアプリケーションは単純に画像を読み込み、二値化するだけの機能を有しています。
画面で設定される閾値をもとに画像を二値化して加工画像として画面に表示するということをしています。

メイン画面

さて、皆さんはこのようなアプリケーションを開発するにあたり、UIをC#で、また高速化のため画像処理部分をC++/CLIでプログラミングをすることにしたとします。
一般的に用いられる手法としては、C++/CLIのクラスライブラリを用意して、その中に画像処理を行うための関数を作成し、そのDLLの関数をC#から呼び出すといった方法ではないでしょうか。
すなわち、C#を上位アプリケーションと見立てて、必要最小限の機能だけC++/CLIに委譲してしまうという考え方です。

それに対して、今回お話するのはC++/CLIからWPFアプリケーションを呼び出そうといった手法です。
この手法を使うことで、上記の方法では得られないメリットもあります。
実際に作ったアプリケーションをもとに紹介していきたいと思います。

設計思想

上で紹介したアプリケーションのソースコードはGitHubにあげています。

また、クラス設計の概略図を載せておきます。

クラス概略図

C++/CLIからWPFアプリケーションを呼び出す際のポイントは以下の3つです。

①WPFアプリケーションをMVVMパターンで実装する
 (Viewクラス:MainWindow
  ViewModelクラス:MainWindowViewModelBase
  Modelクラス:MainWindowModel)
②C#で作成したViewModelクラスをC++側で継承したクラスを用意する
 (MainWindowViewModelBaseを継承したMainWindowViewModel)
③C++側でアプリケーションのViewクラスを生成した際に、C++で作成したViewModelクラスをデータバインドする

実際のメイン関数は以下のような処理になっています。
ViewModelクラスとViewクラスを生成し、ViewクラスのDataContextにViewModelクラスを指定するという流れです。

[STAThreadAttribute]
int main(array<System::String ^> ^args)
{
	MainWindowViewModel ^viewModel = gcnew MainWindowViewModel();
	MainWindow ^main = gcnew MainWindow();
	main->DataContext = viewModel;

	main->ShowDialog();
   return 0;
}

このように設計すると、アプリケーションのViewModelクラスにおいて、継承先のクラスがC++/CLIにあり、継承元のクラスがC#にあるという何とも不思議な状態になりますが、UIからイベントを取得した際に、C++/CLIで処理を行うのがとても簡単になります。

この設計でプログラミングを実装するメリットは大きく2つあると考えています。

一つ目はViewModelクラスにおいて、継承元のプロパティに継承先が簡単にアクセスすることができる点です。
継承先もUIとデータバインドされているプロパティに直接アクセスできるので、C++/CLIに処理を委譲させる際に、わざわざ引数として画面で設定した変数を渡してやる必要はありませんし、C++/CLI側でプロパティを直接書き換えることも可能です。
したがって、受け渡しの処理が必要なくなる分だけ処理が簡潔になりますし、ソースコードのメンテナンスもしやすくなります。

二つ目は、限定的なメリットになります。
例えば、MFCなどのC++やC++/CLIだけで実装されているレガシーなソースコードがあったとして、そこに機能追加で新しい画面を実装したいという要望があがったとします。
今までよりもリッチなUIを作成したいからC#も使いたいけど、既存の処理もなるべく使える機能は使っていきたいというときにこそ、今回のような設計思想は力を発揮するのではないかなと考えております。

まとめ

今回はだいぶマニアックな話になってしまいましたが、C#とC++/CLIを上手に連動させたいという悩みを持つ方々の助けになるような話になっていたら幸いです。
また、ここではWPFアプリケーションを取り上げていますが、Windows FormアプリケーションでもUWPアプリケーションでもMVVMパターンで実装していれば取り入れることができる手法ですので、ぜひ試してみてください。
最後までお読みいただき、ありがとうございました。

この記事が気に入ったらサポートをしてみませんか?