Notitie
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen u aan te melden of de directory te wijzigen.
Voor toegang tot deze pagina is autorisatie vereist. U kunt proberen de mappen te wijzigen.
Wanneer een COM-client een .NET-object aanroept, maakt de algemene taalruntime het beheerde object en een COM-aanroepbare wrapper (CCW) voor het object. Com-clients kunnen niet rechtstreeks verwijzen naar een .NET-object en gebruiken de CCW als proxy voor het beheerde object.
De runtime maakt precies één CCW voor een beheerd object, ongeacht het aantal COM-clients dat de services aanvraagt. Zoals in de volgende afbeelding wordt weergegeven, kunnen meerdere COM-clients een verwijzing bevatten naar de CCW die de INew-interface beschikbaar maakt. De CCW bevat op zijn beurt één verwijzing naar het beheerde object dat de interface implementeert en afval wordt verzameld. Com- en .NET-clients kunnen tegelijkertijd aanvragen indienen voor hetzelfde beheerde object.
Aanroepbare COM-wrappers zijn onzichtbaar voor andere klassen die worden uitgevoerd in de .NET-runtime. Hun primaire doel is het aanroepen te marshallen tussen beheerde en onbeheerde code; echter, COM Callable Wrappers (CCW's) beheren ook de objectidentiteit en levensduur van de beheerde objecten die ze omvatten.
Objectidentiteit
De runtime wijst geheugen toe voor het .NET-object vanuit een heap beheerd door garbagecollection, zodat de runtime het object indien nodig in het geheugen kan verplaatsen. Daarentegen wijst de runtime geheugen toe voor de CCW vanuit een niet-verzamelbare heap, zodat COM-clients rechtstreeks naar de wrapper kunnen verwijzen.
Levensduur van object
In tegenstelling tot de .NET-client, wordt bij de CCW referenties geteld op traditionele COM-wijze. Wanneer het aantal verwijzingen op de CCW nul bereikt, geeft de wrapper de verwijzing voor het beheerde object vrij. Een beheerd object zonder resterende verwijzingen wordt tijdens de volgende vuilnisopruimcyclus verwijderd.
COM-interfaces simuleren
CCW maakt alle openbare, com-zichtbare interfaces, gegevenstypen beschikbaar en retourneert waarden aan COM-clients op een manier die consistent is met het afdwingen van interactie op basis van een interface. Voor een COM-client is het aanroepen van methoden voor een .NET-object identiek aan het aanroepen van methoden op een COM-object.
Om deze naadloze aanpak te creëren, produceert de CCW traditionele COM-interfaces, zoals IUnknown en IDispatch. Zoals in de volgende afbeelding wordt weergegeven, maakt de CCW gebruik van een enkele referentie voor het .NET-object dat het omsluit. Zowel de COM-client als het .NET-object communiceren met elkaar via de proxy en stub-constructie van de CCW.
Naast het beschikbaar maken van de interfaces die expliciet zijn geïmplementeerd door een klasse in de beheerde omgeving, levert de .NET-runtime implementaties van de COM-interfaces die namens het object worden vermeld in de volgende tabel. Een .NET-klasse kan het standaardgedrag overschrijven door een eigen implementatie van deze interfaces te bieden. De runtime biedt echter altijd de implementatie voor de IUnknown - en IDispatch-interfaces .
gebruikersinterface | Beschrijving |
---|---|
IDispatch | Biedt een mechanisme voor late binding aan types. |
IErrorInfo- | Biedt een tekstuele beschrijving van de fout, de bron, een Help-bestand, de Help-context en de GUID van de interface die de fout heeft gedefinieerd (altijd GUID_NULL voor .NET-klassen). |
IProvideClassInfo | Hiermee kunnen COM-clients toegang krijgen tot de ITypeInfo-interface die door een beheerde klasse is geïmplementeerd. Retourneert COR_E_NOTSUPPORTED op .NET Core voor typen die niet zijn geïmporteerd uit COM. |
ISupportErrorInfo | Hiermee kan een COM-client bepalen of het beheerde object de IErrorInfo-interface ondersteunt. Zo ja, dan kan de client een aanwijzer ophalen naar het meest recente uitzonderingsobject. Alle beheerde typen ondersteunen de IErrorInfo-interface . |
ITypeInfo (alleen .NET Framework) | Biedt typegegevens voor een klasse die precies hetzelfde is als de typegegevens die door Tlbexp.exeworden geproduceerd. |
IUnknown- | Biedt de standaard implementatie van de IUnknown-interface waarmee de COM-client de levensduur van de CCW beheert en type coercion biedt. |
Een beheerde klasse kan ook de COM-interfaces bieden die in de volgende tabel worden beschreven.
gebruikersinterface | Beschrijving |
---|---|
De klasse-interface (_classname) | Interface, beschikbaar gemaakt door de runtime en niet expliciet gedefinieerd, waarmee alle openbare interfaces, methoden, eigenschappen en velden worden weergegeven die expliciet worden weergegeven op een beheerd object. |
IConnectionPoint en IConnectionPointContainer | Interface voor objecten die gebeurtenissen genereren op basis van delegatie (een interface voor het registreren van abonnees van gebeurtenissen). |
IDispatchEx (alleen .NET Framework) | Interface die wordt geleverd door de runtime als de klasse IExpando implementeert. De IDispatchEx-interface is een uitbreiding van de IDispatch-interface die, in tegenstelling tot IDispatch, opsomming, toevoeging, verwijdering en hoofdlettergevoelige aanroepen van leden mogelijk maakt. |
IEnumVARIANT | Interface voor verzamelingstypeklassen, waarmee de objecten in de verzameling worden opgesomd als de klasse IEnumerable implementeert. |
Inleiding tot de klasse-interface
De klasse-interface, die niet expliciet is gedefinieerd in beheerde code, is een interface waarmee alle openbare methoden, eigenschappen, velden en gebeurtenissen worden weergegeven die expliciet worden weergegeven op het .NET-object. Deze interface kan een dual- of alleen-dispatch interface zijn. De klasse-interface ontvangt de naam van de .NET-klasse zelf, voorafgegaan door een onderstrepingsteken. Voor klasse Zoogdieren is de klasse-interface bijvoorbeeld _Mammal.
Voor afgeleide klassen bevat de klasse-interface ook alle openbare methoden, eigenschappen en velden van de basisklasse. De afgeleide klasse maakt ook een klasse-interface beschikbaar voor elke basisklasse. Als klasse Mammal bijvoorbeeld klasse MammalSuperclass uitbreidt, die zelf System.Object uitbreidt, stelt het .NET-object aan COM-clients drie klasseinterfaces ter beschikking met de namen _Mammal, _MammalSuperclass en _Object.
Denk bijvoorbeeld aan de volgende .NET-klasse:
' Applies the ClassInterfaceAttribute to set the interface to dual.
<ClassInterface(ClassInterfaceType.AutoDual)> _
' Implicitly extends System.Object.
Public Class Mammal
Sub Eat()
Sub Breathe()
Sub Sleep()
End Class
// Applies the ClassInterfaceAttribute to set the interface to dual.
[ClassInterface(ClassInterfaceType.AutoDual)]
// Implicitly extends System.Object.
public class Mammal
{
public void Eat() {}
public void Breathe() {}
public void Sleep() {}
}
De COM-client kan een aanwijzer verkrijgen naar een klasse-interface met de naam _Mammal
. In .NET Framework kunt u het hulpprogramma Type Library Exporter (Tlbexp.exe) gebruiken om een typebibliotheek met de _Mammal
interfacedefinitie te genereren. De typebibliotheekexporteur wordt niet ondersteund op .NET Core. Als de Mammal
klasse een of meer interfaces heeft geïmplementeerd, worden de interfaces weergegeven onder de coklasse.
[odl, uuid(…), hidden, dual, nonextensible, oleautomation]
interface _Mammal : IDispatch
{
[id(0x00000000), propget] HRESULT ToString([out, retval] BSTR*
pRetVal);
[id(0x60020001)] HRESULT Equals([in] VARIANT obj, [out, retval]
VARIANT_BOOL* pRetVal);
[id(0x60020002)] HRESULT GetHashCode([out, retval] short* pRetVal);
[id(0x60020003)] HRESULT GetType([out, retval] _Type** pRetVal);
[id(0x6002000d)] HRESULT Eat();
[id(0x6002000e)] HRESULT Breathe();
[id(0x6002000f)] HRESULT Sleep();
}
[uuid(…)]
coclass Mammal
{
[default] interface _Mammal;
}
Het genereren van de klasse-interface is optioneel. Com-interoperabiliteit genereert standaard een interface voor alleen-verzenden voor elke klasse die u naar een typebibliotheek exporteert. U kunt het automatisch maken van deze interface voorkomen of wijzigen door de ClassInterfaceAttribute interface toe te passen op uw klas. Hoewel de klasse-interface de taak van het blootstellen van beheerde klassen aan COM kan vereenvoudigen, zijn de toepassingen beperkt.
Waarschuwing
Het gebruik van de klassedefinitie, in plaats van expliciet uw eigen interface te definiëren, kan het toekomstige versiebeheer van uw beheerde klasse bemoeilijken. Lees de volgende richtlijnen voordat u de klasse-interface gebruikt.
Definieer een expliciete interface voor COM-clients om te gebruiken in plaats van de klasse-interface te genereren.
Omdat COM-interoperabiliteit automatisch een klasse-interface genereert, kunnen wijzigingen na de versie in uw klasse de indeling van de klasse-interface wijzigen die wordt weergegeven door de algemene taalruntime. Omdat COM-clients doorgaans niet voorbereid zijn om wijzigingen in de lay-out van een interface te verwerken, vallen ze uit als u de lay-out van de klasse wijzigt.
Deze richtlijn versterkt het idee dat interfaces die worden blootgesteld aan COM-clients onveranderbaar moeten blijven. Als u het risico wilt beperken dat COM-clients worden onderbroken door de interface-indeling per ongeluk opnieuw te ordenen, moet u alle wijzigingen in de klasse isoleren van de interface-indeling door expliciet interfaces te definiëren.
Gebruik classInterfaceAttribute om de automatische generatie van de klasse-interface los te koppelen en een expliciete interface voor de klasse te implementeren, zoals in het volgende codefragment wordt weergegeven:
<ClassInterface(ClassInterfaceType.None)>Public Class LoanApp
Implements IExplicit
Sub M() Implements IExplicit.M
…
End Class
[ClassInterface(ClassInterfaceType.None)]
public class LoanApp : IExplicit
{
int IExplicit.M() { return 0; }
}
De waarde ClassInterfaceType.None voorkomt dat de klasse-interface wordt gegenereerd wanneer de klassemetagegevens worden geëxporteerd naar een typebibliotheek. In het voorgaande voorbeeld hebben COM-clients alleen toegang tot de LoanApp
klasse via de IExplicit
interface.
Vermijd het cachen van identificatiecodes (DispIds)
Het gebruik van de class-interface is een acceptabele optie voor scriptclients, Visual Basic 6.0-clients van Microsoft, of een laat gebonden client die de DispIds van interfaceleden niet in de cache opslaat. DispIds identificeren interfaceleden om late binding in te schakelen.
Voor de klasse-interface is het genereren van DispIds gebaseerd op de positie van het lid in de interface. Als u de volgorde van het lid wijzigt en de klasse exporteert naar een typebibliotheek, wijzigt u de DispIds die zijn gegenereerd in de klasse-interface.
Gebruik de ClassInterfaceAttribute met de waarde ClassInterfaceType.AutoDispatch om te voorkomen dat laatgebonden COM-clients worden onderbroken bij het gebruiken van de klasse-interface. Deze waarde implementeert een alleen-dispatch interface, maar laat de interfacebeschrijving uit de typebibliotheek weg. Zonder een interfacebeschrijving kunnen clients dispIds niet opslaan tijdens het compileren. Hoewel dit het standaardinterfacetype voor de klasse-interface is, kunt u de kenmerkwaarde expliciet toepassen.
<ClassInterface(ClassInterfaceType.AutoDispatch)> Public Class LoanApp
Implements IAnother
Sub M() Implements IAnother.M
…
End Class
[ClassInterface(ClassInterfaceType.AutoDispatch)]
public class LoanApp
{
public int M() { return 0; }
}
Com-clients kunnen IDispatch.GetIdsOfNames aanroepen om de DispId van een interfacelid tijdens runtime op te halen. Als u een methode op de interface wilt aanroepen, geeft u de geretourneerde DispId door als een argument aan IDispatch.Invoke.
Beperk het gebruik van de optie voor dubbele interface voor de klasse-interface.
Dubbele interfaces maken vroege en late binding mogelijk voor interfaceleden door COM-clients. Tijdens het ontwerpen en testen kan het handig zijn om de klasse-interface in te stellen op dual. Voor een beheerde klasse (en de basisklassen) die nooit worden gewijzigd, is deze optie ook acceptabel. Vermijd in alle andere gevallen dat u de klasse-interface instelt op dual.
Een automatisch gegenereerde dubbele interface kan in zeldzame gevallen geschikt zijn, maar meestal veroorzaakt het complicaties die verband houden met versies. COM-clients die de klasse-interface van een afgeleide klasse gebruiken, kunnen bijvoorbeeld eenvoudig breken met wijzigingen in de basisklasse. Wanneer een derde partij de basisklasse levert, valt de indeling van de klasse-interface buiten uw beheer. In tegenstelling tot een interface voor alleen verzenden biedt een dual-interface (ClassInterfaceType.AutoDual) een beschrijving van de klasse-interface in de geëxporteerde typebibliotheek. Een dergelijke beschrijving stimuleert laat-gebonden clients om DispIds tijdens de compilatietijd in de cache op te slaan.
Zorg ervoor dat alle COM-gebeurtenismeldingen laat gebonden zijn.
Com-typegegevens worden standaard rechtstreeks ingesloten in beheerde assembly's, waardoor primaire interop-assembly's (PIA's) niet meer nodig zijn. Een van de beperkingen van ingesloten typegegevens is echter dat het geen ondersteuning biedt voor de levering van COM-gebeurtenismeldingen door vroegtijdige vtable-aanroepen, maar alleen ondersteuning biedt voor late aanroepen IDispatch::Invoke
.
Als uw applicatie vroege gebonden aanroepen naar COM-gebeurtenisinterfacemethoden vereist, kunt u de eigenschap Interop-typen insluiten in Visual Studio op true
instellen, of het volgende element in uw projectbestand opnemen:
<EmbedInteropTypes>True</EmbedInteropTypes>