WPF と OpenGL の空域問題への対処

WPF を使っていて厄介な問題の1つに空域の問題があります。特に DirectX や OpenGL, Vulkan といった HWND を使うものを扱って WPF の世界に持ち込むと遭遇します。他にも HWND を必要とする(従来型の)コントロールを配置すると出遭います。ブラウザのコントロールなどが該当するようです。

具体的には HWND を使用したコントロールを配置、ホストすると、その上には WPF のコントロールを配置できません。配置してエラーになるというわけで無く、 HWND のコントロールが最前面に来てしまうため見えない状態となってしまいます。

今までは、描画結果を D3DImage や Image など画像にしてしまって配置する方法を考えていましたが、もっと別の手段があるようだったので試してみることにしました。

WPF Hwnd Adorner

Microsoft の ブログで “WPF Hwnd Adorner” というものを見つけました。
このブログでは、まさに先に述べたように空域の問題を説明しています。そして、 HwndHost タイプの各コントロールをうまく配置するための WPF Hwnd Adorner プロジェクトを公開してくれています。
サンプルでは、 WebBrowser をホストするコントロールの上に、さらに WPF のコントロールを乗せるといったものを用意してくれています。

このプロジェクトはよく出来ていて、 HwndHost を継承して独自のコントロールを持っているものに対してもうまく機能するように整っているようです。

実験

手元には C++/CLR で作成した OpenGL の描画を行うコントロールを作ってありました。これは単に HwndHost を継承して作ったクラスです。
HWND のウィンドウを作って、 OpenGL の描画をそこに行うというものです。このようなものなので、通常であればこの描画領域の上に WPF のコントロールを配置することが(基本的には)出来ません。

※コンテキストメニューのような POPUP タイプのものは表示できますが・・・。

この OpenGLView コントロールは WPF HwndAdorner のことは考慮せずに作ったものとなっています。

この OpenGLView の上にのせるパーツとして以下のような xaml で作ってみました。

このユーザーコントロールを OpenGLView の上に載せるために、 WPF Hwnd Adorner を使って以下のように書いてみました。

上に描かれる様子を見るために若干変更しましたが、実行すると以下のような感じになります。

OpenGL の描画領域の上にユーザーコントロールとして作った xaml の内容が描画できているのを確認できました。

まとめ

この WPF Hwnd Adorner を利用すれば HWND のコントロール群を WPF の世界に持ってきて使うときに、レイアウトに課題に対して柔軟に対処できるようになりそうです。 DirectX11 (D3D11) の場合であれば、WPFDXInterop を使えば出来ましたが、 OpenGL では対応に限界がありました。
WPF Hwnd Adorner を作成してくれた方に感謝です。

シェアする

  • このエントリーをはてなブックマークに追加

フォローする