定义接口
//
// Iface.h
//
// 接口,所有COM接口都必须实现 IUnkown 接口
interface IX : IUnknown
{
virtual void __stdcall Fx() = 0 ;
} ;
interface IY : IUnknown
{
virtual void __stdcall Fy() = 0 ;
} ;
interface IZ : IUnknown
{
virtual void __stdcall Fz() = 0 ;
} ;
// GUIDs 的前向引用
// extern是C/C++语言中表明函数和全局变量作用范围(可见性)的关键字,该关键字
// 告诉编译器,其声明的函数和变量可以在本模块或其它模块中使用。
// IID:代表COM组件的接口
extern "C"
{
extern const IID IID_IX ;
extern const IID IID_IY ;
extern const IID IID_IZ ;
}
定义组件, 从DLL中输出函数
//
// Cmpnt1.cpp
// 编译时, 使用: cl /LD Cmpnt1.cpp GUIDs.cpp UUID.lib Cmpnt1.def
//
#include <iostream.h>
//定义了 #define interface struct
#include <objbase.h>
#include "Iface.h"
void trace(const char* msg)
{
cout << "Component 1:\t" << msg << endl ;
}
//
// Component
//
class CA : public IX
{
// 实现 IUnknown 接口
virtual HRESULT __stdcall QueryInterface(const IID& iid, void** ppv) ;
virtual ULONG __stdcall AddRef() ;
virtual ULONG __stdcall Release() ;
// 实现 IX 接口
virtual void __stdcall Fx() { cout << "Fx" << endl ;}
public:
// 构造
CA() : m_cRef(0) {}
// 析构
~CA() { trace("Destroy self.") ;}
private:
long m_cRef ;
} ;
//接口查询
//IID:代表COM组件的接口,所需接口的常量
//ppv: 存放所请求接口指针的地址
//HRESULT: 具有特定结构的32位值
HRESULT __stdcall CA::QueryInterface(const IID& iid, void** ppv)
{
if (iid == IID_IUnknown)
{
trace("Return pointer to IUnknown.") ;
*ppv = static_cast<IX*>(this) ; //类型转换
}
else if (iid == IID_IX)
{
trace("Return pointer to IX.") ;
*ppv = static_cast<IX*>(this) ;
}
else
{
trace("Interface not supported.") ;
*ppv = NULL ; //客户所查询的接口不被支持时,将ppv置为NULL
return E_NOINTERFACE ;
}
reinterpret_cast<IUnknown*>(*ppv)->AddRef() ;
return S_OK ;
}
//引用计数加1
ULONG __stdcall CA::AddRef()
{
return InterlockedIncrement(&m_cRef) ;
}
//引用计数减1
ULONG __stdcall CA::Release()
{
if (InterlockedDecrement(&m_cRef) == 0)
{
delete this ;
return 0 ;
}
return m_cRef ;
}
//从DLL中输出该函数
//建立一个组件,并返回一个IUnknown指针
//extern "C" 以C语言的方式编译,防止C++编译器在函数名上加上类型信息
extern "C" IUnknown* CreateInstance()
{
IUnknown* pI = static_cast<IX*>(new CA) ;
pI->AddRef() ;
return pI ;
}
定义DLL要输出的函数
Cmpnt1.def
;
; Cmpnt1 模块-定义 文件
; 告诉连接程序需要输出什么函数
; LIBRARY:加上DLL的实际名称
; EXPORTS:列出待从DLL中输出的函数的名称,对每个名称,还可加上一个序号
LIBRARY Cmpnt1.dll
DESCRIPTION '(c)1996-1997 Dale E. Rogerson'
EXPORTS
CreateInstance @1 PRIVATE
DLL的装载
//
// Create.h
//
//name:DLL的名称
IUnknown* CallCreateInstance(char* name) ;
//
// Create.cpp
//
#include <iostream.h>
#include <unknwn.h> // 声明 IUnknown.
#include "Create.h"
typedef IUnknown* (*CREATEFUNCPTR)() ;
//name:所装载的DLL名称
IUnknown* CallCreateInstance(char* name)
{
// 将动态链接库加载到进程中
// 返回一个所装载的DLL名称句柄
HINSTANCE hComponent = ::LoadLibrary(name) ;
if (hComponent == NULL)
{
cout << "CallCreateInstance:\tError: Cannot load component." << endl ;
return NULL ;
}
// 得到 CreateInstance 函数的地址
// hComponent:DLL的句柄
// "CreateInstance":函数的名称
CREATEFUNCPTR CreateInstance
= (CREATEFUNCPTR)::GetProcAddress(hComponent, "CreateInstance") ;
if (CreateInstance == NULL)
{
cout << "CallCreateInstance:\tError: "
<< "Cannot find CreateInstance function."
<< endl ;
return NULL ;
}
return CreateInstance() ;
}
连接客户和组件
可以使用GUIDGEN.exe生成一个GUID
//
// GUIDs.cpp - 接口 ID
//
#include <objbase.h>
extern "C"
{
// {32bb8320-b41b-11cf-a6bb-0080c7b2d682}
extern const IID IID_IX =
{0x32bb8320, 0xb41b, 0x11cf,
{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ;
// {32bb8321-b41b-11cf-a6bb-0080c7b2d682}
extern const IID IID_IY =
{0x32bb8321, 0xb41b, 0x11cf,
{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ;
// {32bb8322-b41b-11cf-a6bb-0080c7b2d682}
extern const IID IID_IZ =
{0x32bb8322, 0xb41b, 0x11cf,
{0xa6, 0xbb, 0x0, 0x80, 0xc7, 0xb2, 0xd6, 0x82}} ;
// The extern is required to allocate memory for C++ constants.
}
客户
//
// Client1.cpp
// 编译时, 使用: cl Client1.cpp Create.cpp GUIDs.cpp UUID.lib
#include <iostream.h>
#include <objbase.h>
#include "Iface.h"
#include "Create.h"
void trace(const char* msg) { cout << "Client 1:\t" << msg << endl ;}
//
// Client1
//
int main()
{
HRESULT hr ;
// Get the name of the component to use.
char name[40] ;
cout << "Enter the filename of a component to use [Cmpnt?.dll]: " ;
cin >> name ;
cout << endl ;
// 客户首先要求用户输出DLL名称
// 然后调用指定DLL中输出的CreateInstance函数创建相应的组件
trace("Get an IUnknown pointer.") ;
IUnknown* pIUnknown = CallCreateInstance(name) ;
if (pIUnknown == NULL)
{
trace("CallCreateInstance Failed.") ;
return 1 ;
}
trace("Get interface IX.") ;
//查询接口
IX* pIX ;
hr = pIUnknown->QueryInterface(IID_IX, (void**)&pIX) ;
if (SUCCEEDED(hr))
{
trace("Succeeded getting IX.") ;
pIX->Fx() ; // 使用接口 IX.
pIX->Release() ; // 引用计数减1
}
else
{
trace("Could not get interface IX.") ;
}
trace("Release IUnknown interface.") ;
pIUnknown->Release() ; // 引用计数减1
return 0 ;
}