COM Callable WrapperCOM Callable Wrapper

Quando un client COM chiama un oggetto .NET, Common Language Runtime crea l'oggetto gestito e un COM Callable Wrapper (CCW) per l'oggetto.When a COM client calls a .NET object, the common language runtime creates the managed object and a COM callable wrapper (CCW) for the object. Incapaci di fare riferimento diretto a un oggetto .NET, i client COM usano il CCW come un proxy per l'oggetto gestito.Unable to reference a .NET object directly, COM clients use the CCW as a proxy for the managed object.

Il runtime crea esattamente un CCW per ciascun oggetto gestito, indipendentemente dal numero di client COM che ne richiedono i servizi.The runtime creates exactly one CCW for a managed object, regardless of the number of COM clients requesting its services. Come mostrato nella figura seguente, più client COM possono mantenere un riferimento allo stesso CCW che espone l'interfaccia INew.As the following illustration shows, multiple COM clients can hold a reference to the CCW that exposes the INew interface. Il CCW mantiene a sua volta un solo riferimento all'oggetto gestito che implementa l'interfaccia ed è sottoposto alla procedura di Garbage Collection.The CCW, in turn, holds a single reference to the managed object that implements the interface and is garbage collected. Sia i client COM che i client .NET possono effettuare contemporaneamente richieste sullo stesso oggetto gestito.Both COM and .NET clients can make requests on the same managed object simultaneously.

Più client COM contenenti un riferimento al CCW che espone INew.

Gli oggetti COM Callable Wrapper sono invisibili alle altre classi in esecuzione nel runtime .NET Framework.COM callable wrappers are invisible to other classes running within the .NET runtime. Il loro scopo principale è effettuare il marshalling delle chiamate tra il codice gestito e quello non gestito. Tuttavia, i CCW gestiscono anche l'identità e la durata degli oggetti gestiti di cui eseguono il wrapping.Their primary purpose is to marshal calls between managed and unmanaged code; however, CCWs also manage the object identity and object lifetime of the managed objects they wrap.

Identità dell'oggettoObject Identity

Il runtime alloca per l'oggetto .NET memoria attinta dall'heap sottoposto a Garbage Collection. In tal modo si consente al runtime di spostare l'oggetto in memoria a seconda delle esigenze.The runtime allocates memory for the .NET object from its garbage-collected heap, which enables the runtime to move the object around in memory as necessary. Al contrario, il runtime alloca per il CCW memoria attinta da un heap non soggetto a Garbage Collection, consentendo così ai client COM di fare riferimento al wrapper direttamente.In contrast, the runtime allocates memory for the CCW from a noncollected heap, making it possible for COM clients to reference the wrapper directly.

Durata dell'oggettoObject Lifetime

Diversamente dal client .NET di cui esegue il wrapping, il CCW è destinatario di riferimenti conteggiati in modo tradizionale (COM).Unlike the .NET client it wraps, the CCW is reference-counted in traditional COM fashion. Quando il conteggio dei riferimenti al CCW raggiunge lo zero, il wrapper rilascia il proprio riferimento all'oggetto gestito.When the reference count on the CCW reaches zero, the wrapper releases its reference on the managed object. Gli oggetti gestiti senza più riferimenti vengono raccolti durante la successiva procedura di Garbage Collection.A managed object with no remaining references is collected during the next garbage-collection cycle.

Simulazione di interfacce COMSimulating COM interfaces

CCW espone ai client COM tutti i tipi di dati, i valori restituiti e le interfacce pubbliche visibili a COM in modo conforme al meccanismo di interazione COM basato sulle interfacce.CCW exposes all public, COM-visible interfaces, data types, and return values to COM clients in a manner that is consistent with COM's enforcement of interface-based interaction. Per un client COM, richiamare i metodi in un oggetto .NET equivale a richiamarli in un oggetto COM.For a COM client, invoking methods on a .NET object is identical to invoking methods on a COM object.

Per assicurare questo approccio naturale, il CCW crea interfacce COM tradizionali quali IUnknown e IDispatch.To create this seamless approach, the CCW manufactures traditional COM interfaces, such as IUnknown and IDispatch. Come mostrato nella figura seguente, il CCW mantiene un solo riferimento all'oggetto .NET di cui esegue il wrapping.As the following illustration shows, the CCW maintains a single reference on the .NET object that it wraps. Il client COM e l'oggetto .NET interagiscono tramite il proxy e lo stub del CCW.Both the COM client and the .NET object interact with each other through the proxy and stub construction of the CCW.

Diagramma che mostra come CCW crea interfacce COM.

Oltre a esporre le interfacce che sono esplicitamente implementate da una classe dell'ambiente gestito, il runtime .NET fornisce le implementazioni delle interfacce COM elencate nella tabella seguente per conto dell'oggetto.In addition to exposing the interfaces that are explicitly implemented by a class in the managed environment, the .NET runtime supplies implementations of the COM interfaces listed in the following table on behalf of the object. Una classe .NET può eseguire l'override del comportamento predefinito fornendo la propria implementazione di queste interfacce.A .NET class can override the default behavior by providing its own implementation of these interfaces. Il runtime, tuttavia, fornisce sempre l'implementazione delle interfacce IUnknown e IDispatch.However, the runtime always provides the implementation for the IUnknown and IDispatch interfaces.

InterfacciaInterface DescrizioneDescription
IdispatchIDispatch Fornisce un meccanismo per l'associazione tardiva al tipo.Provides a mechanism for late binding to type.
IErrorInfoIErrorInfo Fornisce una descrizione testuale dell'errore, la relativa origine, un file della Guida, un contesto della Guida e il GUID dell'interfaccia che ha definito l'errore (sempre GUID_NULL per le classi .NET).Provides a textual description of the error, its source, a Help file, Help context, and the GUID of the interface that defined the error (always GUID_NULL for .NET classes).
IProvideClassInfoIProvideClassInfo Consente ai client COM di ottenere l'accesso all'interfaccia ITypeInfo implementata da una classe gestita.Enables COM clients to gain access to the ITypeInfo interface implemented by a managed class. Restituisce COR_E_NOTSUPPORTED in .NET Core per i tipi non importati da COM.Returns COR_E_NOTSUPPORTED on .NET Core for types not imported from COM.
ISupportErrorInfoISupportErrorInfo Consente a un client COM di determinare se l'oggetto gestito supporta l'interfaccia IErrorInfo.Enables a COM client to determine whether the managed object supports the IErrorInfo interface. Se sì, consente al client di ottenere un puntatore all'ultimo oggetto eccezione.If so, enables the client to obtain a pointer to the latest exception object. Tutti i tipi gestiti supportano l'interfaccia IErrorInfo.All managed types support the IErrorInfo interface.
ITypeInfo (solo .NET Framework)ITypeInfo (.NET Framework Only) Fornisce per le classi le stesse informazioni sul tipo che fornisce Tlbexp.exe.Provides type information for a class that is exactly the same as the type information produced by Tlbexp.exe.
IunknownIUnknown Fornisce l'implementazione standard dell'interfaccia IUnknown con cui il client COM gestisce la durata del CCW e provvede alla coercizione dei tipi.Provides the standard implementation of the IUnknown interface with which the COM client manages the lifetime of the CCW and provides type coercion.

Le classi gestite possono anche fornire le interfacce COM descritte nella tabella che segue.A managed class can also provide the COM interfaces described in the following table.

InterfacciaInterface DescrizioneDescription
Interfaccia_di classe (classname)The (_classname) class interface Interfaccia, esposta dal runtime e non definita esplicitamente, che espone tutte le interfacce, i metodi, le proprietà e i campi pubblici esplicitamente esposti su un oggetto gestito.Interface, exposed by the runtime and not explicitly defined, that exposes all public interfaces, methods, properties, and fields that are explicitly exposed on a managed object.
IConnectionPoint e IConnectionPointContainerIConnectionPoint and IConnectionPointContainer Interfaccia per oggetti che originano eventi basati su delegati (un'interfaccia per la registrazione di sottoscrittori di eventi).Interface for objects that source delegate-based events (an interface for registering event subscribers).
IDispatchEx (solo .NET Framework)IDispatchEx (.NET Framework Only) Interfaccia fornita dal runtime se la classe implementa IExpando.Interface supplied by the runtime if the class implements IExpando. L'interfaccia IDispatchEx è un'estensione dell'interfaccia IDispatch che, diversamente da IDispatch, consente l'enumerazione, l'aggiunta, l'eliminazione e la chiamata dei membri con distinzione tra maiuscole e minuscole.The IDispatchEx interface is an extension of the IDispatch interface that, unlike IDispatch, enables enumeration, addition, deletion, and case-sensitive calling of members.
IEnumVARIANTIEnumVARIANT Interfaccia per classi Collection che enumera gli oggetti della raccolta se la classe implementa IEnumerable.Interface for collection-type classes, which enumerates the objects in the collection if the class implements IEnumerable.

Introduzione all'interfaccia della classeIntroducing the class interface

L'interfaccia della classe, che non è definita esplicitamente nel codice gestito, è un'interfaccia che espone tutte le proprietà, i campi, gli eventi e i metodi pubblici esplicitamente esposti dall'oggetto .NET.The class interface, which is not explicitly defined in managed code, is an interface that exposes all public methods, properties, fields, and events that are explicitly exposed on the .NET object. Tale interfaccia può essere duale o solo dispatch.This interface can be a dual or dispatch-only interface. L'interfaccia della classe riceve il nome dalla classe .NET stessa, preceduto da un carattere di sottolineatura.The class interface receives the name of the .NET class itself, preceded by an underscore. Per la classe Mammal, ad esempio, l'interfaccia della classe sarà _Mammal.For example, for class Mammal, the class interface is _Mammal.

Per le classi derivate, l'interfaccia della classe espone anche tutti i metodi, le proprietà e i campi pubblici della classe base.For derived classes, the class interface also exposes all public methods, properties, and fields of the base class. La classe derivata espone anche un'interfaccia della classe per ciascuna classe base.The derived class also exposes a class interface for each base class. Ad esempio, se la classe Mammal estende la classe MammalSuperclass, che a sua volta estende la classe System.Object, l'oggetto .NET espone ai client COM tre interfacce della classe denominate _Mammal, _MammalSuperclass e _Object.For example, if class Mammal extends class MammalSuperclass, which itself extends System.Object, the .NET object exposes to COM clients three class interfaces named _Mammal, _MammalSuperclass, and _Object.

Si consideri ad esempio la classe .NET seguente:For example, consider the following .NET class:

' 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() {}
}

Il client COM può ottenere un puntatore a un'interfaccia di classe denominata _Mammal.The COM client can obtain a pointer to a class interface named _Mammal. In .NET Framework è possibile usare l'utilità di esportazione della libreria dei tipi (Tlbexp.exe) per generare una libreria dei tipi contenente la definizione dell'interfaccia _Mammal.On .NET Framework, you can use the Type Library Exporter (Tlbexp.exe) tool to generate a type library containing the _Mammal interface definition. L'utilità di esportazione della libreria dei tipi non è supportata in .NET Core.The Type Library Exporter is not supported on .NET Core. Se la classe Mammal implementa una o più interfacce, queste appariranno sotto la coclasse.If the Mammal class implemented one or more interfaces, the interfaces would appear under the coclass.

[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;
}

La generazione dell'interfaccia della classe è facoltativa.Generating the class interface is optional. Per impostazione predefinita, l'interoperabilità COM genera un'interfaccia solo dispatch per ogni classe esportata in una libreria dei tipi.By default, COM interop generates a dispatch-only interface for each class you export to a type library. È possibile modificare o impedire la creazione automatica di questa interfaccia applicando alla classe l'oggetto ClassInterfaceAttribute.You can prevent or modify the automatic creation of this interface by applying the ClassInterfaceAttribute to your class. Benché l'interfaccia della classe possa semplificare l'esposizione di classi gestite a COM, gli usi che è possibile farne sono limitati.Although the class interface can ease the task of exposing managed classes to COM, its uses are limited.

Attenzione

Usare l'interfaccia della classe, anziché definire esplicitamente un'interfaccia personalizzata, può complicare il futuro controllo delle versioni della classe gestita.Using the class interface, instead of explicitly defining your own, can complicate the future versioning of your managed class. Prima di usare l'interfaccia della classe, leggere le indicazioni riportate di seguito.Please read the following guidelines before using the class interface.

Definire un'interfaccia esplicita per i client COM anziché generare l'interfaccia della classe.Define an explicit interface for COM clients to use rather than generating the class interface.

Poiché l'interoperabilità COM genera l'interfaccia della classe automaticamente, le modifiche apportate alla classe dopo l'emissione di una versione possono alterare il layout dell'interfaccia della classe esposta da Common Language Runtime.Because COM interop generates a class interface automatically, post-version changes to your class can alter the layout of the class interface exposed by the common language runtime. Se si cambia il layout dei membri della classe, la maggior parte dei client COM, che solitamente non è in grado di gestire le modifiche al layout di un'interfaccia, cesserà di funzionare.Since COM clients are typically unprepared to handle changes in the layout of an interface, they break if you change the member layout of the class.

Queste indicazioni ribadiscono il concetto che le interfacce esposte ai client COM devono restare immodificabili.This guideline reinforces the notion that interfaces exposed to COM clients must remain unchangeable. Per ridurre il rischio di compromettere il funzionamento dei client COM riordinando inavvertitamente il layout dell'interfaccia, separare tutte le modifiche alla classe dal layout dell'interfaccia definendo esplicitamente le interfacce.To reduce the risk of breaking COM clients by inadvertently reordering the interface layout, isolate all changes to the class from the interface layout by explicitly defining interfaces.

Usare ClassInterfaceAttribute per disattivare la generazione automatica dell'interfaccia della classe e implementare un'interfaccia esplicita per la classe, come illustrato nel frammento di codice seguente:Use the ClassInterfaceAttribute to disengage the automatic generation of the class interface and implement an explicit interface for the class, as the following code fragment shows:

<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; }
}

Il valore ClassInterfaceType.None impedisce la generazione dell'interfaccia della classe quando i metadati della classe vengono esportati in una libreria dei tipi.The ClassInterfaceType.None value prevents the class interface from being generated when the class metadata is exported to a type library. Nel precedente esempio, i client COM possono accedere alla classe LoanApp solo tramite l'interfaccia IExplicit.In the preceding example, COM clients can access the LoanApp class only through the IExplicit interface.

Evitare la memorizzazione nella cache degli identificatori dispatch (DispId)Avoid caching dispatch identifiers (DispIds)

L'uso dell'interfaccia della classe è ammissibile per i client basati su script, i client Microsoft Visual Basic 6.0 o qualsiasi client ad associazione tardiva che non inserisce nella cache i DispId dei membri di interfaccia.Using the class interface is an acceptable option for scripted clients, Microsoft Visual Basic 6.0 clients, or any late-bound client that does not cache the DispIds of interface members. I DispId identificano i membri di interfaccia per abilitare l'associazione tardiva.DispIds identify interface members to enable late binding.

Per l'interfaccia della classe, la generazione dei DispId è basata sulla posizione dei membri nell'interfaccia.For the class interface, generation of DispIds is based on the position of the member in the interface. Se si cambia l'ordine dei membri e si esporta la classe in una libreria dei tipi, si altereranno i DispId generati nell'interfaccia della classe.If you change the order of the member and export the class to a type library, you will alter the DispIds generated in the class interface.

Per evitare di compromettere il funzionamento dei client COM ad associazione tardiva quando si usa questa interfaccia, applicare ClassInterfaceAttribute con il valore ClassInterfaceType.AutoDispatch.To avoid breaking late-bound COM clients when using the class interface, apply the ClassInterfaceAttribute with the ClassInterfaceType.AutoDispatch value. Tale valore implementa un'interfaccia della classe solo dispatch, ma omette la descrizione dell'interfaccia dalla libreria dei tipi.This value implements a dispatch-only class interface, but omits the interface description from the type library. Senza una descrizione dell'interfaccia, i client non potranno inserire i DispId nella cache in fase di compilazione.Without an interface description, clients are unable to cache DispIds at compile time. Benché questo sia il tipo di interfaccia predefinito per l'interfaccia della classe, è possibile applicare il valore dell'attributo in modo esplicito.Although this is the default interface type for the class interface, you can apply the attribute value explicitly.

<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; }
}

Per ottenere il DispId di un membro di interfaccia in fase di esecuzione, i client COM possono chiamare IDispatch.GetIdsOfNames.To get the DispId of an interface member at run time, COM clients can call IDispatch.GetIdsOfNames. Per richiamare un metodo sull'interfaccia, passare il DispId restituito come argomento a IDispatch.Invoke.To invoke a method on the interface, pass the returned DispId as an argument to IDispatch.Invoke.

Limitare l'uso dell'opzione di interfaccia duale per l'interfaccia della classe.Restrict using the dual interface option for the class interface.

Le interfacce duali permettono ai client COM di effettuare sia l'associazione anticipata che l'associazione tardiva ai membri di interfaccia.Dual interfaces enable early and late binding to interface members by COM clients. In fase di progettazione e durante il test, può risultare utile impostare l'interfaccia della classe su duale.At design time and during testing, you might find it useful to set the class interface to dual. Per una classe gestita (e le relative classi base) che non verrà mai modificata, questa opzione è accettabile.For a managed class (and its base classes) that will never be modified, this option is also acceptable. In tutti gli altri casi è preferibile evitare di impostare l'interfaccia della classe su duale.In all other cases, avoid setting the class interface to dual.

Un'interfaccia duale generata automaticamente può essere appropriata in alcuni casi meno comuni. Nella maggior parte dei casi creerà invece complicazioni in relazione alla gestione delle versioni.An automatically generated dual interface might be appropriate in rare cases; however, more often it creates version-related complexity. Ad esempio, il funzionamento dei client COM che usano l'interfaccia della classe di una classe derivata verrà facilmente compromesso in conseguenza di modifiche della classe base.For example, COM clients using the class interface of a derived class can easily break with changes to the base class. Quando la classe base è fornita da terzi, il layout dell'interfaccia della classe sarà fuori dal proprio controllo.When a third party provides the base class, the layout of the class interface is out of your control. Diversamente da un'interfaccia solo dispatch, un'interfaccia duale (ClassInterfaceType.AutoDual) fornisce anche una descrizione dell'interfaccia della classe nella libreria dei tipi esportata.Further, unlike a dispatch-only interface, a dual interface (ClassInterfaceType.AutoDual) provides a description of the class interface in the exported type library. Tale descrizione invita i client ad associazione tardiva a memorizzare nella cache i DispId in fase di compilazione.Such a description encourages late-bound clients to cache DispIds at compile time.

Verificare che tutte le notifiche degli eventi COM siano ad associazione tardiva.Ensure that all COM event notifications are late-bound.

Per impostazione predefinita, le informazioni sui tipi COM sono incorporate direttamente negli assembly gestiti, eliminando così la necessità di assembly di interoperabilità primari.By default, COM type information is embedded directly into managed assemblies, which eliminates the need for primary interop assemblies (PIAs). Tuttavia, uno dei limiti delle informazioni sui tipi incorporate è dato dal fatto che non è supportato il recapito di notifiche di eventi COM tramite chiamate vtable ad associazione anticipata, ma sono supportate solo le chiamate IDispatch::Invoke ad associazione tardiva.However, one of the limitations of embedded type information is that it does not support delivery of COM event notifications by early-bound vtable calls, but only supports late-bound IDispatch::Invoke calls.

Se l'applicazione richiede chiamate ad associazione anticipata ai metodi dell'interfaccia di eventi COM, è possibile impostare la proprietà Incorpora tipi di interoperabilità di Visual Studio su true o includere l'elemento seguente nel file di progetto:If your application requires early-bound calls to COM event interface methods, you can set the Embed Interop Types property in Visual Studio to true, or include the following element in your project file:

<EmbedInteropTypes>True</EmbedInteropTypes>

Vedere ancheSee also