C++中COM组件初始化方法实例分析
什么是COM组件
COM(Component Object Model)是一种基于Windows操作系统的二进制接口标准,用于组件化应用程序的开发和集成。COM组件是可以独立被调用和管理的二进制对象模块,因为它们可以被跨语言、跨平台地使用。
COM组件初始化方法
COM组件的初始化方法有两种:基于CoCreateInstance的懒加载和基于DllGetClassObject的预加载。懒加载是在调用COM对象之后才会将自己放在进程内存空间中,而预加载则是在进程启动时就将所有COM对象放置在内存空间中。
基于CoCreateInstance的懒加载
基于CoCreateInstance的懒加载方法的示例代码如下:
#include <objbase.h>
#include "MyCOMObject.h"
HRESULT MyCOMObjectCreateInstance(REFCLSID rclsid, REFIID riid, void** ppvObj)
{
MyCOMObject* pObj = new MyCOMObject();
if (!pObj)
{
return E_OUTOFMEMORY;
}
HRESULT hr = pObj->QueryInterface(riid, ppvObj);
if (FAILED(hr))
{
delete pObj;
pObj = NULL;
}
return hr;
}
int main()
{
CoInitialize(NULL);
IMyCOMObject* pObj = NULL;
HRESULT hr = CoCreateInstance(CLSID_MyCOMObject, NULL, CLSCTX_INPROC_SERVER,
IID_IMyCOMObject, (void**)&pObj);
if (FAILED(hr))
{
return hr;
}
// 使用COM对象
pObj->DoSomething();
// 释放COM对象
pObj->Release();
CoUninitialize();
}
在这个示例代码中,MyCOMObjectCreateInstance
是用于创建COM对象实例的函数,这个函数会在调用CoCreateInstance
函数时被调用。在这个函数里,我们通过new运算符创建了一个MyCOMObject
的实例,并且通过QueryInterface
函数将其转换成了需要创建的COM组件的接口类型。如果创建COM对象实例失败会返回错误码,成功则将COM对象指针传递回去。
在main
函数中,首先调用CoInitialize
函数进行COM初始化,然后使用CoCreateInstance
函数创建COM对象实例,COM对象的GUID、所在.dll文件以及请求的接口类型都在这里确定。创建COM对象实例的函数MyCOMObjectCreateInstance
就会被调用,它会返回COM组件的指针句柄,在之后的代码中我们通过这个句柄调用COM对象的方法。
基于DllGetClassObject的预加载
基于DllGetClassObject的预加载方法的示例代码如下:
#include <windows.h>
#include <objbase.h>
#include "MyCOMObject.h"
HRESULT MyCOMObjectCreateInstance(REFCLSID rclsid, REFIID riid, void** ppvObj)
{
MyCOMObject* pObj = new MyCOMObject();
if (!pObj)
{
return E_OUTOFMEMORY;
}
HRESULT hr = pObj->QueryInterface(riid, ppvObj);
if (FAILED(hr))
{
delete pObj;
pObj = NULL;
}
return hr;
}
class MyCOMClassFactory : public IClassFactory
{
public:
// IUnknown
STDMETHOD(QueryInterface)(REFIID riid, LPVOID FAR* ppvObj)
{
if (IsEqualIID(riid, IID_IUnknown) ||
IsEqualIID(riid, IID_IClassFactory))
{
*ppvObj = static_cast<IClassFactory*>(this);
AddRef();
return S_OK;
}
*ppvObj = NULL;
return E_NOINTERFACE;
}
STDMETHOD_(ULONG, AddRef)()
{
return InterlockedIncrement(&m_cRef);
}
STDMETHOD_(ULONG, Release)()
{
LONG lRefCount = InterlockedDecrement(&m_cRef);
if (lRefCount == 0)
{
delete this;
}
return lRefCount;
}
// IClassFactory
STDMETHOD(CreateInstance)(LPUNKNOWN pUnkOuter,
REFIID riid,
LPVOID FAR* ppvObj)
{
return MyCOMObjectCreateInstance(CLSID_MyCOMObject, riid, ppvObj);
}
STDMETHOD(LockServer)(BOOL fLock)
{
// Not implemented for this example
return E_NOTIMPL;
}
private:
LONG m_cRef;
};
class MyCOMModule : public IUnknown
{
public:
// IUnknown
STDMETHOD(QueryInterface)(REFIID riid, VOID** ppvObj)
{
if (IsEqualIID(riid, IID_IUnknown) ||
IsEqualIID(riid, IID_IClassFactory))
{
*ppvObj = this;
AddRef();
return S_OK;
}
*ppvObj = NULL;
return E_NOINTERFACE;
}
STDMETHOD_(ULONG, AddRef)()
{
return InterlockedIncrement(&m_cRef);
}
STDMETHOD_(ULONG, Release)()
{
LONG lRefCount = InterlockedDecrement(&m_cRef);
if (lRefCount == 0)
{
delete this;
}
return lRefCount;
}
MyCOMModule()
{
m_pClassFactory = new MyCOMClassFactory;
}
~MyCOMModule()
{
if (m_pClassFactory)
{
m_pClassFactory->Release();
m_pClassFactory = NULL;
}
}
STDMETHOD(RegisterServer)()
{
// Not implemented for this example
return S_OK;
}
STDMETHOD(UnregisterServer)()
{
// Not implemented for this example
return S_OK;
}
STDMETHOD(GetClassObject)(REFCLSID rclsid, REFIID riid, VOID** ppvObj)
{
if (IsEqualCLSID(rclsid, CLSID_MyCOMObject))
{
return m_pClassFactory->QueryInterface(riid, ppvObj);
}
return E_FAIL;
}
private:
MyCOMClassFactory* m_pClassFactory;
LONG m_cRef;
};
MyCOMModule* g_pModule = NULL;
BOOL APIENTRY DllMain(HMODULE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved)
{
switch (ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
g_pModule = new MyCOMModule();
break;
case DLL_PROCESS_DETACH:
if (g_pModule)
{
g_pModule->Release();
g_pModule = NULL;
}
break;
}
return TRUE;
}
在这个示例代码中,我们需要用到创建COM对象实例的函数MyCOMObjectCreateInstance
,它与前面基于CoCreateInstance懒加载的示例代码相同。
另外,我们需要自定义一个实现了IClassFactory
接口的类MyCOMClassFactory
,在其中实现了CreateInstance
和LockServer
方法,其中CreateInstance
方法调用之前提到的MyCOMObjectCreateInstance
函数来创建COM对象实例并返回指针句柄。LockServer
方法则用于锁定COM组件非核心部分的类对象在内存中的计数器。
我们还定义了一个自定义的MyCOMModule
类,实现了IUnknown
接口,其中包括了一个m_pClassFactory
成员变量,它的类型是之前我们定义的MyCOMClassFactory
。MyCOMModule
还重载了GetClassObject
方法,根据传进来的clsid来创建COM对象实例。在DLLMain函数中会实例化MyCOMModule
类并将其存储在全局变量中。当调用CoCreateInstance
时,COM
会调用MyCOMModule
的GetClassObject
函数来创建COM对象。
最后,我们需要将这个DLL文件注册到系统中,可以使用regsvr32.exe
来执行这个操作。
小结
本文介绍了C++中COM组件的初始化方法,包括基于CoCreateInstance的懒加载和基于DllGetClassObject的预加载。在示例代码中,我们使用了一个简单的COM对象MyCOMObject
来说明这两种初始化方法的使用。为了预加载COM对象的示例代码更加复杂,我们添加了自定义的MyCOMClassFactory
和MyCOMModule
类。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:C++中COM组件初始化方法实例分析 - Python技术站