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

Windows Presentation Foundation (WPF) は、アプリケーションの作成に適した環境を提供します。 ただし、Win32 コードに多くの投資を行った場合は、コードを記述し直すよりも、WPF の機能をアプリケーションに追加する方が、より効率的である場合があります。 アプリケーション内で現在使用されている Win32 と WPF グラフィック サブシステムのサポートを提供するため、WPF は Win32 ウィンドウのオブジェクトをホストする機能を提供します。

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

このトピックは、次のセクションで構成されています。

  • 要件
  • ホスト Win32 ウィンドウの作成
  • ホスト Win32 ウィンドウへのビジュアル オブジェクトの追加
  • Win32 メッセージ フィルターの実装
  • Win32 メッセージの処理
  • 関連トピック

要件

このチュートリアルは、WPF および Win32 のプログラミングに関する基本的な知識があることを前提としています。 WPF プログラミングの概要については、「チュートリアル: WPF の概要」を参照してください。 Win32 プログラミングの概要については多数の書籍が出版されていますので、それらを参照してください。特に『プログラミング Windows』(Charles Petzold 著) が参考になります。

メモメモ

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

ホスト Win32 ウィンドウの作成

Win32 ウィンドウの WPF オブジェクトをホストするキーとなるのは、HwndSource クラスです。 このクラスは Win32 ウィンドウの WPF オブジェクトをラップし、そのオブジェクトを子ウィンドウとして user interface (UI) に組み込むことができます。

次の例では、ビジュアル オブジェクトの Win32 コンテナー ウィンドウとして HwndSource オブジェクトを作成するためのコードを示します。 Win32 ウィンドウのウィンドウ スタイル、位置、およびその他のパラメーターを設定する場合は、HwndSourceParameters オブジェクトを使用します。

' 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
// 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;
}
メモメモ

ExtendedWindowStyle プロパティの値を WS_EX_TRANSPARENT に設定することはできません。これは、ホスト Win32 ウィンドウを透明にできないことを意味します。このため、ホスト Win32 ウィンドウの背景色はその親ウィンドウと同じ背景色に設定されます。

ホスト Win32 ウィンドウへのビジュアル オブジェクトの追加

ビジュアル オブジェクトのホスト Win32 コンテナー ウィンドウを作成したら、そのコンテナー ウィンドウにビジュアル オブジェクトを追加できます。 アニメーションなどでビジュアル オブジェクトが変形しても、ビジュアル オブジェクトがホスト Win32 ウィンドウの境界を示す四角形を超えて拡大されないようにする必要があります。

次の例では、HwndSource オブジェクトを作成し、ビジュアル オブジェクトを追加するコードを示します。

メモメモ

HwndSource オブジェクトの RootVisual プロパティが、ホスト Win32 ウィンドウに追加される最初のビジュアル オブジェクトに設定されます。ルートのビジュアル オブジェクトによりビジュアル オブジェクト ツリーの最上位ノードが定義されます。ホスト Win32 ウィンドウに追加される後続のビジュアル オブジェクトは、子オブジェクトとして追加されます。

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
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);
    }
}

Win32 メッセージ フィルターの実装

ビジュアル オブジェクトのホスト Win32 ウィンドウでは、アプリケーション キューからウィンドウに送信されるメッセージを処理するために、ウィンドウ メッセージのフィルター プロシージャが必要です。 ウィンドウ プロシージャは Win32 システムからのメッセージを受け取ります。 受け取るメッセージは、入力メッセージまたはウィンドウ管理メッセージです。 ウィンドウ プロシージャでメッセージを処理するか、システムにメッセージを渡して既定の処理を行うこともできます。

ビジュアル オブジェクトの親として定義した HwndSource オブジェクトは、提供するウィンドウ メッセージのフィルター プロシージャを参照する必要があります。 HwndSource オブジェクトを作成する場合は、HwndSourceHook プロパティがウィンドウ プロシージャを参照するように設定します。

parameters.HwndSourceHook = New HwndSourceHook(AddressOf ApplicationMessageFilter)
parameters.HwndSourceHook = new HwndSourceHook(ApplicationMessageFilter);

次の例では、左右のマウス ボタンのメッセージを処理するコードを示します。 マウスのヒット位置の座標値は、lParamパラメーターの値に格納されます。

' 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
// 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;
}

Win32 メッセージの処理

次のコード例では、ホスト Win32 ウィンドウに格納されたビジュアル オブジェクトの階層に対して、ヒット テストがどのように実行されるかを示します。 HitTest メソッドを使用することにより、ビジュアル オブジェクトのジオメトリ内にポイントがあるかどうかを識別して、ヒット テストを実行するルートのビジュアル オブジェクトと座標値を指定できます。 この場合、ルートのビジュアル オブジェクトは、HwndSource オブジェクトの RootVisual プロパティの値です。

        ' 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
// 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();
    }
}

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

参照

参照

HwndSource

概念

ビジュアル層でのヒット テスト

その他の技術情報

Win32 相互運用によるヒット テストのサンプル