Как я использую COM DLL с LoadLibrary в C++

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

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

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

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

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

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

7
задан Etienne Savard 2 February 2010 в 20:27
поделиться

6 ответов

Как правило, вы бы использовали CoCreateInstance () для создания объекта от COM DLL. Когда вы делаете это, нет необходимости загружать DLL сначала и получить адреса proc, как вам нужно будет делать с обычной 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 они реализуются в

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

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

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

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

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

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

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

11
ответ дан 6 December 2019 в 04:58
поделиться

Используйте модуль лесозаготовок вместо предупреждений .

-121--1303857-

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


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

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

  1. Call DLLGELASSASCOBJECT (CLSID, IID_ICLASSFFORTORY, & CF) , где CLSID - это CLSID, который вы хотите получить объект класса, и CF , конечно, классовый завод.
  2. Вызов CF-> CreateInstance (0, IID, & OBJ) , где IID - это IID интерфейса, который вы хотели бы использовать, и OBJ Конечно, объект.
  3. ???
  4. Прибыль!

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

22
ответ дан 6 December 2019 в 04:58
поделиться

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

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

6
ответ дан 6 December 2019 в 04:58
поделиться

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

#import "whatever.dll"

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

3
ответ дан 6 December 2019 в 04:58
поделиться

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

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

0
ответ дан 6 December 2019 в 04:58
поделиться

Сначала добавить

filterContext.HttpContext.Response.Clear();

и это в конце:

filterContext.HttpContext.Response.End();

Надеюсь, это поможет.

-121--2663128-

Я бы пошел с boost:: scoped _ ptr здесь:

class A: boost::noncopyable
{
    typedef boost::scoped_ptr<B> b_ptr;
    b_ptr pb_;

public:

    A() : pb_() {}

    void calledVeryOften( /*…*/ )
    {
        pb_.reset( new B( params )); // old instance deallocated
        // safely use *pb_ as reference to instance of B
    }
};

Нет необходимости в ручном деструкторе, A не копируется, как это должно быть в вашем оригинальном коде, не утечка памяти при копировании/назначении.

Я бы предложил переосмыслить дизайн, хотя если вам нужно очень часто перераспределять какой-то внутренний государственный объект. Ознакомьтесь с параметрами Flyweight и State узоров.

-121--2666428-

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

Чтобы использовать эту функцию, необходимо выделить экземпляр структуры ComModureInfo и установить для 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;
}
1
ответ дан 6 December 2019 в 04:58
поделиться
Другие вопросы по тегам:

Похожие вопросы: