API DLL или COM объект? Создание COM объектов без регистрации

создание COM объектов без регистрацииПри создании многокомпонентных проектов одним из основных вопросов, стоящих перед проектировщиком, является вопрос о том, каким, собственно, образом компоненты будут взаимодействовать друг с другом. Если мы говорим о компонентах, экспортирующих некий набор функций (по сути, библиотеках), то механизмом взаимодействия может быть использование COM интерфейсов и традиционный импорт/экспорт функций и классов. Создание COM объектов «на лету» снижает сложность использования второго метода.

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

А что, если регистрировать COM компонент и не придется?

Да, это возможно. Один из способов используется Microsoft, например, для создания DirectDraw объекта. Это, по сути, объединение обоих подходов. Т.е. на стадии создания объекта используется вызов экспортируемой функции, а далее работа идет с интерфейсами COM объекта.

HRESULT WINAPI DirectDrawCreate(GUID         FAR* lpGUID, 
                                LPDIRECTDRAW FAR* lplpDD, 
                                IUnknown     FAR* pUnkOuter); 

Второй метод, на мой взгляд, красивей. Он заключается в использовании функции DllGetClassObject, которую каждый COM объект обязан экспортировать. Именно эту функцию вызывает COM подсистема Windows для зарегистрированных компонентов в тот момент, когда какая-либо программа пытается создать их копию вызовом CoCreateInstance.

HRESULT CoCreateInstance(REFCLSID   rclsid,
                         LPUNKNOWN  pUnkOuter,
                         DWORD      dwClsContext,
                         REFIID     riid,
                         LPVOID *   ppv);

CoCreateInstance -> 
    поиск регистрационных данных объекта -> 
        чтение пути расположения файла из регистрационных данных ->
            вызов DllGetClassObject компонента для создания копии запрашиваемого объекта

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

        HINSTANCE hModule = CoLoadLibrary(pszModulePathName);
        if (hModule)
        {
            LPFNGETCLASSOBJECT pfnGetClassObject = 
                (LPFNGETCLASSOBJECT)GetProcAddress(hModule, "DllGetClassObject");

            if (pfnGetClassObject)
            {
                hr = pfnGetClassObject(rclsid, riid, ppv);
                ...

Причем параметры вызова pfnGetClassObject те же, что и в случае CoCreateInstance, считая, что pUnkOuter равен нулю (не использовать агрегацию) и dwClsContext равен константе CLSCTX_INPROC_SERVER.

Заключение

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

libcom.zip

Добавить комментарий