Interopérabilité WPF et Win32

Cette rubrique fournit une vue d’ensemble de l’interopérabilité du code WINDOWS Presentation Foundation (WPF) et Win32. 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 de réutiliser certains de ce code.

Notions de base de l’interopérabilité WPF et Win32

Il existe deux techniques de base pour l’interopérabilité entre le code WPF et Win32.

  • Héberger du contenu WPF dans une fenêtre Win32. Avec cette technique, vous pouvez utiliser les fonctionnalités graphiques avancées de WPF dans l’infrastructure d’une fenêtre et d’une application Win32 standard.

  • Héberger une fenêtre Win32 dans le contenu WPF. Avec cette technique, vous pouvez utiliser un contrôle Win32 personnalisé existant dans le contexte d’autres contenus WPF et transmettre des données à travers les limites.

Cette rubrique présente les concepts inhérents à chacune de ces techniques. Pour obtenir une illustration plus orientée code de l’hébergement de WPF dans Win32, consultez procédure pas à pas : hébergement de contenu WPF dans Win32. Pour obtenir une illustration plus orientée code de l’hébergement de Win32 dans WPF, consultez procédure pas à pas : hébergement d’un contrôle Win32 dans WPF.

Projets d’interopérabilité WPF

Les API WPF sont du code managé, mais la plupart des programmes Win32 existants sont écrits en C++non managé. Vous ne pouvez pas appeler des API WPF à partir d’un vrai programme non managé. Toutefois, en utilisant l’option /clr avec le compilateur Microsoft Visual C++, vous pouvez créer un programme mixte non managé où vous pouvez combiner en toute transparence des appels d’API managés et non managés.

Une complication au niveau du projet est que vous ne pouvez pas compiler les fichiers XAML (Extensible Application Markup Language) dans un projet C++. Il existe toutefois plusieurs techniques de division du projet qui permettent de contourner ce problème.

  • Créez une DLL C# qui contient toutes vos pages XAML en tant qu’assembly compilé, puis ajoutez votre exécutable C++ à cette DLL comme référence.

  • Créez un exécutable C# pour le contenu WPF et faites-le référence à une DLL C++ qui contient le contenu Win32.

  • Permet Load de charger n’importe quel code XAML au moment de l’exécution, au lieu de compiler votre code XAML.

  • N’utilisez pas du tout XAML et écrivez tout votre WPF dans le code, en créant l’arborescence d’éléments à partir de Application.

Utilisez la technique qui vous convient le mieux.

Remarque

Si vous n’avez pas déjà utilisé C++/CLI, vous remarquerez peut-être des mot clé « nouvelles » telles que gcnew et nullptr dans les exemples de code d’interopérabilité. Ces mot clé remplacent l’ancienne syntaxe de soulignement double (__gc) et fournissent une syntaxe plus naturelle pour le code managé en C++. Pour en savoir plus sur les fonctionnalités gérées par C++/CLI, consultez Extensions de composant pour les plateformes runtime.

Utilisation des HWND par WPF

Pour tirer le meilleur parti de WPF « interopérabilité HWND », vous devez comprendre comment WPF utilise des HWND. Pour tout HWND, vous ne pouvez pas combiner le rendu WPF avec le rendu DirectX ou le rendu GDI/GDI+. Ceci a plusieurs implications. D’une part, pour pouvoir combiner ces modèles de rendu, vous devez créer une solution d’interopérabilité et utiliser les segments d’interopérabilité désignés pour chaque modèle de rendu à utiliser. D’autre part, le comportement de rendu crée une restriction d’« espace de rendu » (« airspace » en anglais) relative aux objectifs de la solution d’interopérabilité. Le concept d’« espace de rendu » est expliqué en détail dans la rubrique Vue d’ensemble des régions de technologie.

Tous les éléments WPF sur l’écran sont finalement soutenus par un HWND. Lorsque vous créez un fichier WPF, WPF Windowcrée un HWND de niveau supérieur et utilise un HwndSource élément pour placer le Window contenu WPF et son contenu dans le HWND. Le reste de votre contenu WPF dans l’application partage ce HWND singulier. Les menus, les zones de liste déroulante et les autres menus contextuels constituent une exception à ce principe. Ces éléments créent leur propre fenêtre de niveau supérieur, c’est pourquoi un menu WPF peut potentiellement dépasser le bord de la fenêtre HWND qui le contient. Lorsque vous utilisez HwndHost pour placer un HWND dans WPF, WPF informe Win32 comment positionner le nouveau HWND enfant par rapport au HWND WPF Window .

La transparence dans et entre les HWND est un concept connexe des HWND. Ceci est également expliqué dans la rubrique Vue d’ensemble des régions de technologie.

Hébergement de contenu WPF dans une fenêtre Microsoft Win32

La clé d’hébergement d’un FICHIER WPF dans une fenêtre Win32 est la HwndSource classe. Cette classe encapsule le contenu WPF dans une fenêtre Win32, afin que le contenu WPF puisse être incorporé dans votre interface utilisateur en tant que fenêtre enfant. L’approche suivante combine win32 et WPF dans une seule application.

  1. Implémentez votre contenu WPF (l’élément racine de contenu) en tant que classe managée. En règle générale, la classe hérite de l’une des classes qui peuvent contenir plusieurs éléments enfants et/ou utilisées comme élément racine, tel que DockPanel ou Page. Dans les étapes suivantes, cette classe est appelée classe de contenu WPF, et les instances de la classe sont appelées objets de contenu WPF.

  2. Implémentez une application Windows avec C++/CLI. Si vous commencez par une application C++ non managée existante, vous pouvez généralement l’activer pour appeler du code managé en modifiant les paramètres de votre projet pour inclure l’indicateur du /clr compilateur (l’étendue complète de ce qui peut être nécessaire pour prendre en charge /clr la compilation n’est pas décrite dans cette rubrique).

  3. Définissez le thread unique cloisonné (STA) comme modèle de thread. WPF utilise ce modèle de thread.

  4. Gérez la notification WM_CREATE dans votre procédure de fenêtre.

  5. Dans le gestionnaire (ou une fonction appelée par le gestionnaire), effectuez les opérations suivantes :

    1. Créez un HwndSource objet avec la fenêtre parente HWND comme parent paramètre.

    2. Créez une instance de votre classe de contenu WPF.

    3. Affectez une référence à l’objet de contenu WPF à la propriété d’objet HwndSourceRootVisual .

    4. La HwndSource propriété d’objet Handle contient le handle de fenêtre (HWND). Pour obtenir un HWND que vous pouvez utiliser dans la partie non managée de l'application, effectuez un cast de Handle.ToPointer() en HWND.

  6. Implémentez une classe managée qui contient un champ statique qui contient une référence à votre objet de contenu WPF. Cette classe vous permet d’obtenir une référence à l’objet de contenu WPF à partir de votre code Win32, mais plus important encore, cela empêche votre HwndSource nettoyage par inadvertance.

  7. Recevez des notifications de l’objet de contenu WPF en attachant un gestionnaire à un ou plusieurs événements d’objet de contenu WPF.

  8. Communiquez avec l’objet de contenu WPF à l’aide de la référence que vous avez stockée dans le champ statique pour définir des propriétés, appeler des méthodes, etc.

Remarque

Vous pouvez effectuer une définition ou une partie de la classe de contenu WPF pour Step One en XAML à l’aide de la classe de contenu partielle par défaut, si vous produisez un assembly distinct, puis le référencer. Bien que vous incluiez généralement un Application objet dans le cadre de la compilation du code XAML dans un assembly, vous ne finissez pas par l’utiliser Application dans le cadre de l’interopérabilité, vous utilisez simplement une ou plusieurs des classes racines pour les fichiers XAML référencés par l’application et référencez leurs classes partielles. Le reste de la procédure est quasiment identique à celle présentée ci-dessus.

Chacune de ces étapes est illustrée par du code dans la rubrique Procédure pas à pas : hébergement de contenu WPF dans Win32.

Hébergement d’une fenêtre Microsoft Win32 dans WPF

La clé permettant d’héberger une fenêtre Win32 dans d’autres contenus WPF est la HwndHost classe. Cette classe encapsule la fenêtre dans un élément WPF qui peut être ajouté à une arborescence d’éléments WPF. HwndHost prend également en charge les API qui vous permettent d’effectuer des tâches telles que des messages de traitement pour la fenêtre hébergée. La procédure de base est la suivante :

  1. Créez une arborescence d’éléments pour une application WPF (peut être par le biais de code ou de balisage). Recherchez un point approprié et autorisé dans l’arborescence d’éléments où l’implémentation HwndHost peut être ajoutée en tant qu’élément enfant. Dans les étapes suivantes, cet élément est appelé élément de réservation.

  2. Dérivez de HwndHost pour créer un objet qui contient votre contenu Win32.

  3. Dans cette classe d’hôte, remplacez la HwndHost méthode BuildWindowCore. Retournez le HWND de la fenêtre hébergée. Vous souhaiterez peut-être encapsuler le ou les contrôles réels en tant que fenêtre enfant de la fenêtre retournée ; L’habillage des contrôles dans une fenêtre hôte offre un moyen simple pour votre contenu WPF de recevoir des notifications des contrôles. Cette technique permet de corriger certains problèmes Win32 concernant la gestion des messages au niveau de la limite de contrôle hébergé.

  4. Remplacez les HwndHost méthodes DestroyWindowCore et WndProc. L’objectif est d’effectuer un nettoyage et de supprimer les références au contenu hébergé, en particulier si vous avez créé des références à des objets non managés.

  5. Dans votre fichier code-behind, créez une instance de la classe d’hébergement de contrôle et définissez-la comme enfant de l’élément de réservation. En règle générale, vous utilisez un gestionnaire d’événements tel que Loaded, ou utilisez le constructeur de classe partiel. Vous pouvez également ajouter le contenu d’interopérabilité via un comportement au moment de l’exécution.

  6. Traitez les messages de fenêtre sélectionnés, tels que les notifications de contrôle. Il y a deux approches possibles, qui fournissent un accès identique au flux de messages. Votre choix est donc essentiellement motivé par le côté pratique de la programmation.

    • Implémentez le traitement des messages pour tous les messages (pas seulement les messages d’arrêt) dans votre remplacement de la HwndHost méthode WndProc.

    • Pour que l’élément WPF d’hébergement traite les messages en gérant l’événement MessageHook . Cet événement est déclenché pour chaque message qui est envoyé à la procédure de fenêtre principale de la fenêtre hébergée.

    • Vous ne pouvez pas traiter les messages des fenêtres hors processus à l’aide WndProcde .

  7. Communiquez avec la fenêtre hébergée en effectuant un appel de code non managé pour appeler la fonction SendMessage non managée.

L’exécution de ces étapes crée une application qui fonctionne avec des entrées de la souris. Vous pouvez ajouter la prise en charge des tabulations pour votre fenêtre hébergée en implémentant l’interface IKeyboardInputSink .

Chacune de ces étapes est illustrée par du code dans la rubrique Procédure pas à pas : hébergement d’un contrôle Win32 dans WPF.

HWND dans WPF

Vous pouvez considérer comme HwndHost un contrôle spécial. (Techniquement, HwndHost il s’agit d’une FrameworkElement classe dérivée, et non d’une Control classe dérivée, mais elle peut être considérée comme un contrôle à des fins d’interopérabilité.) HwndHost extrait la nature Win32 sous-jacente du contenu hébergé, de sorte que le reste de WPF considère le contenu hébergé comme un autre objet de type contrôle, qui doit afficher et traiter l’entrée. HwndHost se comporte généralement comme n’importe quel autre WPF FrameworkElement, bien qu’il existe des différences importantes autour de la sortie (dessin et graphismes) et de l’entrée (souris et clavier) en fonction des limitations de ce que les HWND sous-jacents peuvent prendre en charge.

Principales différences dans le comportement de sortie

  • FrameworkElement, qui est la HwndHost classe de base, a assez quelques propriétés qui impliquent des modifications apportées à l’interface utilisateur. Celles-ci incluent des propriétés telles que FrameworkElement.FlowDirection, qui modifient la disposition des éléments dans cet élément en tant que parent. Toutefois, la plupart de ces propriétés ne sont pas mappées à des équivalents Win32 possibles, même si ces équivalents peuvent exister. Un trop grand nombre de ces propriétés et de leurs significations reposent essentiellement sur la technologie de rendu, ce qui rend les mappages difficiles à utiliser. Par conséquent, la définition de propriétés telles que FlowDirection sur HwndHost n’a aucun effet.

  • HwndHost ne peut pas être pivoté, mis à l’échelle, asymétrique ou affecté par une transformation.

  • HwndHost ne prend pas en charge la Opacity propriété (fusion alpha). Si le contenu à l’intérieur des HwndHost opérations effectue des opérations qui incluent des System.Drawing informations alpha, ce n’est pas une violation, mais l’ensemble HwndHost prend uniquement en charge Opacity = 1,0 (100 %).

  • HwndHost s’affiche sur d’autres éléments WPF dans la même fenêtre de niveau supérieur. Toutefois, un ToolTip menu ou ContextMenu un menu généré est une fenêtre de niveau supérieur distincte, et se comporte donc correctement avec HwndHost.

  • HwndHost ne respecte pas la région de découpage de son parent UIElement. Il s’agit potentiellement d’un problème si vous tentez de placer une HwndHost classe à l’intérieur d’une région de défilement ou Canvas.

Principales différences dans le comportement d’entrée

  • En général, alors que les appareils d’entrée sont étendus dans la HwndHost région Win32 hébergée, les événements d’entrée sont directement dirigés vers Win32.

  • Bien que la souris soit sur le HwndHostpoint, votre application ne reçoit pas d’événements de souris WPF et la valeur de la propriété IsMouseOver WPF sera false.

  • Bien que le HwndHost focus clavier soit activé, votre application ne recevra pas d’événements de clavier WPF et la valeur de la propriété IsKeyboardFocusWithin WPF sera false.

  • Lorsque le focus se trouve dans le HwndHost contrôle et change à l’intérieur du HwndHostcontrôle, votre application ne recevra pas les événements GotFocus WPF ou LostFocus.

  • Les propriétés et événements de stylet connexes sont analogues et ne signalent pas d’informations pendant que le stylet est terminé HwndHost.

Tabulation, mnémoniques et accélérateurs

Les IKeyboardInputSink interfaces et IKeyboardInputSite les interfaces vous permettent de créer une expérience clavier transparente pour les applications WPF et Win32 mixtes :

  • Tabulation entre les composants Win32 et WPF

  • Mnémoniques et accélérateurs fonctionnant quand le focus est sur un composant Win32 et sur un composant WPF.

Les HwndHost classes et HwndSource les deux fournissent des implémentations, IKeyboardInputSinkmais elles peuvent ne pas gérer tous les messages d’entrée souhaités pour des scénarios plus avancés. Dans ce cas, substituez les méthodes appropriées pour obtenir le comportement de clavier souhaité.

Les interfaces fournissent uniquement la prise en charge de ce qui se passe lors de la transition entre les régions WPF et Win32. Dans la région Win32, le comportement de tabulation est entièrement contrôlé par la logique implémentée par Win32 pour la tabulation, le cas échéant.

Voir aussi