Преобразование импортированного типа
В данном разделе описывается преобразование следующих типов в процессе импорта:
интерфейсов,
Классы
структуры;
Перечисления
Константы
Определения типов
Обычно программа Tlbimp.exe импортирует типы, сохраняя для них имена, использовавшиеся в исходной библиотеке типов. Имена в библиотеке типов должны быть уникальными, что предотвращает конфликты имен во время преобразования. Все допустимые имена библиотек типов являются допустимыми именами сборок.
Область импортированных типов ограничена пространством имен, к которому они принадлежат и которое совпадает с пространством имен исходной библиотеки типов. Для идентификации отдельных типов используется полное пространство имен и имя типа.
Атрибут библиотеки типов позволяет явным образом задавать управляемое имя импортируемого типа в библиотеке типов. Идентификатор пользовательского атрибута равен 0F21F359-AB84-41e8-9A78-36D110E6D2F9. В следующей библиотеке типов демонстрируется добавление пользовательского атрибута.
Представление библиотеки типов
[ uuid(…),
version(1.0)
]
library AcmeLib {
interface Widget {};
[custom(0F21F359-AB84-41e8-9A78-36D110E6D2F9,
"Acme.WidgetLib.Slingshot")]
coclass Slingshot {};
};
Хотя программа Tlbimp.exe импортирует библиотеку типов в пространство имен AcmeLib, класс Slingshot становится классом Acme.WidgetLib.Slingshot.
Интерфейсы
Когда процедура импорта выполняет преобразование интерфейса, удаляются все методы IUnknown и IDispatch. В процессе преобразования к интерфейсу применяется атрибут GuidAttribute для сохранения идентификатора интерфейса (IID), назначенного в библиотеке типов, а также атрибут InterfaceTypeAttribute, если интерфейс не является сдвоенным (производным от IDispatch).
Представление библиотеки типов
[uuid(…), ]
interface IWidget : IUnknown {
HRESULT New()
HRESULT Start()
};
[uuid(…), ]
interface IGadget : IWidget {
HRESULT Baz()
};
Во время преобразования процедура импорта добавляет методы базового интерфейса в производный интерфейс. В следующем примере методы New и Start добавляются в интерфейс IGadget:
<Guid(…), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
Interface IWidget
Sub [New]()
Sub Start()
End Interface
<Guid(…), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)> _
Interface IGadget
Inherits IWidget
Shadows Sub [New]()
Shadows Sub Start()
Sub Baz()
End Interface
[Guid(…), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IWidget {
void New();
void Start();
};
[Guid(…), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IGadget : IWidget {
new void New();
new void Start();
void Baz();
};
Классы
Процедура импорта создает управляемый класс для представления каждого компонентного класса COM и присваивает управляемому классу имя исходного компонентного класса с добавлением слова Class. Например, компонентный класс NewNewer преобразуется в класс NewNewerClass. При преобразовании для сохранения идентификатора компонентного класса (CLSID) к классу добавляется атрибут GuidAttribute.
Помимо управляемого класса, процедура импорта добавляет интерфейс с именем компонентного класса и применяет атрибут CoClassAttribute для задания идентификатора CLSID исходного компонентного класса. Идентификатор IID этого интерфейса совпадает с идентификатором интерфейса по умолчанию компонентного класса. С помощью этого интерфейса клиенты всегда могут зарегистрироваться в качестве приемников событий.
В отличие от компонентного COM-класса управляемый класс может содержать члены класса. В соответствии с моделью программирования .NET процедура преобразования добавляет в каждый класс члены, связанные с каждым из интерфейсов, реализованных компонентным классом. Пользователи управляемого класса могут вызывать методы и свойства управляемого типа, не выполняя предварительного приведения к конкретному интерфейсу. Процедура импорта также добавляет к каждому преобразованному компонентному классу конструктор по умолчанию. Конструктор позволяет создавать класс из управляемого кода. (Классы без конструктора не могут быть созданы.) У конструктор по умолчанию нет аргументов, и его реализация обеспечивает вызов конструктора базового класса. Если к компонентному классу применяется атрибут библиотеки типов noncreatable, процедура импорта не создает для этого класса конструктор по умолчанию.
Поскольку имена членов интерфейса не всегда уникальны, между членами возможны конфликты имен и идентификаторов DispId. Программа TlbImp.exe разрешает конфликты имен, добавляя к имени каждого конфликтующего члена класса имя интерфейса и подчеркивание в качестве префикса. В случае конфликта имен членов класса первый интерфейс, указанный в инструкции компонентного класса, не меняется.
Если происходит конфликт идентификаторов DispId, процедура импорта присваивает идентификаторы DispId членам интерфейса по умолчанию компонентного класса и не присваивает идентификаторов конфликтующим членам класса. Но процедура импорта всегда присваивает идентификаторы DispId членам интерфейса.
Представление библиотеки типов
[uuid(…)]
interface INew : IDispatch {
[id(0x100)] HRESULT DoFirst();
[id(0x101)] HRESULT DoSecond();
}
[uuid(…)]
interface INewer : IDispatch {
[id(0x100)] HRESULT DoNow();
[id(0x101)] HRESULT DoSecond();
}
[uuid(…)]
coclass NewNewer {
[default] interface INew;
interface INewer;
}
Ниже представлены преобразованные типы:
<Guid(…)> Public Interface INew
…
End Interface
<Guid(…)> Public Interface INewer
…
End Interface
<Guid(…)> Public Interface NewNewer
Inherits INew
…
End Interface
<Guid(…)> Public Class NewNewerClass
Implements INew
Implements INewer
Implements NewNewer
' Method implementation
<DispId(100)> _
…
End Class
[Guid(…)]
public interface INew {…}
[Guid(…)]
public interface INewer {…}
[Guid(…)]
public interface NewNewer : INew {…}
[Guid(…)]
public class NewNewer : INew, INewer, NewNewer{
// Method implementation.
[DispId(100)]…
}
Структуры
Структуры, определенные в библиотеке типов, импортируются как метаданные. Если поле структуры является ссылочным типом, программа Tlbimp.exe импортирует этот тип как IntPtr и применяет атрибут ComConversionLossAttribute. Этот атрибут показывает, что в процессе преобразования были потеряны сведения.
Перечисления
Программа импорта библиотеки типов (Tlbimp.exe) импортирует неуправляемые перечисления как управляемые типы Enum.
Константы
В данном выпуске константы не будут импортироваться из библиотеки типов.
Определения типов
Определения типов, находящиеся в библиотеке типов, не импортируются. Вместо этого параметры и поля импортируются как базовые типы. Например, параметр с типом BUTTON_COLOR импортируется как целочисленный тип, поскольку BUTTON_COLOR — это псевдоним целого числа.
Импортированные параметры и поля содержат сведения, связывающие их с исходным типом, в атрибуте ComAliasNameAttribute. Для связывания поля, параметра или возвращаемого значения с именем библиотеки типов и типом в библиотеке, использовавшимся в качестве псевдонима, в процессе преобразования применяется атрибут ComAliasNameAttribute.
В следующем представлении библиотеки типов показан параметр cl с типом BUTTON_COLOR, который является псевдонимом для целого числа.
Представление библиотеки типов
library MyLib {
typedef [public] int BUTTON_COLOR;
interface ISee {
HResult SetColor([in] BUTTON_COLOR cl);
HResult GetColor([out, retval] BUTTON_COLOR *cl);
};
coclass See {
[default] interface ISee
};
};
Ниже представлены преобразованные типы:
public interface ISee {
void SetColor([ComAliasName("MyLib.BUTTON_COLOR")]] int cl);
[return: ComAliasName("MyLib.BUTTON_COLOR")] int GetColor();
};
public class See {
public void SetColor([ComAliasName("MyLib.BUTTON_COLOR")]] int cl);
[return: ComAliasName("MyLib.BUTTON_COLOR")] int GetColor();
};
Обратите внимание, что в результирующих метаданных не определен сам тип BUTTON_COLOR. Вместо этого к параметрам, имеющим тип BUTTON_COLOR в библиотеке типов, применяется базовый тип, int, и атрибут ComAliasNameAttribute. Процедура преобразования также применяет этот атрибут к аргументам методов класса.
См. также
Основные понятия
Преобразование импортированной библиотеки
Преобразование импортированного модуля
Преобразование импортированного члена
Преобразование импортированного параметра