如何在 C++ 中使用带有 LoadLibrary 的 COM DLL

2021-12-22 00:00:00 dll com visual-c++ c++ loadlibrary

首先,COM 对我来说就像黑魔法.但是我需要在我正在处理的一个项目中使用 COM dll.

First, COM is like black magic for me. But I need to use COM dll in one project I'm working on.

所以,我有一个正在开发的 DLL,我需要一些在单独的 COM DLL 中可用的功能.当我使用 Depends.exe 查看 COM DLL 时,我看到了像 DllGetClassObject() 和其他函数这样的方法,但没有一个我感兴趣的函数.

So, I have a DLL I am developing and I need some functionalities that are available in a separate COM DLL. When I look to the COM DLL with Depends.exe I see methods like DllGetClassObject() and other functions but none of the functions I'm interested in.

我可以访问 COM DLL(旧版)源代码,但它很混乱,我宁愿像一个不??知道里面发生了什么的大黑盒子一样以二进制形式使用 COM DLL.

I have access to the COM DLL (legacy) source code but it's a mess and I'd rather like to use the COM DLL in binary like a big black box not knowing what's going on inside.

那么,如何使用 LoadLibrary 从我的代码中调用 COM DLL 函数?是否可以?如果是的话,你能给我举个例子说明怎么做吗?

So, how can I call the COM DLL functions from my code using LoadLibrary? Is it possible? If, yes, could you give me an example of how to do it?

我在这个项目中使用 Visual Studio 6.

I'm using Visual Studio 6 for this project.

非常感谢!

推荐答案

通常您会使用 CoCreateInstance() 从 COM DLL 实例化一个对象.执行此操作时,无需像处理普通 DLL 那样首先加载 DLL 并获取 proc 地址.这是因为 Windows知道"COM DLL 实现的类型、它们在什么 DLL 中实现以及如何实例化它们.(当然,假设 COM DLL 已注册,通常是这样).

Typically you would use CoCreateInstance() to instantiate an object from a COM DLL. When you do this, there's no need to load the DLL first and get proc addresses like you would need to do with a normal DLL. This is because Windows "knows" about the types that a COM DLL implements, what DLL they are implemented in, and how to instantiate them. (Assuming of course that the COM DLL is registered, which it typically is).

假设您有一个带有要使用的 IDog 接口的 COM DLL.在这种情况下,

Suppose you have a COM DLL with the IDog interface you want to use. In that case,

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 提供了智能指针,使实例化 & 任务成为可能.更轻松地管理这些对象:

All this memory management stuff can get pretty grungy, though, and the ATL provides smart pointers that make the task of instantiating & managing these objects a little easier:

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

当我上面说的时候:

When I said above that:

Windows知道"COM DLL 实现的类型[...并且]它们是在什么 DLL 中实现的

Windows "knows" about the types that a COM DLL implements [...and] what DLL they are implemented in

...我真的忽略了 Windows 是如何知道这一点的.这不是魔法,虽然一开始看起来有点神秘.

...I really glossed over exactly how Windows knows this. It's not magic, although it might seem a little occult-ish at first.

COM 库附带类型库,其中列出了库提供的接口和 CoClass.该类型库以文件的形式存在于您的硬盘驱动器上――通常它与库本身直接嵌入在同一个 DLL 或 EXE 中.通过查看 Windows 注册表,Windows 知道在哪里可以找到类型库和 COM 库本身.注册表中的条目告诉 Windows DLL 在硬盘上的位置.

COM libraries come with Type Libraries, which list the Interfaces and CoClasses that the library provides. This Type Library is in the form of a file on your hard drive -- very often it is embedded directly in the same DLL or EXE as the library itself. Windows knows where to find the Type Library and the COM Library itself by looking in the Windows Registry. Entries in the Registry tell Windows where on the hard drive the DLL is located.

当您调用 CoCreateInstance 时,Windows 在 Windows 注册表中查找 clsid,找到相应的 DLL,加载它,并在实现 COM 对象的 DLL 中执行正确的代码.

When you call CoCreateInstance, Windows looks the clsid up in the Windows Registry, finds the corresponding DLL, loads it, and executes the proper code in the DLL that implements the COM object.

此信息如何进入 Windows 注册表?安装 COM DLL 后,它就会被注册.这通常通过运行 regsvr32.exe 来完成,它依次将您的 DLL 加载到内存中并调用一个名为 DllRegisterServer 的函数.该功能在您的 COM 服务器中实现,将必要的信息添加到注册表中.如果您使用 ATL 或其他 COM 框架,这可能是在后台完成的,因此您不必直接与注册表交互.DllRegisterServer 只需要在安装时调用一次.

How does this information get in to the Windows Registry? When a COM DLL is installed, it is registered. This is typically done by running regsvr32.exe, which in turn loads your DLL in to memory and calls a function named DllRegisterServer. That function, implemented in your COM server, adds the necesarry information to the Registry. If you are using ATL or another COM framework, this is probably being done under the hood so that you don't have to interface with the Registry directly. DllRegisterServer only needs to be called once, at install-time.

如果您尝试为尚未通过 regsvr32/DllRegisterServer 进程注册的 COM 对象调用 CoCreateInstance,则 CoCreateInstance 将失败并显示以下错误:

If you try to call CoCreateInstance for a COM object that has not yet been registered via the regsvr32/DllRegisterServer process, then CoCreateInstance will fail with an error that says:

未注册课程

幸运的是,解决此问题的方法是在您的 COM 服务器上调用 regsvr32,然后重试.

Fortunately, the fix for this is to simply call regsvr32 on your COM server, and then try again.

相关文章