Добавил:
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Роджерсон Д. - Основы COM - 2000.pdf
Скачиваний:
411
Добавлен:
13.08.2013
Размер:
2.4 Mб
Скачать

7 глава

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

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

Уже появились машинки, которые называют трехмерными принтерами (3D-printers), — и это название очень им подходит. Они похожи на струйные принтеры, но выбрасывают тонкую струю пластика под давлением, а не чернила. Такой принтер наносит пластмассу слоями тоньше миллиметра. Повторная «печать» по одному и тому же месту позволяет создать сложные трехмерные объекты. Их можно использовать как прототипы или формы для изготовления деталей, а иногда и как готовые детали. С такой машинкой можно было бы организовать Домашнюю Фабрику Пластиковых Деталей. При помощи пакета САПР можно было бы в мгновение ока проектировать и производить новые детали. На такой домашней фабрике Вы могли бы сделать ту хитрую детальку с переходом 1x3, без которой никак не собиралась вся модель. Вообще у Вас больше не было бы недостатка в деталях — хотя компания Lego, вероятно, предпочла бы все же продавать Вам свои.

В этой главе я собираюсь рассмотреть своего рода фабрику, на которой производятся не детали Lego, а компоненты. Эта фабрика класса — просто компонент с интерфейсом для создания других компонентов, так что обойдется она нам дешевле, чем трехмерный принтер за 50000 долларов.

Но прежде чем заняться фабрикой класса, мы познакомимся с самым простым способом создания компонентов

— при помощи функции CoCreateInstance. Не удивительно, что этим способом пользуются чаще всего. К сожалению, он недостаточно гибок и годится не для всех компонентов. Все компоненты создаются на этой фабрике — CoCreateInstance при создании компонента тоже пользуется ее услугами, но неявно и незаметно для вызывающей программы. Клиент получает большую свободу в создании компонентов, если он прямо использует фабрику. Точно так же, как у Вас было бы больше возможностей, если бы Вы не покупали детали Lego у фирмы, а делали их сами, на Домашней Фабрике Пластиковых Деталей.

CoCreateInstance

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

Прототип CoCreateInstance

Объявление CoCreateInstance приведено ниже:

HRESULT __stdcall CoCreateInstance(

 

const CLSID& clsid,

// Внешний компонент

IUnknown* pUnknownOuter,

DWORD dwClsContext,

// Контекст сервера

const IID& iid,

 

void** ppv

 

);

 

У функции четыре входных параметра (in) и единственный выходной (out). Первый параметр — CLSID создаваемого компонента. Второй параметр используется для агрегирования компонентов и будет обсуждаться в следующей главе. Третий параметр — dwClsContext — ограничивает контекст исполнения компонента, с которым данный клиент может работать. Этот параметр мы рассмотрим позже.

92

Четвертый параметр, iid — это IID интерфейса, который мы хотим использовать для работы с компонентом. Указатель на этот интерфейс возвращается через последний параметр — ppv. Поскольку в CoCreateInstance передается IID, клиент может не вызывать QueryInterface для созданного компонента.

Использование CoCreateInstance

Используется CoCreateInstance так же просто, как и QueryInterface:

// Создать компонент

IX* pIX = NULL;

HRESULT hr = ::CoCreateInstance( CLSID_Component1, NULL, CLSCTX_INPROC_SERVER, IID_IX,

(void**)&pIX

);

if (SUCCEEDED(hr))

{

pIX->Fx(); pIX->Release();

};

В данном примере мы создаем компонент, задаваемый CLSID_Component1. Мы не агрегируем его, поэтому значением второго параметра является NULL. В следующей главе мы будем передавать функции значение, отличное от NULL. Параметр CLSCTX_INPROC_SERVER заставляет CoCreateInstance загружать только те компоненты, которые содержатся в серверах в процесса или в DLL.

Значения, передаваемые CoCreateInstance в качестве двух последних параметров, — те же самые, которые мы передавали бы QueryInterface. В данном примере мы передаем IID_IX, чтобы запросить интерфейс IX, который возвращается указателем pIX. Если вызов CoCreateInstance был успешным, то интерфейс IX готов к работе. Освобождение же интерфейса IX указывает, что клиент завершил использование и этого интерфейса, и самого компонента.

Контекст класса

Третий параметр CoCreateInstance dwClsContext — используется для управления тем, где может исполняться компонент: в том же процессе, что и клиент, в другом процессе или на другой машине. Значением параметра может быть комбинация признаков, приведенных ниже:

CLSCTX_INPROC_SERVER

Клиент принимает только компоненты, которые исполняются в одном с ним

 

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

CLSCTX_INPROC_HANDLER

Клиент будет работать с обработчиками в процессе. Обработчик в процессе

 

— это компонент внутри процесса, который реализует только часть

 

компонента. Другие части реализуются компонентом вне процесса —

 

локальным или удаленным сервером.

CLSCTX_LOCAL_SERVER

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

 

процесса, но на той же самой машине. Локальные серверы реализуются в

 

EXE, как мы увидим в гл. 10.

CLSCTX_REMOTE_SERVER

Клиент допускает компоненты, выполняющиеся на другой машине.

 

Использование этого флага требует задействования DCOM. Мы рассмотрим

 

его в гл. 10.

Один и тот же компонент может быть доступен во всех трех контекстах: удаленном, локальном и в процессе. В некоторых случаях клиент может пожелать использовать только компоненты в процессе, так как они работают быстрее. В других случаях он может не захотеть использовать компоненты, работающие в его собственном процессе, так как они имеют доступ к любому участку памяти процесса, что не слишком безопасно. Однако в большинстве случаев клиента не интересует контекст, в котором исполняется компонент. Поэтому в OBJBASE.H определены удобные константы, которые комбинируют (с помощью побитового ИЛИ) приведенные выше значения (см. табл. 7-1).

Значение CLSCTX_REMOTE_SERVER добавляется к CLSCTX_ALL и CLSCTX_SERVER, только если перед включением OBJBASE.H Вы определили символ препроцессора _WIN32_WINNT большим или равным 0x0400. (Тот же эффект даст определение перед включением OBJBASE.H символа препроцессора _WIN32_DCOM.) Предупреждение: если Вы передадите функции CoCreateInstance значение CLSCTX_REMOTE_SERVER на системе, которая не поддерживает DCOM, то CoCreateInstance возвратит ошибку E_INVALIDARG. Это легко

93

может случиться, если Вы компилируете свою программу с _WIN32_WINNT, большим или равным 0x0400, и затем запускаете ее в системе Microsoft Windows NT 3.51 или Microsoft Windows 95, которые не поддерживают

DCOM. Более подробно CLSCTX_LOCAL_SERVER и CLSCTX_REMOTE_SERVER рассматриваются в гл. 10.

Таблица 7-1 Предопределенные комбинации признаков контекста исполнения

Константы

Значения

CLSCTX_INPROC

CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER

CLSCTX_ALL

CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER |

 

CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER

CLSCTX_SERVER

CLSCTX_INPROC_SERVER | CLSCTX_LOCAL_SERVER |

 

CLSCTX_REMOTE_SERVER

Листинг кода клиента

В качестве примера в этой главе мы создадим наши первые настоящие клиент и компонент СОМ. Копии всех исходных файлов находятся на прилагающемся диске. Листинг 7-1 содержит код клиента. Единственным его существенным отличием от клиентов в гл. 5 является создание компонента с помощью CoCreateInstance. Среди других особенностей можно назвать использование CoInitialize и CoUninitialize для инициализации библиотеки СОМ (как обсуждается в гл. 6).

CLIENT.CPP

//

// Client.cpp – реализация клиента

//

#include <iostream.h> #include <objbase.h>

#include "Iface.h"

void trace(const char* msg) { cout << "Клиент: \t\t" << msg << endl; }

//

// функция main

//

int main()

{

// Инициализация библиотеки COM CoInitialize(NULL);

trace("Вызвать CoCreateInstance для создания"); trace(" компонента и получения интерфейса IX");

IX* pIX = NULL;

HRESULT hr = ::CoCreateInstance(CLSID_Component1, NULL, CLSCTX_INPROC_SERVER, IID_IX, (void**)&pIX);

if (SUCCEEDED(hr))

{

trace("IX получен успешно");

pIX->Fx(); // Использовать интерфейс IX

trace("Запросить интерфейс IY"); IY* pIY = NULL;

hr = pIX->QueryInterface(IID_IY, (void**)&pIY); if (SUCCEEDED(hr))

{

trace("IY получен успешно");

pIY->Fy(); // Использовать интерфейса IY

pIY->Release();

trace("Освободить интерфейс IY");

}

else

{

trace("Не могу получить интерфейс IY");

}

Соседние файлы в предмете Программирование на C++