COM特性
潘爱民
http://www.icst.pku.edu.cn/compcourse
内容
!复习:COM实现
!COM可重用模型 √
!COM跨进程模型 √
!COM线程模型
!COM安全性
复习:对象创建过程
客户
组件
创建实例对象
DllGetClassObject
{
}
创建类厂对象
复习:TreeView组件的注册信息
Microsoft TreeView Control
C:\WINDOWS\SYSTEM\COMCTL32.OCX
COMCTL.TreeCtrl.1
{6B7E6392-850A-101B-AFC0-4210102A8DA7}
C:\WINDOWS\SYSTEM\COMCTL32.OCX
复习:类厂(Class Factory)
!类厂:用于创建COM对象的COM对象
!目标:完成COM对象的创建过程,更好
地把客户与对象隔离开来。
!特殊性:
–实现一个或多个创建接口,缺省的接口
为IClassFactory
–类厂本身没有CLSID
–但是类厂的引用计数不参与对组件生命周期
的控制,如果需要,可以使用锁计数功能
复习:类厂(续)
!类厂与COM对象有一一对应
组件
IClassFactory
类厂
对象
IDictionary
ISpellCheck
多对象 多类厂组件
类厂1
对象1
类厂 2
对象 2
复习:COM创建 数
!CoGetClassObject
!CoCreateInstance
!CoCreateInstanceEx
!注 :对于DLL组件,创建
数 用DllGetClassObject引
数创建类厂, 类厂创建
COM对象
复习:COM
!COM 的
!COM 的内
!组件程 的
! 用 数 HRESULT
– GUID
–创建 数
– 数
–内 数
– 使用OLECHAR类型
复习:实现一个进程内COM组件的
! 要的CLSID IID
!实现COM对象
– 过QueryInterface ?¢接口
– 引用计数,注 对全£引用计数的?¥
!实现类厂对象
–对象的引用计数不?§全£对象引用计数内
–?¥锁计数
!实现DllGetClassObject DllCanUnloadNow
!(可currency1)实现'个注册 数
可重用性“reuse,复用?
!重用性:?一个程 ?fi能fl对¢ 的程 ?fi–
?功能?· ,?可能地重用??程 ?fi的?”,
?可以§…?”一‰重用, 可以§可? ?”一‰
重用。
!COM重用性:`为COM是建′§?进制?”?ˉ
?的标˙,¨以¢重用性 建′于?进制?”?。
!COM重用模型:?容 ?
!??的重用:是实现重用ˇ不是?”重用
C++类的重用模型
!—–: 有一个?类COldClass
!目标:实现一个 类CNewClass,要 重
用COldClass 的功能,ˇ不是重 实现
! :' 模型
– CNewClass COldClass 生,
class CNewClass: public COldClass {...};
–复 类或 类,§CNewClass ?
一个数?成 ,¢类型为COldClass
C++类的' 重用模型
!a 模型, 接a ?类COldClass的¨
有 数?成 , is-a?
–客户 接???类的接口(public成 )
!复 模型,把?类的功能? §内o,
has-a?
–客户?不??类的信息
COM重用模型
!—–: 有一个COM对象A
!目标:实现一个 对象B,要 重用对象A
的功能,ˇ不是重 实现?来 有的功能
! :' 模型
–?容(containment)
–? (aggregation)
COM?容模型
对象B
ISomeInterface
对象A
ISomeInterface
客户程
用
用
IOtherInterface
?容模型
! o对象?容内o对象的接口
! o对象的接口与内o对象的接口可以不
!?容模型的实?是客户-组件 ,§?容?
”的— 可以 ¢ 的?”,? 可以有
件地重用
!客户?不?内o对象
!内o对象的生 期? § o对象的生 期
?内
? 模型
对象B
IOtherInterface
对象A
ISomeInterface
客户程
用
??
用
? 模型
!? 对象 ?? 对象
!客户 接与内o对象 互,但它并不知道
!IUnknown唯一性是COM的?本要
!重用针对某个接口ˇ言,? ?容并不
矛盾,§一个对象?可以 使用
!? ?容的currency1择策略
?容模型实现
! 接口:
class ISomeInterface : public IUnknown
{
public:
virtual HRESULT __stdcall SomeFunction() = 0;
};
class IOtherInterface : public IUnknown
{
public:
virtual HRESULT __stdcall OtherFunction() = 0;
};
?容:
o对
象
class CB : public ISomeInterface , public IOtherInterface
{
protected:
ULONG m_Ref;
public:
CB ( );
~ CB ();
HRESULT __stdcall QueryInterface(const IID& iid, void **ppv);
ULONG __stdcall AddRef();
ULONG __stdcall Release();
//ISomeInterface members
HRESULT __stdcall SomeFunction( ) ;
//IOtherInterface members
HRESULT __stdcall OtherFunction( ) ;
HRESULT Init();
private :
ISomeInterface *m_pSomeInterface;
};
?容: o对象的实现
CB::CB ( )
{
m_pSomeInterface = NULL;
m_Ref = 0;
}
CB::~CB ( )
{
if (m_pSomeInterface ! = NULL)
m_pSomeInterface->Release() ;
}
HRESULT CB::Init()
{
HRESULT result = ::CoCreateInstance(CLSID_ComponentA, NULL,
CLSCTX_INPROC_SERVER, IID_ISomeInterface,
(void **)&m_pSomeInterface) ;
if (FAILED(result)) return E_FAIL;
else return S_OK;
}
?容: o对象的实现(续)
HRESULT __stdcall CB::SomeFunction( )
{
return m_pSomeInterface->SomeFunction( );
}
HRESULT __stdcall CB::OtherFunction( )
{
......
}
?容: o对象类厂的实现
HRESULT CBFactory::CreateInstance(IUnknown *pUnknownOuter,
const IID& iid, void **ppv)
{
CB *pObj; HRESULT hr; *ppv=NULL;
if (pUnknownOuter != NULL) return CLASS_E_NOAGGREGATION;
pObj=new CB ();
if (pObj == NULL) return E_OUTOFMEMORY;
hr = pObj->Init();
if (FAILED(hr) ) {
g_ObjectNumber --;
delete pObj;
}
//Obtain the first interface pointer (which does an AddRef)
hr=pObj->QueryInterface(iid, ppv);
return hr;
}
?容:灵活应用?容模型
HRESULT __stdcall CB::SomeFunction( )
{
if ( ... )
{
......
HRESULT result = m_pSomeInterface->SomeFunction( );
......
return result;
} else
{
......
}
}
? 实现
!要点: o对象完全重用内o对象的接口
! 键§于 o对象的QueryInterface 数
!内o对象还能fl把接口请 ?回? o对
象来,¨以内o对象 须要支持?
!不 怎么样,我们总是要 ¢ 的组件
是按接口一‰实现引用计数的
预备知识: 数指针
!有'个 数
– int Func1(int x, int y){return x*y;}
– int Func2(int x, int y){return x+y;}
! 数指针
– int (*MyFunc)(int, int);
!?”段1
– MyFunc = Func1;
– int a = MyFunc(10, 20);
!?”段2
– MyFunc = Func2;
– int b = MyFunc(10, 20);
!要点:
– 数名 并不重要,
数指针才决 了
数的功能
预备知识:用vtable 用成 数
!有'个?进制结构一样的vtable
class Vtable1{
class Vtable1{
virtual void __stdcall Method1(int, int) = 0;
virtual void __stdcall Method2(int) = 0;
};
class Vtable2{
class Vtable2{
virtual void __stdcall Operator1(int, int) = 0;
virtual void __stdcall Operator2(int) = 0;
};
预备知识
(续)
! 某段程 实现了¢ ?一
class CMyObject : public Vtable1{
……
virtual void __virtual void __stdcall Method1(int, int);
virtual void __virtual void __stdcall Method2(int);
};
!客户的用
实例 CMyObject :
Vtable1 *p1 = CreateObject(...);
?”片断1:
p1->Method1(a, b);
?”片断1:
Vtable2 *p2 = (Vtable2 *)p1;
p2->Operator1(a, b);
!要点:
– 指针类型并不
重要,vtable
才决 了内o
的功能
回顾:? 模型结构
对象B
IOtherInterface
对象A
ISomeInterface
客户程
用
??
用
o
对
象
的
class CB : public IOtherInterface
{
protected:
ULONG m_Ref;
public:
CB ( );
~ CB ();
//IUnknownIUnknow members
HRESULT __stdcall QueryInterface(const IID& iid, void **ppv);
ULONG __stdcall AddRef();
ULONG __stdcall Release();
//IOtherInterface members
HRESULT __stdcall OtherFunction( ) ;
HRESULT Init();
private :
IUnknown *m_pUnknownInner; // pointer to A's IUnknownIUnknow
};
? : o对象的QueryInterface
HRESULT CB::QueryInterface(const IID& iid, void **ppv)
{
if ( iid == IID_IUnknown ) {
*ppv = (IUnknown *) this ;
((IUnknown *)(*ppv))->AddRef() ;
} else if ( iid == IID_OtherInterface ) {
*ppv = (IOtherInterface *) this ;
((IOtherInterface *)(*ppv))->AddRef() ;
} else if ( iid == IID_SomeInterface ) {
return m_pUnknownInner->QueryInterface(iid, ppv) ;
} else {
*ppv = NULL;
return E_NOINTERFACE ;
}
return S_OK;
}
? :客户??的接口示 图
对象B
IOtherInterface
对象A
ISomeInterface
客户程
pOtherInterface
pSomeInterface
QueryInterface
AddRef
Release
SomeFunction
IUnknown
QueryInterface
AddRef
Release
OtherFunction
IUnknown
? 模型 的内o对象
!客户眼里的内o对象
– 内o对象的AddRef Release 须要 用§ o对象的
引用计数?
– 内o对象的QueryInterface 须要能fl返回 o对象的
接口
– 解决的办 是,?内o对象知道自己?? ? ,把
IUnknown的 用委托给 o对象的IUnknown
! o对象眼里的内o对象
– o对象 须有办 控制内o对象的生命周期,以及
查询请 它的接口
– 解决的办 是,内o对象有一个专门的IUnknown版本
? o对象使用,完成?本的生命周期控制功能 接
口查询功能
? :内o对象的实现 案
!解决办 :内o对象实现'个IUnknown
接口
– 1. 非委托IUnknown接口用于? 处 引用
计数 QI;
– 2. 委托IUnknown接口按情况处 :
!(1) ?对象?? , 用 o对象的IUnknown
接口;
!(2) ?对象未?? , 用非委托IUnknown接
口
对象A
ISomeInterface
客户程
QueryInterface
AddRef
Release
SomeFunction
委托
IUnknown
非委托
IUnknown
? :支持? 的对象§非?
式下的接口示 图
? :支持? 的对象§?
式下的接口示 图
对象B
IOtherInterface
对象A
ISomeInterface
客户程
QueryInterface
AddRef
Release
SomeFunction
QueryInterface
AddRef
Release
OtherFunction
o对象的
IUnknown
委托
IUnknown
非委托
IUnknown
控制
? 模型的要点
!这些要点指导我们如何实现? 对象
– 创建内o对象的 候, o对象 须把自己的
IUnknown接口指针?给内o对象,?称
为controlling unknown
– 内o对象类厂的CreateInstance 须检查pUnkOuter
参数,如果非NULL,则表 ? ,内o对象把指针
保 起来,但不 用AddRef。若内o对象不支持?
,则返回CLASS_E_NOAGGREGATION
– 如果pUnkOuter 参数非NULL,并且 o对象请
IUnknown接口,则内o对象把自己的非委托版本的
IUnknown?给 o对象
? 模型的要点(续)
!这些要点指导我们如何实现? 对象
–如果内o对象本身又? 了¢ 的对象,那
么它 须把 样的pUnkOuter参数??给它
的内o对象
–? o对象接?对于? 接口的请 ,它
须 用非委托版本的IUnknown的
QueryInterface 数,并把结果返回给客户
–对于除了非委托版本的IUnknown? 的接口,
它的三个IUnknown 用 须全o委托给 o
对象的pUnkOuter
? :内o对象如何获得 o
对象的IUnknown接口
HRESULT CoCreateInstance(const CLSID& clsid,
IUnknown *pUnknownOuter,
DWORD dwClsContext,
const IID& iid,
(void **)ppv
);
HRESULT IClassFactory::CreateInstance(
IUnknown *pUnknownOuter,
const IID& iid,
void **ppv
);
? : 非? IUnknown接口
!`为C++类不能 a 实现
'个IUnknown,¨以为非委托接口
一个 的类
class INondelegationUnknown
{
public:
virtual HRESULT __stdcall NondelegationQueryInterface(
const IID& iid, void **ppv) = 0 ;
virtual ULONG __stdcall NondelegationAddRef() = 0;
virtual ULONG __stdcall NondelegationRelease() = 0;
};
内
o
对
象
的
class CA : public ISomeInterface, public INondelegationUnknownwn
{
protected:
ULONG m_Ref;
public:
CA ( IUnknown *pUnknownOuter);
~ CA ( );
public :
virtual HRESULT __stdcall QueryInterface(const IID& iid, void **ppv);
virtual ULONG __stdcall AddRef() ;
virtual ULONG __stdcall Release() ;
virtual HRESULT __stdcall NondelegationQueryInterface(
const IID& iid, void **ppv) ;
virtual ULONG __stdcall NondelegationAddRef() ;
virtual ULONG __stdcall NondelegationRelease() ;
…….
private :
IUnknown *m_pUnknownOuter; // pointer to outer IUnknown
};
? :非委托IUnknown接口的实现
!AddRef Release与? 情况相
HRESULT CA:: NondelegationQueryInterface(const IID& iid, void **ppv)
{
if ( iid == IID_IUnknown ) {
*ppv = (INondelegatingUnknown *) this ;
((IUnknown *)(*ppv))->AddRef() ;
} else if ( iid == IID_SomeInterface ) {
*ppv = (ISomeInterface *) this ;
((ISomeInterface *)(*ppv))->AddRef() ;
} else {
*ppv = NULL;
return E_NOINTERFACE ;
}
return S_OK;
}
? :委托IUnknown接口的实现
ULONG CA:: AddRef ()
{
if ( m_pUnknownOuter != NULL )
return m_pUnknownOuter->AddRef();
else
return NondelegatingAddRef();
}
ULONG CA:: Release ()
{
……
}
HRESULT CA:: QueryInterface(const IID& iid, void **ppv)
{
if ( m_pUnknownOuter != NULL )
return m_pUnknownOuter->QueryInterface(iid, ppv);
else
return NondelegatingQueryInterface(iid, ppv);
}
? : o对象的创建
! o对象类厂§构造了CB? , 用Init 数,类
厂的CreateInstance 数与?容模型相 。但
CB::Init 数不 :
HRESULT CB::Init()
{
IUnknown *pUnknownOuter = (IUnknown *)this;
HRESULT result = ::CoCreateInstance(CLSID_ComponentA,
pUnknownOuter, CLSCTX_INPROC_SERVER,
IID_IUnknown, (void **)& m_pUnknownInner) ;
if (FAILED(result))
return E_FAIL;
else
return S_OK;
}
? : o对象的析构
CB::~CB ( )
{
if (m_pUnknownInner ! = NULL)
m_pUnknownInner->Release() ;
}
内
o
对
象
的
创
建
HRESULT CAFactory::CreateInstance(IUnknown *pUnknownOuter,
const IID& iid, void **ppv)
{
// iid must be IID_IUnknown for aggregating
if ( ( pUnknownOuter != NULL ) && ( iid != IID_IUnknownIUnknow ) )
{
return CLASS_E_NOAGGREGATION;
}
*ppv=NULL;
//Create the object passing function to notify on destruction.
CA *pObj=new CA (pUnknownOuter);
if (pObj == NULL) return E_OUTOFMEMORY;
//Obtain the first interface pointer (which does an AddRef)
HRESULT hr = pObj->NondelegatingQueryInterface(iid, ppv);
return hr;
}
? :内o对象的构造 数
CA::CA (IUnknown *pUnknownOuter)
{
m_pUnknownOuter = pUnknownOuter;
}
? : o对象的创建“修 ?
HRESULT CB::Init()
{
IUnknown *pUnknownOuter = (IUnknownIUnknow *)this;
HRESULT result = ::CoCreateInstance(CLSID_CompA, pUnknownOuter,
CLSCTX_INPROC_SERVER,
IID_IUnknown, (void **)& m_pUnknownInnerkno ) ;
if (FAILED(result)) return E_FAIL;
result = m_pUnknownInner->QueryInterface(IID_ISomeInterface,
(void **)&m_pSomeInterface);
if (FAILED(result)) {
m_pUnknownInnerpUnknownInner->Release();
return E_FAIL;
}
pUnknownOuter->Release();
return S_OK;
}
? : o对象的创建“修 ?
HRESULT CBFactory::CreateInstance(IUnknown *pUnknownOuter,
const IID& iid, void **ppv)
{
CB *pObj; HRESULT hr; *ppv=NULL;
if (NULL != pUnknownOuter) return CLASS_E_NOAGGREGATION;
pObj=new CB ();
if (pObj == NULL) return E_OUTOFMEMORY;
pObj->AddRef(); // The Reference count of pObj is 1
hr = pObj->Init();
if (FAILED(hr) ) { g_CompBNumber --; delete pObj;
return E_FAIL; return E_FAIL; }
hr=pObj->QueryInterface(iid, ppv);
pObj->Release(); // The Reference count of pObj is 1
return hr;
}
? : o对象的析构“修 ?
CB::~CB ( )
{
m_Ref = 1;
IUnknown *pUnknownOuter = this;
pUnknownOuter->AddRef ( );
if (m_pSomeInterface != NULL)
m_pSomeInterface->Release();
if (m_pUnknownInner != NULL)
m_pUnknownInner->Release() ;
}
? 例
客户程
“客户进程?
? 对象
组件程
“组件进程?
?”
LPC/RPC
组件对象
进程 性
!?本的 制: (marshaling)
marshal的 : 组 引导 安
(marshaling)
! :是指客户进程可以 地 用 一进程 的
对象成 数的一 参数处 制。
! 接:客户程 的一个有 接口指针, 接是§
数 用的过程 生的
!客户与进程 组件的 ? :
“1?如何建′一个 接
“2?如何使用 接进 跨进程 用
进程 性:'个 段
!客户 对象 ,对于客户 对象来
是 的
!客户创建对象 ,COM ¢ ,保
了客户 的 果;?· 不完
全
' 式
!“1?自 (custom marshaling)或?本
(basic marshaling architecture)
!“2?标˙ (standard marshaling)
!标˙ 是自 的一个特例
!' 不 ,标˙ 以接口为?ˉ,自
以对象为?ˉ
跨进程建′一个 接
! : ?? 对象的CLSID,或 标˙? 对
象; 数??,? 跨进程信息。这些信息
?称为对象引用(marshaled object reference)
!? :把? 对象的CLSID 数??? ?
客户进程 。
! :客户进程 , ?? 过来的CLSID创建
? 对象,并且把 数???给? 对象。
? 对象 客户返回一个接口指针。
HRESULT CoMarshalInterface( IStream *pStm,
REFIID riid,
IUnknown *pUnk,
void * dwDestContext,
unsigned long pvDestContext,
unsigned long mshlflags
);
HRESULT CoUnmarshalInterface(IStream *pStm,
REFIID riid
void * * ppvObj
);
IMarshal接口
!IMarshal接口是使用自 或标˙
的标?
class IMarshal : public IUnknown
{
HRESULT GetUnmarshalClass( ...) = 0;
HRESULT GetMarshalSizeMax(...) = 0;
HRESULT MarshalInterface( ...) = 0;
HRESULT UnmarshalInterface(...) = 0;
HRESULT DisconnectObject(...) = 0;
HRESULT ReleaseMarshalData(...) = 0;
};
的过程(CoMarshalInterface)
! : 过程¢生§对象进程
! £? 对象查询是?实现了IMarshal接口,如果实现了,则
用¢GetUnmarshalClass成 数获¥? 对象的CLSID
(如果对象没有实现IMarshal接口,则指 使用COM–?的
缺省? 对象,¢CLSID为CLSID_StdMarshal )。
! 用GetMarshalSizeMax 数? 数??§currency1可能的currency1currency1
'“,并? 一 的??。
! 用MarshalInterface成 数建′ 数??。
过程(CoUnmarshalInterface)
! stream fi proxy的CLSID
! ?CLSID创建一个proxy
!获¥proxy的IMarshal接口指针
! 用IMarshal::UnmarshalInterface,把
stream 的数??给proxy,proxy ?
这些数?建′起它与对象??的 接,
并返回客户请 的接口指针
Custom marshalingfl例
! 客户 建′了它与类厂??的
接, –是 它 过CoGetClassObject获
得了类厂的接口指针
!客户要 过类厂创建 一个COM对象,
ˇ这个对象使用custom marshaling
!客户 用IClassFactory::CreateInstance
创建对象,并返回对象的接口指针
过类厂建′? 对象 组件对
象自 过程
组件进程
组件程
客户进程
类厂
? 对象
类厂
?”
类厂对象
组件对象自 ?
对象
客户
?创建组
件对象
? CreateInstance
·LPC/RPC
用
?
?? 信息
?创建?
对象
?返回
” 接
? 用
自 的要点
!对象 须实现IMarshal接口
!? 对象 须实现IMarshal接口,并且?
对象与进程 对象??
!? 对象 须…‰¨有接口的跨进程
! 型用?:
–– 跨进程 用的 `,使用′ ??ˉ?
˙¨
– marshal-by-value
标˙
!对象不需要实现IMarshal,COM–?? 对象,
¢CLSID为CLSID_StdMarshal
! 的控制能?,可以控制?个接口的
marshaling
!跨进程 信? 象成RPC 道,RPC 道 是
一个COM对象
!? 对象按?? 模型实现?一个? 的接
口
!标˙ 式下的对象引用(OR)
标˙ 式下的对象引用(OR)
MEOW
FLAGS
IID
STD FLAGS
cPublicRefs
OXID
OID
IPID
cch secOffset
Host Addresses
Security Package
Info
COM的标˙?程结构
!COM使用ORPC ˇ实现跨进程( ?) 信
!COM ORPC建′§MS RPC?ˉ?
!MS RPC有—好的 性
OR service
OR service
Client
Server
OXID表
OXID表
OR
RPC
stub
proxy
RPC
IPC IPC
标˙ 的proxy stub结构
客户进程
? 对象
组件进程
ITF1
客户程
ITF2
ITFn
?
IRpcChannelBuffer
RPC
组件对象
?”
ITF1
ITF2
ITFn
RPC
IRpcProxyBuffer
IRpcStubBuffer
RPC 道
RPC 道
RPC 道
class IRpcChannelBuffer : public IUnknown
{
HRESULT GetBuffer(RPCOLEMESSAGE *pMessage,
REFIID riid) = 0;
HRESULT SendReceive(RPCOLEMESSAGE pMessage,
ULONG *pStatus) = 0;
HRESULT FreeBuffer(RPCOLEMESSAGE pMessage) = 0;
HRESULT GetDestCtx(DWORD *pdwDestCtx,
void **ppvDestCtx) = 0;
HRESULT IsConnected() = 0;
};
IRpcProxyBuffer
class IRpcProxyBuffer : public IUnknown
{
HRESULT Connect(IRpcChannelBuffer *pRpcChannelBuffer) = 0;
void Disconnect() = 0;
};
! ?个接口? 须实现IRpcProxyBuffer接口,并且是非
委托IUnknown
! ? 过这个接口把接口? 与RPC 道 接起来,
Connect 把RPC 道保 起来
! 接口? 接? 请 , 过IRpcChannelBuffer接口的
GetBuffer SendReceive 处 ?程 用
IRpcStubBuffer
class IRpcStubBuffer : public IUnknown
{
HRESULT Connect(IUnknown *pUnkServer) = 0;
void Disconnect() = 0;
HRESULT Invoke(RPCOLEMESSAGE *pMessage,
IRpcChannelBuffer *pChannel) = 0;
IRPCStubBuffer* IsIIDSupported(REFIID iid) = 0;
ULONG CountRefs() = 0;
HRESULT DebugServerQueryInterface(void **ppv) = 0;
void DebugServerRelease(void *pv) = 0;
};
! 过Connect 把接口 与目标对
象 起来
! Invoke 数处 来自接口? 的 请 , 要
用RPC 道把处 结果¢ 回
? / 对象的注册信息
C:\WINDOWS\SYSTEM\proxy.DLL
{D2029F40-8AB3-11CF-85FB-00401C608501}
PSFactoryBuffer
IEnumRemoteObject
接口? 接口 的创建
clsid = LookUpInRegistry(iid);
CoGetClassObject(clsid, CLSCTX_SERVER,
NULL, IID_IPSFactoryBuffer, &pPSFactory));
pPSFactory->CreateProxy(pUnkOuter, riid, &pProxy,
&piid);
clsid = LookUpInRegistry(iid);
CoGetClassObject(clsid, CLSCTX_SERVER,
NULL, IID_IPSFactoryBuffer, &pPSFactory));
pPSFactory->CreateStub(iid, pUnkServer, &pStub);
跨进程
! 用:客户- 对象,处 [in]或[in,out]参数
– :把数?marshal?一个buffer
!如果是 数?,如 数 ˉ
!如果是接口指针, 用CoMarshalInterface
– ? : 过RPC 道
– : buffer unmarshal 数?
!如果是 数?, 接 复
!如果是接口指针,则 用CoUnmarshalInterface
! 用返回:对象- 客户,处 [out] [in,out]参
数及返回“
– 样?marshal ? unmarshal三个
创建进程 COM对象
!客户 用CoGetClassObject创建类厂对象
!§CoGetClassObject 数内o,它 ?EXE组件的
程 , 组件进程,ˉ ...
!组件进程 , 用CoInitialize ,创建
¨有的类厂, 用CoRegisterClassObject把类厂
注册?COM
! CoRegisterClassObject对于类厂的接口指针
marshaling, 用标˙ 得? 数??
!客户进程 的CoGetClassObject?§ˉ 这些
数??“ 续?
创建进程 COM对象(续)
! CoGetClassObject对类厂unmarshaling,得?类
厂的? 对象
!客户 用类厂? 对象的CreateInstance
! 过标˙ ,类厂? 对象把创建请 过
RPC 道?给类厂
!类厂 用类厂CreateInstance创建目标对象
!类厂 对目标对象的接口指针进 marshaling,
并 过RPC 道?回给客户
!类厂? unmarshal得?目标对象的? 对象并返
回给客户?”
CoRegisterClassObject
STDAPI CoRegisterClassObject(
REFCLSID rclsid, //Class identifier (CLSID) to be registered
IUnknown * pUnk, //Pointer to the class object
DWORD dwClsContext, //Context for running executable code
DWORD flags, //How to connect to the class object
LPDWORD lpdwRegister
);
HRESULT CoRevokeClassObject CoRevokeClassObject( DWORD dwRegister );
typedef enum tagCLSCTX
{
CLSCTX_INPROC_SERVER = 1,
CLSCTX_LOCAL_SERVER = 4
CLSCTX_REMOTE_SERVER = 16
...
} CLSCTX;
typedef enum tagREGCLS
{
REGCLS_SINGLEUSE = 0,
REGCLS_MULTIPLEUSE = 1,
...
} REGCLS;
解?
!为 么要用类厂 为对象创建 制a
–类厂与对象使用 一 ?程 制, 需
建一 专门用来创建对象的跨进程 制
!为 么类厂的引用计数不计 组件总
计数内a
!COM 的 保 了进程 性
标˙ 的实现
!COM –?了缺省的? 对象
以及RPC 道
!我们 需实现?一个接口的? / 组
件。参数 返回“的数?类型是 键。
! 有对非标˙接口才需要实现? /
组件
? / 实现:IDL
import "unknwn.idl";
#define MaxWordLength 32
[
object,
uuid(54BF6568-1007-11D1-B0AA-444553540000),
pointer_default(unique)
]
interface IDictionary : IUnknown
{
HRESULT Initialize();
HRESULT LoadLibrary([in, string] WCHAR *pFilename);
HRESULT InsertWord([in, string] WCHAR *pWord,
[in, string] WCHAR *pWordUsingOtherLang);
HRESULT DeleteWord([in, string] WCHAR *pWord);
HRESULT LookupWord([in, string] WCHAR *pWord,
[out] WCHAR pWordOut[MaxWordLength]);
HRESULT RestoreLibrary([in, string] WCHAR *pFilename);
HRESULT FreeLibrary();
};
IDL 要点
! 不要使用int数?类型,ˇ?用short或 long数?类型。
`为int类型与??相 ,ˇshort long与?? 。
! 指针类型不要使用void *,接口指针类型可使用
IUnknown *或¢ ? 的接口指针类型。
! COM标˙ 的 使用o ,对应§IDL 使
用o 。
! 数的?一个参数 须 ?指 是 参数 参数或
- 参数。
! IDL 可以 结构类型,并以结构类型 为参数类型。
! 数组类型 须 ?指 currency1',如果需要 ?指 currency1'或
用?数组的一o?,可使用size_is length_is max_isˉ
修 。
! IDL 件 的import指 与C/C++ 的include类?。
实用 :MIDL
!命 :
– midl dictionary.idl
!则 生下 的 件:
– dictionary.h —— ? 接口 的 件,可用
于C或 C++?言;
– dictionary_p.c —— C 件实现了接口IDictionary
的? ;
– dictionary_i.c —— C 件 了IDL 件 用?
的¨有全£ GUID,? 接口 ;
– dlldata.c —— C 件? ? / 程 的
口 数以及? 类厂¨需要的数?结构ˉ。
创建? /
! 一个DEF 件。引 ?个标˙ 数,
??GetProxyDllInfo。
! 一个MAKE 件。
! ?currency1? ?
currency1
EGISTER_PROXY_DLL
! 接currency1? ? rpcrt4.lib uuid.lib
!接口注册:regsvr32 dictionary.dll
进程 组件注 ?
!自注册 式的
–命 参数/RegServer /UnregServer
!注册类厂
!何 ?
! 用CoInitialize CoUninitialize
!实现自 接口的? / 组件
自
!? 例
–内o对象的实现
!进程 组件例
– ?了一个? / 程
–组件的注册 式以及 试 式的
– CoRegisterClassObject 数对类厂的用
–客户?” 组件对象?”与以—例 ?本相
——体现了进程 性