声明自定义的接口继承于IUnknown。需要一个GUID与该接口对应。
定义一个类继承于该接口用来实现。
定义一个类Factory继承于IClassFactory,用来创建实现类。需要一个GUID与该factory对应。
实现类除了需要实现自定义的接口外,还要声明一个用来计数的成员,用来统计多少用户引用了自己,并实现IUnknown中声明的三个纯虚函数:
AddRef:计数加1。
Release:计数减一,当计数为0的时候,delete自己。
QueryInterface:根据传入的GUID,把自己的this指针转换成GUID对应的接口类型,传给用户,调用一次AddRef(因为又多了一个使用该对象的用户)。用户得到的是接口类型指针,可以调用函数。
Factory类除了实现上面三个纯虚函数外,还需要实现另外两个纯虚函数:
CreateInstance:创建一个实现类对象,调用一次该对象的QueryInterface(对象计数+1,表示对象已被创建);将对象以IUnknown类型传给用户(用户不需要知道对象具体类型,但需要得到对象)。
LockServer:--
该com组件以DLL形式存在,需要导出以下四个函数:
DllGetClassObject:com库在载入DLL后,会调用此函数,在此函数中创建Factory类对象,调用一次QueryInterface(对象计数+1)。
DllCanUnloadNow:判断DLL是否可以被卸载。
DllRegisterServer: 当执行RegSvr32命令加载DLL时被调用,用来写注册表。
DllUnregisterServer :当执行RegSvr32 -u命令卸载DLL时被调用。
自定义的COM组建在被COM库使用前必须在HKEY_CLASSES_ROOT\CLSID键值下注册。用factory的GUID 作为
键名字,这个键值必须包含两个子键,一是DLL的位置,二是DLL的线程模型。


客户端使用时按如下步骤:
1、调用CoInitialize初始化COM库。
2、调用CoCreateInstance指定factory的GUID,获得IUnknown类型的对象指针(不需要知道对象类型)。
3、调用QueryInterface指定接口的GUID,获得接口指针(实际指向实现类对象)。
4、用该接口指针调用自定义的方法。
5、调用Release释放接口、对象,CoUninitialize释放com库资源。
过程如下图所示:

自定义接口头文件 IMyInterface.h
#ifndef __MY_INTERFACE__
#define __MY_INTERFACE__

#include "Unknwn.h"

//自己的接口
interface IMyInterface: public IUnknown


{
public:
virtual void MyTest() = 0;
};

#endif
实现类头文件 MyClass.h
#ifndef __MY_CLASS__
#define __MY_CLASS__

#include "IMyInterface.h"

//实现接口的类
class MyClass: public IMyInterface


{
public:
MyClass();
~MyClass();

//from IUnknown
ULONG STDMETHODCALLTYPE AddRef();
ULONG STDMETHODCALLTYPE Release();
HRESULT STDMETHODCALLTYPE QueryInterface(const IID& iid, void** ppvObject);

//from IMyInterface
void MyTest();

private:
int m_Ref ;
};

#endif
类工厂头文件 MyFactory.h
#ifndef __MY_FACTORY__
#define __MY_FACTORY__

#include "Unknwn.h"

//创建类的类工厂
class MyFactory: public IClassFactory


{
public:
MyFactory ();
~MyFactory ();

//from IUnknown
HRESULT STDMETHODCALLTYPE QueryInterface(const IID& iid, void **ppv);
ULONG STDMETHODCALLTYPE AddRef();
ULONG STDMETHODCALLTYPE Release();

//from IClassFactory
HRESULT STDMETHODCALLTYPE CreateInstance(IUnknown* , const IID& iid, void **ppv);
HRESULT STDMETHODCALLTYPE LockServer(BOOL);

private:
ULONG m_Ref;
};

#endif
类的实现 MyClass.cpp
#include "MyClass.h"
#include <stdio.h>

//接口的GUID
extern "C" const GUID IID_IMyInterface =

{ 0x54bf6569, 0x1007, 0x11d1,

{ 0xb0, 0xaa, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} } ;

ULONG g_ClassNum = 0; //统计类对象
ULONG g_LockNumber = 0;

MyClass::MyClass()
:m_Ref(0)


{
++g_ClassNum;
}

MyClass::~MyClass()


{
--g_ClassNum;
}

ULONG MyClass::AddRef()


{
++m_Ref;
return (ULONG)m_Ref;
}

ULONG MyClass::Release()


{
--m_Ref;

if (m_Ref == 0 )
{
delete this;
return 0;
}
return (ULONG) m_Ref;
}

HRESULT MyClass::QueryInterface(const IID& iid, void** ppvObject)


{
if ( iid == IID_IUnknown )

{
*ppvObject = (IMyInterface *) this ;
((IMyInterface *)(*ppvObject))->AddRef() ;
}
else if ( iid == IID_IMyInterface )

{
*ppvObject = (IMyInterface *) this ;
((IMyInterface *)(*ppvObject))->AddRef() ;
}
else

{
*ppvObject = NULL;
return E_NOINTERFACE ;
}

return S_OK;
}

void MyClass::MyTest()


{
printf("MyTest called\n");
}
类工厂的实现 MyFactory.cpp
#include "MyFactory.h"
#include "MyClass.h"

extern ULONG g_LockNumber;
extern ULONG g_ClassNum;

MyFactory::MyFactory()
:m_Ref(0)


{

}

MyFactory::~MyFactory()


{

}

HRESULT MyFactory::QueryInterface(const IID& iid, void **ppv)


{
if ( iid == IID_IUnknown )

{
*ppv = (IUnknown *) this ;
((IUnknown *)(*ppv))->AddRef() ;
}
else if ( iid == IID_IClassFactory)

{
*ppv = (IClassFactory *) this ;
((IClassFactory *)(*ppv))->AddRef() ;
}
else

{
*ppv = NULL;
return E_NOINTERFACE ;
}
return S_OK;
}

ULONG MyFactory::AddRef()


{
++m_Ref;
return (ULONG)m_Ref;
}

ULONG MyFactory::Release()


{
--m_Ref;
if (m_Ref == 0)

{
delete this;
return 0;
}
return (ULONG)m_Ref;
}

HRESULT MyFactory::CreateInstance(IUnknown *pUnknownOuter,
const IID& iid, void **ppv)


{
MyClass* pObj;
HRESULT hr;
*ppv=NULL;
hr=E_OUTOFMEMORY;

if (NULL != pUnknownOuter)
return CLASS_E_NOAGGREGATION;
//Create the object
pObj = new MyClass();
if (NULL==pObj)
return hr;
//Obtain the first interface pointer (which does an AddRef)
hr=pObj->QueryInterface(iid, ppv);


if (hr != S_OK)
{
delete pObj;
}
return hr;
}

HRESULT MyFactory::LockServer(BOOL bLock)


{
if (bLock)
g_LockNumber ++;
else
g_LockNumber --;

return NOERROR;
}
需要导出的函数
MyCom.cpp
#include "MyFactory.h"


extern ULONG g_LockNumber;
extern ULONG g_ClassNum;
HANDLE g_hModule = NULL; //用来获得DLL文件名

//对应该com组件
extern "C" const GUID CLSID_Facotry =

{ 0x54bf6567, 0x1007, 0x11d1,

{ 0xb0, 0xaa, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} } ;


//DLL 入口
BOOL APIENTRY DllMain( HANDLE hModule,
DWORD ul_reason_for_call,
LPVOID lpReserved
)


{
g_hModule = hModule;
return TRUE;
}

//写注册表
//先创建,在写值
BOOL SetKey(const WCHAR* key, const WCHAR* value)


{
HKEY hKey;
//创建KEY
long lResult = ::RegCreateKeyEx(HKEY_CLASSES_ROOT ,
key,
0, NULL, REG_OPTION_NON_VOLATILE,
KEY_ALL_ACCESS, NULL,
&hKey, NULL) ;
if (lResult != ERROR_SUCCESS)

{
return FALSE ;
}

//写value
lResult = ::RegSetValueEx(hKey, NULL, 0, REG_SZ, (const BYTE*)value, (DWORD)(wcslen(value)+1)*2);
if (lResult != ERROR_SUCCESS)

{
::RegCloseKey(hKey);
return FALSE ;
}

::RegCloseKey(hKey);
return TRUE;
}

//删除注册表
//因为::RegDeleteKey只能删除没有子key的key,
//所以提供该函数,删除一个key时,先删除其所有子key
BOOL DelKey(HKEY key, const WCHAR* subkey)


{
HKEY hKeyChild ;
//open the key
LONG lRes = RegOpenKeyEx(key, subkey, 0,
KEY_ALL_ACCESS, &hKeyChild) ;
if (lRes != ERROR_SUCCESS)

{
return FALSE ;
}

WCHAR name[1024] ;
DWORD size = 2048;
while (::RegEnumKeyEx(hKeyChild, 0, name, &size, NULL, NULL, NULL, NULL) == S_OK)

{
//若还有子key,则递归调用该函数
BOOL bRes = DelKey(hKeyChild, name) ;
if (FALSE == bRes)

{
// 出错,Close key
::RegCloseKey(hKeyChild) ;
return FALSE;
}
size = 2048 ;
}

//该key没有子key,关闭该key,删除该key
::RegCloseKey(hKeyChild) ;
if(ERROR_SUCCESS != ::RegDeleteKey(key, subkey))
return FALSE;

return TRUE;
}

//供com库调用,创建factory类对象
extern "C" HRESULT __stdcall DllGetClassObject(const CLSID& clsid, const IID& iid, void **ppv)


{
if (clsid == CLSID_Facotry )

{
MyFactory *pFactory = new MyFactory;

if (pFactory == NULL)
{
return E_OUTOFMEMORY ;
}
HRESULT result = pFactory->QueryInterface(iid, ppv);

return result;

} else
{
return CLASS_E_CLASSNOTAVAILABLE;
}
}

//判断dll是否可以被卸载
extern "C" HRESULT __stdcall DllCanUnloadNow(void)


{
if ((g_ClassNum == 0) && (g_LockNumber == 0))
return S_OK;
else
return S_FALSE;
}

//使用regsvr32注册DLL时会被调用
//向注册表中写信息:1、DLL位置;2、线程模型
extern "C" HRESULT __stdcall DllRegisterServer()


{
//Get DLL name
WCHAR szName[1024];
if(0 == ::GetModuleFileName((HMODULE)g_hModule, szName, 2048))
return S_FALSE;

//Get key
LPOLESTR sKey = NULL;
//由GUID获得字符串
if(S_OK != ::StringFromCLSID(CLSID_Facotry, &sKey))
return S_FALSE;
WCHAR wKey_1[1024] = L"CLSID\\";
wcscat_s(wKey_1, sizeof(wKey_1), sKey);
wcscat_s(wKey_1, sizeof(wKey_1), L"\\InprocServer32");

//Set first key and value
SetKey(wKey_1, szName);
WCHAR wKey_2[1024] = L"CLSID\\";
wcscat_s(wKey_2, sizeof(wKey_2), sKey);
wcscat_s(wKey_2, sizeof(wKey_2), L"\\ProgID");

//Set second key and value
SetKey(wKey_2, L"MyCom");
::CoTaskMemFree(sKey);
return S_OK;
}

//使用regsvr32 -u卸载DLL时会被调用
//删除之前在注册表中写入的信息
extern "C" HRESULT __stdcall DllUnregisterServer()


{
//Get key
LPOLESTR sKey = NULL;
if(S_OK != ::StringFromCLSID(CLSID_Facotry, &sKey))
return S_FALSE;
WCHAR wKey[1024] = L"CLSID\\";
wcscat_s(wKey, sizeof(wKey), sKey);
if(FALSE == DelKey(HKEY_CLASSES_ROOT, wKey))
return S_FALSE;

return S_OK;
}


导出声明 Export.def
LIBRARY "TestCom"

EXPORTS
DllGetClassObject PRIVATE
DllCanUnloadNow PRIVATE
DllRegisterServer PRIVATE
DllUnregisterServer PRIVATE
以上文件在同一工程中,生成一个DLL,在注册表中注册后,客户端可以使用自己定义的接口。
客户端代码:
#include <iostream>
#include <comdef.h>
#include "IMyInterface.h"
using namespace std;

//Interface ID
extern "C" const GUID IID_IMyInterface =

{ 0x54bf6569, 0x1007, 0x11d1,

{ 0xb0, 0xaa, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} } ;

//Class Factory ID
extern "C" const GUID CLSID_Facotry =

{ 0x54bf6567, 0x1007, 0x11d1,

{ 0xb0, 0xaa, 0x44, 0x45, 0x53, 0x54, 0x00, 0x00} } ;


int main()


{
IUnknown *pUnknown; //指向对象,不需要知道对象是谁
IMyInterface *pInterface; //接口指针
HRESULT hResult;

//初始化com库

if (CoInitialize(NULL) != S_OK)
{
printf("Initialize COM library failed!\n");
return -1;
}

//创建类对象
hResult = CoCreateInstance(CLSID_Facotry, NULL,
CLSCTX_INPROC_SERVER, IID_IUnknown, (void **)&pUnknown);
if (hResult != S_OK)

{
printf("Create object failed!\n");
return -2;
}

//获得接口
hResult = pUnknown->QueryInterface(IID_IMyInterface, (void **)&pInterface);

if (hResult != S_OK)
{
pUnknown->Release();
printf("QueryInterface IDictionary failed!\n");
return -4;
}

//调用函数
pInterface->MyTest();

//释放
pInterface->Release();
pUnknown->Release();

//释放com库资源
CoUninitialize();

return 0;
}