Архитектура Аудит Военная наука Иностранные языки Медицина Металлургия Метрология
Образование Политология Производство Психология Стандартизация Технологии


Реализация проекта СОМ-сервера на ATL



 

Библиотека активных шаблонов

 

Библиотека активных шаблонов (ATL) представляет собой основу для создания небольших СОМ-компонентов. В ATL использованы новые возможности шаблонов, добавленные в C++. Исходные тексты этой библиотеки поставляются в составе системы разработки Visual C++. Кроме того, в эту систему разработки введено множество мастеров Visual C++, что облегчает начальный этап создания ATL-проектов.

Основные возможности библиотеки ATL

Библиотека ATL обеспечивает реализацию ключевых возможностей СОМ компонентов. Выполнения многих рутинных процедур, с которыми мы столкнулись при разработке последнего примера, можно избежать за счет использования классов шаблонов ATL. Приведем далеко не полный список функций ATL. Некоторые из них будут рассмотрены в этой лекции:

· Утилита AppWizard, предназначенная для создания первичного ATL-проекта.

· Мастер объектов, используемый для добавления в проект компонентов различных типов.

· Поддержка по умолчанию основных интерфейсов COM, таких как IUnknown и IClassFactory.

· Поддержка механизма транспортировки пользовательского интерфейса.

· Поддержка базового механизма диспетчеризации (автоматизации) и двунаправленного интерфейса.

· Существенная поддержка разработки небольших элементов управления ActiveX.

· Сравнение с библиотекой базовых классов фирмы Microsoft

 

Основной задачей ATL является облегчение создания небольших СОМ-компонентов. Задача MFC — ускорение разработки больших Windows-приложений. Функции MFC и ATL несколько перекрываются, в первую очередь в области поддержки OLE и ActiveX.

Например, элементы управления ActiveX можно создавать как с помощью ATL, так и с использованием MFC. Применяя MFC и мастер элементов управления, можно создать полнофункциональный элемент управления, добавив всего несколько собственных строк программы к тем тысячам, которые предоставляет MFC. Однако при использовании этого элемента необходимо учитывать время его загрузки и выполнения. Дело в том, что главный исполняемый DLL-файл MFC имеет размер около одного мегабайта, что недопустимо в средах с узкой полосой пропускания, каковой является WWW. ATL также поддерживает элементы управления ActiveX. Однако в случае ее использования приходится самостоятельно писать большое количество программ, что нельзя сделать без знания СОМ и спецификации элементов управления ActiveX.

Это только один пример. В большинстве случаев при разработке СОМ-компонента с небольшим количеством или полным отсутствием визуальной информации вполне пригодна ATL. Если же приходится разрабатывать Windows-приложение с широкими функциями визуализации, то, вероятно, придется воспользоваться MFC. Мы высказали только общие соображения по этому вопросу и рекомендуем вам, прежде чем принимать окончательное решение, ознакомиться с обеими библиотеками.

Пример сервера

Чтобы проиллюстрировать некоторые свойства ATL, преобразуем пример сервера, написанный ранее на C++. так, чтобы в нем применились некоторые функции ATL. Для создания первоначального проекта воспользуемся утилитой ATL AppWizard пакета Visual C++.

Утилита ATL СОМ AppWizard

Утилита ATL СОМ AppWizard представляет собой мастер Visual C++, облегчающий поэтапное создание первоначального ATL-проекта (см. табл. 10). К этой утилите при создании любого проекта приходится обращаться только один раз. Как только проект создан, для добавления в него компонентов применяйте мастер объектов ATL. Запустите Visual C++ и выполните следующие действия:

 

1. Выберите пункт New... в меню File.

2. Во вкладке Projects отметьте проект ATL СОМ AppWizard.

3. Выберите подходящий каталог и назовите проект AutoSvr.

4. Щелкните на кнопке Finish.

 

Таблица 10. Файлы, создаваемые с помощью ATL AppWizard

Файл Описание
AUTOSVR.CPP Главный файл проекта. В этом файле содержатся функции поддержки, необходимые СОМ для обеспечения хранения компонентов.
AUTOSVR.IDL IDL-файл (файл описания интерфейсов) проекта. Сюда добавляются определения интерфейсов и методов. Этот файл будет обработан компилятором MIDL, после чего для проекта будет создана библиотека типов.
AUTOSVR.DEF Файл определений Windows. Содержит описание точек входа DLL. Для ЕХЕ-проектов такой файл не создается.
AUTOSVR.RC Файл ресурсов проекта.
STDAFX.H и STDAFX.CPP Определения и файлы заголовков ATL.

 

Мастер объектов ATL

Созданный с помощью ATL AppWizard каркас проекта обеспечивает только хранение компонентов, но не содержит файлы, необходимые для создания того или иного компонента. Эти файлы можно создать, обратившись к мастеру объектов ATL, вызвать который можно, выбрав пункт Add ATL Component... меню Insert Visual C++.

Имена, задаваемые в мастере объектов

В зависимости от типа выбранного объекта вам предлагается несколько диалоговых окон. При создании простого СОМ-объекта вся необходимая информация должна быть введена в двух диалоговых окнах Name и Attribute. Для более сложных объектов, таких как элементы управления ActiveX, требуется дополнительная информация.

Таблица 11. Параметры диалогового окна Name мастера объектов

Поле Описание
Short Name Данный элемент обеспечивает введение префикса для остальных элементов диалогового окна. Он непосредственно не связан ни с каким определенным атрибутом объекта. При изменении этого значения элементы оставшейся части страницы также изменятся.
Class Имя С++-класса, реализующего объект.
Файлы Н и СРР Файлы заголовков и файлы реализации.
CoClass Имя СОМ-класса, которое будет использовано внешними клиентами в качестве " типа" компонента.
Interface Имя интерфейса, который требуется создать для объекта. Рассматриваемый нами объект будет предоставлять интерфейс IMath, который мы уже описали в этой лекции.
Type Удобное для восприятия имя компонента, размещаемое в реестре. При программировании значения не имеет.
ProgID Программный идентификатор компонента. Клиенты могут его использовать для размещения и создания экземпляра компонента.

 

Атрибуты мастера объектов

Вкладка Attributes позволяет определить основные параметры хранилища компонента. Многие подробности, касающиеся почти каждого параметра, не являются предметом рассмотрения данной лекции. Дело в том, что мы не рассматривали такие вещи, как потоковые СОМ-модели и понятие СОМ-агрегации, поэтому здесь значения этих параметров принимаются по умолчанию. В табл. 12 подробно описаны все возможные параметры. После задания значений параметров щелкните на кнопке ОК, в результате для нового объекта будут созданы исходные файлы.

Таблица 12. Атрибуты мастера объектов

Поле Описание
Threading Model (потоковая модель) СОМ-компоненты могут использовать следующие потоковые модели: Простую — компонент использует только один поток. Модель изолированных потоков — объекты расположены только внутри собственных потоков. Двойную — компонент может поддерживать как изолированные потоки, так и работу с произвольным количеством потоков. Свободную — компонент поддерживает работу с произвольным количеством потоков.
Interface (интерфейс) Мы еще не рассматривали понятие двунаправленного интерфейса. Отметим, однако, что в соответствии с рекомендациями Microsoft компоненты по возможности должны его поддерживать. Двунаправленный интерфейс реализует как пользовательский, так и стандартный интерфейс автоматизации IDispatch. Это дает возможность клиенту выбирать способ доступа к функциям компонента.
Aggregation (агрегация) Агрегация представляет собой широко используемый в СОМ технический прием, позволяющий включать и использовать в компоненте функции другого компонента. Внутренний компонент должен явно поддерживать эту технологию с помощью своей реализации интерфейса IUnknown. Значение данного атрибута позволяет компоненту выбирать, поддерживать агрегацию или нет.
Support ISupportErrorInfo (поддержка для интерфейса IsupportErrorInfo) При установке данного атрибута мастер объекта добавит в проект реализацию интерфейса ISupportErrorInfo. Таким образом, будет обеспечен устойчивый механизм передачи сообщений об ошибках в системе клиент-сервер.
Support Connection Points (поддержка точек подключения) При установке данного атрибута мастер объектов добавит в проект точку подключения интерфейсов СОМ. Эта процедура будет подробно рассмотрена позже.
Free-Threaded Marshaler (потоковый транспортировщик) В проект добавляются средства транспортировки указателей интерфейсов через границы потоков.

 

Класс CComModule

Класс CComModule обеспечивает базовую поддержку создания хранилищ СОМ-объектов. Этот класс используется как в DLL-, так и ЕХЕ-реализациях. При генерации утилитой AppWizard главного файла проекта AUTOSVR.CPP в него добавляется глобальная переменная — экземпляр класса CComModule с именем _Module. Глобальные объекты создаются, как только модуль начинает выполняться.

В классе CComModule реализовано множество функций поддержки, большинство из которых обеспечивают базовую поддержку функций СОМ. Подробности можно найти в документации на ATL. Здесь мы рассмотрим только те методы, которые будут использованы в нашей реализации. Приведем файл AUTOSVR.CPP из рассматриваемого примера:

// AutoSvr.cpp: Implementation of DLL Exports. // Note: Proxy/Stub Information// To build a separate proxy/stub DLL, // run nmake -f AutoSvrps.mk in the project directory. #include " stdafx.h" #include " resource.h" #include " initguid.h" #include " AutoSvr.h" #include " AutoSvr_i.c" #include " Math.h" CComModule _Module; BEGIN_OBJECT_MAP(ObjectMap) OBJECT_ENTRY(CLSID_MathComponent, CMath)END_OBJECT_MAP() /////////////////////////////////////////////////////////////////////////////// DLL Entry Point extern " C" BOOL WINAPI DllMain(HINSTANCE hInstance, DWORD dwReason, LPVOID /*lpReserved*/){ if (dwReason == DLL_PROCESS_ATTACH) { _Module.Init(ObjectMap, hInstance); DisableThreadLibraryCalls(hInstance); } else if (dwReason == DLL_PROCESS_DETACH) _Module.Term(); return TRUE; // ok} /////////////////////////////////////////////////////////////////////////////// Used to determine whether the DLL can be unloaded by OLE STDAPI DllCanUnloadNow(void){ return (_Module.GetLockCount()==0)? S_OK: S_FALSE; } /////////////////////////////////////////////////////////////////////////////// Returns a class factory to create an object of the requested type STDAPI DllGetClassObject(REFCLSID rclsid, REFIID riid, LPVOID* ppv){ return _Module.GetClassObject(rclsid, riid, ppv); } /////////////////////////////////////////////////////////////////////////////// DllRegisterServer - Adds entries to the system registry STDAPI DllRegisterServer(void){ // registers object, typelib and all interfaces in typelib return _Module.RegisterServer(TRUE); } /////////////////////////////////////////////////////////////////////////////// DllUnregisterServer - Removes entries from the system registry STDAPI DllUnregisterServer(void){ return _Module.UnregisterServer(); }

 

Прежде всего, в этом файле глобально объявлен класс CComModule. После этого следуют макросы ATL, в которых объявляются компонентные объекты, поддерживаемые в данном программном модуле. В нашем случае используется только один такой объект — компонент Math, программа для которого была создана ранее с помощью мастера объектов ATL. Макрос BEGIN_OBJECT_MAP определяет начало массива объявлений компонентных объектов. Для каждого компонента предусмотрена соответствующая строка макроопределения OBJECT_ENTRY. Макрос OBJECT_ENTRY содержит необходимую информацию, CLSID и имя внутреннего класса, необходимые для создания экземпляра компонента с помощью функции DllGetClassObject, предоставляемой для общего пользования.

В оставшейся нерассмотренной части файла реализованы четыре точки входа, необходимые СОМ для организации хранения компонентов в DLL-файле. Функция DllCanUnloadNow использует глобальный экземпляр CComModule для определения возможности выгрузки DLL-файла. Функции DllGetClassObject, DllRegisterServer и DllUnregisterServer работают так, как описано выше. Класс CComModule помогает нам управлять этими функциями.

При создании проекта мы использовали основные функции, предоставляемые утилитой AppWizard. Для добавления класса CMath был применен мастер объектов ATL. Таким образом были созданы файлы МАТH.Н и МАТН.СРР. СРР-файл начинается следующими строками:

//

// Math.cpp: Implementation of CMath

//

 

#include " stdafx.h"

#include " AutoSvr.h"

#include " Math.h"

 

//////////////////

// CMath

//////////////////

 

Сюда осталось добавить только текст написанной нами программы. С файлом заголовков дело обстоит несколько сложнее. Мастер объектов ATL создал файл МАТН.Н в следующем виде:

/////////////////////////////////////////////////////////////////////////////

// CMath

class ATL_NO_VTABLE CMath:

public CComObjectRootEx< CComSingleThreadModel>,

public CComCoClass< CMath, & CLSID_MathComponent>,

public IDispatchImpl< IMath, & IID_IMath, & LIBID_AUTOSVRLib>

{

public:

CMath()

{

}

 

DECLARE_REGISTRY_RESOURCEID(IDR_MATH)

 

BEGIN_COM_MAP(CMath)

COM_INTERFACE_ENTRY(IMath)

COM_INTERFACE_ENTRY(IDispatch)

END_COM_MAP()

 

// IMath

public:

};

 

Подробно рассмотрим использованные здесь макросы.

Макрос ATL_NO_VTABLE

Класс CMath унаследовал свойства многих классов шаблонов ATL. Прежде чем мы рассмотрим каждый из них, обратим внимание на некоторые макросы, использованные в объявлениях заголовков. Самый первый из них фактически эквивалентен директиве _declspec (novtable), которая сообщает компилятору о том, что для класса не требуется создавать виртуальную таблицу. Таким образом, намного уменьшается объем программы его конструирования или удаления.

При использовании макроса ATL_NO_VTABLE необходимо помнить о связанных с ним многочисленных ограничениях. В основном они касаются запрета на вызов чисто виртуальных функций или функций, которые приведут к вызову чисто виртуальной функции в конструкторе либо деструкторе класса. Если вы не уверены в соблюдении этих правил для вашего класса, то можете убрать из объявления макрос ATL_NO_VTABLE, поскольку он отвечает только за уменьшение размера генерируемого кода.

Макрос DECLARE_REGISTRY_RESOURCEID

Следующим макросом в программе является DECLARE_REGISTRY_RESOURCEID. Этот макрос преобразуется в вызов компонента ATL Registry, называемого также Registrar. Компонент Registrar предоставляет простой, управляемый данными механизм обновления содержимого регистра на основе определенной информации о компонентах. Для предоставления такой информации мастер объектов ATL создает файл ComponentName.RGS (в нашем случае это файл MATH.RGS), содержащий сценарий обновления реестра. Он имеет следующий вид:

Для описания разделов реестра каждого компонента в сценарии использован специальный синтаксис БНФ (нормальная форма Бекуса—Наура). Этот сценарий хранится в файле ресурсов проекта. Таким образом, макрос DECLARE_REGISTRY_RESOURCEID разворачивается в следующие строки программы:

static HRESULT WINAPI UpdateRegistry(BOOL bRegister){ return _Module.UpdateRegistryFromResource(IDR_MATH, bRegister); }

 

В конечном итоге приведенный выше метод вызывается обеими функциями, содержащимися в файле AUTOSVR.CPP: DllRegisterServer и DllUnregisterServer. Полное рассмотрение компонента Registrar выходит за рамки этой статьи. Однако следует отметить, что для изменения информации о каком-либо компоненте в реестре требуется отредактировать соответствующий RGS-файл и заново построить проект. Он будет рассматриваться как ресурс, и тогда при регистрации компонента информация реестра обновится.

Затем в нашем примере следуют такие макросы:

BEGIN_COM_MAP(CMath) COM_INTERFACE_ENTRY(IMath) COM_INTERFACE_ENTRY(IDispatch)END_COM_MAP()

СОМ-объекты должны поддерживать саморегистрацию с помощью экспортируемых СОМ-функций DllRegisterServer и DllUnRegisterServer. В предыдущем примере обновление регистра происходило за счет REG-файла. При использовании сценария обновления регистра выполнять эту работу вручную не требуется, поскольку компонент ATL Registrar делает это за нас и, таким образом, для регистрации DLL-сервера можно воспользоваться следующей командной строкой: regsvr32.exe server.dll.

Макрос COM_INTERFACE_ENTRY

Как правило, каждый СОМ-объект поддерживает целый набор интерфейсов. Рассмотренный выше компонент Math поддерживает только два из них: IMath и IDispatch. Являющийся пользовательским для нашего компонента интерфейс IMath уже встречался выше, а IDispatch еще не рассматривался. С помощью этого интерфейса осуществляется поддержка для компонента механизма автоматизации, что делает использование данного компонента более удобным.

В любом случае макросы BEGIN_COM_MAP и END_COM_MAP создают таблицу интерфейсов, доступ к которой в компоненте осуществляется через интерфейс QueryInterface. Каждый интерфейс описывается с помощью макроса COM_INTERFACE_ENTRY. В простом примере, рассматриваемом сейчас, используются только два интерфейса.

Таким образом, мы рассмотрели макросы, используемые в файле заголовков. Теперь обратимся собственно к определению класса:

class ATL_NO_VTABLE CMath: public CComObjectRootEx< CComSingleThreadModel>, public CComCoClass< CMath, & CLSID_MathComponent>, public IDispatchImpl< IMath, & IID_IMath, & LIBID_AUTOSVRLib> {public: CMath() { } // IMathpublic: };

 

Класс CComObjectRootEx

Каждый класс, который является еще и СОМ-объектом, должен быть производным по отношению к одному из классов CComObjectRoot. Класс CComObjectRoot отвечает за подсчет обращений к компоненту. Из предыдущего фрагмента программы ясно, что поддержка интерфейса IUnknown обеспечивается путем наследования его от класса CComObjectRootEx.

Одним из наилучших источников информации об ATL является сама исходная программа, Такие библиотеки шаблонов, как ATL, поставляются с исходными текстами программ. Их можно найти в каталоге \DevStudio\VC\ ATL\Include.

Класс CComCoClass

Класс CMath также является производным от класса CComCoClass. Класс CComCoClass предоставляет рассматриваемому компоненту фабрику классов, а также основные методы, необходимые для получения CLSID и специфичной для компонента информации об ошибках. При разворачивании шаблона получим примерно следующее:

template < class T, const CLSID* pclsid = & CLSID_NULL> class CComCoClass{public: DECLARE_CLASSFACTORY() DECLARE_AGGREGATABLE(T) typedef T _CoClassstatic const CLSID& WINAPI GetObjectCLSID() {return *pclsid; } static LPCTSTR WINAPI GetObjectDescription() {return NULL; } static HRESULT WINAPI Error(LPCOLESTR lpszDesc, const IID& iid = GUID_NULL, HRESULT hRes = 0){ return AtlReportError(GetObjectCLSID(), lpszDesc, iid, hRes); }...};

 

Следует отметить, что класс CComCoClass предоставляет компоненту фабрику классов посредством макроса DECLARE_CLASSFACTORY. Этот макрос разворачивается, формируя класс, содержащий экземпляр одного из классов CComClassFactory. Остальные методы класса CComCoClass в основном отвечают за сообщения об ошибках.

Класс CComClassFactory

Большинство компонентов, использующих ATL, получают фабрику классов с помощью класса CComCoClass. Класс CComClassFactory предоставляет два стандартных метода фабрики классов: CreateInstance и LockServer. Несмотря на простоту реализации, класс CComClassFactory дает возможность не использовать всю программу фабрики классов, как это делалось в предыдущем примере. Взгляните на шаблон класса:

class CComClassFactory: public IClassFactory, public CComObjectRootEx< CComGlobalsThreadModel> { public: BEGIN_COM_MAP(CComClassFactory)COM_INTERFACE_ENTRY(IClassFactory) END_COM_MAP()// IClassFactory STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter, REFIID riid, void** ppvObj); STDMETHOD(LockServer)(BOOL fLock); …};

 

Помните, фабрика классов сама по себе является СОМ-объектом, производным от класса CComObjectRootEx.

Класс IDispatchImp

Последним классом, который использовался в данном примере, является IDispatchImp. Его задачей было обеспечение для компонента реализации интерфейса IDispatch. Компонент содержит двунаправленный интерфейс, состоящий из пользовательского интерфейса (как в рассмотренном выше примере) и из полной реализации интерфейса OLE-автоматизации IDispatch. Для обеспечения работоспособности интерфейса IDispatch необходимо, чтобы в сервере были реализованы четыре метода: GetIDsOfNames, GetTypeInfCount, GetTypeInfo и Invoke. Однако благодаря ATL нам остается реализовать только собственные методы интерфейса IMath.

Интерфейс IDispatch

Автоматизация представляет собой стандартный механизм, позволяющий осуществлять независимое от языка взаимодействие программных модулей. Чтобы обеспечить независимость от языка, большинство СОМ-компонентов поддерживают автоматизацию как механизм предоставления своих функциональных возможностей.

В основе автоматизации лежит СОМ-интерфейс IDispatch, обеспечивающий предоставление набора методов, позволяющих приложению клиента осуществлять динамический доступ к серверу автоматизации. Процедура динамического вызова процесса несколько отличается от СОМ-технологии вызова интерфейса виртуальных таблиц, использованного в примере компонента Math.

При использовании интерфейса виртуальных таблиц приложению клиента в ходе компиляции требуются сведения о состоянии интерфейса компонента, которые предоставляются либо через библиотеку типов, либо путем включения объявления интерфейса компонента в препроцессорную часть программы (например, в файл IMATH.H). Таким образом, реализуется раннее связывание интерфейса компонента.

Компонент, реализующий свои методы с помощью интерфейса IDispatch, отличается от пользовательского тем, что предоставляет много дополнительных возможностей. Взаимодействие между приложениями клиента и сервера может осуществляться с помощью позднего связывания методов интерфейса компонента. В этом случае клиенту не требуются объявления интерфейса сервера и т.п.

Таким образом, серверный компонент может легко изменить свой интерфейс (даже во время выполнения! ) без необходимости перекомпиляции или перекомпоновки приложения клиента. Конечно, при изменении интерфейса сервера должен быть предусмотрен некоторый способ общения этого сервера с клиентом, чтобы последний смог воспользоваться новым интерфейсом.

Другой замечательной особенностью интерфейса IDispatch является стандартный способ транспортировки. Реализация СОМ по умолчанию, обеспечиваемая средой Windows, содержит набор типов данных, который может быть использован компонентами, применяющими интерфейс IDispatch. Внутренняя поддержка этих типов данных упрощает подключение как локальных, так и удаленных компонентов.

Большинство СОМ-интерфейсов похожи на построенный нами в примере интерфейс IMath. Они всегда определяются так, чтобы на основе информации о них можно было точно описать соответствующий абстрактный класс. В СОМ абстрактный класс определен всегда (как интерфейс), а задачей разработчика является обеспечение его конкретной реализации. Интерфейс IDispatch имеет в этом смысле некоторые отличия, поскольку он придает рассматривавшимся до сих пор интерфейсам с виртуальными таблицами определенную " произвольность". Для описания интерфейса рассматриваемого типа используется модификатор dispinterface. Данный модификатор указывает на отличие такого интерфейса от стандартного (с виртуальными таблицами). Теперь клиент не получает доступ к функциональным возможностям компонента посредством указателя на виртуальную таблицу, как это было в примере с IMath, а вначале должен " подыскать" требуемую функцию, определить для нее некий внутренний идентификатор и, наконец, вызвать (выполнить) ее. На рис. 4 отображена суть этого процесса.

 

Рис. 4. Виртуальная таблица IDispatch и таблица Dispatch

 

Как видно из рисунка, интерфейс IDispatch выполняет достаточно много работы. Клиент все еще получает доступ к указателю на виртуальную таблицу, но теперь через нее уже нельзя получить прямой доступ к методам интерфейса IMath, а нужно сначала запросить функцию IDispatch:: Invoke(). Связь вызова с определенным методом осуществляется через параметры метода Invoke(). Такой косвенный вызов обеспечивает механизм позднего связывания методов компонента. В таблице 13 описаны четыре метода интерфейса IDispatch.

Таблица 13. Методы интерфейса IDispatch

Метод Описание
Invoke() Обеспечивает большую часть функциональных возможностей интерфейса IDispatch. Имеет восемь параметров, наиболее важным из которых является DISPID. DISPID связан с определенным смещением в таблице диспетчеризации и задает, какой метод компонентного объекта будет вызван.
GetIDsOfNames() Обеспечивает контроллер возможностью связывать текстовое свойство сервера или имя метода, типа " Multiply", с численным параметром DISPID, который затем может быть использован в функции Invoke() для получения доступа к свойству или методу сервера.
GetTypeInfo() Контроллер, обеспечивающий динамический поиск и вызов методов автоматизации, обычно не обладает всей информацией о типах, необходимой для формирования значений параметров метода Invoke. Серверу автоматизации необходимо вызвать метод GetTypeInfoCount() для определения возможности получения от компонента информации о типах и, если это, возможно, вызвать затем метод GetTypeInfo() для получения указанной информации.
GetTypeInfoCount() Используется контроллером для выяснения, содержит ли компонентный объект необходимую контроллеру информацию о типах. Значение единица переданного параметра означает, что информация о типах доступна, а значение нуль — что недоступна.

 

Двунаправленный интерфейс

Мы уже получили некоторые отрывочные знания, необходимые для понимания того, что такое двунаправленный интерфейс. Двунаправленный интерфейс реализуется серверным компонентом и предоставляет приложению клиента два различных способа доступа к своим функциональным возможностям. Он сочетает в себе интерфейс виртуальной таблицы (например, IMath) с интерфейсом IDispatch. Таким образом, клиент может выбирать, какой из интерфейсов ему, более удобен.

На рис. 5 показано, как будет выглядеть схема компонента Math с двунаправленным интерфейсом. Последний представляет собой сочетание пользовательского интерфейса IMath, реализованного через виртуальную таблицу, и интерфейса IDispatch, реализованного с помощью ATL. Методы компонента Math доступны непосредственно через виртуальную таблицу, а также через IDispatch.

Рис. 5. Схема компонента Math с двунаправленным интерфейсом

 

Возникает вопрос: для чего нужно предоставлять два интерфейса, выполняющих практически одни и те же функции? Прежде всего, из соображений эффективности. Если сервер реализован как внутризадачный (DLL-файл), то не требуется никакой транспортировки. Клиент может напрямую связаться с методами пользовательского интерфейса сервера и быстро произвести все необходимые вызовы. Эффективность этого метода сравнима с прямым связыванием функций С или С++.

Однако если клиенту требуется позднее связывание, то он может обратиться к реализации IDispatch. Такое обращение, конечно, происходит медленнее, поскольку большая часть работы производится во время выполнения, а не компиляции, но во многих случаях позднее связывание предпочтительнее. Ниже мы еще раз вернемся к технологиям связывания.


Поделиться:



Популярное:

Последнее изменение этой страницы: 2016-04-11; Просмотров: 1243; Нарушение авторского права страницы


lektsia.com 2007 - 2024 год. Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав! (0.059 с.)
Главная | Случайная страница | Обратная связь