Conversión de miembros exportados
En este tema se describe cómo el proceso de exportación convierte los miembros siguientes:
Métodos
Propiedades
Eventos
Métodos
Los clientes COM esperan llamar a métodos, pasando tipos de datos COM conocidos (por ejemplo, parámetros) y recibiendo resultados HRESULT devueltos. Sin embargo, en el territorio .NET, las clases no tienen restricción de tipos de valor devuelto; de hecho, no usan resultados HRESULT.
Para poder cumplir con los dos modelos, todos los métodos de un tipo administrado tienen un prototipo .NET y un prototipo COM implícito. Normalmente, los dos prototipos son bastante diferentes. Los clientes .NET interactúan con el servidor usando el prototipo .NET, mientras que los clientes COM (quizás a la vez) lo hacen usando el prototipo COM. El servidor implementa el método con el prototipo .NET y el servicio de cálculo de referencias del motor en tiempo de ejecución se encarga de proporcionar código auxiliar con el prototipo COM que delega la llamada en el método administrado.
Conversión HRESULT
Un prototipo administrado se convierte en prototipo no administrado cambiando el valor devuelto administrado a un parámetro [out, retval] y cambiando el tipo del valor devuelto no administrado a HRESULT. Por ejemplo, el método DoSomething
podría tener los prototipos siguientes:
Prototipo administrado
short DoSomething(short i);
Prototipo no administrado
HRESULT DoSomething([in] short i, [out, retval] short *rv);
Tenga en cuenta que el prototipo COM devuelve un resultado HRESULT y tiene un parámetro out adicional para el valor devuelto. El valor devuelto de la implementación administrada es siempre un parámetro [out, retval] agregado al final del prototipo no administrado, mientras que el prototipo no administrado devuelve siempre un resultado HRESULT. Si el método administrado no devuelve ningún valor, el motor en tiempo de ejecución omite el parámetro [out, retval]. Por ejemplo:
Prototipo administrado
void DoSomething(short i);
Prototipo no administrado
HRESULT DoSomething([in] short i);
En algunas circunstancias, es preferible dejar el prototipo administrado sin modificar. Para hacerlo se puede usar PreserveSigAttribute. Por ejemplo:
Prototipo administrado
[PreserveSig] short DoSomething(short i);
Prototipo no administrado
short DoSomething ([in] short i);
El hecho de tener dos prototipos de método diferentes facilita el uso de la clase de los clientes COM y .NET sin problemas. Además, los clientes COM y .NET pueden usar una clase .NET simultáneamente. Como autor de la clase, el usuario sólo implementa el prototipo administrado. Mediante el uso de Tlbexp.exe (o una API equivalente) el prototipo se exporta automáticamente a una biblioteca de tipos generada para la clase.
Métodos sobrecargados
Aunque .NET es compatible con los métodos sobrecargados, la interfaz IDispatch depende únicamente del nombre del método para el enlace y no del prototipo de método completo. Por ello no es compatible con los métodos sobrecargados. Sin embargo, para proporcionar acceso a los métodos sobrecargados de un tipo, Tlbexp.exe decora los nombres de los métodos sobrecargados con un número ordinal de modo que cada nombre de método sea único.
Los siguientes prototipos administrados y no administrados muestran la inclusión de números:
Prototipo administrado
interface INew {
public:
void DoSomething();
void DoSomething(short s);
void DoSomething(short l);
void DoSomething(float f);
void DoSomething(double d);
}
Prototipo no administrado
interface INew {
void DoSomething();
void DoSomething_2(short s);
void DoSomething_3(short l);
void DoSomething_4(float f);
void DoSomething_5(double d);
}
El prototipo COM de los métodos aparece como un método DoSomething
individual seguido de una serie de métodos DoSomething_
x representativos, donde x comienza en el número 2 y aumenta para cada forma sobrecargada del método. Tenga en cuenta que los métodos sobrecargados se pueden heredar de un tipo base. Sin embargo, no hay garantías de que los métodos sobrecargados mantengan el mismo número al ir avanzando la versión del tipo.
Aunque los clientes .NET pueden usar la forma sobrecargada del método, los clientes COM deben tener acceso a los métodos representativos. Los examinadores de objetos muestran todas las formas del método representativo con el prototipo de método para que el usuario seleccione el método correcto. El cliente en tiempo de ejecución también puede llamar a IDispatch::GetIdsOfNames, pasando el nombre representativo para obtener el identificador DispID de cualquier método sobrecargado.
Propiedades
Las clases y las interfaces administradas pueden tener propiedades. Una propiedad administrada es de un tipo de datos concreto que puede tener asociado un método get y un método set. Estos métodos se definen por separado, igual que cualquier otro método. El siguiente ejemplo de código muestra una interfaz que contiene una propiedad Height
. Las clases que implementan la interfaz deben proporcionar un método get y set para la propiedad.
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; } }
}
Durante la exportación, Tlbexp.exe convierte el método set de la propiedad en [propput] y el método get en [propget]. El nombre de la propiedad en COM sigue siendo el mismo que el de la propiedad administrada. Esta regla tiene las excepciones siguientes:
Si el tipo de propiedad, excepto los tipos de valor, es una clase o una interfaz, el método set de la propiedad se convierte en [propputref], dando a los parámetros un nivel de direccionamiento indirecto agregado.
Si la propiedad no tiene un método get o set, Tlbexp.exe omite la propiedad de la biblioteca de tipos.
Al igual que las propiedades, los campos administrados se exportan a la biblioteca de tipos. El servicio de cálculo de referencias del motor en tiempo de ejecución genera automáticamente los métodos get y set para todos los campos públicos. Durante el proceso de conversión, Tlbexp.exe genera una función [propput] (o [propputref]) y una función [propget] para cada campo, como se muestra en la siguiente representación de biblioteca de tipos.
Representación de biblioteca de tipos
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);
};
Eventos
Si no está familiarizado con el modelo de eventos de la interoperabilidad COM, vea Eventos administrados y no administrados. Los tipos administrados implementan eventos usando un modelo basado en delegados. Por ejemplo, la interfaz Class1Events
del ejemplo de código siguiente provoca el evento 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;
}
Durante la exportación, Tlbexp.exe marca la interfaz de eventos como código fuente en la coclase. Como se muestra en la siguiente representación de biblioteca de tipos, la interfaz exportada ComClass1Events
se marca como la interfaz de origen.
Representación de biblioteca de tipos
disinterface Class1Event {
properties:
methods:
[id(0x60020000)]
HRESULT Click();
};
coclass Class1
{
…
[default, source] Class1Event;
};
Vea también
Conceptos
Conversión de ensamblados exportados
Conversión de módulos exportados
Conversión de tipos exportados
Conversión de parámetros exportados
Otros recursos
Resumen de la conversión de ensamblados en bibliotecas de tipos