Interface IMarshal (objidl.h)

Permet à un objet COM de définir et gérer le marshaling de ses pointeurs d'interface.

Héritage

L’interface IMarshal hérite de l’interface IUnknown. IMarshal a également les types de membres suivants :

Méthodes

L’interface IMarshal a ces méthodes.

 
IMarshal ::D isconnectObject

La méthode IMarshal ::D isconnectObject (objidl.h) libère toutes les connexions à un objet avant l’arrêt.
IMarshal ::GetMarshalSizeMax

Récupère la taille maximale de la mémoire tampon qui sera nécessaire pendant le marshaling.
IMarshal ::GetUnmarshalClass

Récupère le CLSID du code de démarshalation.
IMarshal ::MarshalInterface

La méthode IMarshal ::MarshalInterface (objidl.h) marshale un pointeur d’interface.
IMarshal ::ReleaseMarshalData

La méthode IMarshal ::ReleaseMarshalData (objidl.h) détruit un paquet de données marshalé.
IMarshal ::UnmarshalInterface

La méthode IMarshal ::UnmarshalInterface (objidl.h) désactive un pointeur d’interface.

Remarques

Le marshaling est le processus d’empaquetage de données dans des paquets pour les transmettre à un autre processus ou ordinateur. Le démarshalation est le processus de récupération de ces données à l’extrémité de réception. Dans un appel donné, les arguments de méthode sont marshalés et non délimités dans une direction, tandis que les valeurs de retour sont marshalées et non délimitées dans l’autre.

Bien que le marshaling s’applique à tous les types de données, les pointeurs d’interface nécessitent une gestion spéciale. Le problème fondamental est de savoir comment le code client s’exécutant dans un espace d’adressage peut déréférencer correctement un pointeur vers une interface sur un objet résidant dans un autre espace d’adressage. La solution COM permet à une application cliente de communiquer avec l’objet d’origine par le biais d’un objet de substitution, ou proxy, qui se trouve dans le processus du client. Le proxy contient une référence à une interface sur l’objet d’origine et remet au client un pointeur vers une interface sur lui-même. Lorsque le client appelle une méthode d’interface sur l’objet d’origine, son appel est en fait destiné au proxy. Par conséquent, du point de vue du client, tous les appels sont en cours.

Lors de la réception d’un appel, le proxy marshale les arguments de méthode et par le biais de certains moyens de communication interprocessus, tels que RPC, les transmet au code dans le processus serveur, qui démarshale les arguments et les transmet à l’objet d’origine. Ce même code marshale les valeurs de retour pour la transmission au proxy, qui annule les valeurs et les transmet à l’application cliente.

IMarshal fournit des méthodes pour créer, initialiser et gérer un proxy dans un processus client ; elle ne dicte pas la façon dont le proxy doit communiquer avec l’objet d’origine. L’implémentation COM par défaut d’IMarshal utilise RPC. Lorsque vous implémentez cette interface vous-même, vous êtes libre de choisir n’importe quelle méthode de communication interprocessus que vous jugez appropriée pour votre application (mémoire partagée, canal nommé, handle de fenêtre, RPC). En bref, ce qui fonctionne.

Implémentation par défaut IMarshal

COM utilise sa propre implémentation interne de l’interface IMarshal pour marshaler tout objet qui ne fournit pas sa propre implémentation. COM effectue cette détermination en interrogeant l’objet pour IMarshal. Si l’interface est manquante, COM utilise par défaut son implémentation interne.

L’implémentation COM par défaut d’IMarshal utilise un proxy générique pour chaque objet et crée des stubs et des proxys individuels, selon les besoins, pour chaque interface implémentée sur l’objet. Ce mécanisme est nécessaire, car COM ne peut pas savoir à l’avance quelles interfaces particulières un objet donné peut implémenter. Les développeurs qui n’utilisent pas le marshaling COM par défaut, choisissant à la place d’écrire leurs propres routines de proxy et de marshaling, connaissent au moment de la compilation toutes les interfaces à trouver sur leurs objets et comprennent donc exactement le code de marshaling requis. COM, en fournissant la prise en charge du marshaling pour tous les objets, doit le faire au moment de l’exécution.

Le proxy d’interface réside dans le processus client ; le stub d’interface réside dans le serveur. Ensemble, chaque paire gère tout le marshaling pour l’interface. Le travail de chaque proxy d’interface consiste à marshaler les arguments et à démarshaler les valeurs de retour et les paramètres sortants qui sont passés dans les appels suivants à son interface. Le travail de chaque stub d’interface consiste à démarshaler les arguments de fonction et à les transmettre à l’objet d’origine, puis à marshaler les valeurs de retour et les paramètres sortants que l’objet retourne.

Le proxy et le stub communiquent au moyen d’un canal RPC (appel de procédure distante), qui utilise l’infrastructure RPC du système pour la communication interprocessus. Le canal RPC implémente une interface unique, IRpcChannelBuffer, vers laquelle les proxys d’interface et les stubs contiennent un pointeur. Le proxy et le stub appellent l’interface pour obtenir un paquet de marshaling, envoyer les données à leur équivalent et détruire le paquet quand ils ont terminé. Le stub d’interface contient également un pointeur vers l’objet d’origine.

Pour une interface donnée, le proxy et le stub sont tous deux implémentés en tant qu’instances de la même classe, qui est répertoriée pour chaque interface dans le registre système sous l’étiquette ProxyStubClsid32. Cette entrée mappe l’IID de l’interface au CLSID de ses objets proxy et stub. Lorsque COM doit marshaler une interface, il recherche dans le registre système pour obtenir le CLSID approprié. Le serveur identifié par ce CLSID implémente à la fois le proxy d’interface et le stub d’interface.

Le plus souvent, la classe à laquelle ce CLSID fait référence est générée automatiquement par un outil dont l’entrée est une description des signatures de fonction et de la sémantique d’une interface donnée, écrite dans un langage de description d’interface. Bien que l’utilisation d’un tel langage soit fortement recommandée et encouragée pour des raisons d’exactitude, il n’est pas nécessaire de le faire. Les proxys et les stubs sont simplement des composants COM utilisés par l’infrastructure RPC et, en tant que tels, peuvent être écrits de la manière souhaitée, tant que les contrats externes corrects sont respectés. Le programmeur qui conçoit une nouvelle interface est chargé de s’assurer que tous les proxys et stubs d’interface qui existent sont d’accord sur la représentation de leurs données marshalées.

Une fois créés, les proxys d’interface sont toujours agrégés dans un proxy plus grand, qui représente l’objet dans son ensemble. Ce proxy d’objet agrège également l’objet proxy générique COM, appelé gestionnaire de proxys. Le gestionnaire de proxy implémente deux interfaces : IUnknown et IMarshal. Toutes les autres interfaces qui peuvent être implémentées sur un objet sont exposées dans son proxy d’objet via l’agrégation de proxys d’interface individuels. Un client contenant un pointeur vers le proxy d’objet « croit » qu’il contient un pointeur vers l’objet réel.

Un proxy représentant l’objet dans son ensemble est requis dans le processus client afin qu’un client puisse distinguer les appels aux mêmes interfaces implémentées sur des objets entièrement différents. Toutefois, une telle exigence n’existe pas dans le processus serveur, où réside l’objet lui-même, car tous les stubs d’interface communiquent uniquement avec les objets pour lesquels ils ont été créés. Aucune autre connexion n’est possible.

Les stubs d’interface, contrairement aux proxys d’interface, ne sont pas agrégés, car il n’est pas nécessaire qu’ils apparaissent pour un client externe comme faisant partie d’un ensemble plus grand. Lorsqu’il est connecté, un stub d’interface reçoit un pointeur vers l’objet serveur auquel il doit transférer les appels de méthode qu’il reçoit. Bien qu’il soit utile de faire référence conceptuellement à un gestionnaire de stubs, c’est-à-dire les éléments de code et l’état de l’infrastructure RPC côté serveur qui prennent en charge la communication à distance d’un objet donné, il n’est pas nécessaire que le code et l’état prennent une forme particulière et bien spécifiée.

La première fois qu’un client demande un pointeur vers une interface sur un objet particulier, COM charge un stub IClassFactory dans le processus serveur et l’utilise pour marshaler le premier pointeur vers le client. Dans le processus client, COM charge le proxy générique pour l’objet de fabrique de classe et appelle son implémentation d’IMarshal pour démarshal ce premier pointeur. COM crée ensuite le premier proxy d’interface et lui remet un pointeur vers le canal RPC. Enfin, COM retourne le pointeur IClassFactory vers le client, qui l’utilise pour appeler IClassFactory ::CreateInstance, en lui passant une référence à l’interface.

De retour dans le processus serveur, COM crée maintenant une nouvelle instance de l’objet, ainsi qu’un stub pour l’interface demandée. Ce stub marshale le pointeur d’interface vers le processus client, où un autre proxy d’objet est créé, cette fois pour l’objet lui-même. Est également créé un proxy pour l’interface demandée, pointeur vers lequel est retourné au client. Avec les appels ultérieurs à d’autres interfaces sur l’objet, COM charge les stubs d’interface et les proxys appropriés si nécessaire.

Lorsqu’un proxy d’interface est créé, COM lui remet un pointeur vers l’implémentation de IUnknown par le gestionnaire de proxys, à laquelle il délègue tous les appels QueryInterface . Chaque proxy d’interface implémente ses propres interfaces : l’interface qu’il représente et IRpcProxyBuffer. Le proxy d’interface expose sa propre interface directement aux clients, qui peuvent obtenir son pointeur en appelant QueryInterface sur le gestionnaire de proxys. Toutefois, seul COM peut appeler IRpcProxyBuffer, qui est utilisé pour connecter et déconnecter le proxy au canal RPC. Un client ne peut pas interroger un proxy d’interface pour obtenir un pointeur vers l’interface IRpcProxyBuffer .

Côté serveur, chaque stub d’interface implémente IRpcStubBuffer. Le code du serveur agissant en tant que gestionnaire de stub appelle IRpcStubBuffer ::Connect et transmet au stub d’interface le pointeur IUnknown de son objet.

Lorsqu’un proxy d’interface reçoit un appel de méthode, il obtient un paquet de marshaling de son canal RPC via un appel à IRpcChannelBuffer ::GetBuffer. Le processus de marshaling des arguments copie les données dans la mémoire tampon. Une fois le marshaling terminé, le proxy d’interface appelle IRpcChannelBuffer ::SendReceive pour envoyer le paquet marshalé au stub d’interface correspondant. Lorsque IRpcChannelBuffer ::SendReceive retourne, la mémoire tampon dans laquelle les arguments ont été marshalés a été remplacée par une nouvelle mémoire tampon contenant les valeurs de retour marshalées à partir du stub d’interface. Le proxy d’interface annule les valeurs de retour, appelle IRpcChannelBuffer ::FreeBuffer pour libérer la mémoire tampon, puis retourne les valeurs renvoyées à l’appelant d’origine de la méthode.

C’est l’implémentation de IRpcChannelBuffer ::SendReceive qui envoie la demande au processus serveur et qui sait comment identifier le processus serveur et, dans ce processus, l’objet auquel la demande doit être envoyée. L’implémentation du canal sait également comment transférer la demande au gestionnaire de stub approprié dans ce processus. Le stub d’interface démarshale les arguments de la mémoire tampon fournie, appelle la méthode indiquée sur l’objet serveur et marshale les valeurs de retour dans une nouvelle mémoire tampon allouée par un appel à IRpcChannelBuffer ::GetBuffer. Le canal transmet ensuite le paquet de données de retour au proxy d’interface, qui se trouve toujours au milieu de IRpcChannelBuffer ::SendReceive, qui retourne au proxy d’interface.

Un instance particulier d’un proxy d’interface peut être utilisé pour traiter plusieurs interfaces, tant que les conditions suivantes sont remplies :

  • Les ID IID des interfaces affectées doivent être mappés au ProxyStubClsid approprié dans le registre système.
  • Le proxy d’interface doit prendre en charge les appels à QueryInterface d’une interface prise en charge vers les autres interfaces, comme d’habitude, ainsi que depuis IUnknown et IRpcProxyBuffer.
Une seule instance d’un stub d’interface peut également traiter plusieurs interfaces, mais uniquement si cet ensemble d’interfaces a une relation d’héritage unique stricte. Cette restriction existe, car le stub peut diriger les appels de méthode vers plusieurs interfaces uniquement lorsqu’il sait à l’avance quelles méthodes sont implémentées sur quelles interfaces.

À différents moments, les proxys et les stubs devront allouer ou libérer de la mémoire. Les proxys d’interface, par exemple, devront allouer de la mémoire pour retourner les paramètres à leur appelant. À cet égard, les proxys d’interface et les stubs d’interface ne sont que des composants COM normaux, dans la mesure où ils doivent utiliser l’allocateur de tâche standard. (Voir CoGetMalloc.)

Configuration requise

Condition requise Valeur
Client minimal pris en charge Windows 2000 Professionnel [applications de bureau | Applications UWP]
Serveur minimal pris en charge Windows 2000 Server [applications de bureau | Applications UWP]
Plateforme cible Windows
En-tête objidl.h (inclure ObjIdl.h)

Voir aussi

IStdMarshalInfo