Site icon Заметки разработчика

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

Exit mobile version