Преобразование импортированного типа

В данном разделе описывается преобразование следующих типов в процессе импорта:

  • интерфейсов,

  • Классы

  • структуры;

  • Перечисления

  • Константы

  • Определения типов

Обычно программа 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. Процедура преобразования также применяет этот атрибут к аргументам методов класса.

См. также

Основные понятия

Преобразование импортированной библиотеки

Преобразование импортированного модуля

Преобразование импортированного члена

Преобразование импортированного параметра

Другие ресурсы

Обзор преобразования библиотеки типов в сборку