Как использовать COM DLL с LoadLibrary на C ++ - PullRequest
8 голосов
/ 02 февраля 2010

Во-первых, COM для меня как черная магия.Но мне нужно использовать COM dll в одном проекте, над которым я работаю.

Итак, у меня есть DLL, которую я разрабатываю, и мне нужны некоторые функции, которые доступны в отдельной COM DLL.Когда я смотрю на COM DLL с Depends.exe, я вижу такие методы, как DllGetClassObject () и другие функции, но ни одна из функций, которые меня интересуют.но это беспорядок, и я бы предпочел использовать COM DLL в двоичном виде, как большой черный ящик, не зная, что происходит внутри.

Итак, как я могу вызывать функции COM DLL из моего кода, используя LoadLibrary?Является ли это возможным?Если да, не могли бы вы привести пример, как это сделать?

Я использую Visual Studio 6 для этого проекта.

Большое спасибо!

Ответы [ 6 ]

22 голосов
/ 02 февраля 2010

Как правило, вы предпочитаете CoCreateInstance или CoGetClassObject вместо прямого доступа к DllGetClassObject. Но если вы имеете дело с DLL, которую вы не можете или не хотите регистрировать, затем ниже описывается (часть), что эти функции делают за кулисами.


Учитывая CLSID, DllGetClassObject позволяет вам получить объект класса, из которого вы можете создавать экземпляры (через интерфейс IClassFactory, если я правильно помню).

Сводка шагов (с тех пор, как я последний раз касался COM, прошло много времени, поэтому извините за любые очевидные ошибки):

  1. Вызовите DllGetClassObject(clsid, IID_IClassFactory, &cf), где clsid - это CLSID, для которого вы хотите получить объект класса, а cf - это, конечно, фабрика классов.
  2. Вызовите cf->CreateInstance(0, iid, &obj), где iid - это IID интерфейса, который вы хотите использовать, а obj - это, конечно, объект.
  3. ???
  4. Profit!

(CoCreateInstance выполняет шаги 1 и 2. CoGetClassObject выполняет шаги 1. Вы должны использовать CoGetClassObject, если вам нужно создать много экземпляров одного и того же класса, так что шаг 1 не нужно повторять каждый время.)

11 голосов
/ 03 февраля 2010

Как правило, вы используете CoCreateInstance() для создания экземпляра объекта из COM DLL.Когда вы делаете это, нет необходимости сначала загружать библиотеку DLL и получать адреса прок, как вы должны делать с обычной библиотекой DLL.Это связано с тем, что Windows «знает» о типах, которые реализует COM DLL, в какой DLL они реализованы и как их создавать.(Предполагая, конечно, что COM DLL зарегистрирована, что обычно и происходит).

Предположим, у вас есть COM DLL с интерфейсом IDog, который вы хотите использовать.В этом случае,

dog.idl

interface IDog : IUnknown
{
  HRESULT Bark();
};

coclass Dog
{
  [default] Interface IDog;
};

myCode.cpp

IDog* piDog = 0;
CoCreateInstance(CLSID_DOG, 0,  CLSCTX_INPROC_SERVER, IID_IDOG,  &piDog); // windows will instantiate the IDog object and place the pointer to it in piDog
piDog->Bark();  // do stuff
piDog->Release();  // were done with it now
piDog = 0;  // no need to delete it -- COM objects generally delete themselves

Все эти вещи управления памятью могут быть довольно шероховатыми, и ATL обеспечиваетумные указатели, которые облегчают задачу создания и управления этими объектами:

CComPtr<IDog> dog;
dog.CoCreateInstance(CLSID_DOG);
dog->Bark();

РЕДАКТИРОВАТЬ:

Когда я сказал выше, что:

Windows "знает "о типах, которые реализует COM DLL [...] и какие DLL они реализуют в

... Я действительно не знаю, как именно Windows это знает.Это не волшебство, хотя поначалу это может показаться немного оккультным.

COM-библиотеки поставляются с библиотеками типов, в которых перечислены интерфейсы и классы CoClass, предоставляемые библиотекой.Эта библиотека типов находится в форме файла на вашем жестком диске - очень часто она встроена непосредственно в ту же DLL или EXE, что и сама библиотека.Windows знает, где найти библиотеку типов и саму библиотеку COM, просматривая реестр Windows.Записи в реестре сообщают Windows, где на жестком диске находится DLL.

Когда вы вызываете CoCreateInstance, Windows ищет clsid в реестре Windows, находит соответствующую DLL, загружает ее и выполняетправильный код в DLL, который реализует COM-объект.

Как эта информация попадает в реестр Windows?Когда COM DLL установлена, она зарегистрирована.Обычно это выполняется с помощью regsvr32.exe , который, в свою очередь, загружает вашу DLL в память и вызывает функцию с именем DllRegisterServer.Эта функция, реализованная на вашем COM-сервере, добавляет необходимую информацию в реестр.Если вы используете ATL или другой COM-фреймворк, это, вероятно, делается изнутри, чтобы вам не приходилось напрямую взаимодействовать с реестром.DllRegisterServer нужно вызывать только один раз, во время установки.

Если вы попытаетесь вызвать CoCreateInstance для COM-объекта, который еще не был зарегистрирован в процессе regsvr32 / DllRegisterServer,тогда CoCreateInstance потерпит неудачу с ошибкой, которая говорит:

Класс не зарегистрирован

К счастью, исправление для этого - просто вызвать regsvr32 на вашем COM-сервереи повторите попытку.

6 голосов
/ 03 февраля 2010

Вы напрямую не используете LoadLibrary () с библиотекой COM. CoCreateInstance () вызовет эту функцию, если она еще не создана, а затем добавит экземпляр класса, который вы реализовали в библиотеке, в кучу и, наконец, вернет вам необработанный указатель на этот объект. Конечно, это может привести к сбою во время процесса, и, следовательно, некоторый механизм для проверки статуса, например, HRESULT.

Для простоты использования вы можете рассматривать библиотеку COM как общую DLL с 1) некоторой предопределенной функцией входа (основной), 2) вам нужно вызвать некоторую предопределенную функцию, например CoCreateInstance (), чтобы войти в нее и принять что это так, потому что это должно.

3 голосов
/ 03 февраля 2010

Если библиотека типов встроена в DLL, вы можете импортировать ее в свой проект:

#import "whatever.dll"

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

1 голос
/ 03 февраля 2010

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

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

typedef struct {
   TCHAR   szDLL[MAX_PATH];
   HMODULE hModule;
   HRESULT (WINAPI *pfnGetFactory)(REFCLSID, REFIID, void**);
   } ComModuleInfo;

HRESULT CreateCOMObject(
   ComModuleInfo & mod,  // [in,out] 
   REFCLSID iidClass,    // [in] CLSID of the COM object to create
   REFIID iidInterface,  // [in] GUID of the interface to get
   LPVOID FAR* ppIface)  // [in] on success, interface to the COM object is returned
{
    HRESULT hr = S_OK;

    *ppIface = NULL; // in case we fail, make sure we return a null interface.

    // init the ComModuleInfo if this is the first time we have seen it.
    //
    if ( ! mod.pfnGetFactory)
    {     
       if ( ! mod.hModule)
       {
          mod.hModule = LoadLibrary(mod.szDLL);
          if ( ! mod.hModule)
             return HRESULT_FROM_WIN32(GetLastError());
       }
       mod.pfnGetFactory = (HRESULT (WINAPI *)(REFCLSID, REFIID, void**))GetProcAddress(mod.hModule, "DllGetClassObject");
       if ( ! mod.pfnGetFactory)
          return HRESULT_FROM_WIN32(GetLastError());
    }

    IClassFactory* pFactory = NULL;
    hr = mod.pfnGetFactory(iidClass, IID_IClassFactory, (void**)&pFactory);
    if (SUCCEEDED(hr))
    {
       hr = pFactory->CreateInstance(NULL, iidInterface, (void**)ppIface);
       pFactory->Release();
    }

    return hr;
}
0 голосов
/ 02 февраля 2010

Если это COM DLL, все, что вам нужно сделать, это добавить ее в качестве ссылки на ваш проект, а затем вы можете вызывать функции, которые находятся внутри DLL.

Да, вы можете использовать низкоуровневые функции COM, такие как DLLGetClassObject, но зачем вам это?

...