Share via


Tutorial: hospedando objetos visuais em um aplicativo Win32

O Windows Presentation Foundation (WPF) fornece um ambiente avançado para a criação de aplicativos. No entanto, quando você tem um investimento substancial no código Win32, pode ser mais eficaz adicionar a funcionalidade WPF ao seu aplicativo em vez de reescrever seu código. Para fornecer suporte para subsistemas gráficos Win32 e WPF usados simultaneamente em um aplicativo, WPF fornece um mecanismo para hospedar objetos em uma janela Win32.

Este tutorial descreve como escrever um aplicativo de exemplo, Hit Test with Win32 Interoperation Sample, que hospeda objetos visuais WPF em uma janela Win32.

Requisitos

Este tutorial pressupõe uma familiaridade básica com a programação WPF e Win32. Para obter uma introdução básica à programação WPF, consulte Passo a passo: Meu primeiro aplicativo de desktop WPF. Para uma introdução à programação Win32, consulte qualquer um dos vários livros sobre o assunto, em particular Programming Windows por Charles Petzold.

Observação

Este tutorial inclui vários exemplos de código da amostra associada. No entanto, para facilitar a leitura, não inclui o código de exemplo completo. Para o código de exemplo completo, consulte Exemplo de teste de clique com interoperação Win32.

Criando a janela Win32 de host

A chave para hospedar objetos WPF em uma janela Win32 é a HwndSource classe. Essa classe encapsula os objetos WPF em uma janela Win32, permitindo que eles sejam incorporados à interface do usuário (UI) como uma janela filho.

O exemplo a seguir mostra o código para criar o HwndSource objeto como a janela de contêiner Win32 para os objetos visuais. Para definir o estilo da janela, posição e outros parâmetros para a janela Win32, use o HwndSourceParameters objeto.

// 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

Observação

O valor da ExtendedWindowStyle propriedade não pode ser definido como WS_EX_TRANSPARENT. Isso significa que a janela Win32 do host não pode ser transparente. Por esse motivo, a cor de plano de fundo da janela Win32 do host é definida com a mesma cor de plano de fundo que sua janela pai.

Adicionando objetos visuais na janela do Host Win32

Depois de criar uma janela de contêiner Win32 host para os objetos visuais, você pode adicionar objetos visuais a ele. Você desejará garantir que quaisquer transformações dos objetos visuais, como animações, não se estendam além dos limites do retângulo delimitador da janela Win32 do host.

O exemplo a seguir mostra o código para criar o HwndSource objeto e adicionar objetos visuais a ele.

Observação

A RootVisual propriedade do objeto é definida como o primeiro objeto visual adicionado à janela Win32 do HwndSource host. O objeto visual raiz define o nó mais alto da árvore de objetos visuais. Todos os objetos visuais subsequentes adicionados à janela Win32 do host são adicionados como objetos filho.

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

Implementando o filtro de mensagens do Win32

A janela Win32 do host para os objetos visuais requer um procedimento de filtro de mensagem de janela para manipular mensagens que são enviadas para a janela da fila do aplicativo. O procedimento de janela recebe mensagens do sistema Win32. Eles podem ser mensagens de entrada ou de gerenciamento de janela. Opcionalmente, você pode lidar com uma mensagem em seu procedimento de janela ou passar a mensagem para o sistema para processamento padrão.

O HwndSource objeto que você definiu como pai para os objetos visuais deve fazer referência ao procedimento de filtro de mensagem de janela fornecido. Ao criar o HwndSource objeto, defina a HwndSourceHook propriedade para fazer referência ao procedimento de janela.

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

O exemplo a seguir mostra o código para lidar com mensagens com o botões direito e esquerdo do mouse. O valor da coordenada da posição de acerto do mouse está contido no valor do lParam parâmetro.

// 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

Processando as mensagens do Win32

O código no exemplo a seguir mostra como um teste de acerto é executado em relação à hierarquia de objetos visuais contidos na janela Win32 do host. Você pode identificar se um ponto está dentro da geometria de um objeto visual, usando o método para especificar o objeto visual raiz e o valor da coordenada para acertar o HitTest teste. Nesse caso, o objeto visual raiz é o RootVisual valor da propriedade do HwndSource objeto.

// 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

Para obter mais informações sobre teste de clique em objetos visuais, consulte Teste de clique na camada visual.

Confira também