VC字符串之间的转换.docx_第1页
VC字符串之间的转换.docx_第2页
VC字符串之间的转换.docx_第3页
VC字符串之间的转换.docx_第4页
VC字符串之间的转换.docx_第5页
已阅读5页,还剩25页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

字符串的转换字符串转换用到的地方很多,常见的字符串类型有以下几种:char wchar tchar BSTR _bstr_t CComBSTR CString string。最常涉及到的是在BSTR和CString之间相互转换。1.字符串的根本及其封装其实最基本的字符或串,深究到底,只有三种:字符字符串说明charLPSTR LPCSTR单字节,以 0 标记结束wchar_tLPWSTR LPWCSTR双字节,以 0 标记结束BSTR双字节,前面有4个byte长,用来装字节数。这表明一个BSTR串可能包含多个0而至于以下的封装,其目的多是对其中一种进行封装,并提供了转入和转出的接口。而封装的方式分为两条线,unicode方式和com方式。Windows的兼容UNICODE封装字符字符串说明charLPSTR LPCSTRAnsi单字节wchar_tLPWSTR LPWCSTRUnicode双字节TCHARLPTSTR LPCTSTRCString兼容Ansi和unicode的Windows的兼容com封装分支字符串说明通用标准BSTR多用在IDL中,作为标准接口对外兼容各类语言的使用者com c+_bstr_t多用在c+ 的实现和使用,既有MFC也有标准C+包含comdef.h OLEAUT32.LIB OLEAUT32.dllAtlCComBSTR多用在atl 的组件实现和使用方面,包含atlbase.h atl.lib atl.dllunicode和com有很大的相同-都是双字节。MS将组件的通用字符串类型定义为双字节了。BSTR前进的第一步是双字节;前进的另一步是字符串长度的解决方法。以0结尾的通用的字符串解决方式简单明了;但是在那内存寸土寸金的年代,讲求速度、最大化发挥软件的功能和效率,为所有字符串都省去求长这一步,在最简单的地方前进一步,产生的收益却是无穷大。2.字符串的转换转换与使用的场合相结合。总结如下场合分支字符串说明MFCCStringMFC对兼容unicode的封装通用标准BSTRIDL中使用com c+_bstr_t多用在使用组件时,非MFC程序也可以使用。_bstr_t实际上是将char wchar_t BSTR转换为wchar_t*;同时又可以转换为 char wchar_t BSTR注意:里面的转换函数使用的是标准c+ AtlCComBSTR多用在atl 的组件实现和使用方面,CcomBSTR实际上是也是将非BSTR转换为BSTR的副本但不支持转换为其它非BSTR类型注意:里面的转换函数使用的是win api说明: BSTR实际上可以直接作为wchat_t * 来使用。3BSTR简介COM是一种跨编程语言的平台,需要提供语言无关的数据类型。多数编程语言有自己的字符串表示。C+ 字符串是以0结束的ASCII或Unicode字符数组Visual Basic字符串是一个ASCII字符数组加上表示长度的前缀。Java字符串是以0结束的Unicode字符数组。需要定义一种通用的字符串类型,可以很容易的匹配到不同编程语言。在C+中,就是BSTR。BSTR是Basic STRing的简称,微软在COM/OLE中定义的标准字符串数据类型。对于C+,Windows头文件wtypes.h中定义如下:typedef wchar_t WCHAR;typedef WCHAR OLECHAR;typedef OLECHAR _RPC_FAR *BSTR;在COM中,字符用16-bit OLECHAR表示,这样使COM可以支持各种code pages,包括Unicode。对于windows系统,可以简单理解为OLECHAR使用的就是Unicode 。OLECHAR串与单字节字符串很类似,是一个以null结尾的buffer。唯一的区别是每个字符占两个字节,而不是一个 0 1 2 3 4 5 6 7 8 9 0 1| H | E | L | L | O | /0| OLCHAR使用以Null结尾的简单字符串在COM component间传递不太方便。因此,标准BSTR是一个有长度前缀和null结束符的OLECHAR数组。BSTR的前4字节是一个表示字符串长度的前缀。BSTR长度域的值是字符串的字节数,并且不包括0结束符。由于是Unicode串,所以字符数是字节数的一半。这种方式的优点是允许程序员在BSTR串中间嵌入NULL字符。但是,BSTR的前四个字节表示长度,而OLECHAR数组的前四字节表示前两个字符。这种情况下,对于C+程序,如何实现BSTR和OLECHAR的交换?答案是COM提供了两个BSTR分配用的API:SysAllocString / SysReallocString。函数返回的指针指向BSTR的第一个字符,而不是BSTR在内存的第一个字节。 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 50a000000 | H | E | L | L | O | /0| BSTR下面是SysAllocString和SysFreeString的伪代码。 BSTR SimpleSysAllocString( const OLECHAR * sz) if ( sz = NULL) return NULL; BYTE* buf = new BYTEsizeof(INT32) + (wcslen(sz)+1)*sizeof(OLECHAR) ; if(buf = NULL) return NULL; else INT32 len = wcslen(sz) * sizeof(OLECHAR); *(INT32*) buf) = len; wcscpy( (WCHAR*)(buf+sizeof(INT32), sz); return (BSTR)(buf+sizeof(INT32); VOID SimpleSysFreeString( BSTR bstr) if(bstr != NULL) BYTE* start = (BYTE*)bstr - sizeof(INT32); delete start; BSTR只有在你不得不用的时候才应该使用。使用BSTR一般有以下几种情况: COM interface接口定义,并且不希望额外提供custom marshaling库(MDIL生成或开发人员自己订制),必须使用BSTR传递字符串。使用C/C+类型的字符串在COM DLL传递字符串,表面上可以使用,但违背了COM的基本规则,并且给以后的扩展留下了隐患。例如,把一个In-process COM Object(简单说COM DLL)改成out-of-process object(COM EXE)。理论上,客户端的代码应该不做任何改变。但如果是用了C/C+字符串,又希望只使用系统的automation mashaller(Oleaut32.dll),就会出错。 如果可以提供custom marshaling,也推荐使用BSTR。 客户要求接口必须使用BSTR,和客户讨论后,不能修改。 使用的外部库的接口使用BSTR不使用的情况: 不推荐在IDL结构体中定义BSTR成员,会给结构体的复制和释放带来麻烦。最好直接使用限定最大长度的TCHAR数组。如果确实需要传递变长字符串,BSTR应该被定义成独立的参数或者使用独立的get/set接口。 尽可能缩小的BSTR及相关类型的作用域范围。类的成员变量和函数参数不使用BSTR。局部变量要尽快释放类的内部不使用BSTR。代码处理逻辑中只在接口直接相关部分使用BSTR。接收到一个BSTR时,尽量立刻变成C/C+的字符串副本进行处理。在需要传递BSTR参数前产生BSTR,用过立即释放。字符串相关类型的推荐选择顺序优先级类型说明最高stl:string/wstring 功能最完善,可移植性最好。CString 如果编码规范限制使用STL的时候,推荐CString。 VC 6的版本很不完善。.Net有明显改进,需要进一步研究。C/C+ basic type(TCHAR* / char* / LPTSTR / LPCTSTR / TCHAR) 在结构体中,优先使用指定最大长度的字符数组。 效率最好CComBSTR/ _bstr_t 在必须使用BSTR时的优先选择。 在ATL(COM component)工程或者工程中必须使用ATL中,优先选择CComBSTR。一般Exe/dll如果_bstr_t能满足要求,优先使用_bstr_t。 对于VC6,使用_bstr_t一定要慎重,最好只用作简单临时变量保存调被调用函数的传入参数。因为_bstrt_t不能支持一些关键性操作,比如Detach。 对于VC+ .Net推荐使用_bstr_t,它是C+扩展,不需要额外包含ATL的文件。最低BSTR COM接口BSTR的使用规则在对BSTR进行读取操作的时候,可以把BSTR看作OLECHAR数组。BSTR可以用于const wchar_t*(LPCTSTR/ LPCWSTR/ cosnt TCHAR*/ cosnt WCHAR* in Unicode project),不能用于需要wchar_t* (LPTSTR/ LPWSTR/ TCHAR*/ WCHAR* in Unicode project)的地方。 如果有相应的BSTR处理函数,必须使用BSTR处理函数,不要使用普通字符串函数。特别是一个BSTR包含多个字符串(也就是,包含多个0结束符)的情况。在对BSTR进行修改(包括创建和释放时),必须使用BSTR的专用函数。主要要保证对字符长度前缀的正确修改。不要直接读取BSTR的长度域,应该使用BSTR处理函数计算长度。String Manipulation Functions Descriptions SysAllocStringCreates and initializes a string.SysAllocStringByteLenCreates a zero-terminated string of a specified length.SysAllocStringLenCreates a string of a specified length.SysFreeStringFrees a previously created string.SysReAllocStringChanges the size and value of a string.SysReAllocStringLenChanges the size of an existing string.SysStringByteLenReturns the length of a string in bytes.SysStringLenReturns the length of a string.NULL是BSTR的有效值。按照约定,它可以被看作含有0个字符的字符串。BSTR变量必须等于NULL,或者正确分配的BSTR指针。在改变BSTR变量的之前,必须释放原来指向的BSTR。不要把BSTR直接初始化成常量字符指针,例如,BSTR bs = L”。 Automation会cache BSTR使用的空间,以提高SysAllocString/SysFreeString 的性能,会给测试发现问题带来困难。如果可能推荐在调试时使用Compuware DevPartner 7.x及更高版本的工具。多数时候,BSTR是被用于函数参数。关于BSTR参数的使用规则是BSTR类型的基础。只有熟练掌握,才能分析warpper类或转换函数的正确性。 基本原则:在给by-referencein/out参数赋一个新的值前,被调用者负责释放。其他情况,都是调用者负责释放。调用者使用BSTR的规则如下:释放被调用函数返回的BSTR,或者被调用函数通过by-reference返回的BSTR。HRESULT IWebBrowser2:get_StatusText( BSTR FAR* pbstr ); /.BSTR bstrStatus;pBrowser-get_StatusText( &bstrStatus ); / shows using the Win32 function / to freee the memory for the string: :SysFreeString( bstrStatus ); 释放通过by-value方式传给其他函数的BSTR./.hHRESULT IWebBrowser2:put_StatusText( BSTR bstr ); /.cpp/ shows using the Win32 function / to allocate memory for the string: BSTR bstrStatus = :SysAllocString( LSome text );if (bstrStatus = NULL) return E_OUTOFMEMORY; pBrowser-put_StatusText( bstrStatus );/ Free the string:SysFreeString( bstrStatus );/.被调用者按照如下规则处理BSTR:如果一个BSTR参数是by-reference方式,在给参数赋新值之前,Free以前的值。如果没有给参数赋的新值,不要Free传入值。void RefreshBSTR(BSTR& bs)/ bs is an in/out parameter. BSTR* is the same/ using the bs hereDosomething(bs);/ if (bs is about to be updated)ASSERT(bs != NULL);:SysReallocString(bs, _T(“NEW STRING”); / SysReallocString will call SysFreeString and 043185110505 -0/ SysAllocString in sequence/ If bs is only out parameter, SysAllocString / should be called here.不要Free通过by-value传入的BSTR。void SetBSTR(BSTR bs)/ bs is an in parameter. BSTR* is the same/ using the bs hereDosomething(bs);:SysFreeString(bs); /ERROR 不要Free返回给调用者的 BSTR . BSTR GetBSTR1()BSTR bs = :SysAllocString(_T(“test”);:SysFreeString(bs); /ERRORreturn bs; void GetBSTR2(BSTR* pBs)CComBSTR bs(_T(“test”);*pBS = (BSTR) bs; /ERROR: pBS will be freed automatically 如果需要保存传入的BSTR,被调用着需要用SysAllocString()生成一个新的副本,并保存。输入的BSTR会被调用者释放。void MyClass:SetBSTR(BSTR bs)/BSTR m_bs;m_bs = bs; /ERRORm_bs = :SysReAllocString(bs);如果需要返回一个已经存储的BSTR,返回BSTR的一个拷贝。调用者释放返回的BSTR拷贝。void MyClass:GetBSTR(BSTR* pbs)/BSTR m_bs;*pbs = m_bs; /ERROR*pbs = :SysAllocString(m_bs);4.CComBSTR类介绍CComBSTR是ATL提供的BSTR包装类,是VC 6中提供的最完善的BSTR wrapper。就像MFC CString提供了对TCHAR的封装,CComBSTR提供了对BSTR的封装。Table 1 CComBSTR Methods列出了CComBSTR的主要方法。CComBSTR MethodDescriptionCComBSTR多个版本的构造函数用来创建新的BSTR。可以使用的参数包括LPCOLESTR, LPCSTR, CComBSTR。CComBSTR, Empty 释放内部封装的BSTR.Attach, Detach, CopyAttach把一个已经存在BSTR加入类中。Detach把劣种的BSTR剥离,以便在超出作用域的时候,析构函数不会释放BSTR。Detach用于把CComBSTR 赋给out参数。Copy用于产生一个BSTR的副本。一般用于用于把CComBSTR内容赋给out参数。operator BSTR, operator&允许直接操作内部的BSTR。operator BSTR用于把CComBSTR传给BSTR输入in参数。operator&用于把CComBSTR传给BSTR*类型输出out参数。operator=, operator+=, operator重载运算符,用于赋值、字符串连接、简单比较。Append, AppendBSTR字符串连接Length计算字符串长度LoadString利用字符串资源初始化BSTR。ToLower, ToUpper字符串大小写转换。WriteToStream,ReadFromStream 从IStream中读/写BSTR。下面的伪代码展示了CComBSTR的典型用法: HRESULT CMyObject:MyMethod(IOtherObject* pSomething) CComBSTR bstrText(LHello); bstrText += again; / LPCSTR conversion bstrText.ToUpper(); pSomething-Display(bstrText); / in parameter MessageBoxW(0, bstrText, LTest, MB_OK); / Assumes Windows NT简而言之,CComBSTR 没有提供完整的字符串操作。它的主要用途是把LPCTSTR转换成 BSTR,同时提供一个操作BSTR的类,使程序员可以不使用COM SysXXXXString APIs 。如果需要使用复杂的字符串操作,可以使用STL提供的wstring 类。CComBSTR使用的注意事项使用CComBSTR时需要考虑的问题。 CComBSTR初始化CComBSTR 提供了一个长度初始化函数,CComBSTR(int nSize)。所以简单给CComBSTR初始化成NULL会发生意想不到的调用。/ CComBSTR(int nSize) is called。CComBSTR bstr1 = NULL; CComBSTR bstr2(NULL); / CComBSTR(LPCOLESTR pSrc) is called.CComBSTR bstr3 = static_cast(NULL); CComBSTR bstr4(static_cast(NULL); 上面的例子中,bstr1/bstr2被初始化成长度为0的BSTR,也就是说CComBSTR:m_str是有内容的。bstr3/bstr4的值被初始化成NULL,也就是说CComBSTR:m_str = 0。这样,bstr1/bstr2在被赋新的值前需要考虑是否需要释放其中的BSTR。字符集转换尽管某些CComBSTR方法可以自动把ANSI字符串转换成Unicode。所有的接口返回的都是Unicode字符串。如果需要转回 ANSI,可以使用ATL或MFC转换类,或者Windows API。如果使用文字串修改CComBSTR,使用宽字节字符串。可以减少不必要的转换。例如:/ Declare a CComBSTR object. Although the argument is ANSI,/ the constructor converts it into UNICODE.CComBSTR bstrMyString( Hello World );/ Convert the string into an ANSI stringCW2CT szMyString( bstrMyString );/ Display the ANSI stringMessageBox( NULL, szMyString, _T(String Test), MB_OK ); / The following converts the ANSI string to UnicodeCComBSTR bstr(Test);/ The following uses a Unicode string at compile time CComBSTR bstr(LTest);变量作用域(Scope)象所有设计完整的类一样,CComBSTR会在离开作用域的时候释放资源。如果一个函数返回一个指向CComBSTR 的指针,可能会带来问题:指针有可能指向已经被释放的内存。此时应该使用Copy或Detach方法。参考下面的例子。HRESULT CMyObject:MyMethod3(/*out, retval*/ BSTR* pbstr) CComBSTR bstrText(LHello); bstrText += again; *pbstr = bstrText; / No! Call Detach instead!通过复制语句*pbstr = bstrText,被bstrText封装的BSTR的指针作为传出out参数传递。在MyMethod3 return时,bstrText离开作用域,CComBSTR destructor会掉用SysFreeString释放这个BSTR。因此,调用者得到了一个指向已经被释放的内存的指针,可能导致意想不到的结果。因为bstrText即将超出作用域,所以必须使用CComBSTR Copy或 Detach给*pbstr赋值。CComBSTR Copy生成字符串的一格副本,Detach简单的把BSTR移出包装类。这样,在bstrText离开作用域的时候就不会被释放。HRESULT CMyObject:MyMethod4(/*out, retval*/ BSTR* pbstr) CComBSTR bstrText(LHello); bstrText += L again; /*pbstr = bstrText.Copy(); / Better! *pbstr = bstrText.Detach(); / Much better!在这个例子中,从效率考虑,最好使用Detach而不是Copy。Detach 不需要产生一个额外副本的开销。当CComBSTR 必须在复制之后保持自己的内容的时候,例如CComBSTR是一个成员变量,必须使用Copy。显式释放CComBSTR内容程序员可以在CComBSTR 超出作用域范围前显示释放CComBSTR 中的字符串。一旦释放了,CComBSTR 内容就无效了。CComBSTR 提供了operator BSTR,所以代码中可以显示的释放其中的BSTR。HRESULT CMyObject:MyMethod1()CComBSTR bstrText(LThis is a test); :SysFreeString(bstrText);/ The string will be freed a second time/ when the CComBSTR object goes out of scope,/ which is invalid./ CComBSTR:Empty() should be used in order to / explicitly free the BSTR 在这段代码中,bstrText 中的BSTR被释放了。但是,bstrText 仍然没有超出作用域,看起来仍然可以使用。当bstrText 最终超出作用域的时候,SysFreeString 被第二次调用。为了防止这种意外,需要把operator BSTR 从类中删除。但这样没有办法把它用于需要BSTR类型输入in参数的地方,会使CComBSTR 几乎没有任何用处。外部CComBSTR用作out参数把一个已经初始化好的CComBSTR 的地址传给一个函数作为out参数会导致内存泄漏。当把CComBSTR用于BSTR*类型的传出参数out时,必须首先调用Empty方法清空字符串的内容。HRESULT CMyObject:MyMethod2(ISomething* p) CComBSTR bstrText; bstrText = LSome assignment; / BSTR is allocated. bstrText.Empty(); / Must call empty before pSomething-GetText(&bstrText); / using as an out parameter. if(bstrText != LSchaller) bstrText += Hello; / Convert from LPCSTR.在把CComBSTR作为out参数传递前,调用Empty释必须的。因为按照COM标准中的out参数的使用规则-被调用方法不应该在覆盖BSTR的内容前调用SysFreeString。如果你忘记调用Empty,调用前BSTR的内容占用的资源就会泄漏。对于相同的代码,如果参数类型是in, out,就不会有泄漏。因为函数会在复制之前,Free原有的串。用CComBSTR给BSTR变量赋值在下面的代码中,CStringTest 使用CComBSTR 作为成员变量保存BSTR属性。class CStringTestCComBSTR m_bstrText; / IStringTestpublic: STDMETHOD(put_Text)(/*in*/ BSTR newVal) m_bstrText = newVal; return S_OK; STDMETHOD(get_Text)(/*out, retval*/ BSTR *pVal) *pVal = m_bstrText; / Oops! Call m_bstrText.Copy / instead. return S_OK; ;由于m_bstrText 在get_Text结束没有超出作用域,你可能认为在the *pVal = m_bstrText 赋值时,不需要调用Copy。这是不对的。按照COM规则,调用者负责释放传出out参数的内容。由于*pVal指向了m_bstrText 封装的BSTR,而不是一个副本,调用者和m_bstrText 析构函数都会企图删除字符串。 循环中使用CComBSTR Objects尽管CComBSTR可以分配buffer完成一些操作,例如: += operator或Append。但是,不推荐在一个小循环内部使用CComBSTR完成字符串操作。这种情况下,CString能提供更好的性能。/ This is not an efficient way/ to use a CComBSTR object.CComBSTR bstrMyString;while (bstrMyString.Length()1000) bstrMyString.Append(L*);5._bstr_t Class_bstr_t 是微软C+ COM扩展的一部分。_bstr_t封装了BSTR数据类型。_bstr_t通过SysAllocString and SysFreeString 等BSTR APIs管理资源的分配和释放。_bstr_t提供了内部引用计数来减少额外负担。ConstructionVersion_bstr_tConstructs a _bstr_t object.OperationsAssignCopies a BSTR into the BSTR wrapped by a _bstr_t.AttachVC 7Links a _bstr_t wrapper to a BSTR.copyConstructs a copy of the encapsulated BSTR.DetachVC 7Returns the BSTR wrapped by a _bstr_t and detaches the BSTR from the _bstr_t.GetAddressVC 7Points to the BSTR wrapped by a _bstr_t.GetBSTRVC 7Points to the beginning of the BSTR wrapped by the _bstr_t.lengthReturns the number of characters in the _bstr_t.Operatorsoperator =Assigns a new value to an existing _bstr_t object.operator +=Appends characters to the end of the _bstr_t object.operator +Concatenates two strings.operator !Checks if the encapsulated BSTR is a NULL string.operator =, !=, , =Compares two _bstr_t objects.operator wchar_t* | char*Extract the pointers to the encapsulated Unicode or multibyte BSTR object.VC6中_bstr_t缺少了几个重要的方法:Attach/Detach/GetAddress/GetBSTR,所以比CComBSTR简单,使得_bstr_t的应用场合非常有限。而且,_bstr_t使用了引用计数在不同的对象间共享BSTR,内部实现比CComBSTR复杂。使用注意事项可以参考CComBSTR的类似函数。建议只用于下面的情况:BSTR的作用域管理解决BSTR变量超出作用域范围的自动回收。(1)构造简单的BSTR对象,对BSTR进行基本字符串操作,作为输入in参数传递给被调用者。_bstr_t bs1(Lfirst );bs1 += Lsecond ;SetBs(bs1); / void SetBs(BSTR bs) (2)作为BSTR的wrapper,解决out参数BSTR的生命周期之后的回收问题。HRESULT BetterMethod() BSTR val = NULL; GetBs(&val); /void GetBs(/* out */ BSTR*) _bstr_t bsVal(val, false); / false is IMPORTANT. Other constructor could / store the BSTR, too. But you must free the / BSTR later. HRESULT GoodMethod() BSTR val = NULL; GetBs(&val); /void GetBs(/* out */ BSTR*) / All the function create a copy of BSTR./ But you must free the BSTR immediately. _bstr_t bsVal2(val); _bstr_t bsVal3; bsVal3 = val; SysFreeString(val);使用范围完成简单的BSTR字符串连接、比较等操作。常用字符串件的类型转换。FromToSample字符串常量BSTRRight:BSTR bs = :SysAllocString(_T(Test string);:SysFreeString();Wrong:BSTR bs = _T(Test string); /ERRORLPWSTR /LPCWSTR /WCHAR* / wchar_tBSTRRight:LPCTSTR sz1 = _T(Test String);BSTR bs = :SysAllocString(sz1);:SysFreeString();Wrong:LPTSTR sz1 = _T(Test String);BSTR bs = sz1; /ERRORBSTRLPCWSTR /const WCHAR * /const wchar_t *Right:BSTR bs = .; /.LPCTSTR sz = static_castbs;.:SysFreeString(bs); /Never use sz after this lineWrong:BSTR bs = .; /. LPCTSTR sz = bs;.:SysFreeString(bs); /Never use sz after this line_tcslen(sz); /ERRORBSTRLPWSTR /WCHAR* /wchar_t*Right:BSTR bs = .; /.UINT len = :SysStringLen(bs);/ Do not modify the BSTR content by / C/C+ string functionsLPTSTR sz = new TCHARlen+1;_tcsncpy(sz, bs, len); :SysFreeString(bs);delete sz;Wrong:BSTR bs = .; /./ Do not modify the BSTR content by / C/C+ string functi

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论