VB 字节数组和字符串的转换问题 (StringByte)
VB 字節(jié)數(shù)組和字符串的轉(zhuǎn)換問題 (String<>Byte)
Posted by JiaJia 16 March,2009 (2)Comment一、 前言
數(shù)據(jù)類型轉(zhuǎn)換在編程中經(jīng)常用到,VB6提供了一整套類型轉(zhuǎn)換的函數(shù)。但是,在進(jìn)行類型轉(zhuǎn)換時(shí),有時(shí)候僅僅依靠VB提供的函數(shù)是不能達(dá)到自己的目的的。因此,需要考慮用其他的方法來完成數(shù)據(jù)類型轉(zhuǎn)換。本文僅談VB6中字節(jié)數(shù)組和字符串的相互轉(zhuǎn)換過程中應(yīng)注意的問題及其解決辦法。
在Visual Basic中使用Byte數(shù)組主要是為了32位API函數(shù)的參數(shù)傳遞和函數(shù)的返回。在32位的Visual Basic版本中,字符串被假定為Unicode字符,其中每個(gè)字符占用兩個(gè)字節(jié)。系統(tǒng)自動(dòng)地將Unicode的兩個(gè)連續(xù)字節(jié)轉(zhuǎn)換成1個(gè)字節(jié)的ANSI字符。但是,如果該字符串包含二進(jìn)制數(shù)據(jù),其內(nèi)容將變得很難理解。例如,一個(gè)漢字是兩個(gè)字節(jié),在Visual Basic 6.0中的長度就只是1,這將給我們計(jì)算單個(gè)漢字的國標(biāo)碼帶來一些麻煩。有了Byte數(shù)組,這些問題就將迎刃而解。
另外,Visual Basic中的字符串和C語言中的字符串有一些不同,本文將給出一個(gè)函數(shù),把C字符串轉(zhuǎn)換成Visual Basic字符串。
二、 用Byte數(shù)組代替字符串
Byte數(shù)組包含的是0-255之間的ASCII碼字符,它不會(huì)象字符串那樣被系統(tǒng)作預(yù)處理。你可以在很多API函數(shù)中用來Byte數(shù)組代替字符串。
例如,下面的代碼中用GetSystemDirectory這個(gè)Windows API函數(shù)來取得Windows的系統(tǒng)路徑。一共有兩段代碼,一段代碼是傳遞一個(gè)字符串來存儲(chǔ)函數(shù)返回的系統(tǒng)路徑,另一段代碼是傳遞一個(gè)Byte數(shù)組來代替字符串。
為了更好地比較,兩段代碼的不同部分都用黑體標(biāo)出。讀者可以仔細(xì)比較這兩段代碼的差異,這樣您會(huì)更深入地理解Byte數(shù)組和字符串的差別。
把這兩段代碼的任何一段放入一個(gè)窗體中運(yùn)行,但擊窗體的空白區(qū)域,你將會(huì)在窗體中看到Windows的系統(tǒng)路徑。
下面是使用字符串的代碼:
Private Sub Form_Click()
Dim n As Integer
Dim str As String
str = Space$(256)
n = GetSystemDirectory(str, 256)
str = Left$(str, n)
Print str
End Sub
在上面這段代碼中,字符串參數(shù)lpBuffer返回Windows的系統(tǒng)路徑。在函數(shù)調(diào)用之前,將變量預(yù)定義成256個(gè)字符,并在函數(shù)返回時(shí)清除多余的字符。
注意:
在調(diào)用API函數(shù)之前,通常都需要預(yù)先定義一個(gè)字符串或者Byte數(shù)組以供API函數(shù)存儲(chǔ)數(shù)據(jù)。應(yīng)該養(yǎng)成這種良好的編程習(xí)慣。否則,你的程序有可能崩潰,甚至導(dǎo)致你的系統(tǒng)崩潰。
下面是使用Byte數(shù)組的代碼:
Private Sub Form_Click()
Dim n As Integer
Dim Buffer() As Byte
Dim strA as String
Buffer=Space$(256)
n = GetSystemDirectory(Buffer(0), 256)
strA=StrConv(Buffer,vbUnicode)
strA = Left$(strA, n)
Print strA
End Sub
不知道讀者注意到?jīng)]有,第二段代碼中的GetSystemDirectory API函數(shù)的聲明已經(jīng)改變了。第一個(gè)參數(shù)的聲明由一個(gè)ByVal字符串變成了一個(gè)ByRef的Byte數(shù)組,即由聲明: ByVal lpBuffer As String 變成了 ByRef lpBuffer As Byte
傳遞字符串時(shí),需要一個(gè)ByVal修飾符來把字符串緩沖區(qū)傳遞到API函數(shù)中,因?yàn)樽址兞繉?shí)際上指示了字符串內(nèi)容所在的內(nèi)存地址。在C語言術(shù)語中,這代表了一個(gè)指向指針的指針。ByVal意味著被傳遞的是一個(gè)指向?qū)嶋H字符串內(nèi)容的內(nèi)存地址。而在傳遞Byte數(shù)組Buffer(0)時(shí),使用ByRef修飾符來傳遞變量,它相當(dāng)于傳遞了數(shù)組中第一個(gè)字節(jié)內(nèi)容的地址。事實(shí)上,這兩種結(jié)果是一樣的。
strA=StrConv(Buffer,vbUnicode)
這行代碼把Byte數(shù)組的二進(jìn)制數(shù)據(jù)轉(zhuǎn)換成一個(gè)合法的Visual Basic字符串。
三、 Byte數(shù)組和字符串之間的賦值
為了簡(jiǎn)化Byte數(shù)組和字符串之間的數(shù)據(jù)傳遞,允許你在任何動(dòng)態(tài)Byte數(shù)組和任何字符串之間直接互相賦值。例如:
Buffer=strA 和 StrA=Buffer
注意:
當(dāng)且僅當(dāng)Byte數(shù)組是動(dòng)態(tài)的,而不是固定大小時(shí),你才可以把一個(gè)字符串直接賦給一個(gè)Byte數(shù)組。
聲明一個(gè)動(dòng)態(tài)的Byte數(shù)組最簡(jiǎn)單的方法是在Dim語句中使用空參數(shù),例如: Dim Buffer() as Byte
當(dāng)你把一個(gè)字符串賦給一個(gè)動(dòng)態(tài)Byte數(shù)組時(shí),數(shù)組中的字符數(shù)將是字符串的字符數(shù)目的兩倍。這是因?yàn)閂isual Basic中字符串使用Unicode,并且每個(gè)Unicode字符的實(shí)際大小是兩個(gè)字節(jié)。當(dāng)把一個(gè)ASCII字符轉(zhuǎn)換成一個(gè)Byte數(shù)組時(shí),數(shù)組中的另一個(gè)字節(jié)將是0。
向Unicode的轉(zhuǎn)換是將每個(gè)在緩沖區(qū)中的字符轉(zhuǎn)換成2個(gè)字節(jié),從而實(shí)際上加倍了存儲(chǔ)在結(jié)果字符串的中字節(jié)數(shù)目,當(dāng)你認(rèn)為函數(shù)Len(strA)得到的尺寸大小和Unicode轉(zhuǎn)換后的Ubound(Buffer)函數(shù)所返回的尺寸大小相同時(shí),上述特點(diǎn)就不很明顯了。但是,函數(shù)LenB(strA)確實(shí)返回一個(gè)2倍于Len(strA)返回值的數(shù)值。這是因?yàn)長en函數(shù)返回的是字符串中字符的數(shù)目,而LenB函數(shù)返回的是字符串中字節(jié)的數(shù)目。一個(gè)Unicode串的字符長度僅僅是該串中實(shí)際字節(jié)數(shù)目的一半,這是因?yàn)槊總€(gè)Unicode字符2個(gè)字節(jié)。
四、 字符串轉(zhuǎn)換成VB字符串
當(dāng)我們?cè)赩B中調(diào)用Win32 API函數(shù)時(shí),如果函數(shù)的返回值是一個(gè)字符串,那一般有如下三種情況:
1. 函數(shù)預(yù)先要求你提供一個(gè)有固定空間的字符串,以供存儲(chǔ)函數(shù)的返回值。
2. 函數(shù)的返回是一個(gè)以Null結(jié)尾的C字符串,而不是正規(guī)的VB字符串。
3. Win32 API函數(shù)有時(shí)候會(huì)返回另一種類型的字符串。這種類型的字符串在單個(gè)緩沖區(qū)內(nèi)保存了多個(gè)字符串值,每個(gè)值之間用Null隔開,結(jié)尾的是兩個(gè)Null,一個(gè)Null是最后一個(gè)字符串值的結(jié)尾符,另一個(gè)Null是整個(gè)字符串的結(jié)尾符。這其實(shí)就是我們通常在C中遇到的字符串?dāng)?shù)組。
第一種情況很好辦,只無原則預(yù)先定義好一個(gè)空間足夠大的字符串,然后把API函數(shù)的返回值賦于這個(gè)字符串就可以了。例如,如果你已經(jīng)知道函數(shù)返回值最多不會(huì)走過256個(gè)字符,可以這樣編碼如下:
SAPIReturn=Space$(256)
SAPIReturn=API_Function(…)
對(duì)于第二和第三種情況,就必須把返回的C字符串成標(biāo)準(zhǔn)的VB字符串。下面這個(gè)函數(shù)CStringToVBString把一個(gè)以Null結(jié)尾的C字符串成VB字符串。
'參數(shù)psCString是一個(gè)待轉(zhuǎn)換的C字符串
'函數(shù)返回Null左邊所有的字符
dim sReturn as string
dim iNullCharPos As Integer
iNullCharPos=InStr(psCString,vbNullChar)
if iNullCharPos >0 then
sReturn =left(psCString, iNullCharPos -1)
else
sReturn =pscstring
end if
CStringToVBString=sReturn
End function
下面這個(gè)過程把一個(gè)含有多個(gè)C字符串的緩沖區(qū)轉(zhuǎn)換成一個(gè)字符串?dāng)?shù)組。
'參數(shù)psMultiCString是待轉(zhuǎn)換的多個(gè)C字符串
'參數(shù)psaStrings是返回的VB字符串?dāng)?shù)組,調(diào)用之前它必須是一個(gè)動(dòng)態(tài)的空數(shù)組
Dim iNullPos As Integer
Dim iPrevPos As Integer
Dim iIdx As Integer
'初始化字符串?dāng)?shù)組
iIdx = 0
ReDim psaStrings(0 To iIdx 1)
psaStrings(iIdx 1) = ""
Do
iNullPos = InStr(iPrevPos 1, psMultiCString, vbNullChar)
If iNullPos > iPrevPos 1 Then
'把找到的C字符串賦值給字符串?dāng)?shù)組
psaStrings(iIdx) = Mid$(psMultiCString, (iPrevPos 1), ((iNullPos - 1) - iPrevPos))
iIdx = iIdx 1
ReDim Preserve psaStrings(0 To iIdx)
iPrevPos = iNullPos
Else
'找到了兩個(gè)Null字符,去掉最后一個(gè),然后退出
ReDim Preserve psaStrings(0 To iIdx - 1)
Exit Do
End If
Loop
End Sub
當(dāng)調(diào)用Win32 API函數(shù)時(shí),使用這兩個(gè)簡(jiǎn)單的函數(shù),你可以消除很多冗余的代碼,加快開發(fā)步伐。
注意:
當(dāng)你為API的返回值預(yù)先分配字符串的空間時(shí),一定不要忘了空間內(nèi)必須包含Null結(jié)束符。另外,建議你在使用API時(shí),最好對(duì)每個(gè)變量都進(jìn)行聲明,加上下面這句代碼: Option Explicit
五、小結(jié)
VB6中字節(jié)數(shù)組和字符串的相互轉(zhuǎn)換是編程中,尤其是新手使用中最為頭疼的問題。本文歸納了軟件開發(fā)過程中使用二者的典型情況及其應(yīng)該注意的問題,供參考。不當(dāng)之處還請(qǐng)讀者批評(píng)指正。
總結(jié)
以上是生活随笔為你收集整理的VB 字节数组和字符串的转换问题 (StringByte)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Visual C++下对匿名管道的编程实
- 下一篇: 进程保护 (非Hook;非DKOM)