COM培训.ppt

上传人:ga****84 文档编号:456004 上传时间:2018-10-09 格式:PPT 页数:65 大小:405.50KB
下载 相关 举报
COM培训.ppt_第1页
第1页 / 共65页
COM培训.ppt_第2页
第2页 / 共65页
COM培训.ppt_第3页
第3页 / 共65页
COM培训.ppt_第4页
第4页 / 共65页
COM培训.ppt_第5页
第5页 / 共65页
点击查看更多>>
资源描述

1、COM:可连接对象 & 结构化存储,潘爱民http:/ *p;p-,聚合模型的关键,可连接对象(connectable object),内容:可连接对象结构模型实现可连接对象(源对象)客户-源对象-接收器的协作过程可连接对象的程序实现,双向通信机制 客户与可连接对象的关系,两个概念,入接口(incoming interface)组件对象实现入接口,客户通过入接口调用对象提供的功能客户和组件都需要知道接口的类型信息出接口(outgoing interface)客户端提供的COM对象实现出接口组件端的对象通过出接口调用客户提供的功能组件提供接口类型信息,客户实现该接口类似于回调(callback)

2、,但是要复杂和灵活得多,出接口,类型信息由组件一方提供客户提供出接口的实现,实现出接口的COM对象被称为接收器对象(sink)sink没有CLSID,也不需要类厂也是一个COM接口,有IID每个成员函数代表了:事件event通知notification请求request,源对象 or 可连接对象,Connectable object,source普通的COM对象,支持一个或者多个出接口提供出接口的类型信息通过IProvideClassInfo2接口通过typelib,客户与可连接对象之间的两种结构,可连接对象的基本结构,可连接对象,如何管理多个出接口每个出接口对应一个连接点对象通过连接点枚举器

3、管理对于每个出接口,如何管理多个客户连接通过连接枚举器管理多个连接,实现可连接对象(源对象)(一),枚举器内部对象,不需要类厂和CLSID其含义就如同指针智能指针枚举器接口模板class IEnum : public IUnknownvirtual HRESULT Next( ULONG celt, ELT_T *rgelt, ULONG *pceltFetched ) = 0;virtual HRESULT Skip( ULONG celt ) = 0;virtual HRESULT Reset( void ) = 0;virtual HRESULT Clone( IEnum*ppenum

4、) = 0;,枚举器的用法,class IStringManager : public IUnknown virtual IEnumString* EnumStrings(void) = 0;void SomeFunc(IStringManager * pStringMan) String psz; IEnumString * penum; penum=pStringMan-EnumStrings(); while (S_OK = penum-Next(1, ,实现可连接对象(源对象)(二),IConnectionPointContainer接口class IConnectionPointCo

5、ntainer : public IUnknown virtual HRESULT EnumConnectionPoints(IEnumConnectionPoints *) = 0; virtual HRESULT FindConnectionPoint(const IID *, IConnectionPoint *) = 0;IEnumConnectionPoints接口class IEnumConnectionPoints : public IUnknownvirtual HRESULT Next( ULONG cConnections, IConnectionPoint *rgpcn,

6、 ULONG *pcFetched) = 0; virtual HRESULT Skip( ULONG cConnections) = 0;virtual HRESULT Reset(void) = 0;virtual HRESULT Clone( IEnumConnectionPoints *ppEnum) = 0;,实现可连接对象(源对象)(三),连接点和IConnectionPoint接口class IConnectionPoint : public IUnknown virtual HRESULT GetConnectionInterface( IID *pIID) = 0; virt

7、ual HRESULT GetConnectionPointContainer( IConnectionPointContainer *ppCPC) = 0; virtual HRESULT Advise( IUnknown *pUnk, DWORD *pdwCookie) = 0; virtual HRESULT Unadvise( DWORD dwCookie) = 0; virtual HRESULT EnumConnections(IEnumConnections*ppEnum) = 0; ;连接枚举器 实现IEnumConnections接口允许多个客户连接每个连接用struct C

8、ONNECTDATA来描述,回顾:可连接对象的基本结构,客户与源对象建立连接过程,客户请求IConnectionPointContainer接口客户调用IConnectionPointContainer:FindConnectionPoint找到连接点对象客户调用IConnectionPoint:Advise建立与接收器的连接最后,客户调用IConnectionPoint:Unadvise取消连接,并释放连接点对象,客户方基本结构,客户方实现接收器对象(sink)支持多个与可连接对象之间的连接一般只实现专用的出接口(IUnknown除外)不需要类厂、CLSID与客户代码紧密连接起来建立连接1

9、通过IConnectionPointContainer接口找到连接点对象2 通过连接点对象建立连接连接点相当于连接管理器,接收器的实现,class CSomeEventSet : public ISomeEventSet private: ULONG m_cRef; / Reference count . / other private data members public: DWORD m_dwCookie; / Connection key public: CSomeEventSet (); CSomeEventSet(void); /IUnknown members STDMETHOD

10、IMP QueryInterface(REFIID, PPVOID); STDMETHODIMP_(DWORD) AddRef(void); STDMETHODIMP_(DWORD) Release(void); STDMETHODIMP SomeEventFunction ( . ); .;,接收器的用法,ISomeEventSet *gpSomeEventSet;./ InitializeCSomeEventSet *pSink = new CSomeEventSet;pSink-QueryInterface(IID_ISomeEventSet, pSomeEventSet ); / Re

11、ference count is 1./ connections the sink object to the connectable object we havehr=pConnectionPoint-Advise(pSomeEventSet , / Reference count is 0,事件的激发和处理,BOOL CSourceObject:FireSomeEvent(IConnctionPoint *pConnectionPoint) IEnumConnections *pEnum; CONNECTDATA connectionData; if (FAILED(pConnection

12、Point-EnumConnections(,与出接口有关的类型信息,客户如何知道出接口?运行时刻?编译时刻?动态构造接收器对象?动态构造vtable?支持部分成员?类型信息的协商通过IProvideClassInfo2能否用标准的接口作为出接口?,用IDispatch接口作为出接口(一),IDispatch接口class IDispatch : public IUnknown public: virtual HRESULT GetTypeInfoCount( UINT *pctinfo) = 0; virtual HRESULT GetTypeInfo( UINT iTInfo, LCID

13、lcid, ITypeInfo *ppTInfo) = 0; virtual HRESULT GetIDsOfNames(REFIID riid, LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId) = 0; virtual HRESULT Invoke( DISPID dispIdMember, REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *p

14、uArgErr) = 0;,用IDispatch接口作为出接口(二),IDispatch出接口的事件激发函数,void CMySourceObj:FireMyMethod (short nInt)COleDispatchDriver driver;POSITION pos = m_xMyEventSet.GetStartPosition();LPDISPATCH pDispatch;while (pos != NULL) pDispatch = (LPDISPATCH) m_xMyEventSet.GetNextConnection(pos);ASSERT(pDispatch != NULL)

15、;driver.AttachDispatch(pDispatch, FALSE);TRYdriver.InvokeHelper(eventidMyMethod, DISPATCH_METHOD, VT_EMPTY, NULL,(BYTE *) (VTS_I2), nInt);END_TRYdriver.DetachDispatch();,用连接点机制实现回调的讨论,比传统的回调函数功能强大,灵活可以跨进程、跨机器Tightly coupled vs loosely coupled (COM+)要求客户与组件同步没有第三方的参与,所以双方必须保持共识,MFC对连接和事件的支持,用MFC实现源对象

16、,创建工程支持COM定义出接口编辑.odl文件利用MFC宏加入连接点声明以及连接点对象的定义在对象构造函数中调用EnableConnections();在接口映射表中加入接口IConnectionPointContainer的表项,再加入连接映射表定义连接点类的虚函数(至少为GetIID)加入事件激发函数,用MFC在客户程序中实现接收器,初始化 AfxOleInit定义出接口成员类实现出接口成员类创建源对象建立连接和取消连接完成可触发事件的动作,用MFC实现的例子,ATL实现可连接对象,在IDL中定义一个用作出接口的automation接口在coclass中加入出接口,含source属性增加I

17、ConnectionPointContainer接口在基类列表中增加IConnectionPointConntainerImpl在COM MAP中加入COM_INTERFACE_ENTRY(IConnectionPointConntainer),模板类IConnectionPointImpl,CMyClass继承IConnectionPointImpl一次或多次IConnectionPointImpl实现了独立的引用计数用法:在基类列表中增加IConnectionPointImpl加入connection point map,如下BEGIN_CONNECTION_POINT_MAP(CMyCl

18、ass)CONNECTION_POINT_ENTRY(DIID_IEventSet)END_CONNECTION_POINT_MAP(),激发事件辅助函数,手工激发事件IConnectionPointImpl包含一个m_vec成员,内含所有已经建立的接收器连接遍历m_vec数组,逐一调用Invoke函数利用VC IDE提供的源码产生工具ATL连接点代理生成器,启动对话框Implement Connection Point产生名为CProxy_的模板类例如CProxy_IEventSet,它从IConnectionPointImpl派生对于每一个事件或者请求,都有一个对应的Fire_Xxx成员函

19、数用模板类代替IConnectionPointImpl基类,Implement Connection Point对话框,创建对象时选择Connection PointClassView中,在对象类上右键点击选择此项功能,ATL实现连接点:最后的工作,在需要激发事件的地方调用CProxy_提供的辅助函数增加对IProvideClassInfo2接口的支持需要typelib的支持加入基类IProvideClassInfo2Impl在COM MAP中加入:COM_INTERFACE_ENTRY(IProvideClassInfo2)COM_INTERFACE_ENTRY(IProvideClassI

20、nfo),ATL实现接收器sink,IDispEventSimpleImpl轻量,不需要typelib的支持IDispEventImpl需要typelib的支持Event Sink MapBEGIN_SINK_MAP(CMyCLass)SINK_ENTRY_EX(.)/ 适合用于non-UI objectSINK_ENTRY(.) / 适合用于UI objectEND_SINK_MAP,ATL:建立sink和source之间的连接,IDispEventSimpleImpl成员DispEventAdviseDispEventUnadviseAtlAdviseSinkMap建立sink与sourc

21、e缺省源接口的连接,VB中使用出接口,使用浏览器控件的事件函数使两个窗口同步,结构化存储(structured storage),内容:结构化存储模型复合文档永久对象,问题的由来,文件系统的诞生多个应用程序共享同一个存储设备文件服务功能的抽象进展到结构化存储多个组件共享同一个文件组件软件存储功能的基本要求OLE的需求组件共享句柄方案,如何定位?避免冲突?,文件系统结构,结构化存储,多个组件程序共享一个复合文件,复合文件,文件内部的文件系统只有两种对象:存储对象和流对象实现了部分访问和增量访问的功能,流对象,COM库提供实现,实现了IStream接口class IStream : public

22、IUnknownpublic :virtual HRESULT Read (void *pv, unsigned long cb, unsigned long *pcbRead) = 0;virtual HRESULT Write (void *pv, unsigned long cb, unsigned long *pcbWritten) = 0;virtual HRESULT Seek (LARGE_INTEGER dlibMove, unsigned long dwOrigin,ULARGE_INTEGER *plibNewPosition) = 0;virtual HRESULT Se

23、tSize (ULARGE_INTEGER libNewSize) = 0;virtual HRESULT CopyTo (LPSTREAM pStm, ULARGE_INTEGER cb,ULARGE_INTEGER *pcbRead, ULARGE_INTEGER *pcbWritten) = 0;virtual HRESULT Commit (unsigned long dwCommitFlags) = 0;virtual HRESULT Revert ()= 0;virtual HRESULT LockRegion (ULARGE_INTEGER libOffset, ULARGE_I

24、NTEGER cb,unsigned long dwLockType) = 0;virtual HRESULT UnlockRegion (ULARGE_INTEGER libOffset, ULARGE_INTEGER cb,unsigned long dwLockType) = 0;virtual HRESULT Stat (STATSTG *pStatStg, unsigned long grfStatFlag) = 0;virtual HRESULT Clone(LPSTREAM * ppStm) = 0;,存储对象,COM库提供实现,实现了IStorage接口class IStora

25、ge : public IUnknownvirtual HRESULT CreateStream (const WCHAR * , unsigned long , LPSTREAM * ) = 0;virtual HRESULT OpenStream (const WCHAR * , unsigned long , LPSTREAM * ) = 0;virtual HRESULT CreateStorage (const WCHAR * , unsigned long ,LPSTORAGE * ) = 0; virtual HRESULT OpenStorage (const WCHAR* ,

26、 LPSTORAGE *, unsigned long , SNB , unsigned long , LPSTORAGE * ) = 0;virtual HRESULT CopyTo(unsigned long , IID const *, SNB snbExclude, LPSTORAGE * pStgDest) = 0;virtual HRESULT MoveElementTo(const WCHAR * , LPSTORAGE *,char const * , unsigned long ) = 0;virtual HRESULT Commit (unsigned long ) = 0

27、;virtual HRESULT Revert ()= 0;virtual HRESULT EnumElements (unsigned long , void *,unsigned long , LPENUMSTATSTG * ) = 0;virtual HRESULT DestroyElement (const WCHAR * pwcsName) = 0;virtual HRESULT RenameElement (const WCHAR * pwcsOldName, const WCHAR * pwcsNewName) = 0;virtual HRESULT SetElementTime

28、s(const WCHAR *,FILETIME const *,FILETIME const*,FILETIME const *) = 0;virtual HRESULT SetClass (REFCLSID rclsid) = 0;virtual HRESULT SetStateBits (unsigned long grfStateBits, unsigned long grfMask) = 0;virtual HRESULT Stat (STATSTG *pStatStg, unsigned long grfStatFlag) = 0;,客户如何获取存储对象和流对象,如何得到指向根存储

29、对象的接口指针?CreateStorage和OpenStorage成员函数得到一个子存储对象,是唯一的途径CreateStream和OpenStream成员函数得到一个流对象,也是唯一的途径,用结构化存储设计应用(一),用普通文件组织的文档结构,用结构化存储设计应用(二),复合文件格式的文档结构,结构化存储特性访问模式,STGM_CREATESTGM_CONVERTSTGM_FAILIFTHERESTGM_DELETEONRELEASESTGM_DIRECTSTGM_TRANSACTEDSTGM_PRIORITYSTGM_READSTGM_WRITESTGM_READWRITESTGM_SHA

30、RE_DENY_READSTGM_SHARE_DENY_WRITESTGM_SHARE_EXCLUSIVESTGM_SHARE_DENY_NONE,结构化存储特性事务机制,数据一致性和完整性操作:Commit、Revert事务嵌套:以STGM_TRANSACTED标志为基础事务机制需要消耗较多系统资源Commit参数:STGC_DEFAULTSTGC_OVERWRITESTGC_ONLYIFCURRENTSTGC_DANGEROUSLYCOMMITMERELYTODISKCACHE,结构化存储特性命名规则,根存储对象的名字遵守文件系统的命名约定长度不超过32个字符首字符使用大于32的字符,小于

31、32的字符作为首字符有特殊意义不能使用字符“”、“/”、“:”和“!”名字“.”和“.”被保留名字保留大小写,但比较操作大小写无关,结构化存储特性增量访问,减少保存和打开文件的时间降低了应用程序对系统资源的要求问题:通过根存储逐层找到目标对象空间回收,复合文档,结构化存储的具体实现底层机制:LockBytes对象把存储介质描述成一般化的字节序列复合文档API函数零内存保存特性,复合文档模型,root,LockBytes对象,ILockBytes接口class ILockBytes : public IUnknownpublic :virtual HRESULT ReadAt (ULARGE_I

32、NTEGER , VOID *pv, unsigned long ,unsigned long *) = 0;virtual HRESULT WriteAt (ULARGE_INTEGER , VOID *pv, unsigned long ,unsigned long *) = 0; virtual HRESULT Flush ()= 0;virtual HRESULT SetSize (ULARGE_INTEGER cb) = 0;virtual HRESULT LockRegion (ULARGE_INTEGER , ULARGE_INTEGER ,unsigned long ) = 0

33、;virtual HRESULT UnlockRegion (ULARGE_INTEGER , ULARGE_INTEGER ,unsigned long ) = 0;virtual HRESULT Stat (STATSTG *, unsigned long ) = 0;,复合文档API函数,创建复合文档的API函数StgCreateDocfile、StgCreateDocfileOnILockBytes打开复合文档的API函数StgOpenStorage、StgOpenStorageOnILockBytes与内存句柄有关的一组操作函数CreateILockBytesOnHGlobal、Ge

34、tHGlobalFromILockBytesCreateStreamOnHGlobal、GetHGlobalFromStream其他,零内存保存特性,意义:资源耗尽之后,保留修改信息资源预留,对于所有的流对象和存储对象“Save”操作,只要调用Commit函数即可“Save As”操作,利用根存储对象上的IRootStorage接口,调用SwitchToFile成员函数,再调用Commit函数即可。,与CLSID的联系,IStorage:SetClass函数把存储对象与CLSID联系起来GetClassFile函数,从文件到CLSID:复合文件,直接得到根存储的CLSID非复合文件:(1) 文

35、件扩展名-ProgID-CLSID(2) HKEY_CLASSES_ROOTFileType键提供了匹配规则:HKEY_CLASSES_ROOT FileType = , = ,复合文档与COM的关系,复合文档技术以COM为基础应用程序在处理复合文档时把storage或stream直接交给COM组件来处理COM组件接受storage或stream作为数据存储多个组件协同处理同一个文件-永久对象,永久对象,永久对象实现了IPersistXXX接口的COM对象永久接口:class IPersist : public IUnknownclass IPersistStream : public IPersistclass IPersistStreamInit : public IPersistclass IPersistFile : public IPersistclass IPersistStorage : public Ipersist永久接口的成员函数:GetClassID、IsDirty、Load和Save,.永久对象可以实现多个永久接口,但使用时要保持一致性,永久对象用法,永久对象与结构化存储模型结合永久对象例子用MFC实现的COM对象功能:永久状态为一段文本,使用永久接口对文本维护实现了IPersistStream和一个自动化接口,复合文档例子,复合文档查看工具,

展开阅读全文
相关资源
相关搜索

当前位置:首页 > 学术论文资料库 > 毕业论文

Copyright © 2018-2021 Wenke99.com All rights reserved

工信部备案号浙ICP备20026746号-2  

公安局备案号:浙公网安备33038302330469号

本站为C2C交文档易平台,即用户上传的文档直接卖给下载用户,本站只是网络服务中间平台,所有原创文档下载所得归上传人所有,若您发现上传作品侵犯了您的权利,请立刻联系网站客服并提供证据,平台将在3个工作日内予以改正。