チュートリアル: Win32 アプリケーションでのビジュアル オブジェクトのホスト

コードを書き換えるのではないアプリケーションへの WPF 機能。 アプリケーションで同時に使用される Win32 と WPF のグラフィックス サブシステムをサポートするために、WPF では、Win32 ウィンドウ内でオブジェクトをホストするための機構が提供されています。

このチュートリアルでは、Win32 ウィンドウで WPF のビジュアル オブジェクトをホストするサンプル アプリケーション (Win32 相互運用によるヒット テストのサンプル) の記述方法について説明します。

必要条件

このチュートリアルは、WPF と Win32 の両方のプログラミングの基礎知識があることを前提としています。 WPF のプログラミングの基本的な概要については、「チュートリアル: 初めての WPF デスクトップ アプリケーション」をご覧ください。 Win32 のプログラミングの概要については、この主題に関する数多くの書籍、特に「Programming Windows」(Charles Petzold 著) を参照してください。

注意

このチュートリアルには、関連するサンプルからのコード例が多数含まれています。 しかし、読みやすくするため、完全なサンプル コードは含まれていません。 完全なサンプル コードについては、「Win32 相互運用によるヒット テストのサンプル」を参照してください。

ホストの Win32 ウィンドウを作成する

Win32 のウィンドウで WPF のオブジェクトをホストするときに鍵となるのは、HwndSource クラスです。 このクラスは、Win32 ウィンドウ内の WPF オブジェクトをラップして、それらを子ウィンドウとしてユーザー インターフェイス (UI) に組み込めるようにします。

次の例は、HwndSource オブジェクトを、ビジュアル オブジェクトの Win32 コンテナー ウィンドウとして作成するためのコードを示しています。 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

ビジュアル オブジェクトに対するヒット テストについて詳しくは、「ビジュアル層でのヒット テスト」を参照してください。

関連項目