MIDL (Microsoft Interface Definition Language)
Последнее изменение этой страницы: 20:05, 1 июня 2016.
Парадигма | мультипарадигменный: рефлексивно-ориентированный, объектно-ориентированный, императивный, скриптовый |
---|---|
Спроектировано | Microsoft Corporation |
Печать дисциплины | статическая, слабая |
Портал: | msdn.microsoft.com |
Под влиянием | |
C, С++ |
Microsoft Interface Definition Language (MIDL) определяет интерфейсы между клиентскими и серверными программами. Microsoft включает компилятор MIDL в комплект средств Software Development Kit (SDK), что позволяет разработчикам создавать файлы языка описания интерфейсов (IDL) и файлы конфигурации приложения (ACF), необходимые для удаленного вызова процедур (RPC) интерфейсов и COM/DCOM интерфейсов.
Содержание
- 1 Области применения
- 2 Необходимые навыки для использования MIDL
- 3 Интерфейс в распределённых объектах
- 4 Interface Definition (IDL) File
- 5 Пример IDL файла
- 6 Компиляция MIDL
- 7 Параметры компиляции MIDL
- 8 Загрузка и регистрация типа библиотека
- 9 Сборка и регистрация прокси DLL
- 10 Ручная регистрация прокси DLL
- 11 Литература
Области применения
MIDL может быть использован во всех клиент-серверных приложениях, написанных для операционных систем семейства Windows. Он также может применяться для создания клиентских и серверных программ для гетерогенных сетевых сред, включающих такие операционные системы, как Unix и Apple. Для взаимодействия Microsoft поддерживает стандарт Open Group (ранее известный как Фонд открытого программного обеспечения) DCE RPC.
Необходимые навыки для использования MIDL
При использовании MIDL с RPC, требуется знакомство с языком программирования C/C++ и знание RPC парадигмы. При использовании MIDL с COM (англ. Component Object Model — объектная модель компонентов), необходимо понимание как C++ и RPC применяются в COM, или, в качестве альтернативы, требуется опыт работы с OLE Automation моделью сценариев и типом библиотек.
Интерфейс в распределённых объектах
В распределенных вычислительных системах, интерфейс представляет собой набор определений и удаленных функций, который позволяет двум и более программам взаимодействовать различными способами. В приложении RPC, интерфейс определяет:* Как клиентские и серверные приложения идентифицируют себя.
- Как данные передаются между клиентом и сервером.
- Удаленные процедуры, которые могут обратиться к клиентскому приложению.
- Типы данных для параметров и возвращаемых значений удаленных процедур.
Microsoft Interface Definition Language (MIDL) служит для реализации интерфейсов, используемых в распределенных приложениях. С MIDL, приложение может иметь один или несколько интерфейсов. Каждый интерфейс определяет уникальный распределенный протокол между программами клиента и сервера. Приложения, основанные на удаленных вызовов процедур (RPC), Component Object Model (COM), и Distributed Component Object Model (DCOM) указывают свои интерфейсы, используя MIDL.
Interface Definition (IDL) File
Файл, который содержит в себе интерфейс и определения библиотек, называется файлом IDL, и имеет IDL-расширение. На практике, компилятор MIDL будет разбирать файл описания интерфейса, независимо от его расширения. Интерфейс идентифицируется набором ключевых слов. Каждый интерфейс состоит из заголовка и тела. Заголовок содержит атрибуты, которые применяются ко всему интерфейсу. Тело содержит оставшиеся определения интерфейса.
Пример IDL файла
Example.idl
В примере файла IDL определяется два COM интерфейса. Из этого IDL файла, утилита Midl.exe будет генерировать прокси/заглушки, файлы заголовков и проводить маршалинг кода.
//
// Example.idl
//
import "mydefs.h","unknwn.idl";
[
object,
uuid(a03d1420-b1ec-11d0-8c3a-00c04fc31d2f),
] interface IFace1 : IUnknown
{
HRESULT MethodA([in] short Bread, [out] BKFST * pBToast);
HRESULT MethodB([in, out] BKFST * pBPoptart);
};[
object,
uuid(a03d1421-b1ec-11d0-8c3a-00c04fc31d2f),
pointer_default(unique)
] interface IFace2 : IUnknown
{
HRESULT MethodC([in] long Max,
[in, max_is(Max)] BkfstStuff[ ],
[out] long * pSize,
[out, size_is( , *pSize)] BKFST ** ppBKFST);
};
Директива IDL import используется, чтобы подключить файл заголовка, Mydefs.h, который содержит пользовательские типы, и Unknwn.idl, содержащий определение IUnknown, от которого наследуются IFace1 и IFace2.
Атрибут object идентифицирует интерфейс в качестве объекта интерфейса и сообщает компилятору о необходимости сгенерировать код MIDL прокси/заглушек вместо RPC на клиенте и серверных заглушек. Методы интерфейса должны возвращать тип HRESULT, чтобы позволить основному механизму RPC сообщить об ошибках при вызове методов, которые не получилось завершить из-за проблем с сетью.
Использование uuid атрибута определяет идентификатор интерфейса (IID). Каждый интерфейс, класс и тип библиотеки должны быть идентифицированы собственным уникальным идентификатором. Для генерации набора с уникальными идентификаторами для интерфейсов и других компонентов используется утилита Uuidgen.exe.
Ключевое слово interface определяет имя интерфейса. Все объекты должны быть производными, прямо или косвенно, от IUnknown.
Параметр in определяет передаваемое значение, устанавливаемое вызывающим методом. Параметр out определяет данные, которые будут переданы обратно. Использование обоих атрибутов для одного параметра указывает, что он используется как для отправки данных и для их передачи назад вызывающей стороне.
Атрибут pointer_default определяет тип указателя по умолчанию (unique, ref, or ptr) для всех указателей кроме тех, что включенны в списки параметров. Если тип по умолчанию не задан, MIDL предполагает, что отдельные указатели являются unique. Тем не менее, если у вас есть несколько уровней указателей, вы должны явно указать тип указателя по умолчанию, даже если вы хотите, чтобы тип был unique.
В предыдущем примере, массив BkfstStuff[] является динамически расширяемым массивом, размер которого определяется во время выполнения программы. Атрибут max_is определяет переменную, содержащую максимальное значение индекса массива.
Атрибут size_is также используется, чтобы указать размер массива, или, как в предыдущем примере, несколько уровней указателей. В примере, вызов может быть сделан, несмотря на то, что заранее может быть не известно, сколько данных будет возвращено.
Example2.idl
Следующий пример IDL (который повторно использует интерфейсы, описанные в предыдущем примере IDL) показывает различные способы получения типов информационных библиотек для интерфейсов.
//
// Example2.idl
//
import "example.idl","oaidl.idl";
[
uuid(a03d1422-b1ec-11d0-8c3a-00c04fc31d2f),
helpstring("IFace3 interface"),
pointer_default(unique);
dual,
oleautomation
]
interface IFace3 : IDispatch
{
HRESULT MethodD([in] BSTR OrderIn,
[out, retval] * pTakeOut);
}; //end IFace3 def
[
uuid(a03d1423-b1ec-11d0-8c3a-00c04fc31d2f),
version(1.0),
helpstring("Example Type Library"),
] library ExampleLib
{
importlib("stdole32.tlb");
interface IFace3;
[
uuid(a03d1424-b1ec-11d0-8c3a-00c04fc31d2f),
helpstring("Breakfast Component Class")
] coclass BkfstComponent
{
[default]interface IFace1;
interfaceIFace2
}; //end coclass def
[
uuid(a03d1424-b1ec-11d0-8c3a-00c04fc31d2f),
helpstring("IFace4 interface"),
pointer_default(unique);
dual,
oleautomation
]
interface IFace4 : IDispatch
{
[propput] HRESULT MethodD([in] BSTR OrderIn);
[propget] HRESULT MethodE([out, retval] * pTakeOut);
}; //end IFace4 def}; //end library def
Атрибут helpstring является обязательным; вы используете его для краткого описания объекта или предоставления строки состояния. Это помогает строкам быть читаемым из объекта браузера, например, из того, который предоставляет Microsoft Visual Basic.
Атрибут dual на IFace3 создает интерфейс, который является одновременно интерфейсом доставки и интерфейсом COM Поскольку он является производным от IDispatch. Двойной интерфейс поддерживает автоматизацию, что определяет атрибут oleautomation. IFace3 импортирует oaidl.idl, чтобы получить определение IDispatch.
Оператор library определяет библиотеку типов ExampleLib, которая имеет свои собственные атрибуты uuid, helpstring, и version.
В определении типа библиотека, директива importlib импортирует составленный тип библиотеки. Все определения типа библиотека должны быть внесены в библиотеку базового типа, определенную в Stdole32.tlb.
Предложенное определение типа библиотека демонстрирует три различных пути включения интерфейсов. IFace3 подключается лишь путем обращения его к объявлению библиотеки.
Оператор coclass определяет совершенно новый класс компонента, BkfstComponent, который включает в себя два ранее определенных интерфейса, IFace1 и IFace2. Атрибут default определяет IFace1 как интерфейс по умолчанию.
IFace4 описывается в операторе library. Атрибут propput на MethodD показывает, что метод выполняет определенное действие со свойством с тем же именем. Атрибут propget указывает, что метод извлекает информацию из свойства с тем же именем, что и метод. Атрибут retval в MethodD обозначает выходной параметр, который содержит возвращаемое значение функции.
Компиляция MIDL
Используя IDL файл, например Example2.idl, который определяет один или несколько COM интерфейсов и типов библиотек, компилятор MIDL (Midl.exe) генерирует файлы, описанные в следующей таблице в качестве вывода по умолчанию.
Имя файла | Описание |
---|---|
Example2.h | Файл заголовка, содержащий определения типа и объявления функций для всех интерфейсов, определенных в файле IDL, а также опережающее объявление для подпрограмм, вызывающих заглушки. |
Example2_p.c | Прокси/заглушка файл, который включает в себя суррогатные точки входа и для клиентов, и для серверов. |
Example2_i.c | Файл идентификатор интерфейса, который определяет идентификатор GUID для каждого интерфейса, указанного в файле IDL. |
Example2.tlb | Файл, который содержит информацию о типах и объектах. |
Dlldata.c | Содержит данные, необходимые для создания DLL прокси/заглушки. |
Вы можете использовать файл заголовка и все .c файлы для создания DLL прокси, который может поддерживать интерфейс, используемый как клиентскими приложениями, так и объектами серверов. Вы можете использовать файл заголовка интерфейса (Example2.h) и файл идентификатор интерфейса (Example2_i.c) при создании исполняемого файла для клиентского приложения, использующего интерфейс. Вы можете включить файл типа библиотека в качестве ресурса в ваш EXE или DLL, или вы можете отправить его в виде отдельного файла.
Параметры компиляции MIDL
Вы можете использовать следующие параметры командной строки, чтобы переопределить некоторые значения по умолчанию компилятора MIDL и выбрать оптимизацию подходящую для вашего приложения.
Параметр | Описание |
---|---|
/acf | Используется для явной подачи ACF файла. Этот переключатель также позволяет использовать различные имена интерфейсов в файлах IDL и ACF. |
/dlldata | Определяет имя файла для генерируемого файла данных DLL для DLL прокси. Имя файла по умолчанию Dlldata.c. |
/env | Указывает MIDL генерировать заглушки или тип библиотека для целевой среды. |
/header, /h | Задает имя файла заголовка интерфейса. По умолчанию именем является то, что лежит в IDL файле с расширением .h. |
/iid | Определяет файл идентификатор интерфейса, который перекрывает файл идентификатор интерфейса по умолчанию в интерфейсе для COM. |
/lcid | Обеспечивает полную поддержку DBCS, так что вы можете использовать международные символы в свои входных файлах, именах файлов и путей к каталогам. |
/no_format_opt | По умолчанию, чтобы уменьшить размер кода, MIDL устраняет дубликаты дескрипторов. Этот переключатель отключает эту возможность оптимизации. |
/Oi, /Oic, /Oif | Указывает MIDL использовать полностью интерпретированный метод маршалинга. /Oic и /Oicf коммутаторы обеспечивают дополнительные улучшения производительности. |
/out | Определяет каталог, в который компилятор MIDL запишет выходные файлы. Каталог вывода может быть указан буквой имени диска, абсолютным именем пути, или и тем и другим. По умолчанию, MIDL выводит файлы в текущий каталог. |
/proxy | Определяет имя прокси-файла интерфейса для интерфейса COM. По умолчанию используется имя файла IDL плюс "_p.c". |
/tlb | Определяет имя файла типа библиотека. По умолчанию используется имя файла IDL, с .tlb расширением. |
Загрузка и регистрация типа библиотека
Автоматическая динамическая ссылочная библиотека, Oleaut32.dll, предоставляет несколько функций, которые можно вызывать для загрузки и регистрации файлов типа библиотека. Вызов LoadTypeLibEx, как показано в следующем примере, и загружает библиотеку, и создает записи в реестре.
Пример
ITypeLib *pTypeLib;
HRESULT hr;
hr = LoadTypeLibEx("example.tlb", REGKIND_REGISTER, &pTypeLib);
if(SUCCEEDED(hr))
{
pTypeLib->Release();
} else {
exit(0); // Handle errors here.
}
Сборка и регистрация прокси DLL
Если вы выбрали прокси/заглушка для маршалинга вашего приложения, то .c и .h файлы, которые MIDL сгенерирует должны быть скомпилированы и слинкованы так, чтобы создать прокси DLL, и DLL должен быть отражён в системном реестре, чтобы клиенты могли найти свои интерфейсы. MIDL-сгенерированный файл Dlldata.c содержит необходимые процедуры и другую информацию для создания и регистрации прокси/заглушка DLL.
Первым шагом в построении DLL является написание файла определения модуля для линкера, как показано в следующем примере:
LIBRARY example.dll
DESCRIPTION 'generic proxy/stub DLL'
EXPORTS DllGetClassObject @1 PRIVATE
DllCanUnloadNow @2 PRIVATE
DllRegisterServer @4 PRIVATE
DllUnregisterServer @5 PRIVATE
В качестве альтернативы, вы можете указать эти экспортируемые функции в LINK в командной строке вашего Makefile.
Экспортируемые функции, объявленные в Rpcproxy.h, которая включает в себя Dlldata.c и реализацию по умолчанию, являются частью библиотеки RPC run-time. COM использует эти функции, чтобы создать фабрику классов, разгрузить библиотеки DLL (убедившись, что не существует ни одного объекта или lock элемента), получить информацию о прокси-DLL и самостоятельно зарегистрироваться и отменить регистрацию DLL-прокси. Чтобы воспользоваться этими функциями, вы должны ссылаться на Cpreprocessor / D (или -D) опция, когда вы компилируете файлы Dlldata.c и Example_p.c, как показано в следующем Makefile:
example.h example.tlb example_p.c example_i.c dlldata.c : example.idl
midl example.idl
dlldata.obj : dlldata.c
CL /c /DWIN32 /DREGISTER_PROXY_DLL dlldata.c
example.obj : example_p.c
CL /c /DWIN32 /DREGISTER_PROXY_DLL example_p.c
iids.obj : example_i.c
PROXYSTUBOBJS = dlldata.obj example.obj iids.obj
PROXYSTUBLIBS = kernel32.lib rpcndr.lib rpcns4.lib rpcrt4.lib uuid.lib
proxy.dll : $(PROXYSTUBOBJX) example.def
link /dll /out:proxy.dll /def:example.def
$(PROXYSTUBOBJS) $(ORIXYSTUBLIBS)
regsvr32 /s proxy.dll
Если вы не укажете эти определения препроцессора во время компиляции, эти функции не определятся автоматически. (То есть, макросы в Rpcproxy.c ничего не расширят) Тогда вы должны определить их явно в другом исходном файле, модуль которого будет также включен в окончательную линковку и компиляцию в командной строке компилятора C.
Когда определяется REGISTER_PROXY_DLL, Rpcproxy.h обеспечивает дополнительное условное управление компиляции с PROXY_CLSID = GUID, PROXY_CLSID_IS = явное значение GUID, и ENTRY_PREFIX = префикс строки.
Ручная регистрация прокси DLL
Если по какой-то причине вы не можете использовать прокси-процедуры по умолчанию для регистрации заглушек, вы можете вручную зарегистрировать библиотеку DLL, добавив следующие записи в системный реестр, используя Regedt32.exe.
HKEY_CLASSES_ROOT
Interface
iid
(Default) = ICustomInterfaceName
ProxyStubClsid32 = {clsid}
HKEY_CLASSES_ROOT
CLSID
clsid
(Default) = ICustomInterfaceName_PSFactory
InprocServer32 = proxstub.dll
Литература
- Microsoft Interface Definition Language
- Interface Definition (IDL) File
- Anatomy of an IDL File
- MIDL Compilation
- MIDL Compiler Options
- Loading and Registering a Type Library
- Building and Registering a Proxy DLL
Автор статьи: Желудков А.В.
ISSN 2542-0356
Следуй за Полисом
Оставайся в курсе последних событий
Лицензия
Если не указано иное, содержание этой страницы доступно по лицензии Creative Commons «Attribution-NonCommercial-NoDerivatives» 4.0, а примеры кода – по лицензии Apache 2.0. Подробнее см. Условия использования.