共用方式為


教學課程:在 Win32 應用程式中裝載視覺物件

Windows Presentation Foundation (WPF) 提供用來建立應用程式的豐富環境。 不過,若您已對 Win32 程式碼投入相當的心力,更有效的方法是將 WPF 功能加入應用程式,而不是重新撰寫程式碼。 為了提供在應用程式中同時 Win32 和 WPF 圖形子系統的支援,WPF 提供了一種將物件裝載在 Win32 視窗中的機制。

本教學課程說明如何撰寫範例應用程式使用 Win32 互通性進行點擊測試範例 (英文),該應用程式會將 WPF 視覺物件裝載在 Win32 視窗中。

這個主題包含下列章節。

  • 需求
  • 建立裝載 Win32 視窗
  • 將視覺物件加入至裝載 Host Win32 視窗
  • 實作 Win32 訊息篩選
  • 處理 Win32 訊息
  • 相關主題

需求

本教學課程假設您已熟悉 WPF 和 Win32 程式設計的基本概念。 如需 WPF 程式設計的基本簡介,請參閱逐步解說:WPF 使用者入門。 如需 Win32 程式設計的簡介,請參閱討論此主題的各種書籍,尤其是 Charles Petzold 所著的《Programming Windows》。

注意事項注意事項

本教學課程包括摘錄自相關範例的許多程式碼範例。不過,為了方便閱讀,此課程並未包含完整的範例程式碼。如需完整範例程式碼,請參閱使用 Win32 互通性進行點擊測試範例 (英文)。

建立裝載 Win32 視窗

將 WPF 物件裝載在 Win32 視窗中的關鍵在於 HwndSource 類別。 這個類別會將 WPF 物件包裝在 Win32 視窗中,讓您可以將這些物件當做子視窗加入 user interface (UI) 中。

下列範例顯示的程式碼可用來建立 HwndSource 物件,做為視覺物件的 Win32 容器視窗。 若要設定 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 視窗的背景色彩會設定成與其父視窗相同的背景色彩。

將視覺物件加入至裝載 Host Win32 視窗

建立視覺物件的裝載 Win32 容器視窗之後,您就可以將視覺物件加入視窗中。 您必須確定視覺物件的任何變化 (例如動畫) 都不會超過裝載 Win32 視窗周框的範圍。

下列範例顯示的程式碼可用來建立 HwndSource 物件,並將視覺物件加入其中。

注意事項注意事項

HwndSource 物件的 RootVisual 屬性會設定為加入至裝載 Win32 視窗的第一個視覺物件。這個根 (Root) 視覺物件定義了視覺物件樹狀結構的最上層節點。後續加入至裝載 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 系統傳來的訊息。 這些訊息可能是輸入訊息或視窗管理訊息。 您可以選擇在視窗程序中處理訊息,或是將訊息傳送給系統進行預設處理。

已定義為視覺物件父代 (Parent) 的 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 互通性進行點擊測試範例