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 数对类厂的用 –客户?” 组件对象?”与以—例 ?本相 ——体现了进程 性