次の方法で共有


チュートリアル: 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

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

関連項目