Partager via


Didacticiel : hébergement d’objets visuels dans une application Win32

Windows Presentation Foundation (WPF) fournit un environnement riche pour la création d’applications. Toutefois, lorsque vous avez un investissement important dans le code Win32, il peut être plus efficace d’ajouter des fonctionnalités WPF à votre application plutôt que de réécrire votre code. Pour prendre en charge les sous-systèmes graphiques Win32 et WPF utilisés simultanément dans une application, WPF fournit un mécanisme d’hébergement d’objets dans une fenêtre Win32.

Ce tutoriel explique comment écrire un exemple d’application, Hit Test avec l’exemple d’interopérabilité Win32, qui héberge des objets visuels WPF dans une fenêtre Win32.

Spécifications

Ce tutoriel suppose une connaissance de base de la programmation WPF et Win32. Pour une présentation de base de la programmation WPF, consultez Procédure pas à pas : Ma première application de bureau WPF. Pour une présentation de la programmation Win32, consultez l’un des nombreux livres sur le sujet, en particulier Programmation Windows par Charles Petzold.

Remarque

Ce didacticiel comprend plusieurs exemples de code tirés de l'exemple associé. Cependant, pour une meilleure lecture, il n'inclut pas la totalité de l'exemple de code. Pour voir l’exemple de code complet, consultez la page Hit Test with Win32 Interoperation Sample (Exemple de test de positionnement avec interopérabilité Win32).

Création de la fenêtre Win32 hôte

La clé permettant d’héberger des objets WPF dans une fenêtre Win32 est la HwndSource classe. Cette classe encapsule les objets WPF dans une fenêtre Win32, ce qui leur permet d’être incorporés dans votre interface utilisateur en tant que fenêtre enfant.

L’exemple suivant montre le code permettant de créer l’objet HwndSource en tant que fenêtre de conteneur Win32 pour les objets visuels. Pour définir le style de fenêtre, la position et d’autres paramètres de la fenêtre Win32, utilisez l’objet 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

Remarque

La valeur de la ExtendedWindowStyle propriété ne peut pas être définie sur WS_EX_TRANSPARENT. Cela signifie que la fenêtre Win32 hôte ne peut pas être transparente. Pour cette raison, la couleur d’arrière-plan de la fenêtre Win32 hôte est définie sur la même couleur d’arrière-plan que sa fenêtre parente.

Ajout d’objets visuels à la fenêtre Win32 hôte

Une fois que vous avez créé une fenêtre de conteneur Win32 hôte pour les objets visuels, vous pouvez y ajouter des objets visuels. Vous devez vous assurer que toutes les transformations des objets visuels, telles que les animations, ne s’étendent pas au-delà des limites du rectangle englobant de la fenêtre Win32 hôte.

L’exemple suivant montre le code permettant de créer l’objet HwndSource et d’y ajouter des objets visuels.

Remarque

La RootVisual propriété de l’objet HwndSource est définie sur le premier objet visuel ajouté à la fenêtre Win32 hôte. L’objet visuel racine définit le nœud supérieur de l’arborescence des objets visuels. Tous les objets visuels suivants ajoutés à la fenêtre Win32 hôte sont ajoutés en tant qu’objets enfants.

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

Implémentation du filtre de messages Win32

La fenêtre Win32 hôte pour les objets visuels nécessite une procédure de filtre de message de fenêtre pour gérer les messages envoyés à la fenêtre à partir de la file d’attente de l’application. La procédure de fenêtre reçoit les messages du système Win32. Ces messages peuvent être des messages de gestion de fenêtre ou des messages de saisie. Vous pouvez choisir de gérer un message dans votre procédure de fenêtre ou de transférer le message au système de traitement par défaut.

L’objet HwndSource que vous avez défini comme parent pour les objets visuels doit référencer la procédure de filtre de message de fenêtre que vous fournissez. Lorsque vous créez l’objet HwndSource , définissez la HwndSourceHook propriété pour référencer la procédure de fenêtre.

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

L’exemple suivant montre le code permettant de gérer les messages lorsque les boutons gauche et droit de la souris sont relâchés. La valeur de coordonnée de la position de positionnement de la souris est contenue dans la valeur du lParam paramètre.

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

Traitement des messages Win32

Le code de l’exemple suivant montre comment effectuer un test de positionnement sur la hiérarchie des objets visuels contenus dans la fenêtre Win32 hôte. Vous pouvez identifier si un point se trouve dans la géométrie d’un objet visuel, à l’aide de la HitTest méthode pour spécifier l’objet visuel racine et la valeur de coordonnées pour effectuer un test de positionnement. Dans ce cas, l’objet visuel racine est la valeur de la RootVisual propriété de l’objet HwndSource .

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

Pour plus d’informations au sujet des tests de positionnement sur des objets visuels, consultez l’article Test de positionnement dans la couche visuelle.

Voir aussi