名字对象.ppt

上传人:sccc 文档编号:5378585 上传时间:2023-07-01 格式:PPT 页数:26 大小:212.54KB
返回 下载 相关 举报
名字对象.ppt_第1页
第1页 / 共26页
名字对象.ppt_第2页
第2页 / 共26页
名字对象.ppt_第3页
第3页 / 共26页
名字对象.ppt_第4页
第4页 / 共26页
名字对象.ppt_第5页
第5页 / 共26页
点击查看更多>>
资源描述

《名字对象.ppt》由会员分享,可在线阅读,更多相关《名字对象.ppt(26页珍藏版)》请在三一办公上搜索。

1、1,十四.名字对象,概念IMoniker接口名字对象的创建根据显示名创建名字对象类名字对象的创建其他名字对象的创建简单名字对象的绑定过程。ROT表文件名字对象的绑定CoGetInstanceFromFile 函数复合名字对象概念及其绑定过程概念单项和复合名字对象的创建单项名字对象的绑定过程复合名字对象的绑定过程,2,1 概念,我们已知创建COM对象的两种方法:通过CoGetClassObject 得到类厂,通过类厂接口调用CreateInstance.直接使用CoCreateInstance 或CoCreateInstanceEx.客户使用以上两种方法在创建COM对象时,必须提供对象的CLSI

2、D或ProgID。COM提供了提供了第三种方法,即利用名字对象(moniker 绰号,名字)创建COM对象的方法。名字对象本身也是一个COM对象。名字对象为另一个COM对象提供了的符号化的表示方法,同时也对组件对象的创建过程进行封装。客户程序只需创建相应的名字对象,并使用名字对象的绑定功能得到组件对象。在这个意义上,名字对象类似于类厂对象,但是它比类厂对象提供了更多的功能.其关系对比图如下:,3,名字对象与类厂对象的功能对比示意图,4,之所以在类厂对象之外衍生出名字对象,是因为:名字对象可以以名字的方式来创建COM对象,有时候比使用CLSID的方式更方便.在一些复杂的应用中,COM对象形成了逻

3、辑上的上下级关系或者是包容的关系.在每一个级别上都是一个COM对象,下级的对象只有在上级的对象范围内才有意义,而且在确定了上级对象以后,下级对象可以更加简单(且更加明确和直观)地使用名字的方式来描述.在这种情形下,使用从上到下的名字比使用一串的CLSID更加方便合理地创建COM对象.比如Excel中的文档对象以Excel Application,WorkBook,WorkSheet、Range等层次的COM对象的方式给应用程序员提供访问接口。这些对象的状态存储在复合文档的不同级别的存储对象和流对象中.比如“c:My DocumentsMyTable.xls!Sheet2!R1C1:R2C2”表

4、示存储在文件My DocumentsMyTable.xls 的工作表Sheet2的Range R1C1:R2C2对象。这些对象往往都是永久对象。它们不仅有方法,而且有状态.它们的状态数据以复合文档的形式存储在磁盘上。如果只使用CLSID,根本不能准确地表明是标识为CLSID的COM对象的此实例,而非彼实例.所以,不仅是更直观,而且是必须以“复合名字”的方式才能准确地创建或还原这个COM对象.,5,2.IMoniker接口,名字对象是COM对象的封装和创建者.它实现了IMoniker接口.interface IMoniker:IPersistStream HRESULT BindToObject

5、(in IBindCtx*pbc,in,unique IMoniker*pmkToLeft,in REFIID riid,out,iid_is(riid)void*ppv);/其他成员未列出 IMoniker接口 派生自IPersistStream接口(p242)接口成员函数功能上分为四组:1。名字管理 2。实现绑定 3。管理复合名字对象。4。名字解析。其中最为重要的是绑定操作函数BindToObject。所有的名字对象都实现了IMoniker接口,名字对象封装了组件对象的所有状态处理过程,客户使用IMoniker接口成员。按照统一的方法处理名字对象。,6,3 名字对象的创建,3.1 根据显示

6、名创建名字对象名字对象的名字称为显示名(display name)是一种用户可读的名字.显示名可以是文件路径名,这时返回文件名字对象,也可以是组件对象的CLSID,这时返回类名字对象。也可以是经过扩充的以“!”等间隔开的复合名字,(这时返回复合名字对象)。IMoniker接口有一个方法GetDisplayName可以返回对象的显示名.然而更重要的是根据显示名来创建名字对象.WINOLEAPI MkParseDisplayName(LPBC pbc,/绑定环境LPCOLESTR szUserName,/显示名ULONG*pchEaten,/绑定过程中解析的字符个数LPMONIKER FAR*pp

7、mk/结果名字对象的指针);MkParseDisplayName根据显示名进行解析的结果生成名字对象,并以IMoniker指针的方式返回给客户。,7,名字对象有很多种,也有很多别的方法来创建名字对象。创建一个类名字对象WINOLEAPI CreateClassMoniker(REFCLSID rclsid,/该名字对象所命名的对象的CLSIDIMoniker*ppmk/结果名字对象的指针);该类名字对象将指向所命名对象的类厂对象.下面是一个客户从类名字对象得到组件对象的例子:,3.2 类名字对象的创建,8,HRESULT GetMyInterface(IMyInterface*rgpc)ICl

8、assFactory*pcf=0;/声明目标组件对象的CLSID为一个显示名 const OLECHAR pwsz=OLESTR(“clsid:E2F41FB8-BE92-4d00-A3DD-D9C285B959C1”);/为绑定和解析名字对象创建一个新的绑定环境 IBindCtx*pbc=0;ULONG cchEaten;IMoniker*pmk=0;HRESULT hr=CreatBindCtx(0,9,创建一个文件名字对象。WINOLEAPI CreateFileMoniker(LPCOLESTR lpszPathName,/文件路径LPMONIKER FAR*ppmk/结果名字对象的指

9、针);创建一个单项名字对象。WINOLEAPI CreateItemMoniker(LPCOLESTR lpszDelim,/分割符LPCOLESTR lpszItem,/显示名LPMONIKER FAR*ppmk/结果名字对象的指针);创建一个复合名字对象。WINOLEAPI CreateGenericComposite(LPMONIKER pmkFirst,/第一个名字对象LPMONIKER pmkRest,/第二个名字对象LPMONIKER FAR*ppmkComposite/结果名字对象的指针);,3.3 其他名字对象的创建:,10,4 简单名字对象的绑定过程。,4.1 ROT表COM

10、对象的激活是由COM服务的SCM(服务控制管理器)来完成的.每台支持COM的机器上都有本地的SCM。它响应客户的加载COM对象的请求。一旦对象被激活,SCM就不再介入到客户和组件对象的方法调用过程。客户以名字对象或底层API的形式访问SCM提供的服务。SCM使用ROT(Running Object Table)来管理正在运行的,已经被注册的名字对象。如果一个名字对象所指的组件对象已经在运行了,在名字对象的绑定过程中,可以直接连接到此对象上,而不必再启动新的对象。有两种方式可以得到ROT表:,11,使用GetRunningObjectTable来得到ROT表的IRunningObjectTabl

11、e指针WINOLEAPI GetRunningObjectTable(DWORD reserved,/保留LPRUNNINGOBJECTTABLE*pprot);/IRunningObjectTable 接口指针名字对象在绑定过程中要使用到绑定环境。绑定环境是COM实现的系统对象。客户可以使用CreateBindCtx函数来创建一个绑定环境对象。WINOLEAPI CreateBindCtx(DWORD reserved,/保留 LPBC FAR*ppbc);/IBindCtx 接口指针 客户可以从绑定环境中使用接口函数GetRunningObjectTable得到ROT,同时可以控制绑定过程

12、中的一些行为。以下以文件名字对象为例研究名字对象的绑定过程.,12,比如客户程序通过文件名字对象来访问一个电子表格文档对象。电子表格文件名为:“c:My DocumentsMyTable.xls”.Excel中的文档对象以Excel Application,WorkBook,WorkSheet、Range等层次的COM对象的方式给应用程序员提供访问接口。这几个对象都是永久对象。它们的状态数据以复合文档的形式存储在磁盘上。在VBA环境下或VisualBasic环境下,我们可以方便地使用VisualBasic语言访问电子表格文档对象。在C环境下,可以对这些对象进行更精细的控制。客户程序调用Crea

13、teFileMoniker或MkParseDisplayName函数来创建一个文件名字对象。得到文件名字对象的IMoniker指针。然后调用名字对象的IMoniker:BindToObject函数,一旦函数成功返回,就得到了电子表格文档对象。BindToObject内部调用了CoGetInstanceFromFile,见下:,4.2 文件名字对象的绑定,13,STDMETHODIMP FileMoniker:BindToObject(IBindCtx*pbc,IMoniker*pmkToLeft,REFIID riid,void*ppv)*ppv=0;HRESULT hr=E_FAIL;if(

14、pmkToLeft=0)/左边没有名字对象的情形 MULTI_QI mqi=CoGetInstanceFromFile函数完成了实际的创建COM对象的过程.如下:,14,4.3 CoGetInstanceFromFile 函数,HRESULT CoGetInstanceFromFile(COSERVERINFO*pServerInfo,/指向远程主机CLSID*pclsid,/要创建的对象的CLSIDIUnknown*punkOuter,/用于被聚合的情形,指向外部的 IUnknownDWORD dwClsCtx,/环境变量DWORD grfMode,/打开模式OLECHAR*szName,/

15、对象文件名ULONG cmq,/MULTI_QI 数组的大小,即接口的个数.MULTI_QI*rgmqResults/MULTI_QI 数组);其中:typedef struct _MULTI_QI const IID*pIID;/客户指定的要返回的目标对象的接口IIDIUnknown*pItf;/用来保存接口的指针HRESULT hr;MULTI_QI;此结构可以保存多个接口指针。,15,CoGetInstanceFromFile函数的过程:1。首先要获得对象的CLSID,客户有可能直接在参数中提供,如果没有提供,CoGetInstanceFromFile调用GetClassFile函数以获

16、得与文件相关的CLSID HRESULT GetClassFile(in,string OLECHAR*pwszFileName,out CLSID*pclsid);如果文件是复合文档,那么该复合文档的根存储对象的IPersist接口的GetClassID成员函数将返回CLSID,如果不是复合文档那么通过注册表查找文件的扩展名与ProgID的Association关系,然后再查找ProgID与CLSID的对应关系取得文件相关的CLSID2。得到了对象的CLSID后,由于客户在调用CoGetInstanceFromFile之前已经得到了绑定环境。CoGetInstanceFromFile可以利用

17、此绑定环境得到ROT(Running Object Table)。ROT表中包含这样的入口项(pmkObjectName,pUnkObject)其中pmkObjectName指向关联目标对象的名字对象的指针,pUnkObject指向运行的对象的指针。那些允许名字对象关联的对象在运行时会在ROT表中注册,即加入入口项。名字对象如果检测到此入口项时,就可以使用ROT表的GetObject函数直接返回目标对象的接口指针(IUnkown指针)。如果没有检测到,那么:,16,3.如果在ROT表中没有找到对应的入口项,那么CoGetInstanceFromFile使用CoCreateInstance或Co

18、GetClassObject再由类厂接口的CreateInstance创建新对象,并返回对象的IUnkown接口指针。4。从IUnkown接口查询对象的IPersistFile接口。(既然复合文档中把它的CLSID记下来了,说明此对象肯定是永久对象,并实现了IPersistFile接口)。从IPersistFile接口调用Load方法,并把文件名传入作为参数,Load从文件读取数据对对象的状态进行初始化,并且在ROT表中进行注册。Load方法如下:,17,STDMETHODIMP MyWorkBook:Load(const OLECHAR*pszFileName,DWORD grfMode)/

19、从文件中读入对象状态hr=this-MyReadStateFromFile(pszFile,grfMode);if(FAILED(hr)return hr;IRunningObjectTable*prot=0;hr=GetRunningObjectTable(0,以后再用同样的文件名调用CoGetInstanceFromFile函数将不会创建新的对象,而是返回指向这个对象的引用。使用文件名字对象达到了两个目的:允许对象把自身注册到ROT中,使得以后的CoGetInstanceFromFile能找到它。把CoGetInstanceFromFile隐藏到IMoniker接口后面了。客户只是调用名字

20、对象,并没有调用CoGetInstanceFromFile。见BindToObject的实现代码。,18,5 复合名字对象概念及其绑定过程,5.1 概念对于简单名字对象而言,名字对象仅仅是利用字符串间接创建COM对象的一种手段。而且客户通过名字对象引用组件程序的内部对象也非常不方便(比如我们通过以上办法得到了Excel Application对象,但是如果我们要访问其中的一个单元格,以上步骤是不够的。)复合名字对象将真正体现名字对象的优越性。复合名字对象按从左到右的顺序保存各成员名字对象。比如“c:My DocumentsMyTable.xls!Sheet2!R1C1:R2C2”表示一个复合名

21、字对象,它表示存储在文件My DocumentsMyTable.xls 的工作表Sheet2的Range R1C1:R2C2对象。从根本上说,复合名字对象是为了描述现实中存在的一些对象模型,比如Office中的对象模型,这些对象模型中存在着上下级的包容关系。比如Excel 的Application对象是WorkBook对象的上级,WorkBook对象是WorkSheet对象的上级,WorkSheet对象是Range对象的上级。这些都是COM对象,而且都是永久对象,自动化对象。这些对象我们称为单项名字对象.每个对象只有在它的上级对象(或者称为包容器对象)的环境下才有意义。所以这些对象天生就是“复

22、合”的。而且它们的名字只有在上级对象的命名空间下才有意义。而且,上级对象应该能控制下级对象,比如解析它的名字,创建子对象等等。,19,复合名字对象由一组名字对象组成,也可以包括其他的复合名字对象。创建一个复合名字对象。WINOLEAPI CreateGenericComposite(LPMONIKER pmkFirst,/第一个名字对象LPMONIKER pmkRest,/第二个名字对象LPMONIKER FAR*ppmkComposite/结果名字对象的指针);从此函数的结构可知复合名字对象是如何构成的。,20,创建一个单项名字对象。WINOLEAPI CreateItemMoniker(L

23、PCOLESTR lpszDelim,/分割符LPCOLESTR lpszItem,/显示名LPMONIKER FAR*ppmk/结果名字对象的指针);以下代码可以创建一个复合名字对象“File1!Item1!Item2”:CreateFileMoniker(“File1”,pmkComp1-ComposeWith(pmkItem2,FALSE,&pmkComp2)/或者 CreateGenericComposite(pmkComp1,pmkItem2,&pmkComp2),5.2 单项和复合名字对象的创建,21,单项名字对象所命名的对象的上级对象(或容器对象)必须实现IOleItemCont

24、ainer接口.以把容器对象和下级对象联系起来,接口的定义如下:/from oleidl.idl object,uuid(0000011c-0000-0000-C000-000000000046)interface IOleItemContainer:IOleContainer/ask for object named by pszItem HRESULT GetObject(in LPOLESTR pszItem,/对象的显示名 in DWORD dwSpeedNeeded,/时限 in,unique IBindCtx*pbc,/绑定环境 in REFIID riid,/对象的接口 out,

25、iid_is(riid)void*ppv);/返回的接口指针/其他方法 此接口类似于类厂接口,GetObject则类似于类厂接口的CreateInstance函数.容器对象利用此接口来创建下级对象.单项名字对象的绑定过程如下:,5.3 单项名字对象的绑定过程,22,STDMETHODIMP ItemMoniker:BindToObject(IMoniker*pmkToLeft,IBindCtx*pbc,REFIID riid,void*ppv)*ppv=0;if(pmkToLeft=0)return E_INVALIDARG;/需要一个作用域/首先绑定左边的。IOleItemContainer

26、*poic=0;HRESULT hr=pmkToLeft-BindToObject(0,pbc,IID_IOleItemContainer,(void*)注意poic是左边的名字对象所指的对象的IOleItemContainer接口指针。它当然应该知道如何创建自己的下级对象。并返回接口指针。,23,5.4 复合名字对象的绑定过程,在简单文件名字的对象的绑定过程中演示了“c:My DocumentsMyTable.xls”的绑定过程.文件“c:My DocumentsMyTable.xls”代表了一个WorkBook对象。而这个WorkBook的第二张工作表Sheet2是它的一个下级对象。She

27、et2对象的状态数据存储在复合文档c:My DocumentsMyTable.xls的某一个子存储对象或流对象中。如果我们要在程序中访问这个对象,那么可以使用“c:My DocumentsMyTable.xls!Sheet2”这个名字。以下将演示如何绑定这个复合名字对象.首先仍然要使用CreateFileMoniker或MkParseDisplayName创建文件名字对象。OLECHAE pwsz=OLESTR(“c:My DocumentsMyTable.xls!Sheet2”)IBindCtx*pbc=0;ULONG cchEaten;IMoniker*pmk=0;HRESULT hr=C

28、reatBindCtx(0,24,绑定工作分为以下几步:检查ROT表,如果找到与它相等的名字对象,则调用此名字对象所指对象的IUnknown接口的QueryInterface函数返回接口指针即可.避免启动同一个实例.如果没有找到,则下一步:把名字对象分成两个部分.pmkLeft和pmkRight.pmkRight是一个简单的名字对象,左边可能是一个复合的或简单的名字对象.pmkRight-BindToObject(pmkLeft).在以上函数中,将调用pmkLeft-BindToObject.如果pmkLeft是一个简单名字对象,则按照上节的途径进行绑定工作,如果pmkLeft本身是一个复合名字对象,则重新回到步骤1.绑定过程形成了递归循环.复合名字对象的成员个数有限,所以循环一定会终止.以下条件会终止循环:在ROT表中找到了要绑定的对象.pmkLeft是简单名字对象pmkRight不需要左边的对象进行绑定支持.绑定过程完成以后,最左边的对象(最上层的)使用简单名字对象到达方式创建对象(CoCreateInstance见前节).然后上层容器对象的IOleItemContainer接口 的GetObject函数完成下层对象的创建过程.,25,绑定和构造的方向,26,File!Item1!Item2的绑定和构造过程,

展开阅读全文
相关资源
猜你喜欢
相关搜索
资源标签

当前位置:首页 > 建筑/施工/环境 > 农业报告


备案号:宁ICP备20000045号-2

经营许可证:宁B2-20210002

宁公网安备 64010402000987号