Conversão de tipo exportado
Este tópico descreve como o processo de exportação converte os seguintes tipos:
Classes
Interfaces
Tipos de valor
Enumerações
Em geral, os tipos exportados mantêm o mesmo nome que tinham dentro de um assembly, excluindo o namespace associado com o nome gerenciado. Por exemplo, o tipo de A.B.IList no seguinte código exemplo converte em IList na biblioteca de tipos exportados. Um cliente COM pode referir-se o tipo IList em vez de A.B.IList.
Namespace A
Namespace B
Interface IList
…
End Interface
End Namespace
End Namespace
namespace A {
namespace B {
interface IList {
…
}
}
}
Com essa abordagem, os nomes de tipo dentro de um assembly podem potencialmente colidem porque os tipos em namespaces diferentes podem ter o mesmo nome. Quando o processo de exportação detecta uma colisão, ele retém o namespace para eliminar ambigüidades de nomes. O exemplo de código a seguir mostra dois espaços para nome com o mesmo nome de tipo.
Namespace A
Namespace B
Public Class LinkedList
Implements IList
End Class
Public Interface IList
End Interface
End Namespace
End Namespace
Namespace C
Public Interface IList
End Interface
End Namespace
namespace A {
namespace B {
public class LinkedList : IList {…}
public interface IList {…}
}
}
namespace C {
public interface IList {…}
}
A representação de biblioteca de tipo seguinte mostra a resolução do nome de cada tipo. Além disso, como períodos não são válidos em nomes de biblioteca de tipo, o processo de exportação substitui cada período sublinhados.
Representação de biblioteca de tipo
library Widgets
{
[…]
coclass LinkedList
{
interface A_B_IList
};
[…]
interface A_B_IList {…};
[…]
interface C_IList {…};
};
O processo de exportação também gera automaticamente um identificador programático (ProgId), combinando o nome do namespace e tipo. Por exemplo, o ProgId gerado para o gerenciado LinkedList classe mostrado nos exemplos anteriores é A.B.LinkedList.
O nome do namespace e tipo de combinação pode resultar em um ProgId inválido. ProgId é limitado a 39 caracteres e não pode conter nenhum caractere de pontuação diferente de períodos. Para evitar essas limitações, você pode especificar um ProgId no seu código fonte, aplicando a ProgIdAttribute, em vez de permitir o processo de exportação gerar um identificador para você.
Classes
O processo de exportação converte cada classe pública (que omite o atributo de ComVisible (false)) em um assembly para uma coclass em uma biblioteca de tipos. Um coclass exportado possui métodos nem propriedades; No entanto, ele mantém o nome da classe gerenciada e implementa todas as interfaces explicitamente implementadas pela classe gerenciada.
O exemplo de código a seguir mostra a definição da IShape interface e o Circle classe, que implementa IShape. A representação da biblioteca de tipo convertido segue o exemplo de código.
Public Interface IShape
Sub Draw()
Sub Move(x As Integer, y As Integer)
End Interface
Class Circle
Implements IShape
Sub Draw Implements IShape.Draw
…
Sub Move(x As Integer, y As Integer) Implements IShape.Move
…
Sub Enlarge(x As Integer)
…
End Class
public interface IShape {
void Draw();
void Move(int x, int y);
}
class Circle : IShape {
void Draw();
void Move(int x, int y);
void Enlarge(int x);
}
Representação de biblioteca de tipo
[ uuid(…), dual, odl, oleautomation ]
interface IShape : IDispatch {
HRESULT Draw();
HRESULT Move(int x, int y);
}
[ uuid(…) ]
coclass Circle {
interface IShape;
}
Cada coclass pode implementar uma interface, chamada de interface de classe, o processo de exportação pode gerar automaticamente. A interface de classe expõe todos os métodos e propriedades disponíveis na classe gerenciada original, permitindo a clientes COM para acessá-las, chamada por meio da interface de classe.
Você pode atribuir um identificador universal exclusivo (UUID) específico para a classe aplicando o GuidAttribute imediatamente acima da definição de classe gerenciada. Durante o processo de conversão, o processo de exportação transfere o valor fornecido para o GuidAttribute para o UUID na biblioteca de tipos. Caso contrário, o processo de exportação obtém UUIDs de um hash que inclui o nome completo da classe, incluindo o namespace. Usar o nome completo garante que uma classe com um determinado nome de um dado namespace sempre gera o mesmo UUID e que duas classes com nomes diferentes nunca geram o mesmo UUID.
Classes abstratas e classes sem público, os construtores padrão são marcados com o noncreatable atributo da biblioteca de tipo. Outros atributos de biblioteca de tipo que se aplicam a coclasses de, como licenciado, oculto, restritos, e controle não estão definidas.
Interfaces
O processo de exportação converte interfaces gerenciadas em interfaces COM os mesmos métodos e propriedades como a interface gerenciada, mas as assinaturas de método diferem consideravelmente.
Identidades de interface.
Interfaces COM incluem um identificador de interface (IID) para diferenciar uma interface do outro. Você pode atribuir um IID fixo para qualquer interface gerenciada, aplicando o GuidAttribute atributo. Se você omite esse atributo e não atribuir um IID de fixo, o processo de exportação atribui automaticamente um durante a conversão. Um IID atribuído em tempo de execução compreende o nome da interface (incluindo o namespace) e a assinatura completa de todos os métodos definidos dentro da interface. Reorganizando os métodos na interface gerenciada ou alterando o argumento do método e tipos de retorno, você pode alterar a IID atribuída à interface. Alterar o nome do método não afeta a IID.
Usando o QueryInterface o método implementado pelo tempo de execução, clientes COM podem obter uma interface que ter um IID fixo ou a IID atribuído em tempo de execução. IIDs geradas pelo runtime não são mantidas nos metadados para o tipo.
Tipos de interface
A menos que você especifique o contrário, o processo de exportação converte todas as interfaces gerenciadas interfaces duplas em uma biblioteca de tipos. Interfaces duas permitem que os clientes COM escolha entre ligação antecipada e atrasada.
Você pode aplicar o InterfaceTypeAttribute de atributo para uma interface para seletivamente indicar que a interface deve ser exportada como uma interface dupla, uma interface derivada de IUnknown ou uma interface somente de distribuição (dispinterface). Todas as interfaces exportadas estendem diretamente de um IUnknown ou IDispatch, independentemente de sua hierarquia de herança em código gerenciado.
O exemplo de código a seguir mostra os valores opcionais para controlar o tipo de interface. Depois de exportado para uma biblioteca de tipos, essas opções produzem os resultados mostrados na representação de biblioteca de tipo que segue o código.
' Creates a Dual interface by default.
Public Interface InterfaceWithNoInterfaceType
Sub test()
End Interface
' Creates a Dual interface explicitly.
<InterfaceType(ComInterfaceType.InterfaceIsDual)> _
Public Interface InterfaceWithInterfaceIsDual
Sub test()
End Interface
' Creates an IUnknown interface (not dispatch).
<InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
Public Interface InterfaceWithInterfaceIsIUnknown
Sub test()
End Interface
' Creates a Dispatch-only interface (dispinterface).
<InterfaceType(ComInterfaceType.InterfaceIsIDispatch)> _
Public Interface InterfaceWithInterfaceIsIDispatch
Sub test()
End Interface
// Creates a Dual interface by default.
public interface InterfaceWithNoInterfaceType {
void test();
}
// Creates a Dual interface explicitly.
[InterfaceType(ComInterfaceType.InterfaceIsDual)]
public interface InterfaceWithInterfaceIsDual {
void test();
}
// Creates an IUnknown interface (not dispatch).
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
public interface InterfaceWithInterfaceIsIUnknown {
void test();
}
// Creates a Dispatch-only interface(dispinterface).
[InterfaceType(ComInterfaceType.InterfaceIsIDispatch)]
public interface InterfaceWithInterfaceIsIDispatch {
void test();
}
Representação de biblioteca de tipo
[ odl, uuid(…), dual, oleautomation ]
interface InterfaceWithNoInterfaceType : IDispatch {
HRESULT test();
};
[ odl, uuid(…), dual, oleautomation ]
interface InterfaceWithInterfaceIsDual : IDispatch {
HRESULT test();
};
[ odl, uuid(…), oleautomation ]
interface InterfaceWithInterfaceIsIUnknown : IUnknown {
HRESULT test();
};
[ uuid(…) ]
dispinterface InterfaceWithInterfaceIsIDispatch {
properties:
methods:
void test();
};
A maioria das interfaces são marcadas com o odl, e oleautomation atributos da biblioteca de tipo durante o processo de exportação. (Dispinterfaces são a exceção). Interfaces duplas são marcados com o dual atributo da biblioteca de tipo. Uma interface dupla deriva do IDispatch interface, mas ele também expõe os slots de vtable para seus métodos.
Interfaces de classe
Para obter uma descrição completa da interface de classe e recomendações de uso, consulte apresentando a Interface de classe. O processo de exportação pode gerar essa interface automaticamente em nome de uma classe gerenciada sem uma interface explicitamente definida no código gerenciado. Clientes COM não podem acessar diretamente os métodos de classe.
O exemplo de código a seguir mostra uma classe base e uma classe derivada. Nenhuma classe implementa uma interface explícita. O processo de exportação oferece uma interface de classe para ambas as classes gerenciadas.
Public Class BaseClassWithClassInterface
Private Shared StaticPrivateField As Integer
Private PrivateFld As Integer
Private Property PrivateProp() As Integer
Get
Return 0
End Get
Set
End Set
End Property
Private Sub PrivateMeth()
Return
End Sub
Friend Shared StaticInternalField As Integer
Friend InternalFld As Integer
Friend Property InternalProp() As Integer
Get
Return 0
End Get
Set
End Set
End Property
Friend Sub InternalMeth()
Return
End Sub
Public Shared StaticPublicField As Integer
Public PublicFld As Integer
Public Property PublicProp() As Integer
Get
Return 0
End Get
Set
End Set
End Property
Public Sub PublicMeth()
Return
End Sub
End Class
Public Class DerivedClassWithClassInterface
Inherits BaseClassWithClassInterface
Public Sub Test()
Return
End Sub
End Class
public class BaseClassWithClassInterface {
private static int StaticPrivateField;
private int PrivateFld;
private int PrivateProp{get{return 0;} set{;}}
private void PrivateMeth() {return;}
internal static int StaticInternalField;
internal int InternalFld;
internal int InternalProp{get{return 0;} set{;}}
internal void InternalMeth() {return;}
public static int StaticPublicField;
public int PublicFld;
public int PublicProp{get{return 0;} set{;}}
public void PublicMeth() {return;}
}
public class DerivedClassWithClassInterface : BaseClassWithClassInterface {
public void Test() {return;}
}
Representação de biblioteca de tipo
[odl,uuid(…), hidden, dual, nonextensible, oleautomation]
interface _BaseClassWithClassInterface : IDispatch {
[id(00000000),propget] HRESULT ToString([out, retval] BSTR* p);
[id(0x60020001)] HRESULT Equals([in] VARIANT obj,
[out, retval] VARIANT_BOOL* p);
[id(0x60020002)] HRESULT GetHashCode([out,retval] long* p);
[id(0x60020003)] HRESULT GetType([out, retval] _Type** p);
[id(0x60020004),propget] HRESULT PublicProp([out,retval] long* p);
[id(0x60020004),propput] HRESULT PublicProp([in] long p);
[id(0x60020006)] HRESULT PublicMeth();
[id(0x60020007),propget] HRESULT PublicFld([out, retval]long* p);
[id(0x60020007),propput] HRESULT PublicFld([in] long p);
};
[odl,uuid(…), hidden, dual, nonextensible, oleautomation]
interface _DerivedClassWithClassInterface : IDispatch {
[id(00000000),propget] HRESULT ToString([out, retval] BSTR* p);
[id(0x60020001)] HRESULT Equals([in] VARIANT obj,
[out, retval] VARIANT_BOOL* p);
[id(0x60020002)] HRESULT GetHashCode([out,retval] long* p);
[id(0x60020003)] HRESULT GetType([out, retval] _Type** p);
[id(0x60020004),propget] HRESULT PublicProp([out,retval] long* p);
[id(0x60020004),propput] HRESULT PublicProp([in] long p);
[id(0x60020006)] HRESULT PublicMeth();
[id(0x60020007),propget] HRESULT PublicFld([out, retval]long* p);
[id(0x60020007),propput] HRESULT PublicFld([in] long p);
[id(0x60020008)] HRESULT Test();
}
As interfaces de classe exportado têm as seguintes características:
Cada interface de classe mantém o nome da classe gerenciada, mas é prefixado com um sublinhado. Quando uma interface nome conflita com um nome de interface definida anteriormente, o novo nome é acrescentado com um sublinhado e um número incremental. Por exemplo, o próximo nome disponível para _ClassWithClassInterface é _ClassWithClassInterface_2.
O processo de exportação sempre gera novos identificadores de interface (IID). Você não pode definir explicitamente o IID da interface de classe.
Por padrão, ambas as interfaces de classe derivam de interfaces de IDispatch.
As interfaces têm ODL, dual, oculto, e os atributos de oleautomation.
Ambas as interfaces têm todos os membros públicos de sua classe base (System. Object).
Eles não contêm os membros privados ou internos da classe.
Cada membro é atribuído automaticamente um DispId exclusivo. Os DispIds pode definir explicitamente aplicando DispIdAttribute para o membro da classe a.
Assinaturas de método são transformadas em retornar HRESULTs e ter [out, retval] Parâmetros.
Os campos e propriedades são transformados em [propget] [propput] e [propputref].
Interface padrão
COM tem a noção de uma interface padrão. Membros da interface padrão são tratados como os membros da classe por linguagens de ligação tardia como Visual Basic. No.NET Framework, não é necessário para uma interface padrão, porque as próprias classes podem ter membros. No entanto, ao expor classes COM, classes são muito mais fácil de usar que elas tenham uma interface padrão.
Quando uma classe gerenciada é exportada para uma biblioteca de tipos como um coclass, uma interface é normalmente identificada como interface padrão para a classe. Se nenhuma interface for identificada como padrão na biblioteca de tipos, a maioria dos aplicativos do COM pressupõem que a primeira interface implementada é a interface padrão do que coclass.
Como mostra o exemplo de código a seguir, o processo de exportação converte uma classe gerenciada que não tem nenhuma interface de classe e marca a primeira interface implementada como padrão na biblioteca de tipos exportados. A representação da biblioteca de tipo da classe convertida segue o exemplo de código.
<ClassInterface(ClassInterfaceType.None)> _
Public Class ClassWithNoClassInterface
Implements IExplicit
Implements IAnother
Sub M()
…
End Class
[ClassInterface(ClassInterfaceType.None)]
public class ClassWithNoClassInterface : IExplicit, IAnother {
void M();
}
Representação de biblioteca de tipo
coclass ClassWithNoClassInterface {
[default] IExplicit;
IAnother;
}
A exportação sempre processar marcas a interface de classe como interface padrão para a classe, independentemente de qualquer interface que a classe implementa explicitamente. O exemplo a seguir mostra duas classes.
<ClassInterface(ClassInterfaceType.AutoDispatch)> _
Public Class ClassWithAutoDispatch
Implements IAnother
Sub M()
…
End Class
<ClassInterface(ClassInterfaceType.AutoDual)> _
Public Class ClassWithAutoDual
Implements IAnother
Sub M()
…
End Class
[ClassInterface(ClassInterfaceType.AutoDispatch)]
public class ClassWithAutoDispatch : IExplicit, IAnother {
void M();
}
[ClassInterface(ClassInterfaceType.AutoDual)]
public class ClassWithAutoDual : IExplicit, IAnother {
void M();
}
Representação de biblioteca de tipo
// ClassWithAutoDispatch: IDispatch
coclass ClassWithAutoDispatch {
[default] _ClassWithAutoDispatch;
interface _Object;
IExplicit;
IAnother;
}
interface _ClassWithAutoDual {…}
coclass ClassWithAutoDual {
[default] _ClassWithAutoDual;
IExplicit;
IAnother;
}
Tipos de valor
Tipos de valor (tipos estendem System.Value) são exportados para bibliotecas de tipos como estruturas de estilo c com a definição de tipo. O layout dos membros da estrutura é controlado com o StructLayoutAttribute atributo, que é aplicado ao tipo. Somente os campos do tipo de valor são exportados. Se um tipo de valor tem métodos, são inacessíveis a partir do COM.
Por exemplo:
[StructLayout(LayoutKind.Sequential)]
public struct Point {
int x;
int y;
public void SetXY(int x, int y){
this.x = x;
this.y = y;
}
};
O tipo de valor de ponto é exportado para COM um ponto de TypeDef, conforme mostrado no exemplo a seguir:
typedef
[uuid(…)]
struct tagPoint {
short x;
short y;
} Point;
Observe que o processo de conversão remove o método de SetXY a typedef.
Enumerações
O processo de exportação adiciona uma enumeração gerenciada digitar bibliotecas como uma enumeração com os nomes de membro alteradas para garantir o nomeação de membro exclusivo. Para garantir que o nome de cada membro é exclusivo, Tlbexp. exe prefixos de um sublinhado ao nome da enumeração para cada membro durante o processo de exportação. Por exemplo, a enumeração simple a seguir produz um conjunto de representações de biblioteca de tipo.
Enum DaysOfWeek {
Sunday = 0;
Monday;
Tuesday;
…
};
Representação de biblioteca de tipo
enum DaysOfWeek {
DaysOfWeek_Sunday = 0;
DaysOfWeek_Monday;
DaysOfWeek_Tuesday;
…
};
Os escopos de tempo de execução gerenciado membros de enumeração para a enumeração na qual eles pertencem. Por exemplo, todas as referências a Sunday na DaysOfWeek enumeração, como mostrada no exemplo anterior, deve ser qualificada com DaysOfWeek. Você não pode referenciar Sunday no lugar de DaysOfWeek.Sunday. Nomeação de membro exclusivo é um requisito de enumerações de COM.
Consulte também
Conceitos
Conversão de Assembly exportados
Conversão do parâmetro exportado