チュートリアル: Win32 アプリケーションでのビジュアル オブジェクトのホスト
Windows Presentation Foundation (WPF) は、アプリケーションを作成するための豊富な環境を提供します。 ただし、Win32 コードに多額の投資がある場合は、コードを書き直すのではなく、WPF 機能をアプリケーションに追加する方が効果的な場合があります。 アプリケーションで同時に使用される Win32 および WPF グラフィックス サブシステムのサポートを提供するために、WPF には Win32 ウィンドウでオブジェクトをホストするためのメカニズムが用意されています。
このチュートリアルでは、Win32 ウィンドウで WPF ビジュアル オブジェクトをホストするサンプル アプリケーション (Win32 相互運用サンプルを使用したヒット テスト
必要条件
このチュートリアルでは、WPF と Win32 の両方のプログラミングに関する基本的な知識を前提としています。 WPF プログラミングの基本的な概要については、「チュートリアル: 初めての WPF デスクトップ アプリケーションの」を参照してください。 Win32 プログラミングの概要については、このテーマに関する多数の書籍、特に Charles Petzold による Windows のプログラミング
手記
このチュートリアルには、関連するサンプルのコード例が多数含まれています。 ただし、読みやすくするために、完全なサンプル コードは含まれていません。 完全なサンプル コードについては、「Win32 相互運用 サンプルを使用したヒット テスト」を参照してください。
ホスト Win32 ウィンドウの作成
Win32 ウィンドウで WPF オブジェクトをホストするキーは、HwndSource クラスです。 このクラスは、WPF オブジェクトを Win32 ウィンドウでラップし、子ウィンドウとしてユーザー インターフェイス (UI) に組み込むことができます。
次の例は、ビジュアル オブジェクトの Win32 コンテナー ウィンドウとして HwndSource オブジェクトを作成するコードを示しています。 Win32 ウィンドウのウィンドウ スタイル、位置、およびその他のパラメーターを設定するには、HwndSourceParameters オブジェクトを使用します。
// Constant values from the "winuser.h" header file.
internal const int WS_CHILD = 0x40000000,
WS_VISIBLE = 0x10000000;
internal static void CreateHostHwnd(IntPtr parentHwnd)
{
// Set up the parameters for the host hwnd.
HwndSourceParameters parameters = new HwndSourceParameters("Visual Hit Test", _width, _height);
parameters.WindowStyle = WS_VISIBLE | WS_CHILD;
parameters.SetPosition(0, 24);
parameters.ParentWindow = parentHwnd;
parameters.HwndSourceHook = new HwndSourceHook(ApplicationMessageFilter);
// Create the host hwnd for the visuals.
myHwndSource = new HwndSource(parameters);
// Set the hwnd background color to the form's background color.
myHwndSource.CompositionTarget.BackgroundColor = System.Windows.Media.Brushes.OldLace.Color;
}
' Constant values from the "winuser.h" header file.
Friend Const WS_CHILD As Integer = &H40000000, WS_VISIBLE As Integer = &H10000000
Friend Shared Sub CreateHostHwnd(ByVal parentHwnd As IntPtr)
' Set up the parameters for the host hwnd.
Dim parameters As New HwndSourceParameters("Visual Hit Test", _width, _height)
parameters.WindowStyle = WS_VISIBLE Or WS_CHILD
parameters.SetPosition(0, 24)
parameters.ParentWindow = parentHwnd
parameters.HwndSourceHook = New HwndSourceHook(AddressOf ApplicationMessageFilter)
' Create the host hwnd for the visuals.
myHwndSource = New HwndSource(parameters)
' Set the hwnd background color to the form's background color.
myHwndSource.CompositionTarget.BackgroundColor = System.Windows.Media.Brushes.OldLace.Color
End Sub
手記
ExtendedWindowStyle プロパティの値を WS_EX_TRANSPARENT に設定することはできません。 これは、ホスト Win32 ウィンドウを透明にできないことを意味します。 このため、ホスト Win32 ウィンドウの背景色は、親ウィンドウと同じ背景色に設定されます。
ホスト Win32 ウィンドウへのビジュアル オブジェクトの追加
ビジュアル オブジェクトのホスト Win32 コンテナー ウィンドウを作成したら、ビジュアル オブジェクトを追加できます。 アニメーションなどのビジュアル オブジェクトの変換が、ホスト Win32 ウィンドウの外接する四角形の境界を超えないようにする必要があります。
次の例は、HwndSource オブジェクトを作成し、それにビジュアル オブジェクトを追加するためのコードを示しています。
手記
HwndSource オブジェクトの RootVisual プロパティは、ホスト Win32 ウィンドウに追加された最初のビジュアル オブジェクトに設定されます。 ルート ビジュアル オブジェクトは、ビジュアル オブジェクト ツリーの最上位ノードを定義します。 ホスト Win32 ウィンドウに追加された後続のビジュアル オブジェクトは、子オブジェクトとして追加されます。
public static void CreateShape(IntPtr parentHwnd)
{
// Create an instance of the shape.
MyShape myShape = new MyShape();
// Determine whether the host container window has been created.
if (myHwndSource == null)
{
// Create the host container window for the visual objects.
CreateHostHwnd(parentHwnd);
// Associate the shape with the host container window.
myHwndSource.RootVisual = myShape;
}
else
{
// Assign the shape as a child of the root visual.
((ContainerVisual)myHwndSource.RootVisual).Children.Add(myShape);
}
}
Public Shared Sub CreateShape(ByVal parentHwnd As IntPtr)
' Create an instance of the shape.
Dim myShape As New MyShape()
' Determine whether the host container window has been created.
If myHwndSource Is Nothing Then
' Create the host container window for the visual objects.
CreateHostHwnd(parentHwnd)
' Associate the shape with the host container window.
myHwndSource.RootVisual = myShape
Else
' Assign the shape as a child of the root visual.
CType(myHwndSource.RootVisual, ContainerVisual).Children.Add(myShape)
End If
End Sub
Win32 メッセージ フィルターの実装
ビジュアル オブジェクトのホスト Win32 ウィンドウには、アプリケーション キューからウィンドウに送信されるメッセージを処理するためのウィンドウ メッセージ フィルター プロシージャが必要です。 ウィンドウ プロシージャは、Win32 システムからメッセージを受信します。 これらは、入力メッセージまたはウィンドウ管理メッセージです。 必要に応じて、ウィンドウ プロシージャでメッセージを処理するか、既定の処理のためにメッセージをシステムに渡すことができます。
ビジュアル オブジェクトの親として定義した HwndSource オブジェクトは、指定したウィンドウ メッセージ フィルター プロシージャを参照する必要があります。 HwndSource オブジェクトを作成するときに、ウィンドウ プロシージャを参照するように HwndSourceHook プロパティを設定します。
parameters.HwndSourceHook = new HwndSourceHook(ApplicationMessageFilter);
parameters.HwndSourceHook = New HwndSourceHook(AddressOf ApplicationMessageFilter)
次の例は、マウスの左右のボタンアップ メッセージを処理するコードを示しています。 マウス ヒット位置の座標値は、lParam
パラメーターの値に含まれています。
// Constant values from the "winuser.h" header file.
internal const int WM_LBUTTONUP = 0x0202,
WM_RBUTTONUP = 0x0205;
internal static IntPtr ApplicationMessageFilter(
IntPtr hwnd, int message, IntPtr wParam, IntPtr lParam, ref bool handled)
{
// Handle messages passed to the visual.
switch (message)
{
// Handle the left and right mouse button up messages.
case WM_LBUTTONUP:
case WM_RBUTTONUP:
System.Windows.Point pt = new System.Windows.Point();
pt.X = (uint)lParam & (uint)0x0000ffff; // LOWORD = x
pt.Y = (uint)lParam >> 16; // HIWORD = y
MyShape.OnHitTest(pt, message);
break;
}
return IntPtr.Zero;
}
' Constant values from the "winuser.h" header file.
Friend Const WM_LBUTTONUP As Integer = &H202, WM_RBUTTONUP As Integer = &H205
Friend Shared Function ApplicationMessageFilter(ByVal hwnd As IntPtr, ByVal message As Integer, ByVal wParam As IntPtr, ByVal lParam As IntPtr, ByRef handled As Boolean) As IntPtr
' Handle messages passed to the visual.
Select Case message
' Handle the left and right mouse button up messages.
Case WM_LBUTTONUP, WM_RBUTTONUP
Dim pt As New System.Windows.Point()
pt.X = CUInt(lParam) And CUInt(&HFFFF) ' LOWORD = x
pt.Y = CUInt(lParam) >> 16 ' HIWORD = y
MyShape.OnHitTest(pt, message)
End Select
Return IntPtr.Zero
End Function
Win32 メッセージの処理
次の例のコードは、ホスト Win32 ウィンドウに含まれるビジュアル オブジェクトの階層に対してヒット テストを実行する方法を示しています。 ポイントがビジュアル オブジェクトのジオメトリ内にあるかどうかを識別するには、HitTest メソッドを使用して、ルート ビジュアル オブジェクトとヒット テストの対象となる座標値を指定します。 この場合、ルート ビジュアル オブジェクトは、HwndSource オブジェクトの RootVisual プロパティの値です。
// Constant values from the "winuser.h" header file.
public const int WM_LBUTTONUP = 0x0202,
WM_RBUTTONUP = 0x0205;
// Respond to WM_LBUTTONUP or WM_RBUTTONUP messages by determining which visual object was clicked.
public static void OnHitTest(System.Windows.Point pt, int msg)
{
// Clear the contents of the list used for hit test results.
hitResultsList.Clear();
// Determine whether to change the color of the circle or to delete the shape.
if (msg == WM_LBUTTONUP)
{
MyWindow.changeColor = true;
}
if (msg == WM_RBUTTONUP)
{
MyWindow.changeColor = false;
}
// Set up a callback to receive the hit test results enumeration.
VisualTreeHelper.HitTest(MyWindow.myHwndSource.RootVisual,
null,
new HitTestResultCallback(CircleHitTestResult),
new PointHitTestParameters(pt));
// Perform actions on the hit test results list.
if (hitResultsList.Count > 0)
{
ProcessHitTestResultsList();
}
}
' Constant values from the "winuser.h" header file.
Public Const WM_LBUTTONUP As Integer = &H0202, WM_RBUTTONUP As Integer = &H0205
' Respond to WM_LBUTTONUP or WM_RBUTTONUP messages by determining which visual object was clicked.
Public Shared Sub OnHitTest(ByVal pt As System.Windows.Point, ByVal msg As Integer)
' Clear the contents of the list used for hit test results.
hitResultsList.Clear()
' Determine whether to change the color of the circle or to delete the shape.
If msg = WM_LBUTTONUP Then
MyWindow.changeColor = True
End If
If msg = WM_RBUTTONUP Then
MyWindow.changeColor = False
End If
' Set up a callback to receive the hit test results enumeration.
VisualTreeHelper.HitTest(MyWindow.myHwndSource.RootVisual, Nothing, New HitTestResultCallback(AddressOf CircleHitTestResult), New PointHitTestParameters(pt))
' Perform actions on the hit test results list.
If hitResultsList.Count > 0 Then
ProcessHitTestResultsList()
End If
End Sub
ビジュアル オブジェクトに対するヒット テストの詳細については、「ビジュアル レイヤーの
関連項目
.NET Desktop feedback