Чтение онлайн

на главную - закладки

Жанры

Программирование на Visual C++. Архив рассылки

Jenter Алекс

Шрифт:

Для примеров я взял реализацию COM-объекта , а именно структуры CATEGORYINFO и интерфейсов IEnumGUID, IEnumCATEGORYINFO и ICatInformation.

Описание структур – атрибут StructLayout

Применяется ко всей структуре и позволяет управлять физическим расположением членов структуры в памяти. В общем случае CLR управляет расположением данных структур и классов самостоятельно, если же нужно передавать класс или структуру в неуправляемый код, используется атрибут StructLayout.

Поле Pack этого атрибута может иметь следующие значения:

• Sequential – в этом случае данные будут

расположены в памяти последовательно в порядке их объявления. 

• Explicit – в этом случае можно управлять точным расположением каждого члена структуры с помощью задания дополнительного атрибута FieldOffset для каждого поля. 

• CharSet – задает правила маршалинга строковых данных и может принимать следующие значения: 

 • Ansi –строки передаются в виде 1-байтовых ANSI символов 

 • Auto– строки автоматически конвертируются в зависимости от системы (Unicode в WindowsNT и ANSI в Windows9x) 

 • None = Ansi

 • Unicode – строки передаются в виде 2-байтовых символов. 

Пример использования атрибутов StructLayout и MarshalAs приведен ниже: 

IDL

#define CATDESC_MAX 128

typedef struct tagCATEGORYINFO {

 CATID catid;

 LCID lcid;

 OLECHAR szDescription[CATDESC_MAX];

} CATEGORYINFO, *LPCATEGORYINFO;

C#

[StructLayout(LayoutKind.Sequential, CharSet=CharSet.Unicode)]

public struct CATEGORYINFO {

 public Guid catid;

 public uint lcid;

 [MarshalAs(UnmanagedType.ByValTStr, SizeConst=128)]

 public String szDescription;

};

Можно видеть, что в данном случае строка szDescription передается в виде массива фиксированной длины из Unicode-символов. Для маршалинга остальных полей применяются правила по умолчанию. 

ПРИМЕЧАНИЕ

В документации Miscrosoft утверждается, что поле SizeConst атрибута MarshalAs задает размер массива в байтах, на самом деле это поле задает количество элементов в массиве.

Обработка ошибок в COM и .NET

COM методы сообщают об ошибках, возвращая соответствующий HRESULT, .NET методы – генерируя исключения. Здесь возникает одна проблема – .NET игнорирует любые положительные значения HRESULT, что приводит к неправильной работе перечислителей типа IEnumXXX, так как последние сигнализируют о достижении конца последовательности возвратом значения S_FALSE = 1. Чтобы решить эту проблему - для методов введен атрибут PreserveSig. Задание этого атрибута позволяет подавить генерацию исключений .NET, и гарантирует возврат точного значения HRESULT из COM метода, в противном случае результатом метода всегда будет S_OK = 0. Пример использования этого атрибута приведен ниже.

Описание интерфейсов – атрибуты ComImport, Guid, InterfaceType

Для описания интерфейсов и классов применяются атрибуты ComImport и Guid. Атрибут ComImport – показывает, что тип был ранее определен в COM. CLR обращается

с такими типами не так, как с , в частности – по другому создает объекты таких типов, выполняет приведение типов, удержание объектов в памяти и т.д. Этот атрибут обязательно сопровождается атрибутом Guid, название которого говорит само за себя.

Атрибут InterfaceType применяется для описания базового COM интерфейса и может принимать следующие значения: дуальный, IDispatch или IUnknown. Если этот атрибут опущен, то считается, что интерфейс дуальный. В нашем случае все интерфейсы наследуют от IUnknown.

Описания параметров методов – атрибуты In, Out, MarshalAs

Параметры могут передаваться разными способами. Правильное описание параметров определяется не только атрибутами, но и модификаторами языка C#.

Для примера рассмотрим метод ICatInformation.GetCategoryDesc. 

void ICatInformation.GetCategoryDesc([In] ref Guid rcatid, [In] uint lcid, [Out, MarshalAs(UnmanagedType.LPWStr)] out String pszDesc);
 

ПРИМЕЧАНИЕ

Данный метод можно описать в виде функции:

[return : MarshalAs(UnmanagedType.LPWStr)]

String ICatInformation.GetCategoryDesc([In] ref Guid rcatid, [In] uint lcid);

Такой синтаксис можно использовать для функций Win32API и методов COM-интерфейсов, имеющих последний параметр типа out и возвращающих HRESULT. Далее, в примерах интерфейсов и в демонстрационном приложении методы будут записываться подобным образом. Модификатор return нужен только при задании атрибута MarshalAs для методов COM-интерфейсов. 

Если посмотреть на IDL-описание этого метода, видно, что передается ссылка на CLSID (GUID), по правилам языка C# структуры передаются по значению, а Guid является именно структурой. Поэтому, чтобы правильно передать параметр в COM метод, мало задать атрибут [In], нужно еще указать ключевое слово ref для параметра rcatid. Точно также, для задания выходных параметров нужно не только задавать атрибут [Out], но и ключевое слово out. При несоблюдении этих правил возможны ошибки компиляции или, что хуже, ошибки времени выполнения.

Атрибут MarshalAs задает правила передачи параметров, наиболее часто он используется в следующих видах:

• MarshalAs(UnmanagedType.LPWStr) – Unicode-строка. Память под строку распределяется и освобождается через системные функции. 

• MarshalAs(UnmanagedType.LPArray, SizeParamIndex=n) – передается одномерный массив, размер массива задается параметром с номером n, нумерация параметров начинается с нуля.

• MarshalAs(UnmanagedType.Interface) – передается COM интерфейс.

Примеры интерфейсов

IDL

[object, uuid(0002E000-0000-0000-C000-000000000046), pointer_default(unique)]

interface IEnumGUID : IUnknown {

 HRESULT Next([in] ULONG celt,

[out, size_is(celt), length_is(*pceltFetched)] GUID *rgelt,

[out] ULONG *pceltFetched);

 HRESULT Skip([in] ULONG celt);

 HRESULT Reset;

 HRESULT Clone([out] IEnumGUID **ppenum);

Поделиться:
Популярные книги

Сын Тишайшего

Яманов Александр
1. Царь Федя
Фантастика:
попаданцы
альтернативная история
фэнтези
5.20
рейтинг книги
Сын Тишайшего

"Искажающие реальность" Компиляция. Книги 1-14

Атаманов Михаил Александрович
Искажающие реальность
Фантастика:
боевая фантастика
космическая фантастика
киберпанк
рпг
5.00
рейтинг книги
Искажающие реальность Компиляция. Книги 1-14

Школа. Первый пояс

Игнатов Михаил Павлович
2. Путь
Фантастика:
фэнтези
7.67
рейтинг книги
Школа. Первый пояс

Невеста на откуп

Белецкая Наталья
2. Невеста на откуп
Фантастика:
фэнтези
5.83
рейтинг книги
Невеста на откуп

Убивать чтобы жить 2

Бор Жорж
2. УЧЖ
Фантастика:
героическая фантастика
боевая фантастика
рпг
5.00
рейтинг книги
Убивать чтобы жить 2

Вперед в прошлое!

Ратманов Денис
1. Вперед в прошлое
Фантастика:
попаданцы
5.00
рейтинг книги
Вперед в прошлое!

Аргумент барона Бронина 4

Ковальчук Олег Валентинович
4. Аргумент барона Бронина
Фантастика:
попаданцы
аниме
сказочная фантастика
фэнтези
5.00
рейтинг книги
Аргумент барона Бронина 4

Измена. (Не)любимая жена олигарха

Лаванда Марго
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Измена. (Не)любимая жена олигарха

Измена. Право на обман

Арская Арина
2. Измены
Любовные романы:
современные любовные романы
5.00
рейтинг книги
Измена. Право на обман

Бастард Императора. Том 7

Орлов Андрей Юрьевич
7. Бастард Императора
Фантастика:
городское фэнтези
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Бастард Императора. Том 7

Жаба с кошельком

Донцова Дарья
19. Любительница частного сыска Даша Васильева
Детективы:
иронические детективы
8.26
рейтинг книги
Жаба с кошельком

Бастард Императора. Том 11

Орлов Андрей Юрьевич
11. Бастард Императора
Фантастика:
городское фэнтези
попаданцы
аниме
фэнтези
5.00
рейтинг книги
Бастард Императора. Том 11

Академия чаросвет. Тень

Ярошинская Ольга
Любовные романы:
любовно-фантастические романы
5.00
рейтинг книги
Академия чаросвет. Тень

Наследие Маозари 4

Панежин Евгений
4. Наследие Маозари
Фантастика:
фэнтези
попаданцы
5.00
рейтинг книги
Наследие Маозари 4