|
马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有帐号?立即注册
x
C#是不行的,比如说美国的航天飞船里就有java开发的程序以上是我的愚见,其实不管那种语言,你学好了,都能找到好的工作,1、媒介
上回书先容了GUID、CLSID、IID和接口的观点。本回的重点是先容COM中的数据范例。咋还不先容组件程序的计划步骤呀?咳......别发急,别发急!孔子曰:“饭要一口一口地吃”;老子语:“心急吃不了热豆腐”,孙子云:“走一步看一步吧”......先把握需要的常识,未来写出发序来才会轻车熟路也:-)
走进正题之前,请人人紧紧记着一条准绳:COM组件是运转在散布式情况中的。好比,你写了一个组件程序(DLL或EXE),那末利用者多是在本机的某个历程内加载组件(INPROC_SERVER);也多是从另外一个历程中挪用组件的历程(LOCAL_SERVER);也多是在这台盘算机上挪用地球何处盘算机上的组件(REMOTE_SERVER)。以是在了解和计划的时分,要每时每刻想起这句话。快!拿出小本本,记上去!
2、HRESULT函数前往值
每一个人在做程序计划的时分,都有他们各自的哲学头脑。拿函数前往值来讲,就有很多多少种情势。
函数前往值前往值信息doublesin(double)浮点数值
盘算正玄值BOOLDeleteFile(LPCTSTR)布尔值
文件删除是不是乐成。如失利,必要GetLastError()才干获得失利缘故原由void*malloc(size_t)内存指针
内存请求,假如失利,前往空指针NULLLONGRegDeleteKey(HKEY,LPCTSTR)整数
删除注册表项。0暗示乐成,非0失利,同时这个值就反应了失利的缘故原由UINTDragQueryFile(HDROP,UINT,LPTSTR,UINT)整数
获得拖放文件信息。以分歧的参数挪用,则前往分歧的寄义:
一会儿暗示文件个数,一会儿暗示文件名长度,一会儿暗示字符长度...............
............
云云纷纷庞大的前往值,云云寄义多变的前往值,使得人人在进修和利用的过程当中,增添了分外的坚苦。好了,COM的计划标准终究对他们举行了一致。组件API及接口指针中,除IUnknown::AddRef()和IUnknown::Release()两个函数外,别的一切的函数,都以HRESULT作为前往值。人人设想一个组件的接口函数好比叫Add(),完成2个整数的加法运算,在C言语中,我们能够以下界说:- longAdd(longn1,longn2){returnn1+n2;}
复制代码 还记得方才我们说的准绳吗?COM组件是运转在散布式情况中的。也就是说,这个函数大概运转在“地球另外一边”的盘算机上,既然运转在那末悠远的中央,就有大概呈现服务器关机、收集失落线、运转超时、对方不在服务区......等非常。因而,这个加法函数,除必要前往运算了局之外,还应当前往一个值------函数是不是被一般实行了。- HRESULTAdd(longn1,longn2,long*pSum){*pSum=n1+n2;returnS_OK;}
复制代码 假如函数一般实行,则前往S_OK,同时真实的函数运转了局则经由过程参数指针前往。假如碰到了非常情形,则COM体系经由判别,会前往响应的毛病值。罕见的前往值有:
HRESULT值寄义S_OK0x00000000乐成S_FALSE0x00000001函数乐成实行完成,但前往时呈现毛病E_INVALIDARG0x80070057参数有毛病E_OUTOFMEMORY0x8007000E内存请求毛病E_UNEXPECTED0x8000FFFF未知的非常E_NOTIMPL0x80004001未完成功效E_FAIL0x80004005没有具体申明的毛病。一样平常必要获得RichError毛病信息(注1)E_POINTER0x80004003有效的指针E_HANDLE0x80070006有效的句柄E_ABORT0x80004004停止操纵E_ACCESSDENIED0x80070005会见被回绝E_NOINTERFACE0x80004002不撑持接口
<br>
、HRESULT的布局
HRESULT实际上是一个双字节的值,其最高位(bit)假如是0暗示乐成,1暗示毛病。详细拜见MSDN之"StructureofCOMErrorCodes"申明。我们在程序中假如必要判别前往值,则可使用对照运算标记;switch开关语句;也能够利用VC供应的宏:- HRESULThr=挪用组件函数;if(SUCCEEDED(hr)){...}//假如乐成......if(FAILED(hr)){...}//假如失利......
复制代码 3、UNICODE
盘算机创造后,为了在盘算机中暗示字符,人们制订了一种编码,叫ASCII码。ASCII码由一个字节中的7位(bit)暗示,局限是0x00-0x7F共128个字符。他们觉得这128个数字就充足暗示abcd....ABCD....1234这些字符了。
咳......说英语的人就是“笨”!厥后他们俄然发明,假如必要依照表格体例打印这些字符的时分,短少了“制表符”。因而又扩大了ASCII的界说,利用一个字节的全体8位(bit)来暗示字符了,这就叫扩大ASCII码。局限是0x00-0xFF共256个字符。
咳......说中文的人就是伶俐!中国人使用一连2个扩大ASCII码的扩大地区(0xA0今后)来暗示一个汉字,该办法的尺度叫GB-2312。厥后,日文、韩文、阿拉伯文、台湾繁体(BIG-5)......都利用相似的办法扩大了当地字符集的界说,如今一致称为MBCS字符集(多字节字符集)。这个办法是出缺陷的,由于各个国度区域界说的字符集有交集,因而利用GB-2312的软件,就不克不及在BIG-5的情况下运转(显现乱码),反之亦然。
咳......说英语的人终究变“伶俐”一些了。为了把全球国民一切的一切的笔墨标记都一致举行编码,因而制订了UNICODE尺度字符集。UNICODE利用2个字节暗示一个字符(unsignedshorint、WCHAR、_wchar_t、OLECHAR)。这下终究好啦,全球任何一个区域的软件,能够不必修正地就可以在另外一个区域运转了。固然我用IE扫瞄日本网站,显现出我不熟悉的日文笔墨,但最少不会是乱码了。UNICODE的局限是0x0000-0xFFFF共6万多个字符,个中光汉字就占用了4万多个。嘿嘿,中国人赚年夜发了:0)
在程序中利用各类字符集的办法:- constchar*p="Hello";//利用ASCII字符集constchar*p="你好";//利用MBCS字符集,因为MBCS完整兼容ASCII,多半情形下,我们其实不严厉辨别他们LPCSTRp="Hello,你好";//意义同上constWCHAR*p=L"Hello,你好";//利用UNICODE字符集LPCOLESTRp=L"Hello,你好";//意义同上//假如预界说了_UNICODE,则暗示利用UNICODE字符集;假如界说了_MBCS,则暗示利用MBCSconstTCHAR*p=_T("Hello,你好");LPCTSTRp=_T("Hello,你好");//意义同上
复制代码 在下面的例子中,T长短常成心思的一个标记(TCHAR、LPCTSTR、LPTSTR、_T()、_TEXT()...),它暗示利用一种两头范例,既不明白暗示利用MBCS,也不明白暗示利用UNICODE。那究竟利用哪一种字符集那?嘿嘿......编译的时分决意吧。设置前提编译的体例是:VC6中,"ProjectSettings...C/C++卡片Preprocessordefinitions"中增加或修正_MBCS、_UNICODE;VC.NET中,"项目属性设置属性惯例字符集"然后用组合窗举行选择。利用T范例,长短常好的习气,严峻保举!
4、BSTR
COM中除利用一些复杂尺度的数据范例外(注2),字符串范例必要出格重点地申明一下。还记得准绳吗?COM组件是运转在散布式情况中的。普通地说,你不克不及间接把一个内存指针间接作为参数传送给COM函数。你想一想,体系必要把这块内存的内容传送到“地球另外一边”的盘算机上,因而,我最少必要晓得你这块内存的尺寸吧?否则让我怎样传送呀?传送几字节呀?!而字符串又长短经常用的一品种型,因而COM计划者引进了BASIC中字符串范例的暗示体例---BSTR。BSTR实际上是一个指针范例,它的内存布局是:(输出程序片断BSTRp=::SysAllocString(L"Hello,你好");断点实行,然后察看p的内存)
<br>
、BSTR内存布局
BSTR是一个指向UNICODE字符串的指针,且BSTR向前的4个字节中,利用DWORD保留着这个字符串的字节长度(没有含字符串的停止符)。因而体系就可以够准确处置并传送这个字符串到“地球另外一边”了。出格必要注重的是,因为BSTR的指针就是指向UNICODE串,因而BSTR和LPOLESTR能够在必定水平上混用,但必定要注重:
有函数fun(LPCOLESTRlp),则你挪用BSTRp=...;fun(p);准确
有函数fun(constBSTRbstr),则你挪用LPCOLESTRp=...;fun(p);毛病!!!
有关BSTR的处置函数:
API函数申明SysAllocString()请求一个BSTR指针,并初始化为一个字符串SysFreeString()开释BSTR内存SysAllocStringLen()请求一个指定字符长度的BSTR指针,并初始化为一个字符串SysAllocStringByteLen()请求一个指定字节长度的BSTR指针,并初始化为一个字符串SysReAllocStringLen()从头请求BSTR指针CString函数
申明
AllocSysString()从CString失掉BSTRSetSysString()从头请求BSTR指针,并复制到CString中CComBSTR函数
ATL的BSTR包装类。在atlbase.h中界说
Append()、AppendBSTR()、AppendBytes()、ArrayToBSTR()、BSTRToArray()、AssignBSTR()、Attach()、Detach()、Copy()、CopyTo()、Empty()、Length()、ByteLength()、ReadFromStream()、WriteToStream()、LoadString()、ToLower()、ToUpper()
运算符重载:!,!=,==,<,>,&,+=,+,=,BSTR太多了,但从函数称号不克不及看出其基础功效。具体材料,检察MSDN吧。别的,左边函数,有良多是ATL7.0供应的,VC6.0下所带的ATL3.0不撑持。
因为我们未来次要用ATL开辟组件程序,因而利用ATL的CComBSTR为主。VC也供应了别的的包装类_bstr_t。
5、各类字符串范例之间的转换
1、函数WideCharToMultiByte(),转换UNICODE到MBCS。利用典范:- LPCOLESTRlpw=L"Hello,你好";size_twLen=wcslen(lpw)+1;//宽字符字符长度,+1暗示包括字符串停止符intaLen=WideCharToMultiByte(//第一次挪用,盘算所需MBCS字符串字节长度CP_ACP,0,lpw,//宽字符串指针wLen,//字符长度NULL,0,//参数0暗示盘算转换后的字符空间NULL,NULL);LPSTRlpa=newchar[aLen];WideCharToMultiByte(CP_ACP,0,lpw,wLen,lpa,//转换后的字符串指针aLen,//给出空间巨细NULL,NULL);//此时,lpa中保留着转换后的MBCS字符串............delete[]lpa;
复制代码 2、函数MultiByteToWideChar(),转换MBCS到UNICODE。利用典范:- LPCSTRlpa="Hello,你好";size_taLen=strlen(lpa)+1;intwLen=MultiByteToWideChar(CP_ACP,0,lpa,aLen,NULL,0);LPOLESTRlpw=newWCHAR[wLen];MultiByteToWideChar(CP_ACP,0,lpa,aLen,lpw,wLen);............delete[]lpw;
复制代码 3、利用ATL供应的转换宏。
A2BSTROLE2AT2AW2AA2COLEOLE2BSTRT2BSTRW2BSTRA2CTOLE2CAT2CAW2CAA2CWOLE2CTT2COLEW2COLEA2OLEOLE2CWT2CWW2CTA2TOLE2TT2OLEW2OLEA2WOLE2WT2WW2T
上表中的宏函数,实在十分简单影象:2好弄笑的缩写,to的发音和2一样,以是借用来暗示“转换为、转换到”的寄义。AANSI字符串,也就是MBCS。W、OLE宽字符串,也就是UNICODE。T两头范例T。假如界说了_UNICODE,则T暗示W;假如界说了_MBCS,则T暗示ACconst的缩写利用典范:- #include<atlconv.h>voidfun(){USES_CONVERSION;//只必要挪用一次,就能够在函数中举行屡次转换LPCTSTRlp=OLE2CT(L"Hello,你好"));............//不必显式开释lp的内存,由于//因为ATL转换宏利用栈作为一时空间,函数停止后会主动开释栈空间。}
复制代码 利用ATL转换宏,因为不必开释一时空间,以是利用起来十分便利。可是思索到栈空间的尺寸(VC默许2M),利用时要注重几点:
1、只合适于举行短字符串的转换;
2、不要试图在一个次数对照多的轮回体内举行转换;
3、不要试图对字符型文件内容举行转换,由于文件尺寸一样平常情形下是对照年夜的;
4、对情形2和3,要利用MultiByteToWideChar()和WideCharToMultiByte();
6、VARIANT
C++、BASIC、Java、Pascal、Script......盘算机言语多种多样,而它们各自又都有本人的数据范例,COM发生目标,个中之一就是要跨言语(注3)。而VARIANT数据范例就具有跨言语的特征,同时它能够暗示(存储)恣意范例的数据。从C言语的角度来说,VARIANT实际上是一个布局,布局顶用一个域(vt)暗示------该变量究竟暗示的是甚么范例数据,同时真实的数据则存贮在union空间中。布局的界说太长了(固然长,但实在很复杂)人人往看MSDN的形貌吧,这里给出怎样利用的复杂示例:
先生:我想用VARIANT暗示一个4字节长的整数,怎样做?
先生:VARIANTv;v.vt=VT_I4;v.lVal=100;
先生:我想用VARIANT暗示布尔值“真”,怎样做?
先生:VARIANTv;v.vt=VT_BOOL;v.boolVal=VARIANT_TRUE;
先生:这么贫苦?我能不克不及v.boolVal=true;如许写?
先生:不成以!由于
范例字节长度假值真值bool1(char)0(false)1(true)BOOL4(int)0(FALSE)1(TRUE)VT_BOOL2(shortint)0(VARIANT_FALSE)-1(VARIANT_TRUE) 以是假如你v.boolVal=true如许赋值,那末未来if(VARIANT_TRUE==v.boolVal)的时分会出成绩(-1!=1)。可是你注重察看,任何布尔范例的“假”都是0,因而作为一个好习气,在做布尔判别的时分,不要和“真值”比拟较,而要与“假值”做对照。
先生:感谢先生,你太牛了。我对先生的仰慕如滚滚江水,绵延不停......
先生:我想用VARIANT保留字符串,怎样做?
先生:VARIANTv;v.vt=VT_BSTR;v.bstrVal=SysAllocString(L"Hello,你好");
先生:哦......我分明了。但是这么操纵真够贫苦的,有无复杂一些的办法?
先生:有呀,你可使用现成的包装类CComVariant、COleVariant、_variant_t。好比下面三个成绩就能够如许誊写:CComVariantv1(100),v2(true),v3("Hello,你好");复杂了吧?!(注4)
先生:先生,我再问最初一个成绩,我怎样用VARIANT保留一个数组?
先生:这个成绩很庞大,我如今不克不及告知你,我如今告知你怕你印象不深......(注5)
先生:~!@#$%^&*()......晕!
7、小结
以上所先容的内容,是基础功,必需纯熟把握。先到这里吧,歇息一会儿......更多出色内容,敬请存眷《COM组件计划与使用(四)》
[code][/code]
注1:在后续的ISupportErrorInfo接口中先容。
注2:罕见的数据范例,请参考IDL文件的申明。(别发急,还没写那......嘿嘿)
注3:跨言语就是各类言语中都能利用COM组件。但啥时分能跨平台呢?
注4:CComVariant/COlevariant/_variant_t请参看MSDN。
注5:关于平安数组SafeArray的利用,在后续的文章中会商。
原文链接:http://www.vckbase.com/document/viewdoc/?id=1488
还得说上一点,就java本质而言,是面相对象的,但是你有没有发现,java也不全是,比如说基本类型,int,那他就是整型而不是对象,转换类型是还得借助包装类。 |
|