На этом шаге мы рассмотрим алгоритм создания объектов с помощью функции CoCreateInstance().
Получив CLSID с помощью функции CLSIDFromProgID(), клиент передает его в библиотеку СОМ для загрузки объекта и получения указателя на интерфейс. Для этого служит функция CoCreateInstance(). Используя CLSID и реестр, CoCreateInstance() находит указанный объект, создает его экземпляр и возвращает указатель на его интерфейс.
Вот как выглядит описание CoCreateInstance():
STDAPI CoCreateInstance (REFCLSID rclsid, LPUNKNOWN pUnkOuter, DWORD dwClsContext, REFIID riid, LPVOID * ppv);
Первый параметр - это CLSID объекта. Второй параметр используется для агрегации (aggregation) объекта в качестве части другого объекта.
В третьем параметре задается контекст исполнения объекта. Вот допустимые значения для этого параметра:
Конекст выполнения мы рассмотрим на следующих шагах.
Параметр riid - это IID запрашиваемого интерфейса. В параметре ppv будет возвращен указатель на интерфейс, но только после успешного создания СОМ-объекта и при условии, что он поддерживает запрошенный клиентом интерфейс.
Детальный порядок операций при создании СОМ-объекта функцией CoCreateInstance() показан на рисунке 1.
Рис.1. Порядок создания объекта COM
На этой схеме показана последовательность формирования СOM-объекта. В верхней части схемы расположены все объекты, участвующие в нем, а сверху вниз отображена последовательность операций взаимодействия между ними. MV
Клиентское приложение запрашивает доступ к определенному интерфейсу, поддерживаемому СОМ-объектом, с помощью функции CoCreateInstance(), которая в свою очередь обращается к библиотеке СОМ с требованием загрузить этот объект. Библиотека СОM просматривает соответствующие разделы реестра, пытаясь получить и имя компонента-сервера (в данном случае это DLL).
После инициализации сервера создается экземпляр фабрики классов - объекта, способного создавать объекты определенного класса, реализованного в качестве части СОМ-компонента. Фабрика классов представляет интерфейс IClassFactory. После этого указатель на интерфейс фабрики класса возвращается обратно в библиотеку СОМ, которая с его помощью запускает метод фабрики CreateInstance(). Созданная Вами версия этого метода создает экземпляр СОМ-класса, который и предоставляет все методы, доступные клиентам, а также таблицу vtable, чтобы клиентское приложение могло пользоваться этими методами. Указатель на интерфейс IUnknown возвращается в библиотеку СОМ, которая, получив его, освобождает объект фабрики классов и передает указатель на IUnknown в клиентское приложение. Теперь он указывает на компонент vtable, позволяя клиенту запускать методы СОМ-объекта.
Вся описанная выше последовательность операций с объектами выполняется только при первичной инициализации СОМ-объекта. Если методы этого объекта понадобятся еще одному клиенту, он получит указатель на интерфейс этого же СОМ-объекта, а сервер увеличит счетчик использования, вызвав IUnknown::AddRef(). Закончив работу с интерфейсом, клиент обязан вызвать метод IUnknown:: Release() для уменьшения счетчика. Если какой-то из клиентов забудет это сделать, счетчик никогда не обнулится и интерфейс не будет удален, что может вызвать серьезные утечки памяти.
Со следующего шага мы начнем знакомиться с маршалингом.