Partager via


QueryInterface : navigation dans un objet

Une fois que vous avez un pointeur initial vers une interface sur un objet, COM dispose d’un mécanisme très simple pour déterminer si l’objet prend en charge une autre interface spécifique et, le cas échéant, pour obtenir un pointeur vers celle-ci. (Pour plus d’informations sur l’obtention d’un pointeur initial vers une interface sur un objet, consultez Obtention d’un pointeur vers un objet.) Ce mécanisme est la méthode QueryInterface de l’interface IUnknown . Si l’objet prend en charge l’interface demandée, la méthode doit retourner un pointeur vers cette interface. Cela permet à un objet de naviguer librement à travers les interfaces prises en charge par un objet. QueryInterface sépare la demande « Prenez-vous en charge un contrat donné ? » de l’utilisation haute performance de ce contrat une fois les négociations réussies.

Lorsqu’un client obtient initialement l’accès à un objet, ce client reçoit au minimum un pointeur d’interface IUnknown (l’interface la plus fondamentale) par le biais duquel il peut contrôler la durée de vie de l’objet ( en indiquant à l’objet quand il est effectué à l’aide de l’objet ) et appeler QueryInterface. Le client est programmé pour demander à chaque objet qu’il gère d’effectuer certaines opérations, mais l’interface IUnknown n’a aucune fonction pour ces opérations. Au lieu de cela, ces opérations sont exprimées via d’autres interfaces. Le client est donc programmé pour négocier avec des objets pour ces interfaces. Plus précisément, le client appelleRa QueryInterface pour demander à un objet une interface par le biais de laquelle le client peut appeler les opérations souhaitées.

Étant donné que l’objet implémente QueryInterface, il peut accepter ou rejeter la demande. Si l’objet accepte la requête du client, QueryInterface retourne un nouveau pointeur vers l’interface demandée vers le client. Par le biais de ce pointeur d’interface, le client a accès aux méthodes de cette interface. Si, en revanche, l’objet rejette la requête du client, QueryInterface retourne un pointeur null (une erreur) et le client n’a pas de pointeur par lequel appeler les fonctions souhaitées. Dans ce cas, le client doit gérer correctement cette possibilité. Par exemple, supposons qu’un client dispose d’un pointeur vers l’interface A sur un objet et demande les interfaces B et C. Supposons également que l’objet prend en charge l’interface B, mais pas l’interface C. Le résultat est que l’objet retourne un pointeur vers B et signale que C n’est pas pris en charge.

Un point clé est que lorsqu’un objet rejette un appel à QueryInterface, il est impossible pour le client de demander à l’objet d’effectuer les opérations exprimées via l’interface demandée. Un client doit avoir un pointeur d’interface pour appeler des méthodes dans cette interface. Si l’objet refuse de fournir le pointeur demandé, le client doit être prêt à s’en passer, soit en ne faisant pas ce qu’il avait prévu de faire avec cet objet, soit en tentant de se replier sur une autre interface, peut-être moins puissante. Cette fonctionnalité de la fonctionnalité COM fonctionne bien par rapport à d’autres systèmes orientés objet dans lesquels vous ne pouvez pas savoir si une fonction fonctionnera tant que vous n’appelez pas cette fonction, et même dans ce cas, la gestion de l’échec est incertaine. QueryInterface fournit un moyen fiable et cohérent de savoir si un objet prend en charge une interface avant de tenter d’appeler ses méthodes.

La méthode QueryInterface fournit également un moyen robuste et fiable pour un objet d’indiquer qu’il ne prend pas en charge un contrat donné. Autrement dit, si, lors d’un appel à QueryInterface , on demande à un objet « ancien » s’il prend en charge une « nouvelle » interface (une, par exemple, qui a été inventée après l’expédition de l’ancien objet), l’ancien objet répond de manière fiable, sans provoquer de blocage, « non ». La technologie qui prend en charge cela est l’algorithme par lequel les ID sont alloués. Bien que cela puisse sembler un petit point, il est extrêmement important pour l’architecture globale du système, et la possibilité de se renseigner sur les éléments hérités sur les nouvelles fonctionnalités est, étonnamment, une fonctionnalité qui n’est pas présente dans la plupart des autres architectures d’objets.

Utilisation et implémentation d’IUnknown