Contenedor CCWCOM Callable Wrapper

Cuando un cliente COM llama a un objeto .NET, Common Language Runtime crea el objeto administrado y un contenedor CCW (COM callable wrapper) para el objeto.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. Como no pueden hacer referencia a los objetos .NET directamente, los clientes COM usan el CCW como un proxy del objeto administrado.Unable to reference a .NET object directly, COM clients use the CCW as a proxy for the managed object.

El motor en tiempo de ejecución crea exactamente un CCW para un objeto administrado, independientemente del número de clientes COM que soliciten sus servicios.The runtime creates exactly one CCW for a managed object, regardless of the number of COM clients requesting its services. Como se muestra en la siguiente ilustración, varios clientes COM pueden guardar una referencia al CCW que expone la interfaz INew.As the following illustration shows, multiple COM clients can hold a reference to the CCW that exposes the INew interface. A su vez, el CCW contiene una única referencia al objeto administrado que implementa la interfaz y se recolectan los elementos no utilizados.The CCW, in turn, holds a single reference to the managed object that implements the interface and is garbage collected. Los clientes COM y .NET pueden hacer solicitudes en un objeto administrado simultáneamente.Both COM and .NET clients can make requests on the same managed object simultaneously.

Varios clientes COM que guardan una referencia al CCW que expone la interfaz INew.

Los contenedores CCW no están visibles para otras clases en ejecución en .NET Framework.COM callable wrappers are invisible to other classes running within the .NET Framework. Su objetivo principal es serializar llamadas entre código administrado y no administrado; sin embargo, los CCW también pueden administrar la identidad y la duración de los objetos administrados que contienen.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.

Identidad de objetosObject Identity

El motor en tiempo de ejecución asigna memoria para el objeto .NET desde su montón tras haber eliminado la memoria no utilizada, lo que permite que el motor en tiempo de ejecución mueva el objeto en la memoria como sea necesario.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. En contraposición, el motor en tiempo de ejecución asigna al CCW memoria de un montón en el que no se ha eliminado la memoria no utilizada, con lo que los clientes COM pueden hacer referencia al contenedor directamente.In contrast, the runtime allocates memory for the CCW from a noncollected heap, making it possible for COM clients to reference the wrapper directly.

Duración de objetosObject Lifetime

A diferencia del cliente .NET que contiene, las referencias del CCW se cuentan siguiendo la manera habitual de COM.Unlike the .NET client it wraps, the CCW is reference-counted in traditional COM fashion. Cuando el número de referencias del CCW llega a cero, el contenedor libera su referencia en el objeto administrado.When the reference count on the CCW reaches zero, the wrapper releases its reference on the managed object. Los objetos administrados a los que ya no quedan referencias se recogen en el siguiente ciclo de recolección de memoria no utilizada.A managed object with no remaining references is collected during the next garbage-collection cycle.

Simulación de interfaces COMSimulating COM interfaces

CCW expone todos los tipos de datos, interfaces visibles para COM públicas y valores devueltos a los clientes COM de manera coherente con los requisitos de COM de interacción basada en la interfaz.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. Para un cliente COM, la invocación de métodos en un objeto .NET Framework es idéntica a la invocación de métodos en un objeto COM.For a COM client, invoking methods on a .NET Framework object is identical to invoking methods on a COM object.

Para crear este enfoque uniforme, el CCW genera interfaces COM tradicionales como IUnknown e IDispatch.To create this seamless approach, the CCW manufactures traditional COM interfaces, such as IUnknown and IDispatch. Como se muestra en la siguiente ilustración, el CCW mantiene una sola referencia en el objeto .NET que encapsula.As the following illustration shows, the CCW maintains a single reference on the .NET object that it wraps. El cliente COM y el objeto .NET interactúan entre sí a través de la construcción de proxy y código auxiliar del CCW.Both the COM client and the .NET object interact with each other through the proxy and stub construction of the CCW.

Diagrama que muestra cómo CCW crea interfaces de COM.

Además de exponer las interfaces implementadas explícitamente por una clase en el entorno administrado, .NET Framework proporciona implementaciones de las interfaces COM enumeradas en la tabla siguiente en nombre del objeto.In addition to exposing the interfaces that are explicitly implemented by a class in the managed environment, the .NET Framework supplies implementations of the COM interfaces listed in the following table on behalf of the object. Una clase .NET puede proporcionar su propia implementación de estas interfaces para invalidar el comportamiento predeterminado.A .NET class can override the default behavior by providing its own implementation of these interfaces. El tiempo de ejecución proporciona siempre la implementación de las interfaces IUnknown e IDispatch.However, the runtime always provides the implementation for the IUnknown and IDispatch interfaces.

InterfazInterface DescripciónDescription
IDispatchIDispatch Proporciona un mecanismo para el enlace en tiempo de ejecución al tipo.Provides a mechanism for late binding to type.
IErrorInfoIErrorInfo Proporciona una descripción textual del error, su origen, un archivo de ayuda, contexto de ayuda y el GUID de la interfaz que definió el error (siempre GUID_NULL para las clases. 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 Permite que los clientes COM tengan acceso a la interfaz ITypeInfo implementada por una clase administrada.Enables COM clients to gain access to the ITypeInfo interface implemented by a managed class.
ISupportErrorInfoISupportErrorInfo Permite a un cliente COM determinar si el objeto administrado es compatible con la interfaz IErrorInfo.Enables a COM client to determine whether the managed object supports the IErrorInfo interface. Si es así, permite al cliente obtener un puntero al objeto de excepción más reciente.If so, enables the client to obtain a pointer to the latest exception object. Todos los tipos administrados son compatibles con la interfaz IErrorInfo.All managed types support the IErrorInfo interface.
ITypeInfoITypeInfo Proporciona información de tipos para una clase que es exactamente igual que la información de tipos producida Tlbexp.exe.Provides type information for a class that is exactly the same as the type information produced by Tlbexp.exe.
IUnknownIUnknown Proporciona la implementación estándar de la interfaz IUnknown con la que el cliente COM administra la duración del CCW y proporciona coerción de tipos.Provides the standard implementation of the IUnknown interface with which the COM client manages the lifetime of the CCW and provides type coercion.

Una clase administrada también puede proporcionar las interfaces COM que se describe en la tabla siguiente.A managed class can also provide the COM interfaces described in the following table.

InterfazInterface DescripciónDescription
Interfaz de clase (_nombreDeClase)The (_classname) class interface Interfaz, expuesta por el runtime y no definida explícitamente, que expone todas las interfaces públicas, métodos, propiedades y campos que se exponen explícitamente en un objeto administrado.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 Interfaz para objetos que son origen de eventos basados en delegados (interfaz para registrar suscriptores de eventos).Interface for objects that source delegate-based events (an interface for registering event subscribers).
IDispatchExIDispatchEx Interfaz proporcionada por el tiempo de ejecución si la clase implementa IExpando.Interface supplied by the runtime if the class implements IExpando. La interfaz IDispatchEx es una extensión de la interfaz IDispatch que, a diferencia de IDispatch, permite enumerar, agregar, eliminar y llamar a miembros con distinción de mayúsculas y minúsculas.The IDispatchEx interface is an extension of the IDispatch interface that, unlike IDispatch, enables enumeration, addition, deletion, and case-sensitive calling of members.
IEnumVARIANTIEnumVARIANT Interfaz para clases de tipo de colección que enumera los objetos de la colección si la clase implementa IEnumerable.Interface for collection-type classes, which enumerates the objects in the collection if the class implements IEnumerable.

Presentar la interfaz de claseIntroducing the class interface

La interfaz de clase, que no se define explícitamente en el código administrado, es una interfaz que expone todos los métodos, propiedades, campos y eventos públicos que se exponen explícitamente en el objeto .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. Puede ser una interfaz dual o sólo de envío.This interface can be a dual or dispatch-only interface. La interfaz de clase recibe el nombre de la propia clase .NET, precedida por un carácter de subrayado.The class interface receives the name of the .NET class itself, preceded by an underscore. Por ejemplo, para la clase Mammal, la interfaz de clase es _Mammal.For example, for class Mammal, the class interface is _Mammal.

Para las clases derivadas, la interfaz de clase también expone todos los métodos, propiedades y campos públicos de la clase base.For derived classes, the class interface also exposes all public methods, properties, and fields of the base class. La clase derivada también expone una interfaz de clase para cada clase base.The derived class also exposes a class interface for each base class. Por ejemplo, si la clase Mammal extiende la clase MammalSuperclass, que a su vez extiende System.Object, el objeto .NET expone a los clientes COM tres interfaces de clase llamadas _Mammal, _MammalSuperclass y _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.

Por ejemplo, observe la siguiente clase .NET: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() {}
}

El cliente COM puede obtener un puntero a una interfaz de clase denominada _Mammal, que se describe en la biblioteca de tipos que genera la herramienta Exportador de la biblioteca de tipos (Tlbexp.exe).The COM client can obtain a pointer to a class interface named _Mammal, which is described in the type library that the Type Library Exporter (Tlbexp.exe) tool generates. Si la clase Mammal implementó una o más interfaces, estas aparecerán bajo la coclase.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;
}

Generar la interfaz de clase es una acción opcional.Generating the class interface is optional. De manera predeterminada, la interoperabilidad COM genera una interfaz solo de envío para cada clase que se exporta a una biblioteca de tipos.By default, COM interop generates a dispatch-only interface for each class you export to a type library. La creación automática de esta interfaz se puede impedir o modificar aplicando ClassInterfaceAttribute a la clase.You can prevent or modify the automatic creation of this interface by applying the ClassInterfaceAttribute to your class. Si bien la interfaz de clase puede facilitar la tarea de exponer clases administradas a COM, sus usos son limitados.Although the class interface can ease the task of exposing managed classes to COM, its uses are limited.

Precaución

Si se usa la interfaz de clase en lugar de definir una interfaz propia de manera explícita, el control de las futuras versiones de la clase administrada puede ser más complicado.Using the class interface, instead of explicitly defining your own, can complicate the future versioning of your managed class. Antes de usar la interfaz de clase lea las instrucciones siguientes.Please read the following guidelines before using the class interface.

Defina una interfaz explícita para que la usen los clientes COM en lugar de generar la interfaz de clase.Define an explicit interface for COM clients to use rather than generating the class interface.

Dado que la interoperabilidad COM genera automáticamente una interfaz de clase, los cambios en versiones posteriores de la clase pueden modificar el diseño de la interfaz de clase expuesta por 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. Puesto que los clientes COM no están preparados normalmente para controlar cambios en el diseño de una interfaz, se interrumpen si se cambia el diseño de miembro de la clase.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.

Esta instrucción enfatiza la idea de que las interfaces expuestas a los clientes COM no se deben modificar.This guideline reinforces the notion that interfaces exposed to COM clients must remain unchangeable. Para reducir el riesgo de que los clientes COM se interrumpan por volver a ordenar involuntariamente el diseño de interfaz, aísle del diseño de interfaz todos los cambios que se hagan en la clase definiendo las interfaces de manera explícita.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.

Use ClassInterfaceAttribute para desactivar la generación automática de la interfaz de clase e implemente una interfaz explícita para la clase, como se muestra en el fragmento de código siguiente: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; }
}

El valor ClassInterfaceType.None impide que la interfaz de clase se genere cuando los metadatos de la clase se exportan a una biblioteca de tipos.The ClassInterfaceType.None value prevents the class interface from being generated when the class metadata is exported to a type library. En el ejemplo anterior, los clientes COM tan solo pueden tener acceso a la clase LoanApp a través de la interfaz IExplicit.In the preceding example, COM clients can access the LoanApp class only through the IExplicit interface.

Evitar almacenamiento en caché de identificadores de envío (DISPID)Avoid caching dispatch identifiers (DispIds)

El uso de la interfaz de clase es una opción aceptable para los clientes con scripts, los clientes de Microsoft Visual Basic 6.0 o cualquier cliente enlazado en tiempo de ejecución que no almacene en caché los identificadores DispId de los miembros de la interfaz.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. Los identificadores DispId identifican los miembros de la interfaz para admitir enlaces en tiempo de ejecución.DispIds identify interface members to enable late binding.

Para la interfaz de clase, la generación de identificadores DispId se basa en la posición del miembro en la interfaz.For the class interface, generation of DispIds is based on the position of the member in the interface. Si cambia el orden del miembro y exporta la clase a una biblioteca de tipos, modificará los identificadores DispId generados en la interfaz de clase.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.

Para evitar que los clientes COM enlazados en tiempo de ejecución se interrumpan al usar la interfaz de clase, aplique ClassInterfaceAttribute con el valor ClassInterfaceType.AutoDispatch.To avoid breaking late-bound COM clients when using the class interface, apply the ClassInterfaceAttribute with the ClassInterfaceType.AutoDispatch value. Este valor implementa una interfaz de clase de solo envío, pero omite la descripción de la interfaz de la biblioteca de tipos.This value implements a dispatch-only class interface, but omits the interface description from the type library. Sin una descripción de la interfaz, los clientes no pueden almacenar en caché los identificadores DispId en tiempo de compilación.Without an interface description, clients are unable to cache DispIds at compile time. Aunque este es el tipo predeterminado de la interfaz de clase, se puede aplicar el valor del atributo de forma explícita.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; }
}

Para obtener el DispId de un miembro de interfaz en tiempo de ejecución, los clientes COM pueden llamar a IDispatch.GetIdsOfNames.To get the DispId of an interface member at run time, COM clients can call IDispatch.GetIdsOfNames. Para invocar un método en la interfaz, pase el DispId devuelto como argumento a IDispatch.Invoke.To invoke a method on the interface, pass the returned DispId as an argument to IDispatch.Invoke.

Restrinja el uso de la opción de interfaz dual en la interfaz de clase.Restrict using the dual interface option for the class interface.

Las interfaces duales permiten el enlace en tiempo de diseño y en tiempo de ejecución de los clientes COM con los miembros de interfaz.Dual interfaces enable early and late binding to interface members by COM clients. El establecimiento de la interfaz de clase en dual puede ser útil en tiempo de diseño y durante las pruebas.At design time and during testing, you might find it useful to set the class interface to dual. Esta opción también es aceptable para una clase administrada (y sus clases base) que no se va a modificar nunca.For a managed class (and its base classes) that will never be modified, this option is also acceptable. En todos los demás casos, no es necesario establecer la interfaz de clase en dual.In all other cases, avoid setting the class interface to dual.

Una interfaz dual generada automáticamente puede ser apropiada en algunos casos, pero a menudo genera complicaciones de control de versiones.An automatically generated dual interface might be appropriate in rare cases; however, more often it creates version-related complexity. Por ejemplo, los clientes COM que usen la interfaz de clase de una clase derivada se pueden interrumpir con facilidad si se hacen cambios en la clase base.For example, COM clients using the class interface of a derived class can easily break with changes to the base class. Si la clase base es de terceros, el usuario no tiene control sobre el diseño de la interfaz de clase.When a third party provides the base class, the layout of the class interface is out of your control. Además, a diferencia de una interfaz de solo envío, una interfaz dual (ClassInterfaceType.AutoDual) proporciona una descripción de la interfaz de clase en la biblioteca de tipos exportada.Further, unlike a dispatch-only interface, a dual interface (ClassInterfaceType.AutoDual) provides a description of the class interface in the exported type library. Dicha descripción hace que los clientes enlazados en tiempo de ejecución almacenen en caché los identificadores DispId en tiempo de ejecución.Such a description encourages late-bound clients to cache DispIds at run time.

Asegúrese de que todas las notificaciones de eventos COM están enlazadas tardíamente.Ensure that all COM event notifications are late-bound.

De forma predeterminada, la información de tipos COM se inserta directamente en los ensamblados administrados, lo que elimina la necesidad de ensamblados de interoperabilidad primarios (PIA).By default, COM type information is embedded directly into managed assemblies, which eliminates the need for primary interop assemblies (PIAs). Sin embargo, una de las limitaciones de la información de tipo insertada es que no admite la entrega de notifications de eventos COM mediante llamadas enlazadas tempranamente vtable, sino que solo admite llamadas IDispatch::Invoke enlazadas tardíamente.However, one of the limitations of embedded type information is that it does not supported delivery of COM event notifications by early-bound vtable calls, but only supports late-bound IDispatch::Invoke calls.

Si la aplicación requiere las llamadas enlazadas tempranamente a los métodos de interfaz de eventos COM, puede establecer la propiedad Incrustar tipos de interoperabilidad en Visual Studio en true o incluir el siguiente elemento en el archivo de proyecto: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>

Vea tambiénSee also