COM接口与对象
潘爱民
panaimin@icst.pku.edu.cn
内容
!组件的接口
!COM接口
!COM IDL
!COM对象
从历史看COM
!COM产生的背景
– 93年因为OLE 2的需要而产生
– OLE 1的缺陷
!COM又从OLE中脱颖而出
– COM的优势不限于OLE
– COM成为Microsoft跟上Internet的
一项重要基础技术
!今天的Windows平台上,COM无
处不在
COM基础——几个概念
!COM组件
–可独立发布的二进制组件
–在Windows平台上为DLL或者EXE
!COM对象
–通过COM接口提供服务
–符合OO中对象的基本概念
!COM接口
–客户与对象之间的协议,对象实
现COM接口,客户使用COM接口
如何设计?
!COM组件
–为 , Windows平台
上DLL 的组件
!COM对象
–如何 一个对象?对象
在?客户如何 对象?
–对象如何 接口?一个或 个?
!COM接口
–要 平台
设计COM接口——从C++ ?
!C++ 接口与实现的¢£
–接口 的public?¢
class CMyString
{
private:
char *m_psz;
public:
CMyString(const char * psz);
~CMyString();
const char*Find(const char *psz);
int Length();
};
设计COM接口——从C++ ?(¥)
!C++ 的实现
CMyString::CMyString(const char * psz)
: m_psz( new char[psz ? strlen(psz)+1 :1]) {
if ( psz )
strcpy(m_psz,psz);
else
m_psz[0] = 0;
}
CMyString::~CMyString() {
delete [] m_psz;
}
const char*CMyString::Find(const char *psz) {
return strstr(m_psz,psz);
}
int CMyString::Length() {
return strlen(m_psz);
}
C++ 的?接linking
!§currency1?接
–' “的??
– ?fi的?接
!§currency1?接的缺fl
– –重? 个?· ???的
–,需要? 的内
–客户?·”?? 的… ‰间
–“ –? 需要重 ??的
客户?·
C++ 的?接linking(¥)
! currency1?接
–`′?fi的?接
! currency1?接
– ?fi通过? “
–`′?fi?ˉ currency1
#ifdef MYSTRINGDLL
#define EXPORTORIMPORT _declspec(dllexport)
#else
#define EXPORTORIMPORT _declspec(dllimport)
#endif
class EXPORTORIMPORT CMyString
{
private:
char *m_psz;
public:
CMyString(const char * psz);
~CMyString();
const char*Find(const char *psz);
int Length();
};
C++接口如何?˙COM接口
! currency1?接符合COM的需要
!C++中 的接口 在的¨
–客户看?? ?
– 用Visual C++ 5.0/6.0
??0CMyString@@QAE@PBD@Z
??1CMyString@@QAE@XZ
?Find@CMyString@@QAEPBDPBD@Z
?Length@CMyString@@QAEHXZ
客户?中的C++ (¥)
!如? Borland C++ (4.02)
@CMyString@$bctr$qpxc
@CMyString@$bdtr$qv
@CMyString@Find$qpxc
@CMyString@Length$qv
!¨ 1 ˇ—
ˇ 1
! 件(.def)中 出 ˇ
LIBRARY MYSTRING
EXPORTS
@CMyString@$bctr$qpxc=??0CMyString@@QAE@PBD@Z
@CMyString@$bdtr$qv=??1CMyString@@QAE@XZ
@CMyString@Find$qpxc=?Find@CMyString@@QAEPBDPBD@Z
@CMyString@Length$qv=?Length@CMyString@@QAEHXZ
ˇ 2
! 件(.def)中 出· ˇ
LIBRARY MYSTRING
EXPORTS
??0CMyString@@QAE@PBD@Z @1
??1CMyString@@QAE@XZ @2
?Find@CMyString@@QAEPBDPBD@Z @3
?Length@CMyString@@QAEHXZ @4
LIBRARY MYSTRING
EXPORTS
@CMyString@$bctr$qpxc @1
@CMyString@$bdtr$qv @2
@CMyString@Find$qpxc @3
@CMyString@Length$qv @4
ˇ 3
!使用C++ 的vtable
!C++ 的vtable不 而 ?
!vtable a? 个 的 , ·?
,?个 的? o ,
ˇ 不重要
!vtable要 接口 ?
!客户如何 ?vtable?
–? 需要?一 ??? C++
– new/delete?需要对象的二进制??——
¨ 2
C++对象的二进制??
!C++的 ?上的 ,而不 二
进制
!new/delete 的
– 不仅要知道public信息,也要知道
private信息
!C++对象的二进制?? 的
!即使客户看?的C++ 公开接口没?
?,但 C++ 的实现改 ?,? 会
打破客户与对象之间的连接
C++对象与客户之间的连接¨
!客户与C++对象之间的连接fl越小越好
– ?接口?¢?要的信息才放 接口
–把C++ 的实现细节与接口¢开
–提取出针对?? 都不 的因素作为
客户与对象共享的接口信息
! 1 句柄
句柄
! 1 句柄
#ifndef CMyString
class CMyString;
#endif
class EXPORTORIMPORT IMyString
{
private:
CMyString *m_pthis;
public:
IMyString(const char * psz);
~IMyString();
const char*Find(const char *psz);
int Length();
};
class CMyString
{
private:
char *m_psz;
int m_nLength;
public:
CMyString(const char * psz);
~CMyString();
const char*Find(const char *psz);
int Length();
};
纯 基
!前提条件
–在 平台上??的 都会产生同
样的二进制??
–纯 在单继承情况下满足 一条件
!纯 基 a ,限 ?个
的调用习惯
!对于 平台的情 ,我们肯 要通过
中间层,? 暂?可 不考虑
的继承布局情况
class B : pulic A {
private :
int value1;
public:
virtual void Func1(void)
virtual void Func2(void)
};
量 偏移量
value 0
vptr 4
value1 8
B::Func1
B::Func2
vtable
纯 基 例子
! ?ˇ—
! ?C++ 的二进制布局不兼容¨
– 客户 看?vtable,没?看?其他的实现细节
– 保证不同 写的?·可 互操作
– 在不改 接口的情况下,可 单独升级客户或者对象
class IString
{
virtual const char*Find(const char *psz)=0;
virtual int Length()=0;
};
量 偏移量
vptr 4
Find
Length
vtable
纯 接口的使用?
!假如?一个C++对象实现?IString
!客户怎 使用?
–怎 拿?vtable接口
#include "istring.h"
class CMyString : public IString
{
private:
char *m_psz;
public:
CMyString(const char * psz);
~CMyString();
const char*Find(const char *psz);
int Length();
};
如何 对象?
!不能使用new
!DLL的唯一接口 ?出
!可′ 单独提供一个?出 供
客户调用
extern "C" _declspec(dllexport)IString *CreateString(const char *psz);
extern "C" IString *CreateString(const char *psz)
{
return new CMyString(psz);
}
通过?出 对象
extern "C" _declspec(dllimport)
IString *CreateString(const char *psz);
void main() {
IString *p;
p = CreateString("Hello");
if (p) {
const char*psz = p->Find("llo");
int n = p->Length();
}
};
对
象
#include "istring.h"
typedef IString * (*PfnCreateString)(const char *psz);
void main() {
IString *p;
HANDLE h = LoadLibrary("c:\\temp\mystring.dll");
if (NULL!=h) {
PfnCreateString pfn =
(PfnCreateString)GetProcAddress(h,"CreateString");
if (pfn) {
p = pfn("Hello");
if (p) {
const char*psz = p->Find("llo");
int n = p->Length();
}
}
// Be careful about calling FreeLibrary.
}
};
如何删除对象?
!删除对象发生在客户与对象 立联系之
后,? 比较好?
!但 不能用delete
!可 让对象??把??删除
!在IString中增加一个 ?
class IString
{
virtual void Delete()=0;
virtual const char*Find(const char *psz)=0;
virtual int Length()=0;
};
删除对象?身
#include "istring.h"
class CMyString : public IString
{
private:
char *m_psz;
public:
CMyString(const char * psz);
virtual ~CMyString();
void Delete();
const char*Find(const char *psz);
int Length();
};
void CMyString::Delete() {
delete this;
}
#include "istring.h"
void main() {
IString *p;
p = CreateString("Hello");
if (p) {
const char*psz = p->Find("llo");
int n = p->Length();
p->Delete();
}
};
小?
!我们已经 立 对象与客户之间的基本
通信
!?高的要
–接口的升级
–增加 的功能
–生 周期管
! ? 删除对象
! 个客户共享同一个对象,如何管 ?
对象的进?
!在 ?接口的基础上增加 的功能,例如
class IString
{
virtual void Delete();
virtual const char*Find(const char *psz);
virtual int Length();
virtual char FindAt(int index);
};
客户 的对象
对象的进? ¥
!?ˉ增加 的功能
class IPersist
{
virtual void Delete();
virtual void Save(const char *pszFile);
virtual void Load(const char *pszFile);
};
客户
对象
IString
IPersist
?
接口的进?
!对象的接口不能发生 ?
–如?接口中需要增加 的 ?,可 生出
的接口?
class IString2 : public IString
{
virtual char FindAt(int index);
};
! 对象实现 个接口 IString2 IString
–不打 的客户与 的对象之间的 系
–但 客户? 知道对象 实现??
? 的接口
对象实现 个接口
!假如对象实现? 个接口IString IPersist
–客户需要在runtime中 知道接口的
信息, 通过 ?的 接口
– at runtime,客户可 从一个接口
? 一个接口,如?对象不 个接口,客
户???知道
– RTTI(Runtime type identification)
!dynamic_cast
!RTTI 于 的实现
!RTTI 能用于 的继承层 中
对象实现 个接口(¥一)
!? 我们需要??? 一 ?制,要
–?个接口都要提供 ¢ ?制,能¢ ?同
一对象上实现的其他接口中
–客户 要 ??一个接口£可 ?其他的接
口,? 可 o ?一个接口
–如?对象不 个接口,客户? 能
知道,而不 发生¥? —— robust
– Dynamic_cast
对象实现 个接口(¥二)
!一个对象实现IString2 IString接口
class IString
{
virtual void Delete()=0;
virtual void *Dynamic_cast(const char *psz)=0;
virtual const char*Find(const char *psz)=0;
virtual int Length()=0;
};
class IString2 : public IString
{
virtual char FindAt(int index)=0;
};
对象实现 个接口(¥§)
!实现Dynamic_cast
class CMyString : public IString2{...}
void *CMyString::Dynamic_cast(const char *psz)
{
if (strcmp(psz,"IString")==0)
return static_cast<IString *>(this);
else
if (strcmp(psz,"IString2")==0)
return static_cast<IString2 *>(this);
return NULL;
}
对象实现 个接口(¥currency1
currency1
)
#include "istring.h"
void main() {
IString *p = CreateString("Hello");
if (p) {
IString2 *p2;
const char*psz = p->Find("llo");
int n = p->Length();
if ((p2=(IString2 *)p->Dynamic_cast("IString2")))
char c = p2->FindAt(3);
p->Delete();
}
};
class IPersist
{
virtual void Delete()=0;
virtual void *Dynamic_cast(const char *psz)=0;
virtual void Save(const char *pszFile)=0;
virtual void Load(const char *pszFile)=0;
};
对象实现 个接口(¥')
!一个对象实现 个没?继承 系的接口
#include "istring.h"
class CMyString : public IString2, public IPersist {...}
void *CMyString::Dynamic_cast(const char *psz) {
if (strcmp(psz,"IString")==0)
return static_cast<IString *>(this);
else
if (strcmp(psz,"IString2")==0)
return static_cast<IString2 *>(this);
else
if (strcmp(psz,"IPersist")==0)
return static_cast<IPersist *>(this);
return NULL;
}
对象实现 个接口(¥“)
void main() {
IString *p = CreateString("Hello");
if (p) {
IString2 *p2;
IPersist *p3;
const char*psz = p->Find("llo");
int n = p->Length();
if ((p2=(IString2 *)p->Dynamic_cast("IString2")))
char c = p2->FindAt(3);
if ((p3=(IPersist *)p->Dynamic_cast("IPersist")))
p3->Save("c:\\temp\\str.txt");
p->Delete();
}
};
对象实现 个接口(¥?)
接口的¢
!?个接口提供一个用于接口¢ 的
!对象实现接口的? ,可 使用C++
本身提供的 ¢ 功能
!?个接口的Dynamic_cast ?
客户可 ?¨其他? 接口
对象的生 周期管
!对象 需要fi删除一 fl?个对象都
?Delete ? ?一个对象都
??进一–, ? 删除对象?
!客户可能?? 个?˙对象的?用,
?个?用 ???的lifetime
!?个?用从fi?· ?开 ,一??
生 周期??, 期间fi?为
outstanding reference ”???用
!客户管 ?个?用的lifetime,也£
?…要‰ ?对象?用无·?
对象的生 周期管 (¥)
!?个对象要管 一个fi?为?用计
(reference count)的 ?fl
!为??· 管 对象的生 周期,…`
提供一 ′? 操作,供客户?ˉ 使用
!′? 保 ?用计 的 ?a ,也£
˙¨ 前outstanding reference的 ?fl
?用计 从0开 ,? 把接口 ? 客
户?为1, 后?客户管 , ?用计
?0?,删除??fl
! 客户通过?制ˇ 的接口?针?,?
用计 加一, 个接口不用?,—一
?用计 的 个操作
!我们用?用计
的 个管 操作
? 单的
Delete
class IString
{
virtual void DestroyPointer()=0;
virtual void *Dynamic_cast(const char *psz)=0;
virtual void DuplicatePointer()=0;
virtual const char*Find(const char *psz)=0;
virtual int Length()=0;
};
class IPersist
{
virtual void DestroyPointer()=0;
virtual void *Dynamic_cast(const char *psz)=0;
virtual void DuplicatePointer()=0;
virtual void Save(const char *pszFile)=0;
virtual void Load(const char *pszFile)=0;
};
实现?用计 的 个操作
CMystring::CMyString(const char * psz)
: m_psz( new char[psz ? strlen(psz)+1 :1]),
m_refcount(0) {
if ( psz )
strcpy(m_psz,psz);
else
m_psz[0] = 0;
}
void CMyString::DestroyPointer() {
if (0<m_refcount)
m_refcount--;
if (0==m_refcount)
delete this;
}
void CMyString::DuplicatePointer() {
m_refcount++;
}
#include "istring.h"
class CMyString : public IString2,
public IPersist
{
private:
char *m_psz;
long m_refcount;
public:
CMyString(const char * psz);
~CMyString();
void DuplicatePointer();
void DestroyPointer();
void *Dynamic_cast(const char *);
const char*Find(const char *psz);
int Length();
char FindAt(int index);
void Save(const char *pszFile);
void Load(const char *pszFile);
};
接口¢ ?fi 于接口?制
void *CMyString::Dynamic_cast(const char *psz) {
void *p = NULL;
if (strcmp(psz,"IString")==0)
p = static_cast<IString *>(this);
else
if (strcmp(psz,"IString2")==0)
p = static_cast<IString2 *>(this);
else
if (strcmp(psz,"IPersist")==0)
p = static_cast<IPersist *>(this);
if (NULL!=p)
m_refcount++;
return p;
}
客户管 对象的生 周期
void main() {
IString *p = CreateString("Hello");
if (p) {
IString2 *p2;
IPersist *p3;
const char*psz = p->Find("llo");
int n = p->Length();
if ((p2=(IString2 *)p->Dynamic_cast("IString2"))) {
char c = p2->FindAt(3);
p2->DestroyPointer();
}
if ((p3=(IPersist *)p->Dynamic_cast("IPersist"))) {
p3->Save("c:\\temp\\str.txt");
p3->DestroyPointer();
}
p->DestroyPointer();
}
};
extern "C" void *CreateString(const char *psz,
const char *pszinterface)
{
void *pret = NULL;
CMyString *p = new CMyString(psz);
if (NULL!=p) {
pret= p->Dynamic_cast(pszinterface);
if (NULL==pret)
delete p;
}
return pret;}
改
!让 也 ?用计
接口
!?个接口都需要下 的§个
– Dynamic_cast
– DuplicatePointer
– DeletePointer
!把§个 放?一个基接口中,??的
接口都从 个基接口 生
class IAnyInterface
{
virtual void *DynamicCast(const char *psz)=0;
virtual void DuplicatePointer()=0;
virtual void DestroyPointer()=0;
};
其他 考虑的¨
!Dll ? fi ?
!如何 一个接口?—符 ?
! ? ˉ?
!如何 一个对象?对象的身 ?
! 进?? ? ?对象 ??
!……
COM接口
!概念 , 二进制的 出?
从一 ? 一 的调用′a
!接口 ——IID
!IUnknown
!COM接口二进制??
COM接口的 ——IID
! GUID的一 用?
! GUID 一个128 的
!产生′?保证?唯一
!例子 {54BF6567-1007-11D1-B0AA-444553540000}
! C ??
typedef struct _GUID {
DWORD Data1;
WORD Data2;
WORD Data3;
BYTE Data4[8];
} GUID;
extern "C" const GUID CLSID_MYSPELLCHECKER =
{ 0x54bf6567, 0x1007, 0x11d1,
{ 0xb0, 0xaa, 0x44, 0x45, 0x53,
0x54, 0x00, 0x00} } ;
IUnknown接口
!??的COM接口都从IUnknown 生
!C++
class IUnknown
{
public:
virtual HRESULT__stdcall QueryInterface(
const IID& iid, void **ppv) = 0 ;
virtual ULONG __stdcall AddRef() = 0;
virtual ULONG __stdcall Release() = 0;
};
IUnknown接口(¥)
!C
typedef struct IUnknownVtbl
{
HRESULT ( STDMETHODCALLTYPE __RPC_FAR *QueryInterface )(
IUnknown __RPC_FAR * This, /* [in] */ REFIID riid,
/* [iid_is][out] */ void __RPC_FAR *__RPC_FAR *ppvObject);
ULONG ( STDMETHODCALLTYPE __RPC_FAR *AddRef )(
IUnknown __RPC_FAR * This);
ULONG ( STDMETHODCALLTYPE __RPC_FAR *Release )(
IUnknown __RPC_FAR * This);
} IUnknownVtbl;
interface IUnknown
{
CONST_VTBL struct IUnknownVtbl __RPC_FAR *lpVtbl;
};
COM接口??
接口?针 ?针 ?针 1
?针 2
?针 3
flflflflflfl
对象实现
vtablepVtable
C ??例——IDictionary
struct IDictionaryVtbl;
struct IDictionary
{
IDictionaryVtbl * pVtbl;
};
struct IDictionaryVtbl
{
/* … QueryInterface, AddRef, Release */
BOOL (*Initialize)( IDictionary * this);
BOOL (*LoadLibrary)( IDictionary * this, String);
BOOL (*InsertWord)( IDictionary * this, String, String);
void (*DeleteWord)( IDictionary * this, String);
BOOL (*LookupWord)( IDictionary * this, String, String *);
BOOL (*RestoreLibrary )( IDictionary * this, String);
void (*FreeLibrary)( IDictionary * this);
};
C++ ??例—IDictionary
class IDictionary : public IUnknown
{
virtual BOOL Initialize() = 0;
virtual BOOL LoadLibrary(String) = 0;
virtual BOOL InsertWord(String, String) = 0;
virtual void DeleteWord(String) = 0;
virtual BOOL LookupWord(String, String *) = 0;
virtual BOOL RestoreLibrary(String) = 0;
virtual void FreeLibrary() = 0;
};
pVtable
HRESULT QueryInterface(…)
ULONG AddRef();
ULONG Release();
BOOL Initialize(this *)
BOOL LoadLibrary(this *, String);
BOOL InsertWord)( this *, String);
void DeleteWord)( this *, String);
BOOL LookupWord(this *, String, String *);
BOOL RestoreLibrary(this *, String);
void FreeLibrary(this *);
IDictionary vtable
this
COM接口的内
客户使用的
接口?针
pIDictionary
pVtable QueryInterface
AddRef
Release
Initialize
CDictionary 中
的?o实现
vtable
m_pData
m_DictFilename
flflflflflfl
COM接口的内 (¥一)
客户使用的
接口?针
pIDictionary1
pIDictionary2
pVtable
QueryInterface
AddRef
Release
Initialize
CDictionary 中
的?o实现
vtable
m_pData
m_DictFilename
pVtable
m_pData
m_DictFilename
flflflflflfl
COM接口的内 (¥二)
— 对象1的
接口?针
pIDictionary1
— 对象2的
接口?针
pIDictionary2
pVtable
QueryInterface
AddRef
......
CDictionary 中
的?o实
现
vtable
m_pData
m_DictFilename
pVtable
— ?
......
QueryInterface
AddRef
......
一个— 对象
中 的?
o实现
vtable
接口
!?的 COM′a,一个COM对象可
实现 个接口fl从一个接口? 一个接口
的?¨?
! QueryInterface(iid, ppv)
!用?
– ??一个接口?针之后,调用…的
QueryInterface ,ˇ 一个接口?针
!o ?? ?对象对接口的 情况
!S_OK E_NOINTERFACE
E_UNEXPECTED
接口 用??例
// load the dictionary
retValue = pIDictionary->LoadLibrary("eng_ch.dict");
if (retValue == FALSE)
{ pIDictionary->Release(); return; }
......
ISpellCheck *pISpellCheck;
HRESULT result
= pIDictionary->QueryInterface(IID_SpellCheck,
(void **)&pISpellCheck);
if (result != S_OK)
{ pIDictionary->Release(); return; }
// ...... use interface pISpellCheck
// finally, release dictionary object
pIDictionary->Release();
pISpellCheck ->Release ( );
......
QueryInterface实现
!与对象的 ?
!IUnknown? 个§currency1接口?针,其他
接口?针可 currency1的
!QueryInterface在o 接口之前,? 调
用 接口的AddRef
QueryInterface实现 例
class CDictionary : public IDictionary , public ISpellCheck
{
public :
CDictionary();
~CDictionary();
public :
// IUnknown member function
virtual HRESULT QueryInterface(const IID& iid, void **ppv) ;
virtual ULONG AddRef() ;
virtual ULONG Release() ;
......
private :
int m_Ref ;
......
};
IUnknown
IDictionary
CDictionary
IUnknown
ISpellCheck
QueryInterface实现 例 ¥一
IDictionary的vtable?针
this?针
ISpellCheck的vtable?针
CDictionary
的 ?
QueryInterface
AddRef
Release
......
QueryInterface
AddRef
Release
......
IDictionary
成?
ISpellCheck
成?
vtable
QueryInterface实现 例 ¥二
HRESULT CDictionary::QueryInterface(const IID& iid,
void **ppv)
{
if ( iid == IID_IUnknown ){
*ppv = static_cast<IDictionary *>this ;
((IDictionary *)(*ppv))->AddRef() ;
} else if ( iid == IID_Dictionary ) {
*ppv = static_cast<IDictionary *>this ;
((IDictionary *)(*ppv))->AddRef() ;
} else if ( iid == IID_SpellCheck ){
*ppv = static_cast<ISpellCheck * >this ;
((ISpellCheck *)(*ppv))->AddRef() ;
} else {
*ppv = NULL;
return E_NOINTERFACE ;
}
return S_OK;
}
COM对象的接口 ?
!IUnknown接口一
!接口对?
!接口?
!接口?
!接口 ?间无
?用计
!?的 为??制对象的生 周期
! 个客户可 独立 ?制对象的生
!?用计 ??fi客户?用的个
– Outstanding references
!?用计 个 ,从0开
! 个操作 增一 —一
! ?用计 为0?,??没?客户在使用
对象或者接口——删除
实现?用计
!层 ,或者
组件
对象1
IUnknown
ISomeIntface
组件?用计
对象?用计
接口?用计
对象2
IUnknown
IOtherIntface
flflfl
对象?用计
接口?用计
接口?用计
接口?用计
实现?用计 §
!组件级
–计 ¢ 太粗
!对象级
!接口级
–计 ¢ 太细
?用计 实现?例
class CDictionary : public IDictionary
{
public :
CDictionary();
~CDictionary();
public :
virtual HRESULT QueryInterface(const IID& iid,
void **ppv) ;
virtual ULONG AddRef() ;
virtual ULONG Release() ;
virtual BOOL Initialize();
virtual BOOL LoadLibrary(String);
// ……
private :
struct DictWord *m_pData;
char *m_DictFilename[128];
int m_Ref ;
};
?用计 实现?例(¥)
CDictionary::CDictionary ()
{
m_Ref = 0;
// ... initialize
}
ULONG CDictionary::AddRef ()
{
m_Ref ++;
return (ULONG) m_Ref;
}
ULONG CDictionary::Release ()
{
m_Ref --;
return (ULONG) m_Ref;
}
?用计 用?
!客户要?用接口?——增一操作
–调用IUnknown::AddRef()
!客户用?接口?———一操作
–调用IUnknown::Release()
! 对象的?用计 为0?,释放
! 组件中??对象的?用计 为0?,
!AddRef Release的o ?不可靠
?用计 使用?例
// load the dictionary
BOOL retValue = pIDictionary->LoadLibrary("eng_ch.dict");
if (retValue == FALSE)
{
pIDictionary->Release();
return;
}
......
IDictionary *pIDictionaryForWord = pIDictionary;
pIDictionaryForWord ->AddRef();
// Insert or delete some word
pIDictionaryForWord ->InsertWord("...","...");
pIDictionaryForWord ->DeleteWord("...");
pIDictionaryForWord ->Release ( );
......
// finally, release dictionary object
pIDictionary->Release ( );
使用?用计 ′?
! ?
–输 ?
–输出?
–输 -输出?
!局?接口?针 量
!ˉ局接口?针 量
! 成? 量
使用?用计 ′? ¥
!一般 ′?
–在 ·执′过?中,如?要对一个接口?针
量 ?,?对 ?后的接口?针 量调用
AddRef, 且,如? ?前的接口?针 量
没???,? ?前? 对…调用Release
先??…的使用fl
–如?要??使用一个接口?针 量, 后不再
用?…?,?调用Release fl
!优?
?用计 ¨
!在 个生 期内,AddRef与Release一
要配对, ?
–漏掉AddRef,?·出错
–漏掉Release,对象永不释放
?用计 实现 例
ULONG CDictionary::AddRef ()
{
m_Ref ++;
return (ULONG) m_Ref;
}
ULONG CDictionary::Release ()
{
m_Ref --;
if (m_Ref == 0 )
{
delete this;
return 0;
}
return (ULONG) m_Ref;
}
总? COM接口特fl
!二进制特
!接口不
!继承 (扩展 )
! currency1 ——`′过?中的 currency1
接口 ? IDL
interface IDictionary : IUnknown
{
HRESULT Initialize();
HRESULT LoadLibrary([in] string);
HRESULT InsertWord([in] string, [in] string);
HRESULT DeleteWord([in] string);
HRESULT LookupWord([in] string, [out] string *);
HRESULT RestoreLibrary([in] string);
HRESULT FreeLibrary();
};
! MIDL可 ?IDL 件生成C/C++接口 ?
IDL 介
! OSF IDL为基础
!基本 ?
–与C 非?接近, ?? 联合 枚
typedef
!interface
!coclass
!library
–可 产生 “
IUnknown接口的IDL ?
! IDL接口
[
local, object,
uuid(00000000-0000-0000-C000-000000000046),
pointer_default(unique)
]
interface IUnknown
{
typedef [unique] IUnknown *LPUNKNOWN;
HRESULT QueryInterface( [in] REFIID riid,
[out, iid_is(riid)] void **ppvObject);
ULONG AddRef();
ULONG Release();
}
IDL中 的 ?
[
uuid(1e196b20-1f3c-1069-996b-00dd010fe676),
version(1.0),
helpstring("A class"),
helpcontext(2481), appobject
]
coclass myapp
{
[source] interface IMydocfuncs : IUnknown;
dispinterface DMydocfuncs;
};
IDL中“的 ?
[
uuid(12345678-1234-1234-1234-123456789ABC),
helpstring("Hello 2.0 Type Library"),
lcid(0x0409),
version(2.0)
]
library Hello
{
/* Library definition statements */
};
IDL中library?例
[
object, uuid(. . .), <other interface
attributes>
]
interface IKnown : IUnknown
{
import "unknwn.idl";
<declarations, etc. for IKnown
interface go here>
};
[
<library attributes>
]
library KnownLibrary
{
//reference interface IKnown:
interface IKnown;
//or create a new class:
[
<coclass attributes>
]
coclass KnowMore
{
interface IKnown;
};
};
IDL的意
!IDL 无
– 的中间
!MIDL.exe产生C++头 件
– 于C++
!MIDL.exe产生TLB “
– COM本身提供?一 基础设施? 释 “
!??的 准接口都可 在SDK中找?IDL
?
COM对象
!客户的?互实o
! ?,或者状currency1 操作
currency1
!能够提供服务——通过COM接口
!对象的实现?组件?ˉ ?
COM对象的 ——CLSID
! GUID的一 用?
! 对象的? ? 要提供CLSID
!COM对象的身
–身 一 的可判
COM对象与C++对象的比较
!层 差¥
! 特
!可重用
! currency1 的?现 不同
COM对象 接口图?
— 对象
IUnknown
IDictionary
ISpellCheck
今天讲课内容的?考资料
!“COM 及`用”第二章
!“COM技术内幕”前currency1章
!“COM本质 ”第一 二章
!“COM Tutorial”
二选一
二选一
??作业
!读?·
–“COM 与`用”中
!第二章的“— 组件 — 客户”