通常你会使用
CoCreateInstance()
从COM DLL中实例化一个对象。当你这样做时,不需要像普通DLL那样先加载DLL并获取过程地址。这是因为Windows“知道”COM DLL实现的类型、它们所在的DLL以及如何实例化它们。(当然假设COM DLL已经注册,这通常是这样的)。
假设你有一个带有IDog接口的COM DLL要使用。在这种情况下,
dog.idl
interface IDog : IUnknown
{
HRESULT Bark();
};
coclass Dog
{
[default] Interface IDog;
};
我的代码.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
虽然所有这些内存管理的内容都可能变得相当凌乱,不过ATL提供了智能指针使得实例化和管理这些对象的任务稍微容易了一些:
CComPtr<IDog> dog;
dog.CoCreateInstance(CLSID_DOG);
dog->Bark();
编辑:
在我之前所说的:
Windows“知道”COM DLL实现的类型[...]以及它们实现在哪个DLL中
...我没有详细说明Windows是如何知道这一点的。虽然这可能看起来有点神秘,但它并不是魔术。
COM库带有类型库,其中列出了库提供的接口和Co类。类型库以文件形式存在于硬盘上--通常直接嵌入到与库本身相同的DLL或EXE中。Windows通过查看Windows注册表来知道类型库和COM库本身的位置。注册表中的条目告诉Windows DLL在硬盘上的位置。
当您调用CoCreateInstance
时,Windows查找Windows注册表中的clsid,找到相应的DLL,加载它,并执行实现COM对象的DLL中的正确代码。
这些信息是如何进入Windows注册表中的?当安装COM DLL时,它会被注册。这通常是通过运行regsvr32.exe来完成的,然后将您的DLL加载到内存中并调用名为DllRegisterServer
的函数。该函数在您的COM服务器中实现,向注册表添加必要的信息。如果使用ATL或另一个COM框架,则可能在幕后执行此操作,因此您不必直接与注册表交互。只需要在安装时调用一次DllRegisterServer
。
如果尝试为尚未通过regsvr32
/DllRegisterServer
过程注册的COM对象调用CoCreateInstance
,则CoCreateInstance
将失败,并显示错误信息:
类未注册
幸运的是,修复此问题的方法是简单地在您的COM服务器上调用regsvr32
,然后再次尝试。