首页 名字对象课件

名字对象课件

举报
开通vip

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

名字对象课件
十四.名字对象概念IMoniker接口名字对象的创建根据显示名创建名字对象类名字对象的创建其他名字对象的创建简单名字对象的绑定过程。ROT表文件名字对象的绑定CoGetInstanceFromFile函数复合名字对象概念及其绑定过程概念单项和复合名字对象的创建单项名字对象的绑定过程复合名字对象的绑定过程1概念我们已知创建COM对象的两种方法:通过CoGetClassObject得到类厂,通过类厂接口调用CreateInstance.直接使用CoCreateInstance或CoCreateInstanceEx.客户使用以上两种方法在创建COM对象时,必须提供对象的CLSID或ProgID。COM提供了提供了第三种方法,即利用名字对象(moniker绰号,名字)创建COM对象的方法。名字对象本身也是一个COM对象。名字对象为另一个COM对象提供了的符号化的表示方法,同时也对组件对象的创建过程进行封装。客户程序只需创建相应的名字对象,并使用名字对象的绑定功能得到组件对象。在这个意义上,名字对象类似于类厂对象,但是它比类厂对象提供了更多的功能.其关系对比图如下:名字对象与类厂对象的功能对比示意图类厂客户IClassFactoryCOM对象(1)客户COM对象monikerIMoniker(2)之所以在类厂对象之外衍生出名字对象,是因为:名字对象可以以名字的方式来创建COM对象,有时候比使用CLSID的方式更方便.在一些复杂的应用中,COM对象形成了逻辑上的上下级关系或者是包容的关系.在每一个级别上都是一个COM对象,下级的对象只有在上级的对象范围内才有意义,而且在确定了上级对象以后,下级对象可以更加简单(且更加明确和直观)地使用名字的方式来描述.在这种情形下,使用从上到下的名字比使用一串的CLSID更加方便合理地创建COM对象.比如Excel中的文档对象以ExcelApplication,WorkBook,WorkSheet、Range等层次的COM对象的方式给应用程序员提供访问接口。这些对象的状态存储在复合文档的不同级别的存储对象和流对象中.比如“c:\MyDocuments\MyTable.xls!Sheet2!R1C1:R2C2”表示存储在文件MyDocuments\MyTable.xls的工作表Sheet2的RangeR1C1:R2C2对象。这些对象往往都是永久对象。它们不仅有方法,而且有状态.它们的状态数据以复合文档的形式存储在磁盘上。如果只使用CLSID,根本不能准确地表明是标识为CLSID的COM对象的此实例,而非彼实例.所以,不仅是更直观,而且是必须以“复合名字”的方式才能准确地创建或还原这个COM对象.3名字对象的创建3.1根据显示名创建名字对象名字对象的名字称为显示名(displayname)是一种用户可读的名字.显示名可以是文件路径名,这时返回文件名字对象,也可以是组件对象的CLSID,这时返回类名字对象。也可以是经过扩充的以“!”等间隔开的复合名字,(这时返回复合名字对象)。IMoniker接口有一个方法GetDisplayName可以返回对象的显示名.然而更重要的是根据显示名来创建名字对象.WINOLEAPIMkParseDisplayName(LPBCpbc,//绑定环境LPCOLESTRszUserName,//显示名ULONG*pchEaten,//绑定过程中解析的字符个数LPMONIKERFAR*ppmk//结果名字对象的指针);MkParseDisplayName根据显示名进行解析的结果生成名字对象,并以IMoniker指针的方式返回给客户。名字对象有很多种,也有很多别的方法来创建名字对象。创建一个类名字对象WINOLEAPICreateClassMoniker(REFCLSIDrclsid,//该名字对象所命名的对象的CLSIDIMoniker**ppmk//结果名字对象的指针);该类名字对象将指向所命名对象的类厂对象.下面是一个客户从类名字对象得到组件对象的例子:3.2类名字对象的创建创建一个文件名字对象。WINOLEAPICreateFileMoniker(LPCOLESTRlpszPathName,//文件路径LPMONIKERFAR*ppmk//结果名字对象的指针);创建一个单项名字对象。WINOLEAPICreateItemMoniker(LPCOLESTRlpszDelim,//分割符LPCOLESTRlpszItem,//显示名LPMONIKERFAR*ppmk//结果名字对象的指针);创建一个复合名字对象。WINOLEAPICreateGenericComposite(LPMONIKERpmkFirst,//第一个名字对象LPMONIKERpmkRest,//第二个名字对象LPMONIKERFAR*ppmkComposite//结果名字对象的指针);3.3其他名字对象的创建:4简单名字对象的绑定过程。4.1ROT表COM对象的激活是由COM服务的SCM(服务控制管理器)来完成的.每台支持COM的机器上都有本地的SCM。它响应客户的加载COM对象的请求。一旦对象被激活,SCM就不再介入到客户和组件对象的方法调用过程。客户以名字对象或底层API的形式访问SCM提供的服务。SCM使用ROT(RunningObjectTable)来管理正在运行的,已经被注册的名字对象。如果一个名字对象所指的组件对象已经在运行了,在名字对象的绑定过程中,可以直接连接到此对象上,而不必再启动新的对象。有两种方式可以得到ROT表:使用GetRunningObjectTable来得到ROT表的IRunningObjectTable指针WINOLEAPIGetRunningObjectTable(DWORDreserved,//保留LPRUNNINGOBJECTTABLE*pprot);//IRunningObjectTable接口指针名字对象在绑定过程中要使用到绑定环境。绑定环境是COM实现的系统对象。客户可以使用CreateBindCtx函数来创建一个绑定环境对象。WINOLEAPICreateBindCtx(DWORDreserved,//保留LPBCFAR*ppbc);//IBindCtx接口指针客户可以从绑定环境中使用接口函数GetRunningObjectTable得到ROT,同时可以控制绑定过程中的一些行为。以下以文件名字对象为例研究名字对象的绑定过程.比如客户程序通过文件名字对象来访问一个电子表格文档对象。电子表格文件名为:“c:\MyDocuments\MyTable.xls”.Excel中的文档对象以ExcelApplication,WorkBook,WorkSheet、Range等层次的COM对象的方式给应用程序员提供访问接口。这几个对象都是永久对象。它们的状态数据以复合文档的形式存储在磁盘上。在VBA环境下或VisualBasic环境下,我们可以方便地使用VisualBasic语言访问电子表格文档对象。在C++环境下,可以对这些对象进行更精细的控制。客户程序调用CreateFileMoniker或MkParseDisplayName函数来创建一个文件名字对象。得到文件名字对象的IMoniker指针。然后调用名字对象的IMoniker::BindToObject函数,一旦函数成功返回,就得到了电子表格文档对象。BindToObject内部调用了CoGetInstanceFromFile,见下:4.2文件名字对象的绑定STDMETHODIMPFileMoniker::BindToObject(IBindCtx*pbc,  IMoniker*pmkToLeft,   REFIIDriid,void**ppv){*ppv=0;HRESULThr=E_FAIL;if(pmkToLeft==0){//左边没有名字对象的情形MULTI_QImqi={&riid,0,0};  //用户指定的接口IIDCOSERVERINFO*pcsi;  DWORDgrfMode;  DWORDdwClsCtx;//这三个参数是BindCtx的属性  this->MyGetFromBindCtx(pbc,&pcsi,&grfMode,&dwClsCtx); //得到绑定环境,比如使用COM的CreateBindCtx函数,然后可以得到调用IBindCtx的成员函数GetRunningObjectTable得到ROT。 hr=CoGetInstanceFromFile(pcsi,0,0,dwClsCtx,grfMode,this->m_pszFileName, 1,&mqi);  if(SUCCEEDED(hr))    *ppv=mqi.pItf;}//通过MULTI_QI指针的分量指针返回客户对象的接口指针else{//左边有名字对象的情形,复合名字对象。见下文.}returnhr;}CoGetInstanceFromFile函数完成了实际的创建COM对象的过程.如下:4.3CoGetInstanceFromFile函数HRESULTCoGetInstanceFromFile(COSERVERINFO*pServerInfo,//指向远程主机CLSID*pclsid,//要创建的对象的CLSIDIUnknown*punkOuter,//用于被聚合的情形,指向外部的IUnknownDWORDdwClsCtx,//环境变量DWORDgrfMode,//打开模式OLECHAR*szName,//对象文件名ULONGcmq,//MULTI_QI数组的大小,即接口的个数.MULTI_QI*rgmqResults//MULTI_QI数组);其中:typedefstruct_MULTI_QI{constIID*pIID;//客户指定的要返回的目标对象的接口IIDIUnknown*pItf;//用来保存接口的指针HRESULThr;}MULTI_QI;此结构可以保存多个接口指针。3.如果在ROT表中没有找到对应的入口项,那么CoGetInstanceFromFile使用CoCreateInstance或CoGetClassObject再由类厂接口的CreateInstance创建新对象,并返回对象的IUnkown接口指针。4。从IUnkown接口查询对象的IPersistFile接口。(既然复合文档中把它的CLSID记下来了,说明此对象肯定是永久对象,并实现了IPersistFile接口)。从IPersistFile接口调用Load方法,并把文件名传入作为参数,Load从文件读取数据对对象的状态进行初始化,并且在ROT表中进行注册。Load方法如下:STDMETHODIMPMyWorkBook::Load(constOLECHAR*pszFileName, DWORDgrfMode){//从文件中读入对象状态hr=this->MyReadStateFromFile(pszFile,grfMode);if(FAILED(hr))returnhr;IRunningObjectTable*prot=0;hr=GetRunningObjectTable(0,&prot);//从SCM中获取ROT表if(SUCCEEDED(hr)){//创建一个文件名字对象并在ROT中注册  IMoniker*pmk=0;  hr=CreateFileMoniker(pszFileName,&pmk);  //创建文件名字对象if(SUCCEEDED(hr)){//registerselfinROT    hr=prot->Register(0,this,pmk,&m_dwReg);   //注册 pmk->Release();  }  prot->Release();}returnhr;}以后再用同样的文件名调用CoGetInstanceFromFile函数将不会创建新的对象,而是返回指向这个对象的引用。使用文件名字对象达到了两个目的:允许对象把自身注册到ROT中,使得以后的CoGetInstanceFromFile能找到它。把CoGetInstanceFromFile隐藏到IMoniker接口后面了。客户只是调用名字对象,并没有调用CoGetInstanceFromFile。见BindToObject的实现代码。复合名字对象由一组名字对象组成,也可以包括其他的复合名字对象。创建一个复合名字对象。WINOLEAPICreateGenericComposite(LPMONIKERpmkFirst,//第一个名字对象LPMONIKERpmkRest,//第二个名字对象LPMONIKERFAR*ppmkComposite//结果名字对象的指针);从此函数的结构可知复合名字对象是如何构成的。创建一个单项名字对象。WINOLEAPICreateItemMoniker(LPCOLESTRlpszDelim,//分割符LPCOLESTRlpszItem,//显示名LPMONIKERFAR*ppmk//结果名字对象的指针);以下代码可以创建一个复合名字对象“File1!Item1!Item2”:CreateFileMoniker(“File1”,&pmkFile);CreateItemMoniker(“!”,”Item1”,&pmkItem1);pmkFile->ComposeWith(pmkItem1,FALSE,&pmkComp1)//或者CreateGenericComposite(pmkFile,pmkItem1,&pmkComp1)CreateItemMoniker(“!”,”Item2”,&pmkItem2);pmkComp1->ComposeWith(pmkItem2,FALSE,&pmkComp2)//或者CreateGenericComposite(pmkComp1,pmkItem2,&pmkComp2)5.2单项和复合名字对象的创建单项名字对象所命名的对象的上级对象(或容器对象)必须实现IOleItemContainer接口.以把容器对象和下级对象联系起来,接口的定义如下://fromoleidl.idl[object,uuid(0000011c-0000-0000-C000-000000000046)]interfaceIOleItemContainer:IOleContainer{//askforobjectnamedbypszItemHRESULTGetObject(      [in]LPOLESTRpszItem,//对象的显示名    [in]DWORDdwSpeedNeeded,//时限 [in,unique]IBindCtx*pbc,//绑定环境   [in]REFIIDriid,//对象的接口     [out,iid_is(riid)]void**ppv);//返回的接口指针……//其他方法}此接口类似于类厂接口,GetObject则类似于类厂接口的CreateInstance函数.容器对象利用此接口来创建下级对象.单项名字对象的绑定过程如下:5.3单项名字对象的绑定过程STDMETHODIMPItemMoniker::BindToObject(IMoniker*pmkToLeft,IBindCtx*pbc, REFIIDriid,void**ppv){*ppv=0;if(pmkToLeft==0)returnE_INVALIDARG; //需要一个作用域  //首先绑定左边的。IOleItemContainer*poic=0;HRESULThr=pmkToLeft->BindToObject(0,pbc, IID_IOleItemContainer,(void**)&poic);//返回左边名字对象所指的对象的IOleItemContainer接口。如果左边也是一个单项名字对象,则会继续递归调用.直到能够单独绑定为止.if(SUCCEEDED(hr)){pbc->RegisterObjectBound(poic);//在绑定环境中缓存已绑定对象。 DWORDdwBindSpeed=this->MyGetSpeedFromCtx(pbc);//绑定过程比较耗时,所以要设定时间参数。hr=poic->GetObject(m_pszItem,//即字符串“Sheet2”dwBindSpeed,//实际限制pbc,//绑定环境riid,//客户指定的目标对象的接口IID,比如说IID_IWorkSheetppv); //返回指针 poic->Release();}}注意poic是左边的名字对象所指的对象的IOleItemContainer接口指针。它当然应该知道如何创建自己的下级对象。并返回接口指针。5.4复合名字对象的绑定过程在简单文件名字的对象的绑定过程中演示了“c:\MyDocuments\MyTable.xls”的绑定过程.文件“c:\MyDocuments\MyTable.xls”代表了一个WorkBook对象。而这个WorkBook的第二张工作表Sheet2是它的一个下级对象。Sheet2对象的状态数据存储在复合文档c:\MyDocuments\MyTable.xls的某一个子存储对象或流对象中。如果我们要在程序中访问这个对象,那么可以使用“c:\MyDocuments\MyTable.xls!Sheet2”这个名字。以下将演示如何绑定这个复合名字对象.首先仍然要使用CreateFileMoniker或MkParseDisplayName创建文件名字对象。OLECHAEpwsz[]=OLESTR(“c:\MyDocuments\MyTable.xls!Sheet2”)IBindCtx*pbc=0;ULONGcchEaten;IMoniker*pmk=0;HRESULThr=CreatBindCtx(0,&pbc);hr=MkParseDisplayName(pbc,pwsz,&cchEaten,&pmk);得到名字对象以后进行绑定工作:IMoniker::BindToObject();绑定工作分为以下几步:检查ROT表,如果找到与它相等的名字对象,则调用此名字对象所指对象的IUnknown接口的QueryInterface函数返回接口指针即可.避免启动同一个实例.如果没有找到,则下一步:把名字对象分成两个部分.pmkLeft和pmkRight.pmkRight是一个简单的名字对象,左边可能是一个复合的或简单的名字对象.pmkRight->BindToObject(pmkLeft……).在以上函数中,将调用pmkLeft->BindToObject.如果pmkLeft是一个简单名字对象,则按照上节的途径进行绑定工作,如果pmkLeft本身是一个复合名字对象,则重新回到步骤1.绑定过程形成了递归循环.复合名字对象的成员个数有限,所以循环一定会终止.以下条件会终止循环:在ROT表中找到了要绑定的对象.pmkLeft是简单名字对象pmkRight不需要左边的对象进行绑定支持.绑定过程完成以后,最左边的对象(最上层的)使用简单名字对象到达方式创建对象(CoCreateInstance见前节).然后上层容器对象的IOleItemContainer接口的GetObject函数完成下层对象的创建过程.File!Item1!Item2的绑定和构造过程pmkItem2->BindToObject(厎,pmkFileItem1,IID_IUnknown,ppvObj)客户程序调用pComp->BindToObject(厎,IID_IUnknown,&pUnk)复合名字对象被拆分成pmkFileItem1和pmlItem2两部分pmkFileItem1->BindToObject(厎,NULL,IID_IOleItemContainer,&pItem1Obj)pmkFileItem1被拆分成pmkFile和pmlItem1两部分pmkItem1->BindToObject(厎,pmkFile,IID_IOleItemContainer,&pItem1Obj)pmkFile->BindToObject(厎,NULL,IID_IOleItemContainer,&pFileObj)创建文件对象并返回其IOleItemContainer接口指针pFileObj指向文件对象的IOleItemContainer接口指针pFileObj->GetObject(...,IID_IOleItemContainer,&pItem1Obj)pItem1Obj指向文件对象中Item1对象的IOleItemContainer接口指针pItem1Obj->GetObject(...,IID_IUnknown,&pUnk)pUnk指向文件对象的Item1对象的Item2对象的IUnknown接口指针绑定方向方向构造
本文档为【名字对象课件】,请使用软件OFFICE或WPS软件打开。作品中的文字与图均可以修改和编辑, 图片更改请在作品中右键图片并更换,文字修改请直接点击文字进行修改,也可以新增和删除文档中的内容。
该文档来自用户分享,如有侵权行为请发邮件ishare@vip.sina.com联系网站客服,我们会及时删除。
[版权声明] 本站所有资料为用户分享产生,若发现您的权利被侵害,请联系客服邮件isharekefu@iask.cn,我们尽快处理。
本作品所展示的图片、画像、字体、音乐的版权可能需版权方额外授权,请谨慎使用。
网站提供的党政主题相关内容(国旗、国徽、党徽..)目的在于配合国家政策宣传,仅限个人学习分享使用,禁止用于任何广告和商用目的。
下载需要: 免费 已有0 人下载
最新资料
资料动态
专题动态
个人认证用户
wwlaoba
暂无简介~
格式:ppt
大小:1MB
软件:PowerPoint
页数:26
分类:医药卫生
上传时间:2022-09-23
浏览量:0