C++ 如何在C++;
首先,COM对我来说就像黑魔法。但我需要在一个项目中使用COM dll 所以,我有一个DLL,我正在开发,我需要一些功能,可以在一个单独的COM DLL。当我查看带有Depends.exe的COM DLL时,我会看到类似DllGetClassObject()的方法和其他函数,但我对这些函数都不感兴趣 我可以访问COM DLL(遗留)源代码,但它很混乱,我更愿意使用二进制的COM DLL,就像一个大黑匣子,不知道里面发生了什么 那么,如何使用LoadLibrary从代码中调用COM DLL函数呢?可能吗?如果,是的,你能给我一个如何做的例子吗 我正在使用Visual Studio 6进行此项目C++ 如何在C++;,c++,visual-c++,com,dll,loadlibrary,C++,Visual C++,Com,Dll,Loadlibrary,首先,COM对我来说就像黑魔法。但我需要在一个项目中使用COM dll 所以,我有一个DLL,我正在开发,我需要一些功能,可以在一个单独的COM DLL。当我查看带有Depends.exe的COM DLL时,我会看到类似DllGetClassObject()的方法和其他函数,但我对这些函数都不感兴趣 我可以访问COM DLL(遗留)源代码,但它很混乱,我更愿意使用二进制的COM DLL,就像一个大黑匣子,不知道里面发生了什么 那么,如何使用LoadLibrary从代码中调用COM DLL函数呢?
非常感谢 一般来说,您应该更喜欢或不喜欢直接访问
DllGetClassObject
。但是如果您处理的是一个无法注册或不想注册的DLL,那么下面将介绍这些函数在幕后的作用(部分)
给定CLSID,
DllGetClassObject
允许您获取类对象,您可以从中创建实例(如果我没记错的话,可以通过IClassFactory
接口)
步骤摘要(我上次接触COM已经有一段时间了,请原谅任何明显的错误):
DllGetClassObject(clsid,IID\u IClassFactory,&cf)
,其中clsid
是要获取类对象的clsid,而cf
当然是类工厂cf->CreateInstance(0,iid,&obj)
,其中iid
是您想要使用的接口的iid,而obj
当然是对象(
CoCreateInstance
执行步骤1和2。CoGetClassObject
执行步骤1。如果需要创建同一类的多个实例,则可以使用CoGetClassObject
,这样就不必每次重复步骤1。)如果它是COM DLL,则只需将其添加为对项目的引用,然后可以调用DLL中的函数
是的,您可以使用诸如DLLGetClassObject之类的低级COM函数,但为什么要这样做呢?下面是一些代码,说明如何获取类工厂并使用它创建COM对象。它使用结构跟踪模块句柄和DllGetClassObject函数指针。在处理完COM对象之前,应该一直保持模块句柄 要使用此函数,需要分配ComModuleInfo结构的实例,并将szDLL设置为DLL文件名或完整路径名。然后使用要从该DLL获取的COM对象的类id和接口id调用该函数
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;
}
通常,您会使用
CoCreateInstance()
从COM DLL实例化对象。执行此操作时,无需像处理普通DLL那样首先加载DLL并获取proc地址。这是因为Windows“知道”COM DLL实现的类型、它们在哪个DLL中实现以及如何实例化它们。(当然,假设COM DLL已注册,通常是这样)
假设您有一个带有想要使用的IDog接口的COM DLL。那么,
dog.idl
myCode.cpp
尽管如此,所有这些内存管理的东西都会变得非常单调,ATL提供了智能指针,使实例化和管理这些对象的任务变得更加容易:
CComPtr<IDog> dog;
dog.CoCreateInstance(CLSID_DOG);
dog->Bark();
CComPtr狗;
CoCreateInstance(CLSID_dog);
狗->吠叫();
编辑:
当我在上面说:
Windows“知道”COM DLL实现的类型[…和]
它们是在什么DLL中实现的
…我确实掩饰了Windows是如何知道这一点的。这不是魔法,虽然一开始它看起来有点神秘
COM库附带类型库,其中列出了库提供的接口和类。这个类型库是以硬盘上的文件形式存在的——通常它直接嵌入到与库本身相同的DLL或EXE中。通过在Windows注册表中查找,Windows知道在哪里可以找到类型库和COM库本身。注册表中的条目告诉Windows DLL在硬盘上的位置
调用CoCreateInstance
时,Windows在Windows注册表中查找clsid,找到相应的DLL,加载它,并在DLL中执行实现COM对象的正确代码
这些信息是如何进入Windows注册表的?安装COM DLL后,将对其进行注册。这通常是通过运行来完成的,这反过来会将DLL加载到内存中,并调用名为DllRegisterServer
的函数。该函数在COM服务器中实现,用于向注册表添加必要的注册信息。如果您使用的是ATL或其他COM框架,那么这可能是在幕后完成的,这样您就不必直接与注册表接口DllRegisterServer
只需在安装时调用一次
如果尝试为尚未通过regsvr32
/DllRegisterServer
进程注册的COM对象调用CoCreateInstance
,则CoCreateInstance
将失败,并显示以下错误:
未注册的类别
幸运的是,解决方法是在COM服务器上调用
regsvr32
,然后再试一次。您不直接将LoadLibrary()用于COM库。CoCreateInstance()将调用此函数(如果尚未调用),然后将库中实现的类的一个新实例添加到堆中,最后向您返回指向该对象的原始指针。当然,在这个过程中,它可能会失败,因此需要一些机制来检查状态,如HRESULT
为了使用它的简单性,哟
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
CComPtr<IDog> dog;
dog.CoCreateInstance(CLSID_DOG);
dog->Bark();
#import "whatever.dll"