




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、COM重用模型聚合重用模型1 七 COM重用模型 n聚合 COM重用模型聚合重用模型2 1 包容 n1.1 模型模型 n重用性: 源代码级:C 继承. 二进制级:COM. 如何重用已有的COM对象的功能,而不是重新实现。 COM规范规定了两种重用的方法:包容(Containment)和聚合 (Aggregation) 包容: 假定我们已经实现了一个COM对象,不妨称为对象A,它实现了接口 ISomeInterface,不久,我们需要实现一个新的COM对象,称为对象B, 它既要实现对象A所支持的ISomeInterface,(两者的功能基本一致), 也要实现其他的功能IOtherInterfac
2、e。我们应该考虑在对象B中重用对象 A的功能,而只需在对象B中添加上新的功能即可。 直观的设想:对象B在实现ISomeInterface时调用对象A的 ISomeInterface的成员函数。对象A只是一个普通的COM对象,但是, 它也可以给另一个COM对象B提供服务。对象B在为客户提供服务的同时, 自己也是对象A的客户。对象B既是服务器,也是客户。这种重用方式就 是包容。对象B包容对象A,对象A被对象B包容。 包容的示意图: COM重用模型聚合重用模型3 n包容的示意图。嵌套的客户/服务器模型。 n对象B在调用对象A的接口成员函数时可以完全自由地处理,以响 应客户的请求。客户看到的只是对象B
3、所暴露出来的接口。对象A 的创建和释放完全在对象B的内部进行。 n比较简单直观的做法:对象B在构造时,同时创建对象A,并保留 对象A的接口指针,以便在对象B的接口成员函数中使用。当对象 B被释放时,首先释放对象A。 n更高效率的做法:对象B在需要的时候才创建,并在使用完后及时 销毁。 客户程序 对象B 对象A IOtherInterface ISomeInterface 调用 调用 ISomeInterface COM重用模型聚合重用模型4 假定内部A对象实现了接口ISomeInterface 外部对象B实现了 IOtherInterface接口。接口的定义如下: nclass ISomeIn
4、terface:public IUnkown public: virtual HRESULT _stdcall SomeFunction()=0; nclass IOtherInterface:public IUnkown public: virtual HRESULT _stdcall OtherFunction()=0; 客户程序、内部对象A、外部对象B三者之中,客户并不知道B包容 了A,它仍然和以前一样的方法来调用B,而A也不知道自己被B 包容,仍然和以前一样为所有的客户提供服务。而B则要处理对 象A的创建、调用、释放工作。 对象B的定义如下: 1 .2 包容的实现 COM重用模型聚合重
5、用模型5 nclass CB : public ISomeInterface , public IOtherInterface public : CB();CB(); public : HRESULT _stdcall QueryInterface(const IID ULONG_stdcall AddRef() ; ULONG_stdcall Release() ; HRESULT _stdcall SomeFunction(); / ISomeInterface 的成员函数 HRESULT _stdcall OtherFunction(); / IOtherInterface的成员函数 H
6、RESULT _stdcall Init(); /包容过程的初始化函数 private: ISomeInterface * m_pSomeInterface; /B对象包含一个指向 ISomeInterface接口的指针。 . 其中:CB:CB() if(m_pSomeInterface!=NULL) m_pSomeInterface-Release(); /当对象B被析构时通过调用对象A的Release成员释放对象A。 . 内部对象是在外部对象的Init函数中创建的: COM重用模型聚合重用模型6 nHRESULT CB:Init() HRESULT result= :CoCreateIns
7、tance(CLSID_ComponentA,NULL,CLSCTX_INPRO C_SERVER, IID_ISomeInterface,(void*) if (FAILED(result) return E_FAIL; else return S_OK; /在Init成员函数中,对象B创建了对象A,如果成功,数据成员 m_pSomeInterface记录了对象A的ISomeInterface接口指针 1.而外部对象的Init函数的调用时机可以很灵活,以在必要的时候 才调用,也可以简单地比如在外部对象的类厂接口的 CreateInstance中调用,即创建外部对象的同时也创建内部对象. 如下
8、:. COM重用模型聚合重用模型7 nHRESULT CBFactory:CreateInstance(IUnknown *pUnknownOuter, const IID HRESULT hr; *ppv=NULL; hr=E_OUTOFMEMORY; if (NULL != pUnknownOuter) return CLASS_E_NOAGGREGATION; pObj=new CB(); if (NULL=pObj) return hr; hr=pObj-Init(); /调用Init函数,创建对象A,得到对象A的接口 指针,保存在成员变量中。 if(FAILED(hr) delete
9、 pObj; hr=pObj-QueryInterface(iid, ppv); /返回对象B的接口指针给客户 if(FAILED(hr) delete pObj; return hr; COM重用模型聚合重用模型8 n通过外部接口也可以使用内部接口提供的方法SomeFunction nHRESULT _stdcall CB:SomeFunction() return m_pSomeInterface-SomeFunction(); /对象B实现接口ISomeInterface的SomeFunction成员函数时,只是 调用了对象A的相应的成员函数。重用的概念在此体现出来。当 然,对象B在调用
10、对象A的成员函数SomeFunction时,完全可以 对其进行修改。 外部对象的QueryInterface成员函数可以提供对两个接口的查询,客 户使用不同的接口来分别访问不同的函数。但是,实际上,当使 用ISomeInterface接口去调用SomeFunction时,完全有名不副实 的嫌疑。 COM重用模型聚合重用模型9 2 聚合 n内部对象接口指针的属性 n外部对象的定义 n内部对象的委托和非委托IUnkown接口 n外部对象和内部对象的创建过程。 n外部对象获取内部对象接口指针 n使用聚合对象 n例子 n由内部接口查询外部接口 n内部对象的其他接口 n内部对象在非聚合情形下的使用 CO
11、M重用模型聚合重用模型10 2.1 内部对象接口指针的属性 n在包容模型中, 客户从来没有得到从来没有得到内部对象的指针. 所有的操作都 是由外部对象的接口间接进行的. n聚合 体现了真正意义上的重用。 继续以上例子,如果对象B要提供的ISomeInterface接口的功能在 对象A中已经完全实现,不需任何修改,我们可以采用聚合模型。 (更加可靠!) n 在聚合模型中,对象B并不实现ISomeInterface接口,它只实 现IOtherInterface接口,但是它也能提供ISomeInterface接口的 功能,当客户请求ISomeInterface接口时,对象B把对象A的 ISomeIn
12、terface接口暴露给客户。 n客户真正得到了内部对象的指针客户真正得到了内部对象的指针. 客户虽然与对象A直接交互,但 是客户感觉不到。对象B借助对象A向客户提供ISomeInterface接 口服务,对象A的生存期受对象B控制。 n实现聚合的关键在于对象B的QueryInterface函数,当客户请求当客户请求 ISomeInterface接口时,把对象接口时,把对象A的的ISomeInterface接口指针传接口指针传 递给客户。递给客户。(对比在包容模型中对比在包容模型中,客户不能请求到内部接口指针客户不能请求到内部接口指针) 但是情况比想象的要复杂: COM重用模型聚合重用模型11
13、 当客户得到对象A 的ISomeInterface接口指针时,再调用 QueryInterface函数时,问题出现了,根据COM规范,客户从对 象B的任一个接口可以获得其他任何B支持的接口。所以客户从 ISomeInterface查询IOtherInterface接口和IUnkown接口时应该得 到对象B的IOtherInterface接口和其IUnkown接口。 然而事实上,客户得到的ISomeInterface接口指针指向的是对 象A,而不是对象B,而客户对此一无所知!正常情况下,对象A 根本就不知道什么IOtherInterface,和对象B!所以使用 ISomeInterface接口指
14、针查询不到IOtherInterface接口,查询 Iunkown接口也只能返回对象A的Iunkown接口,而不是对象B的。 所以,如果不作处理,程序很快就会崩溃。 所以,在聚合的情况下,当客户通过内部接口请求内部在聚合的情况下,当客户通过内部接口请求内部COM 对象对象 n所不支持的接口所不支持的接口 n或或Iunkown接口时,接口时, 内部对象必须把控制权交给外部对象。内部对象必须把控制权交给外部对象。 外部对象的定义如下: COM重用模型聚合重用模型12 nclass CB : public IOtherInterface /并不实现并不实现ISomeInterface接口接口 pro
15、tected: ULONG m_Ref; public: CB(); CB(); HRESULT _stdcall QueryInterface(const IID ULONG _stdcall AddRef(); ULONG _stdcall Release(); /IUnknown 成员 HRESULT _stdcall OtherFunction( ) ; /IOtherInterface 成员 HRESULT Init(); /初始化函数,用于构造内部对象 private : IUnknown *m_pUnknownInner; /内部对象内部对象A的的IUnkown接口指针接口指针
16、ISomeInterface *m_pSomeInterface; /内部对象内部对象A的的ISomeInterface接口指针接口指针 ; 客户得到ISomeInterface指针,但是它并不知道对象A的存在,它以为 所有的服务都是对象B提供的。这种透明性是由QueryInterface实现 的。因为客户通过此函数获取ISomeInterface指针: 2.2 外部对象的定义 COM重用模型聚合重用模型13 nHRESULT CB:QueryInterface(const IID (IUnknown *)(*ppv)-AddRef() ; else if ( iid = IID_OtherI
17、nterface ) *ppv = (IOtherInterface *) this ; (IOtherInterface *)(*ppv)-AddRef() ; else if ( iid = IID_SomeInterface ) return m_pUnknownInner-QueryInterface(iid, ppv) ; /* 虽然对象虽然对象B不实现接口不实现接口ISomeInterface,但是,它仍然支持对但是,它仍然支持对 ISomeInterface接口的查询,只是它把查询工作转交给内部对象接口的查询,只是它把查询工作转交给内部对象 的的QueryInterface去完成
18、,然后转交给客户,客户就可以调用对去完成,然后转交给客户,客户就可以调用对 象象A提供的服务了。(注意为什么不用提供的服务了。(注意为什么不用m_pSomeInterface? ) 它是对象它是对象B构造了对象构造了对象A之后保存的对对象之后保存的对对象A的引用。对象的引用。对象B通过通过 它以获得内部对象的接口指针。它以获得内部对象的接口指针。 */ else *ppv = NULL; return E_NOINTERFACE ; return S_OK; COM重用模型聚合重用模型14 n假如客户获得了两个接口指针:IOtherInterface和ISomeInterface, 通过这两个
19、接口指针,客户看到了完全不同的世界: 客户程序 pOtherInterface pSomeInterface 对象B 对象A QueryInterface AddRef Release OtherFunction IUnkown QueryInterface AddRef Release SomeFunction IUnkown IOtherInterface ISomeInterface 2.3 内部对象的委托和非委托IUnkown接口 客户分别通过这两个指针查询IUnkown接口指针分别指向对象B和对象A。另外 从ISomeInterface接口查询不到IOtherInterface接口。
20、这与COM规范相矛盾。 聚合模型必须解决这两个接口查询问题,才能到达透明性。否则客户的操作无 法正常进行。 COM重用模型聚合重用模型15 n解决方案: 内部对象A实现两个IUnkown接口:委托IUnkown接口和非委托 Iunkown接口(delegating unkown和nondelegating unkown)其 中非委托IUnkown接口定义如下: class INondelegatingUnknown public: virtual HRESULT _stdcall NondelegationQueryInterface(const IID virtual ULONG _stdc
21、all NondelegatingAddRef() = 0; virtual ULONG _stdcall NondelegationRelease() = 0; ; 同时 内部对象A通过继承ISomeInterface间接继承IUnkown,以下是 它的定义: COM重用模型聚合重用模型16 nclass CA : public ISomeInterface, public INondelegatingUnknown protected: ULONG m_Ref; public: CA(); CA(IUnknown *pUnknownOuter); /构造函数中带有一个接口指针。构造函数中带
22、有一个接口指针。 public : / 委托委托 IUnknown virtual HRESULT _stdcall QueryInterface(const IID virtual ULONG _stdcall AddRef() ; virtual ULONG _stdcall Release() ; / 非委托非委托 IUnknown virtual HRESULT _stdcall NondelegationQueryInterface(const IID virtual ULONG _stdcall NondelegatingAddRef(); virtual ULONG _stdca
23、ll NondelegationRelease(); virtual HRESULT _stdcall SomeFunction( ) ;/ISomeFunction private : IUnknown *m_pUnknownOuter; /* pointer to outer IUnknown 将被构造函数的参数所赋值,将被构造函数的参数所赋值, 指向外部对象的指向外部对象的IUnkown接口。接口。*/ ; COM重用模型聚合重用模型17 n按照通常使用方式实现的IUnkown接口为非委托接口。非委托接 口的实现方式与普通的IUnkown接口完全一致,但是名字不一样。 前面加上了Nond
24、elegating前缀。 n事实上它的名字是无关紧要的,事实上它的名字是无关紧要的,因为无论是客户还是外部对象都都 不会不会直接调用它(不会试图获取内部对象的INondelegating接口)。 (外部对象通过虚表间接调用)关于非委托IUnkown接口的操作 都是通过委托IUnkown接口来进行的。 n所谓委托IUnkown接口就是我们通常的IUnkown接口,只不过在 对象被聚合的情形下,相对于新加的一个INondelegatingUnkown 而言,这样称呼它而已。它的函数的实现方式却是与通常不同,啥 都不干,“委托”而已. n当对象被正常使用的时候,委托当对象被正常使用的时候,委托IUn
25、kown把调用传递给非委托的把调用传递给非委托的 IUnkown; 当对象被聚合使用时当对象被聚合使用时, 委托委托IUnkown把调用传递到外把调用传递到外 部对象的部对象的IUnkown接口,并且这时外部对象通过接口,并且这时外部对象通过非委托非委托 IUnknown接口对内部对象进行控制。接口对内部对象进行控制。 COM重用模型聚合重用模型18 n支持被聚合的(内部)对象在非聚合方式下的接口示意图 委托IUnkown把调用传递给非委托的IUnkown; 客户程序 对象A 委托 IUnkown QueryInterface AddRef Release SomeFunction 非委托 I
26、Unkown ISomeInterface COM重用模型聚合重用模型19 n支持被聚合的(内部)对象在聚合方式下的接口示意图委托 IUnkown把调用传递到外部对象的IUnkown接口,并且这时外部 对象通过非委托非委托IUnknown接口对内部对象进行控制。 n两个IUnknown的实现如下: 客户程序 pOtherInterface pSomeInterface 对象B 对象A QueryInterface AddRef Release OtherFunction 外部对象的 IUnkown QueryInterface AddRef Release SomeFunction 委托IUn
27、kown IOtherInterface ISomeInterface 非委托IUnkown 控制 COM重用模型聚合重用模型20 n内部对象非委托IUnkown接口的实现: nULONG CA:NondelegatingAddRef() m_Ref +; return (ULONG) m_Ref; nULONG CA:NondelegationRelease () m_Ref -; if (m_Ref = 0 ) g_CompANumber - ; delete this; return 0; return (ULONG) m_Ref; 接口查询函数如下: COM重用模型聚合重用模型21 n
28、HRESULT CA:NondelegationQueryInterface(const IID (IUnknown *)(*ppv)-AddRef() ; else if ( iid = IID_SomeInterface ) *ppv = (ISomeInterface *) this ; (ISomeInterface *)(*ppv)-AddRef() ; else *ppv = NULL; return E_NOINTERFACE ; return S_OK; n非委托IUnkown名字虽然不同,但是实现方法与通常的IUnknown 接口的是否方法完全相同。(因此,当其不被聚合时也可
29、以正常使 用). n注意NondelegationQueryInterface函数把对IID_IUnkown接口的 查询返回非委托IUnknown接口. 这个非委托的IUnknown接口将在 内部对象的类厂的CreateInstance函数返回给外部对象.外表对象 通过此指针控制内部对象. COM重用模型聚合重用模型22 n委托IUnkown接口的实现: nULONG CA:AddRef () if ( m_pUnknownOuter != NULL ) return m_pUnknownOuter-AddRef(); elsereturn NondelegatingAddRef(); nUL
30、ONG CA:Release () if ( m_pUnknownOuter != NULL ) return m_pUnknownOuter-Release (); elsereturn NondelegationRelease(); nHRESULT CA:QueryInterface(const IID else return NondelegationQueryInterface(iid, ppv); 委托IUnkown本身并不进行任何操作,它通过m_pUnkownOuter成 员变量判断是否被聚合: n聚合时, m_pUnkownOuter指向外部的IUnkown接口,则委托 IUn
31、kown把调用传给m_pUnkownOuter; n不聚合时, m_pUnkownOuter为NULL,委托IUnkown把调用 传递给非委托IUnkown的相应函数。 COM重用模型聚合重用模型23 2.4. 外部对象和内部对象的创建过程。 n外部对象B由类厂创建以后,在类厂的CreateInstance函数调用其Init ()成员函数: nHRESULT CB:Init() IUnknown *pUnknownOuter = (IUnknown *)this; HRESULT result = :CoCreateInstance (CLSID_CompA, /外部对象创建内部对象 pUnk
32、nownOuter,/调用CoCreateInstance函数创建对象A时,把自 身的IUnkown指针传了进去,通知内部对象A被外部对象B聚合。 CLSCTX_INPROC_SERVER, IID_IUnknown, /要求得到内部对象的IUnknown,内部对象给了非 委托的那个. (void *)/CoCreateInstance函数返回后得到 了m_pUnkownInner指针,指向对象A的非非委托IUnkown。 if (FAILED(result)return E_FAIL; else return S_OK; n n外部对象B调用的CoCreateInstance函数将调用内部对
33、象A的类厂 的CreateInstance函数: COM重用模型聚合重用模型24 HRESULT CAFactory:CreateInstance (IUnknown *pUnknownOuter, const IID / 要求外部对象传入 IID_IUnknown接口来聚合自己 if ( ( pUnknownOuter != NULL ) *ppv=NULL; hr=E_OUTOFMEMORY; CA *pObj=new CA (pUnknownOuter);/new 内部对象内部对象,同时传入同时传入 外部对象外部对象B的指针的指针 if (NULL=pObj)return hr; hr
34、= pObj-NondelegationQueryInterface(iid, ppv);/ppv将返将返 回内部对象的非委托回内部对象的非委托IUnknown接口接口,见前文见前文. 注意不是使用注意不是使用 QueryInterface方法。方法。 if (hr != S_OK) g_CompANumber -; delete pObj; return hr; n而内部对象的构造函数: nCA:CA (IUnknown *pUnknownOuter) m_Ref = 0;g_CompANumber + ; m_pUnknownOuter = pUnknownOuter; 在外部对象new内
35、部对象时,内部对象保留了外部对象的指针. 创建内部对象的调用堆栈以及指针的传递过程如下图: COM重用模型聚合重用模型25 n上图左半部分:创建内部对象的函数调用堆栈。 n右半部分:外部对象和内部对象相互引用的成员变量的赋值曲线。 下行:外内 上行:内外。 n通过以上方式,内部对象和外部对象相互得到对对方的引用指针。 n而且外部对象使用一个IUnknown型的指针变量保存了内部对象的 INondelegationUnknown指针. 外部对象的类厂的CreateInstance函数 外部对象的Init成员函数 CoCreateInstance函数 内部对象类厂的CreateInstance成员
36、函数 内部对象的构造函数 内部对象的非委托查询接口函数 (IUnkown*)this HRESULT result = :CoCreateInstance(CLSID_CompA, pUnknownOuter, CLSCTX_INPROC_SERVER, IID_IUnknown, (void *) if (FAILED(result)return E_FAIL; result = m_pUnknownInner-QueryInterface(IID_SomeInterface, (void *)/ 执行过程路线?执行过程路线? if (FAILED(result)m_pUnknownInne
37、r-Release(); return E_FAIL; pUnknownOuter-Release();/ 为什么?为什么? return S_OK; n注意外部对象得到的是内部对象的非委托接口。见内部对象的类 厂的CreateInstance成员函数中使用的 hr = pObj-NondelegationQueryInterface(iid, ppv);此函数直接返回 (INonDelegatingUnkown*)this 即内部对象的非委托接口。 COM重用模型聚合重用模型28 n然而然而外部对象使用的对内部对象的引用是普通的IUnkown*类 型的接口指针m_pUnkownInner。不
38、仅如此,外部对象通过 m_pUnkownInner查询接口时使用的是QueryInterface成员函 数。 n这是外部对象第一次查询ISomeInterface接口。我们追踪 m_pUnknownInner-QueryInterface的执行路线。看起来,它 似乎似乎是: nm_pUnknownInner-QueryInterface n m_pUnknownInner是IUnknown指针,因此,由委托接口的 QueryInterface函数: if ( m_pUnknownOuter != NULL ) return m_pUnknownOuter-QueryInterface(iid,
39、 ppv); 由于此时m_pUnknownOuter 在对象A的类厂CreateInstance函 数中已经赋值指向外部对象,所以调用将转向 n m_pUnknownOuter-QueryInterface(iid, ppv); 其中iid即IID_ISomeInterface. 而外部对象查询ISomeInterface接 口又转向m_pUnknownInner-QueryInterface 即重新回到 step1。 进入了无限循环。 问题出在第二步。回忆关于显示类型转换: COM重用模型聚合重用模型29 MTCA *pmtca=new MTCA; MT *pmt=pmtca; CA *pc
40、a=(CA*)pmt; /交叉显式转换可以成功,但是. pca-WhoAmI (); / I am a MTCA pca-TakePhoto (); / MTCA is calling !不是MTCA is takephoto! n显示的cross cast的结果,见棕色部分.尤其注意TakePhoto 函数在它们的 内存位置实际上保存的是Call的函数指针. 绿色是动态转换的结果 WhoAmI 被覆盖 Call被改写 MTCA的虚表 Work WhoAmI 被覆盖 TakePhoto被改写 Work 继承自MT 继承自CA vptr2 vptr1 price rent pmtca pmt p
41、ca pixel price pca WhoAmI 被覆盖 TakePhoto- Call MTCA的虚表 Work WhoAmI 被覆盖 TakePhoto被改写 Work 继承自MT 继承自CA vptr2 price vptr2 price piexel- rent pmtca pmt pixel COM重用模型聚合重用模型30 n 外部对象保存内部对象的指针是采用的如上显示的类型的转换方 式。 IUnkown* m_pUnkownInner= (IUnkown* )(NonDelegratingUnkown)(内部对象指针) 所以Init函数中 m_pUnknownInner-Quer
42、yInterface实际上调用的 是NonDelegatingQueryInterface函数。 if ( iid = IID_SomeInterface ) *ppv = (ISomeInterface *) this ; (ISomeInterface *)(*ppv)-AddRef() ; NonDelegatingQueryInterface函数将内部对象的this指针转换为 ISomeInterface接口指针传出来,保存在外部对象的 m_pSomeInterface中。这就是外部对象查询内部对象这就是外部对象查询内部对象 ISomeInterface的过程的过程。 由此也可以看到非
43、委托IUnknown的类的名称和函数的名称都是无 关紧要的. 重要的是类的定义和函数的签名. COM重用模型聚合重用模型31 n根据COM规范,接口指针复制时,要增加引用计数。那么查询 ISomeInterface接口后,增加谁的引用计数呢?外部的还是内部 的? n 从用户的角度出发,当然应该是外部外部的。因为客户并不知道内部 对象的任何事情!操作仍然由 NonDelegatingQueryInterface函数 完成: if ( iid = IID_SomeInterface ) *ppv = (ISomeInterface *) this ; (ISomeInterface *)(*ppv
44、)-AddRef() ; 内部对象的AddRef函数(委托IUnkown接口成员) if ( m_pUnknownOuter != NULL ) return m_pUnknownOuter-AddRef(); 调用转向外部对象的引用计数增1操作。 这也就是为什么在B的Init函数中要进行pUnknownOuter- Release();操作的原因,因为第一次由外部对象主动向内部对象 询问ISomeInterface接口只是保存对内部对象的引用,并不是由 客户提出来要查询的,如果不进行减1操作,会给客户造成错觉。 COM重用模型聚合重用模型32 n2.6.1 例子例子 nint main(int argc, char* argv) IUnknown *pUnknown;ISomeInterface *pSomeInterface; IOtherInterface *pOtherInterface;HRESULT hResult; GUID compBCLSID; if (CoInitialize(NULL) != S_OK) return -1; hResult = :CLSIDFromProgID(LCompB.Object, if (FAILED(hResult) CoUninitialize();
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 自驾游免责协议书范例二零二五年
- 公司运输司机聘用合同书
- 二零二五设计外包合同书范例
- 二零二五婚生女离婚协议书
- 二零二五工程款转让第三方结算协议书
- 农机作业租赁合同模板二零二五年
- 项目推广合作协议书
- 融资咨询及居间服务协议合同二零二五年
- 借款合同和担保合同的关系
- 二零二五版土地入股合作的协议书范例
- GB/T 9442-2024铸造用硅砂
- 中国椎管内分娩镇痛专家共识(2020版)
- 2023-2024学年天津市红桥区八年级(下)期中数学试卷(含解析)
- 国开2024年《机械设计基础》形考任务1-4答案
- ifix培训教程课件
- 社会单位消防安全风险自查评估报告表模板
- 精神科出院康复指导
- 2024年贵州建筑安全员B证考试题库及答案(推荐)
- sls打印工艺流程
- PHQ-15躯体症状群健康评定量表
- 中医针灸美容技术操作规范2023版
评论
0/150
提交评论