作为进程内组件程序, 必须引出COM 所要求的四个基本函数:
1. 引出DllGetClassObject
STDAPI DllGetClassObject(
REFCLSID rclsid,
REFIID riid,
LPVOID * ppv
);
extern "C" HRESULT __stdcall DllGetClassObject(const CLSID& clsid, const IID& iid, void **ppv) { if (clsid == CLSID_Dictionary ) { CDictionaryFactory *pFactory = new CDictionaryFactory; //创建组件类厂 if (pFactory == NULL) { return E_OUTOFMEMORY ; } HRESULT result = pFactory->QueryInterface(iid, ppv); return result; } else { return CLASS_E_CLASSNOTAVAILABLE; } }
2. STDAPI DllCanUnloadNow(void);
extern "C" HRESULT __stdcall DllCanUnloadNow(void) { if ((g_DictionaryNumber == 0) && (g_LockNumber == 0)) return S_OK; else return S_FALSE; }
3.STDAPI DllRegisterServer(void);和STDAPI DllUnregisterServer(void);
// 这两个函数在用regsvr32.exe 进行组件的注册和反注册很有用,在组件程序里面必须自己实现
自注册进程内组件程序必须引出的两个函数还注册表的创建操作
实现代码如下:
extern "C" HRESULT __stdcall DllRegisterServer() { char szModule[1024]; DWORD dwResult = ::GetModuleFileName((HMODULE)g_hModule, szModule, 1024); if (dwResult == 0) return SELFREG_E_CLASS; return RegisterServer(CLSID_Dictionary, szModule, "Dictionary.Object", "Dictionary Component", NULL); } RegisterServer()函数包含注册表的创建操作 extern "C" HRESULT __stdcall DllUnregisterServer() { return UnregisterServer(CLSID_Dictionary, "Dictionary.Object",NULL); }
下面我来解释一下为什么必须引出这四个函数
在客户程序能用这个组件之前,我们必须对组件进行系统组成:
利用windows 系统给我们提供的regsvr32.exe , 这个可以再系统的systerm32目录下找到
方法一:在 开始—>运行直接输入 regsvr32 My.dll 注意这种方式需要my.dll放在windows下的Syetem32目录下
方法二:在 开始—>运行直接输入 regsvr32.exe D:/My.dll 注意当这种绝对路径方法中含有空格的时候需要regsvr32 "D:/ My.dll"就行了。
在对组件进行注册时候,系统会根据组件引出函数DllRegisterServer,把组件信息写入到注册表相应的地方。
同理,反注册时调用DllUnregisterServer,这也是为什么这两个函数必须要引出的原因。
下面来讲一下客户的调用方式:
当客户调用COM库函数里面的CoCreateInstance时候内部会首先调用COM库函数CoGetClassObject, CoGetClassObject函数内部在调用组件内引出函数DllGetClassObject来创建类厂对象,然后系统自动调用类厂对象的CreateInstance来创建组件对象。
注意:类厂的 CreateInstance必须由我们程序员来使用,见如下代码
HRESULT CDictionaryFactory::CreateInstance(IUnknown *pUnknownOuter, const IID& iid, void **ppv) { CDictionary * pObj; HRESULT hr; *ppv=NULL; hr=E_OUTOFMEMORY; if (NULL != pUnknownOuter) return CLASS_E_NOAGGREGATION; //Create the object passing function to notify on destruction. pObj=new CDictionary(); if (NULL==pObj) return hr; //Obtain the first interface pointer (which does an AddRef) hr=pObj->QueryInterface(iid, ppv); if (hr != S_OK) { //Kill the object if initial creation or FInit failed. g_DictionaryNumber --; // Reference count g_cDictionary be added in constructor delete pObj; } return hr;
参考书:<<COM技术内幕>>
<<COM原理与应用>>