Conversion d'un membre exporté
Mise à jour : novembre 2007
Cette rubrique décrit comment le processus d'exportation convertit les membres suivants :
Méthodes
Propriétés
Événements
Méthodes
Les clients COM s'attendent à appeler des méthodes, en passant des types de données COM familiers tels que des paramètres et en recevant des HRESULT en retour. Dans l'environnement .NET, cependant, les classes ne souffrent d'aucune restriction de cette nature concernant les types de retour (et n'utilisent pas en fait les HRESULT).
Afin de satisfaire aux normes des deux modèles, chaque méthode d'un type managé possède une signature .NET et une signature COM implicite. Les deux signatures sont généralement très différentes. Les clients .NET interagissent avec le serveur en utilisant la signature .NET, tandis que (et peut-être simultanément) les clients COM interagissent avec le serveur en utilisant la signature COM. Le serveur implémente la méthode avec la signature .NET et le service marshaling du runtime est responsable de la fourniture d'un stub avec la signature COM qui délègue l'appel à la méthode managée.
Conversion de HRESULT
Une signature managée est convertie en signature non managée par le remplacement de la valeur de retour managée par un paramètre [out, retval] et le remplacement du type valeur de retour non managé par un HRESULT. Par exemple, la méthode DoSomething peut avoir les signatures suivantes :
Signature managée
short DoSomething(short i);
Signature non managée
HRESULT DoSomething([in] short i, [out, retval] short *rv);
Notez que la signature COM retourne un HRESULT et possède un paramètre out supplémentaire pour la valeur de retour. La valeur de retour issue de l'implémentation managée retourne toujours en tant que paramètre [out, retval] ajouté à la fin de la signature non managée, alors que la signature non managée retourne toujours un HRESULT. Si la méthode managée a un retour de type void, le runtime omet le paramètre [out, retval]. Par exemple :
Signature managée
void DoSomething(short i);
Signature non managée
HRESULT DoSomething([in] short i);
Dans certaines conditions, il est préférable de laisser la signature managée inchangée. Pour ce faire, vous pouvez utiliser PreserveSigAttribute. Par exemple :
Signature managée
[PreserveSig] short DoSomething(short i);
Signature non managée
short DoSomething ([in] short i);
Le fait d'avoir deux signatures de méthode distinctes facilite l'utilisation de la classe à partir des clients COM et .NET. De plus, les clients COM et .NET peuvent utiliser une classe .NET simultanément. En tant qu'auteur de la classe, vous implémentez la signature managée uniquement. L'utilisation de Tlbexp.exe (ou d'une API équivalente) permet d'exporter automatiquement la signature vers une bibliothèque de types générée pour la classe.
Méthodes surchargées
Bien que .NET prenne en charge les méthodes surchargées, l'interface IDispatch se fie uniquement au nom de la méthode pour la liaison, et non à la signature de méthode complète. Elle n'est donc pas capable de prendre en charge les méthodes surchargées. Cependant, pour fournir l'accès aux méthodes surchargées d'un type, Tlbexp.exe décore les noms des méthodes surchargées avec un nombre ordinal de façon que chaque nom de méthode soit unique.
Illustration de l'utilisation de nombres dans les signatures managées et non managées :
Signature managée
interface INew {
public:
void DoSomething();
void DoSomething(short s);
void DoSomething(short l);
void DoSomething(float f);
void DoSomething(double d);
}
Signature non managée
interface INew {
void DoSomething();
void DoSomething_2(short s);
void DoSomething_3(short l);
void DoSomething_4(float f);
void DoSomething_5(double d);
}
La signature COM pour les méthodes apparaît en tant que méthode DoSomething unique suivie d'une série de méthodes DoSomething_x décorées, où x commence à 2 et s'incrémente pour chaque forme surchargée de la méthode. Notez que certaines des méthodes surchargées peuvent être héritées d'un type de base. Cependant, rien ne garantit que les méthodes surchargées conserveront le même nombre à mesure que la version du type évolue.
Bien que les clients .NET puissent utiliser la forme surchargée de la méthode, les méthodes COM doivent accéder aux méthodes décorées. Les explorateurs d'objets affichent toutes les formes de la méthode décorée avec la signature de la méthode afin de vous permettre de sélectionner la méthode appropriée. Le client à liaison tardive peut également appeler IDispatch::GetIdsOfNames, en passant le nom décoré pour obtenir le DispID de toute méthode surchargée.
Propriétés
Les classes managées et les interfaces peuvent avoir des propriétés. Une propriété managée appartient à un type de données spécifique qui peut avoir une méthode get et une méthode set associées. Ces méthodes sont définies séparément comme n'importe quelle autre méthode. L'exemple de code suivant montre une interface contenant une propriété Height. Les classes qui implémentent l'interface doivent fournir une méthode get et set pour la propriété.
interface IMammal {
IMammal Mother{get;set;}
IMammal Father{get;set;}
int Height{get;set;}
int Weight{get;set;}
}
class Human : IMammal
{
int weight;
int height;
IMammal father;
IMammal mother;
public IMammal Mother { get { return mother; } set { mother = value; } }
public IMammal Father { get { return father; } set { father = value; } }
public int Height { get { return height; } set { height = value; } }
public int Weight { get { return weight; } set { weight = value; } }
}
Pendant l'exportation, Tlbexp.exe convertit la méthode set de la propriété en [propput] et la méthode get en [propget]. Le nom de la propriété dans COM reste identique à celui du nom de la propriété managée. Cette règle présente les exceptions suivantes :
Si le type de propriété, sauf les types valeur, est une classe ou une interface, la méthode set de la propriété devient [propputref], donnant aux paramètres un niveau d'indirection supplémentaire.
Si la propriété n'a ni méthode get ni méthode set, Tlbexp.exe omet la propriété dans la bibliothèque de types.
À l'instar des propriétés, les champs managés sont exportés vers la bibliothèque de types. Le service marshaling du runtime génère automatiquement les méthodes get et set pour tous les champs publics. Pendant le processus de conversion, Tlbexp.exe génère une fonction [propput] (ou [propputref]) et une fonction [propget] pour chaque champ, comme l'illustre la représentation de la bibliothèque de types suivante.
Représentation de la bibliothèque de types
interface IMammal : IDispatch {
[propget] HRESULT Mother([out, retval] IMammal** pRetVal);
[propputref] HRESULT Mother([in] IMammal* pRetVal);
[propget] HRESULT Father([out, retval] IMammal** pRetVal);
[propputref] HRESULT Father([in] IMammal* pRetVal);
[propget] HRESULT Height([out, retval] long* pRetVal);
[propput] HRESULT Height([in] long pRetVal);
[propget] HRESULT Weight([out, retval] long* pRetVal);
[propput] HRESULT Weight([in] long pRetVal);
[propget] HRESULT Age([out, retval] long* pRetVal);
[propput] HRESULT Age([in] long pRetVal);
};
Événements
Si vous n'êtes pas très familiarisé avec le modèle d'événement dans COM Interop, consultez Événements managés et non managés. Les types managés implémentent des événements en utilisant un modèle d'événement reposant sur les délégués. Par exemple, l'interface Class1Events dans l'exemple de code suivant déclenche l'événement Click.
Public Delegate Sub ClickDelegate()
<GuidAttribute("1A585C4D-3371-48dc-AF8A-AFFECC1B0967"), _
InterfaceTypeAttribute(ComInterfaceType.InterfaceIsIDispatch)>
Public Interface Class1Event
Sub Click ()
End Interface
<ComSourceInterfaces("Class1Event, EventSrc")> _
Public Class Class1
Public Event Click As ClickDelegate
End Class
public delegate void Click();
public interface Class1Event
{
void Click();
}
[ComSourceInterfaces("Class1Event, EventSrc")]
public class Class1
{
public event ClickDelegate Click;
}
Pendant l'exportation, Tlbexp.exe marque l'interface d'événement comme la source dans sa coclasse. Comme le montre la représentation de la bibliothèque de types suivante, l'interface ComClass1Events exportée est marquée comme l'interface source.
Représentation de la bibliothèque de types
disinterface Class1Event {
properties:
methods:
[id(0x60020000)]
HRESULT Click();
};
coclass Class1
{
…
[default, source] Class1Event;
};
Voir aussi
Concepts
Conversion d'un assembly exporté
Conversion d'un module exporté
Conversion d'un paramètre exporté
Autres ressources
Résumé de la conversion d'un assembly en bibliothèque de types