Поделиться через


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

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

Как правило, существует два способа создания COM-объекта:

  • Модуль, реализующий объект , может предоставлять функцию, специально разработанную для создания экземпляров этого объекта.
  • Кроме того, COM предоставляет универсальную функцию создания с именем CoCreateInstance.

Например, возьмем гипотетический Shape объект из раздела Что такое COM-интерфейс?. В этом примере Shape объект реализует интерфейс с именем IDrawable. Графическая библиотека, реализующая Shape объект , может экспортировать функцию со следующей сигнатурой.

// Not an actual Windows function. 

HRESULT CreateShape(IDrawable** ppShape);

Учитывая эту функцию, можно создать новый Shape объект следующим образом.

IDrawable *pShape;

HRESULT hr = CreateShape(&pShape);
if (SUCCEEDED(hr))
{
    // Use the Shape object.
}
else
{
    // An error occurred.
}

Параметр ppShape имеет тип pointer-to-pointer-to-IDrawable. Если вы не видели этот шаблон ранее, двойное косвенное обращение может быть недоумение.

Учитывайте требования CreateShape функции. Функция должна возвращать IDrawable указатель на вызывающий объект. Но возвращаемое значение функции уже используется для кода ошибки или успешного выполнения. Поэтому указатель должен быть возвращен через аргумент функции . Вызывающий объект передает в функцию переменную типа IDrawable* , а функция перезапишет эту переменную новым IDrawable указателем. В C++ существует только два способа перезаписи значения параметра функцией: передача по ссылке или передача по адресу. COM использует последний сквозной адрес. Адрес указателя является указателем на указатель, поэтому тип параметра должен иметь значение IDrawable**.

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

схема, показывающая косвенное обращение с двойным указателем

Функция CreateShape использует адрес pShape (&pShape) для записи нового значения указателя в pShape.

CoCreateInstance: универсальный способ создания объектов

Функция CoCreateInstance предоставляет универсальный механизм для создания объектов. Чтобы понять coCreateInstance, имейте в виду, что два COM-объекта могут реализовывать один и тот же интерфейс, а один объект может реализовывать два или более интерфейсов. Таким образом, универсальной функции, которая создает объекты, требуется две части информации.

  • Какой объект следует создать.
  • Интерфейс, который следует получить из объекта .

Но как указать эту информацию при вызове функции? В COM объект или интерфейс определяется путем присвоения ему 128-разрядного числа, называемого глобальным уникальным идентификатором (GUID). Идентификаторы GUID создаются таким образом, чтобы они были уникальными. Идентификаторы GUID — это решение проблемы создания уникальных идентификаторов без центрального центра регистрации. Идентификаторы GUID иногда называют универсальными уникальными идентификаторами (UUID). До создания COM они использовались в DCE/RPC (распределенная вычислительная среда или удаленный вызов процедур). Существует несколько алгоритмов для создания новых идентификаторов GUID. Не все эти алгоритмы строго гарантируют уникальность, но вероятность случайного создания одного и того же значения GUID дважды крайне мала — фактически ноль. Идентификаторы GUID можно использовать для идентификации любых сущностей, а не только объектов и интерфейсов. Однако это единственное использование, которое касается нас в этом модуле.

Например, библиотека Shapes может объявить две константы GUID:

extern const GUID CLSID_Shape;
extern const GUID IID_IDrawable; 

(Можно предположить, что фактические 128-разрядные числовые значения для этих констант определены в другом месте.) Константная CLSID_Shape определяет Shape объект , а константная IID_IDrawable определяет IDrawable интерфейс. Префикс CLSID означает идентификатор класса, а префикс IIDидентификатор интерфейса. Это стандартные соглашения об именовании в COM.

Учитывая эти значения, вы создадите новый Shape экземпляр следующим образом:

IDrawable *pShape;
hr = CoCreateInstance(CLSID_Shape, NULL, CLSCTX_INPROC_SERVER, IID_IDrawable,
     reinterpret_cast<void**>(&pShape));

if (SUCCEEDED(hr))
{
    // Use the Shape object.
}
else
{
    // An error occurred.
}

Функция CoCreateInstance имеет пять параметров. Первый и четвертый параметры — это идентификатор класса и идентификатор интерфейса. По сути, эти параметры сообщают функции : "Создайте объект Shape и дайте мне указатель на интерфейс IDrawable".

Присвойте второму параметру значение NULL. (Дополнительные сведения о значении этого параметра см. в разделе Агрегирование документации по COM.) Третий параметр принимает набор флагов, main целью которых является указание контекста выполнения для объекта . Контекст выполнения указывает, выполняется ли объект в том же процессе, что и приложение; в другом процессе на том же компьютере; или на удаленном компьютере. В следующей таблице показаны наиболее распространенные значения для этого параметра.

Flag Описание
CLSCTX_INPROC_SERVER Тот же процесс.
CLSCTX_LOCAL_SERVER Другой процесс, один и тот же компьютер.
CLSCTX_REMOTE_SERVER Другой компьютер.
CLSCTX_ALL Используйте наиболее эффективный вариант, поддерживаемый объектом . (Ранжирование, от наиболее эффективного к наименее эффективному, — внутрипроцессное, внепроцессное и межкомпьютное.)

 

В документации по конкретному компоненту может быть показано, какой контекст выполнения поддерживает объект. В противном случае используйте CLSCTX_ALL. При запросе контекста выполнения, который не поддерживается объектом, функция CoCreateInstance возвращает код ошибки REGDB_E_CLASSNOTREG. Этот код ошибки также может указывать на то, что ИДЕНТИФИКАТОР CLSID не соответствует ни одному компоненту, зарегистрированному на компьютере пользователя.

Пятый параметр CoCreateInstance получает указатель на интерфейс. Так как CoCreateInstance является универсальным механизмом, этот параметр не может быть строго типизирован. Вместо этого используется тип данных void**, а вызывающий объект должен принудить адрес указателя к типу void** . Это и есть цель reinterpret_cast в предыдущем примере.

Важно проверка возвращаемое значение CoCreateInstance. Если функция возвращает код ошибки, указатель COM-интерфейса недопустим, и попытка разыменовать его может привести к сбою программы.

Внутри функции CoCreateInstance используются различные методы создания объекта. В простейшем случае он ищет идентификатор класса в реестре. Запись реестра указывает на библиотеку DLL или EXE-файл, реализующий объект . CoCreateInstance также может использовать сведения из каталога COM+ или параллельного манифеста (SxS). Несмотря на это, сведения прозрачны для вызывающего абонента. Дополнительные сведения о внутренних сведениях о CoCreateInstance см. в разделе COM-клиенты и серверы.

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

Следующая

Пример: диалоговое окно "Открыть"