16+
ComputerPrice
НА ГЛАВНУЮ СТАТЬИ НОВОСТИ О НАС




Яндекс цитирования


Версия для печати

Модуль поиска не установлен.

Технология COM

16.09.2003

Тульчинский Антон, antontul@rambler.ru


Введение

COM (Component Object Model) - это метод разработки программных компонентов, небольших двоичных исполняемых файлов, которые предоставляют необходимые сервисы приложениям, операционным системам и другим компонентам. Другими словами, COM определяет стандартный механизм, с помощью которого одна часть программного обеспечения предоставляет свои сервисы другой независимо от способа их реализации.

COM - это не язык программирования, а подход (спецификация) к созданию программ, обеспечивающий взаимодействие программ любых типов. Компоненты COM объединяются друг с другом для создания приложений или систем компонентов. Компоненты можно менять во время выполнения, без перекомпиляции или перекомпоновки приложения. COM - это основа, на которой построены такие технологии Microsoft, как ActiveX, DirectX и OLE.

Таким образом, ключевое слово при использовании COM - компонент. К компонентам обычно предъявляются следующие требования:

1. Компонент должен скрывать используемый язык программирования.

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

3. Должна быть возможность модернизировать компоненты, не затрагивая уже существующих пользователей. Новые версии компонента должны работать как со старыми, так и с новыми клиентами.

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

Как вы, вероятно, догадались, компоненты COM удовлетворяют всем этим требованиям.

Преимущества использования компонентов

COM обеспечивает создание распределенных модульных систем в архитектуре "клиент-сервер". COM имеет следующие преимущества по сравнению с традиционной архитектурой программных систем:

1. COM предоставляет стандартный набор функций для доступа к провайдеру сервиса (COM-серверу), получения информации о предоставляемых им сервисах и вызова требуемого сервиса. В качестве COM-сервера может выступать операционная система или приложение.

2. COM использует объектно-ориентированные концепции для обеспечения модульности при построении сложных распределенных систем, а также для повторного использования готовых компонентов и их разработки с сохранением совместимости с предыдущими версиями.

3. COM реализует модель вычислений "клиент-сервер", что обеспечивает преимущества распределенной обработки данных.

4. COM обеспечивает вызов сервисов в сетевом окружении, независимо от расположения COM-сервера.

Использование программных компонентов, разработанных на основе технологии COM, значительно расширяет возможности разработчиков приложений, конечных пользователей и предприятий:

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

2. Конечные пользователи получают широкий выбор готовых стандартизированных программных компонентов, которые они могут использовать в своих системах.

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

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

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

Библиотеки компонентов. Одна из самых многообещающих сторон внедрения компонентной архитектуры - быстрая разработка приложений. Компоненты, помещенные в библиотеку, можно использовать как детали вашего нового приложения.

Распределенные компоненты. С возрастанием производительности и общего значения сетей потребность в приложениях, состоящих из разбросанных по разным местам кусков, будет только повышаться. Компонентная архитектура помогает упростить процесс разработки подобных распределенных приложений. Создать из обычного приложения распределенное легче, если это обычное приложение состоит из компонентов.

СОМ и объектно-ориентированный подход

СОМ является объектно-ориентированной технологией, но она отличается от других объектно-ориентированных технологий:

- СОМ-объект поддерживает более одного интерфейса

- Класс в СОМ понимается как описание конкретной реализации набора интерфейсов

- СОМ-объекты поддерживают только наследование интерфейса, т.е. потомок должен самостоятельно определить код методов родителя.

Понятие OLE и ActiveX

OLE (Object Linking and Embedding) - технология создания составных документов связыванием и внедрением. Документ сервера может быть либо связан, либо внедрен в документ контейнера. Методы создания составных документов: копирование и вставка через буфер обмена либо метод drag-and-drop.

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

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

Интерфейсы СОМ-объекта

Интерфейс СОМ предназначен для связи между компонентами и включает в себя набор функций, которые реализуются компонентами и используются клиентами. Свойства СОМ-интерфейса такие: у каждого интерфейса имеется два идентификатора (пользовательский идентификатор и глобальный уникальный идентификатор); интерфейсы после своего опубликования не могут быть изменены; добавление новой функциональности требует определения нового интерфейса; для интерфейса определен стандартный двоичный формат; каждый интерфейс наследует стандартный интерфейс IUnknown; СОМ-объект может описывать свои интерфейсы на любом языке.

Назначение интерфейса Iunknown - запрос указателя на другой интерфейс и отслеживание текущего количества клиентов СОМ-объекта. Описание же интерфейса Iunkown выглядит следующим образом:

#define interface struct
interface IUnknown
{
virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv)=0;
// запрос интерфейса
virtual ULONG __stdcall AddRef()=0; // увеличение счетчика ссылок
virtual ULONG __stdcall Release()=0; // уменьшение счетчика ссылок
};

Глобальный уникальный идентификатор

GUID(Globally Unique IDentifier) или UUID(Universally Unique Identifiers) - это 16-байтовая величина, которая генерируется специальной программной утилитой UUIDGEN.EXE или GUIDGEN.EXE. Любой GUID уникален во времени и пространстве. Он включает в себя время (60 бит - число 100-наносекундных интервалов, прошедших с 00:00:00:00 15 октября 1582 года) и адрес сетевой платы (48 бит). Например:

// {B32093E0-CC12-11d2-BD11-00AA00264239}
static const IID IID_IA =
{ 0xb32093e0, 0xcc12, 0x11d2, { 0xbd, 0x11, 0x0, 0xaa, 0x0, 0x26, 0x42, 0x39 } };

Описание интерфейса на С++ будет таким:

interface IА : IUnknown
{
virtual void __stdcall Fx() =0;
};

Ключевое слово _stdcall указывает, что функция с фиксированным числом аргументов в СОМ-интерфейсах использует вызов в стиле Pascal.

QueryInterface

IUnknown содержит функцию - QueryInterface, при помощи которой клиент определяет, поддерживается ли тот или иной интерфейс. QueryInterface возвращает указатель на интерфейс, если компонент его поддерживает; в противном случае возвращается код ошибки (клиент может запросить указатель на другой интерфейс или аккуратно выгрузить компонент).

У QueryInterface два параметра :

Virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);

Первый параметр - идентификатор интерфейса, так называемая IID-структура.

Второй параметр - адрес, по которому QueryInterface помещает указатель на искомый нтерфейс.

QueryInterface возвращает HRESULT (32-разрядный код результата, записанный в определенном формате). QueryInterface может возвратить либо S_OK, либо E_NOINTERFACE. Клиент не должен прямо сравнивать возвращаемое QueryInterface значение с этими константами; для проверки надо использовать макросы SUCCEEDED или FAILED.

Предположим, что у нас есть указатель на IUnknown, pI. Чтобы определить, можно ли использовать некоторый другой интерфейс, мы вызываем QueryInterface, передавая ей идентификатор нужного нам интерфейса. Если QueryInterface отработала успешно, мы можем пользоваться указателем:

void foo(IUnknown* pI)
{
// Определить указатель на интерфейс IX* pIX = NULL;
// Запросить интерфейс IX
HRESULT hr = pI->QueryInterface(IID_IX, (void**)&pIX);
// Проверить значение результата if (SUCCEEDED(hr))
{
// Использовать интерфейс pIX->Fx();
}
}

В этом фрагменте кода мы запрашиваем у pI интерфейс, идентифицируемый с помощью IID_IX. Определение IID_IX содержится в заголовочном файле, предоставляемом компонентом (или извлекается из библиотеки типа). Для неудачного запроса

QueryInterface должна устанавливать возвращаемый указатель в NULL. Однако, поскольку QueryInterface реализуется программистом компонента, в некоторых реализациях это наверняка не будет сделано. Для безопасности следует установить указатель в NULL самостоятельно. Ниже приведен пример реализации QueryInterface:

HRESULT __stdcall QueryInterface(const IID& iid, void** ppv)
{
if (iid == IID_IUnknown)
{ // Клиент запрашивает интерфейс IUnknown.
*ppv = (*IX)this;
}
else if (iid == IID_IX)
{ // Клиент запрашивает интерфейс IX
*ppv = (*IX)this;
}
else if (iid == IID_IY)
{ // Клиент запрашивает интерфейс IY
*ppv = (*IY)this;
}
else
{ // Нет других интерфейсов
*ppv=NULL;
return E_NOINTERFACE;
}
(IUnknown*)(*ppv)->AddRef(); // Увеличение счетчика ссылок
return S_OK;
}

Тип данных HRESULT

QueryInterface и многие другие функции COM возвращают HRESULT. Что это? HRESULT - это 32-разрядное число, разбитое на три секции: источник ошибки (биты с 16 по 30), код ошибки (биты с 0 по 15) и признак ошибки (31 бит, 0 означает, что ошибки нет).

Коды возврата бывают такие:

- S_OK или NOERROR - функция отработала успешно, значение 0

- S_FALSE - функция отработала успешно, значение 1

- E_UNEXPECTED - неожиданная ошибка

- E_NOTIMPL - функция не реализована

- E_NOINTERFACE - объект не поддерживает интерфейс

- E_OUTOFMEMORY - объект не может выделить память

- E_FAIL - ошибка по неуказанной причине

А источники ошибки такие:

- FACLITY_WINDOWS 8

- FACLITY_STORAGE 3

- FACLITY_SSPI 9

- FACLITY_RPC 1

- FACLITY_Win32 7

- FACLITY_CONTROL 10

- FACLITY_DISPATCH 2

Макросы STDMETHOD и STDMETHODIMP

Макросы STDMETHOD и STDMETHOD_ применяются при объявлении методов интерфейса, а макросы STDMETHODIMP и STDMETHODIMP_ при описании реализации метода.

Вместо
virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
можно записать
STDMETHOD(QueryInterface(const IID& iid, void** ppv));

Вместо
virtual void __stdcall Fy() =0;
можно записать
STDMETHOD_(void, Fy()) PURE;

При описании реализации вместо
virtual void __stdcall Fy() { cout << "Fy" << end1;}
можно записать
STDMETHODIMP_(void) Fy() { cout << "Fy" << end1;}

Пример описания СОМ-объекта на С++

Ниже приведен пример COM-объекта на C++ и пример взаимодействия клиента с СОМ-объектом.

#include <iostream.h>
#include <objbase.h>
interface IX : IUnknown
{
virtual void __stdcall Fx() =0;
};
interface IY : IUnknown
{
virtual void __stdcall Fy() =0;
};
// класс СОМ -объекта
class CA : public IX, public IY
{
// Реализация методов IUnknown
virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv);
virtual ULONG __stdcall AddRef() {return 0;}; // пока ничего не делает
virtual ULONG __stdcall Release() {return 0;}; // пока ничего не делает
// Реализация интерфейса IX
virtual void __stdcall Fx() { cout << "Fx" << end1;}
// Реализация интерфейса IY
virtual void __stdcall Fy() { cout << "Fy" << end1;}
};

Взаимодействие клиента с СОМ-объектом

// Функция создания объекта
IUnknown* CreateInstance()
{
IUnknown * pI=(IX*)new CA;
pI->AddRef();
return pI;
}
void main()
{
HRESULT hr;
// Создание объекта
IUnknown* pIUnknown = CreateInstance();
IX* pIX=NULL;
// Получить интерфейс IX
hr=pIUnknown->QueryInterface(IID_IX, (void**)&pIX);
if (SUCCEEDED(hr))
{ // вызвать метод Fx
pIX->Fx();
}
else cout << "Объект не имеет интерфейса " << end1;
IY* pIY=NULL;
// Получить интерфейс IY
hr=pIUnknown->QueryInterface(IID_IY, (void**)&pIY);
if (SUCCEEDED(hr))
{ // вызвать метод Fy
pIX->Fy();
}
else cout << "Объект не имеет интерфейса " << end1;
// Получить интерфейс IY через интерфейс IX
IY* pIY_IX =NULL;
hr=pIX->QueryInterface(IID_IY, (void**)&pIY_IX);
if (SUCCEEDED(hr))
{ // вызвать метод Fy
pIY_IX->Fy();
}
else cout << "Объект не имеет интерфейса " << end1;
// Получить интерфейс IUnknown через интерфейс IY
IUnknown* pIUknown_IY =NULL;
hr=pIY->QueryInterface(IID_IUnknown, (void**)&pIUnknown_IY);
if (SUCCEEDED(hr))
if (pIUnknown_IY == pIUknown)
{
cout << "указатели совпадают " << end1;
}
else cout << "указатели не совпадают " << end1;
// Удалить объект
delete pIUnknown;
}

Подсчет ссылок

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

В то время как один объект может пользоваться несколькими клиентами одновременно, никто из них не в состоянии узнать, когда все остальные завершатся. Так что разрешить клиенту убивать объект напрямую - небезопасно. Только сам объект может знать, когда он может безопасно завершить свою работу, и только в том случае, если все клиенты сообщают объекту, что они завершили работу с ним. Такой контроль объекты осуществляют с помощью механизма подсчета ссылок (reference counting), поддерживаемого двумя методами интерфейса IDnknown.

Каждый исполняющийся объект поддерживает счетчик ссылок. Всякий раз, выдав вовне указатель на один из своих интерфейсов, объект увеличивает счетчик ссылок на 1. Если один клиент передает указатель интерфейса другому клиенту, т.е. увеличивает число пользователей объекта без ведома последнего, то клиент, получающий указатель, должен вызвать с помощью этого указателя AddRef. В результате объект увеличивает свой счетчик ссылок. Независимо от того, как он получил указатель на интерфейс, клиент всегда обязан вызвать для этого указатель Release, закончив с ним работу. Исполнение этого метода объектом состоит в уменьшении числа ссылок на 1. Обычно объект уничтожает сам себя, когда счетчик ссылок становится равным 0.

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

Серверы объектов СОМ

Каждый объект СОМ реализован внутри некоторого сервера, содержащего код, который реализует методы интерфейсов объекта, а также контролирует данные объекта, пока тот активен. Один сервер может поддерживать более одного объекта некоторого класса. Рассмотрим три основные типа серверов.

Сервер "в процессе": объекты реализуются в динамически подключаемой библиотеке, и, таким образом, исполняются в том же процессе, что и клиент. Локальный сервер: объекты реализованы в отдельном процессе, исполняющемся на той же машине, что и клиент. Удаленный сервер: объекты реализованы в DLL либо в отдельном процессе, которые расположены на удаленном по отношению к клиенту компьютере. Возможность создания таких серверов поддерживает распределенная СОМ (DCOM).

С точки зрения клиента, объекты, реализованные любой из трех разновидностей серверов, выглядят одинаково; доступ к методам объектов клиент по-прежнему осуществляет через указатели интерфейсов. При необходимости он может проводить различие между разными типами серверов, но это не обязательно. Запуск объекта, получение указателей на его интерфейсы, вызов их методов и освобождение указателей выполняются клиентом одинаково независимо от того, каким сервером реализован объект: "в процессе", локальным или удаленным.

Поиск серверов

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

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

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

1. CLSID, выступающий как ключ для поиска записи;

2. указание типа доступного сервера ("в процессе", локальный или удаленный);

3. для серверов "в процессе" и локальных (т.е. для выполняемых на той же машине, что и клиент) должно быть задано полное имя DLL или исполняемого файла сервера; для удаленных серверов (доступных через DCOM) - указание, где искать исполняемый файл сервера.

Обычно приложение добавляет записи к этой таблице при установке. После этого объекты приложения могут создаваться и использоваться клиентами.

Создание объекта

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

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

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

До этого места подразумевалось, что создаваемый объект реализован в сервере "в процессе" или локальном, т.е. будет выполняться на той же машине, что и клиент. Что же происходит в случае удаленного сервера? Как создается удаленный экземпляр объекта?

Поддержка удаленных объектов обеспечивается DCOM. Процесс во многом аналогичен созданию локального объекта: клиент выполняет тот же вызов библиотеки СОМ, она просматривает системный реестр и т.д. Если же указан удаленный сервер, СОМ установит для создания экземпляра объекта связь с удаленной машиной. Как и все межмашинные коммуникации в DCOM, данный запрос выполняется вызовом удаленной процедуры. Просмотрев свой реестр, удаленная система находит исполняемый файл сервера и создает экземпляр объекта. Так же, как и в случае локального сервера, возвращается указатель на интерфейс, после чего клиент может вызывать методы вновь созданного объекта. Для клиента запуск объекта выполняется одинаково, независимо от того, каким сервером реализован объект: "в процессе", локальным или удаленным; данное различие должно учитываться клиентом, лишь когда он сам считает это необходимым.

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

Фабрики классов

Если клиенту нужен только один объект, то проще всего создать его с помощью CoCreateInstance. И все же случается, что клиенту может понадобиться много экземпляров объектов одного и того же класса. Чтобы их создание выполнялось эффективно, клиент может получить доступ к фабрике класса (class factory) - объекту, способному создавать другие объекты. Каждая фабрика класса знает, как создавать объекты одного конкретного класса. Фабрики классов - полноценные объекты СОМ: доступ к ним осуществляется через интерфейсы, они поддерживают IUnknown и т.д. И все же они необычные объекты, так как могут создавать другие объекты СОМ. Дело в том, что все объекты, с которыми мы встречались до сих пор, созданы фабрикой класса. Даже когда клиент просто вызывает CoCreateInstance, реализация этой функции в библиотеке СОМ создает объект с помощью фабрики класса. CoCreateInstance скрывает эти детали от клиента. Но на самом деле она использует методы интерфейса IClassFactory, описываемые ниже.

Чтобы называться фабрикой класса, объект должен поддерживать интерфейс IClassFactory. Этот простой интерфейс содержит только 2 метода: CoCreateInstance создает новый экземпляр класса, объекты которого может создавать данная фабрика.

Клиент не передает этому методу в качестве параметра CLSID, так как класс объекта неявно определяется самой фабрикой. И все же клиент задает IID, чтобы получить указатель на нужный ему интерфейс. LockServer позволяет клиенту сохранить сервер загруженным в память. Объект-фабрика, как и другие объекты, поддерживает собственный счетчик ссылок, для учета количества использующих его клиентов. Однако, по разным соображениям, этого счетчика недостаточно, чтобы удерживать сервер загруженным в память. Чтобы сервер гарантированно продолжал работать, можно использовать IClassFactory::LockServer.

Использование фабрики класса

Чтобы получить доступ к фабрике класса, клиент вызывает функцию библиотеки СОМ CoGetClassObject. Этой функции передается CLSID класса объектов, которые будут создавать фабрики, а не CLSID самой фабрики. Клиент задает также IID интерфейса, нужного ему для работы с фабрикой. Конечно, обычно это IID интерфейса IClassFactory. Кроме того, как и в случае с CoCreateInstance, клиент может также задать тип сервера, который должен быть запущен для фабрики и ее объектов. Если для фабрики запрашивается, например, сервер "в процессе", то и объекты, созданные фабрикой, тоже будут выполняться данным сервером "в процессе". Допустим, клиент уже вызвал CoGetClassObject, библиотека СОМ запустила фабрику класса и возвратила указатель на интерфейс IClassFactory этой фабрики. Получив указатель, клиент вызывает метод IClassFactory::Createlnstance данного интерфейса. Среди параметров этого вызова клиент передает IID интерфейса, указатель на который ему необходим. В ответ фабрика класса создает объект и возвращает клиенту указатель на заданный интерфейс. Теперь клиент может использовать возвращенный ему указатель для вызовов методов интерфейса.



статьи
статьи
 / 
новости
новости
 / 
контакты
контакты