一、前言 數據類型轉換在編程中經常用到,VB6提供了一整套類型轉換的函數。但是,在進行類型轉換時,有時候僅僅依靠VB提供的函數是不能達到自己的目的的。因此,需要考慮用其他的方法來完成數據類型轉換。本文僅談VB6中字節數組和字符串的相互轉換過程中應注意的問題及其解決辦法。
在VisualBasic中使用Byte數組主要是為了32位API函數的參數傳遞和函數的返回。在32位的VisualBasic版本中,字符串被假定為Unicode字符,其中每個字符占用兩個字節。系統自動地將Unicode的兩個連續字節轉換成1個字節的ANSI字符。但是,如果該字符串包含二進制數據,其內容將變得很難理解。例如,一個漢字是兩個字節,在VisualBasic6.0中的長度就只是1,這將給我們計算單個漢字的國標碼帶來一些麻煩。有了Byte數組,這些問題就將迎刃而解。
另外,VisualBasic中的字符串和C語言中的字符串有一些不同,本文將給出一個函數,把C字符串轉換成VisualBasic字符串。
二、用Byte數組代替字符串 Byte數組包含的是0-255之間的ASCII碼字符,它不會象字符串那樣被系統作預處理。你可以在很多API函數中用來Byte數組代替字符串。
例如,下面的代碼中用GetSystemDirectory這個WindowsAPI函數來取得Windows的系統路徑。一共有兩段代碼,一段代碼是傳遞一個字符串來存儲函數返回的系統路徑,另一段代碼是傳遞一個Byte數組來代替字符串。
為了更好地比較,兩段代碼的不同部分都用黑體標出。讀者可以仔細比較這兩段代碼的差異,這樣您會更深入地理解Byte數組和字符串的差別。
把這兩段代碼的任何一段放入一個窗體中運行,但擊窗體的空白區域,你將會在窗體中看到Windows的系統路徑。
下面是使用字符串的代碼:
->PrivateDeclareFunctionGetSystemDirectoryLib"kernel32"Alias_
"GetSystemDirectoryA"(ByVallpBufferAsString,ByValnSizeAsLong)AsLong
PrivateSubForm_Click()
DimnAsInteger
DimstrAsString
str=Space$(256)
n=GetSystemDirectory(str,256)
str=Left$(str,n)
Printstr
EndSub->
在上面這段代碼中,字符串參數lpBuffer返回Windows的系統路徑。在函數調用之前,將變量預定義成256個字符,並在函數返回時清除多余的字符。
注意:
在調用API函數之前,通常都需要預先定義一個字符串或者Byte數組以供API函數存儲數據。應該養成這種良好的編程習慣。否則,你的程序有可能崩潰,甚至導致你的系統崩潰。
下面是使用Byte數組的代碼:
->PrivateDeclareFunctionGetSystemDirectoryLib"kernel32"Alias_
"GetSystemDirectoryA"(ByReflpBufferAsByte,ByValnSizeAsLong)AsLong
PrivateSubForm_Click()
DimnAsInteger
DimBuffer()AsByte
DimstrAasString
Buffer=Space$(256)
n=GetSystemDirectory(Buffer(0),256)
strA=StrConv(Buffer,vbUnicode)
strA=Left$(strA,n)
PrintstrA
EndSub->
不知道讀者注意到沒有,第二段代碼中的GetSystemDirectoryAPI函數的聲明已經改變了。第一個參數的聲明由一個ByVal字符串變成了一個ByRef的Byte數組,即由聲明:
->ByVallpBufferAsString->
變成了:
->ByReflpBufferAsByte->
傳遞字符串時,需要一個ByVal修飾符來把字符串緩沖區傳遞到API函數中,因為字符串變量實際上指示了字符串內容所在的內存地址。在C語言術語中,這代表了一個指向指針的指針。ByVal意味著被傳遞的是一個指向實際字符串內容的內存地址。而在傳遞Byte數組Buffer(0)時,使用ByRef修飾符來傳遞變量,它相當於傳遞了數組中第一個字節內容的地址。事實上,這兩種結果是一樣的。
->strA=StrConv(Buffer,vbUnicode)->
這行代碼把Byte數組的二進制數據轉換成一個合法的VisualBasic字符串。
三、Byte數組和字符串之間的賦值 為了簡化Byte數組和字符串之間的數據傳遞,允許你在任何動態Byte數組和任何字符串之間直接互相賦值。例如:
->Buffer=strA
StrA=Buffer->
注意:
當且僅當Byte數組是動態的,而不是固定大小時,你才可以把一個字符串直接賦給一個Byte數組。
聲明一個動態的Byte數組最簡單的方法是在Dim語句中使用空參數,例如:
->DimBuffer()asByte->
當你把一個字符串賦給一個動態Byte數組時,數組中的字符數將是字符串的字符數目的兩倍。這是因為VisualBasic中字符串使用Unicode,並且每個Unicode字符的實際大小是兩個字節。當把一個ASCII字符轉換成一個Byte數組時,數組中的另一個字節將是0。
向Unicode的轉換是將每個在緩沖區中的字符轉換成2個字節,從而實際上加倍了存儲在結果字符串的中字節數目,當你認為函數Len(strA)得到的尺寸大小和Unicode轉換後的Ubound(Buffer)函數所返回的尺寸大小相同時,上述特點就不很明顯了。但是,函數LenB(strA)確實返回一個2倍於Len(strA)返回值的數值。這是因為Len函數返回的是字符串中字符的數目,而LenB函數返回的是字符串中字節的數目。一個Unicode串的字符長度僅僅是該串中實際字節數目的一半,這是因為每個Unicode字符2個字節。
四、字符串轉換成VB字符串 當我們在VB中調用Win32API函數時,如果函數的返回值是一個字符串,那一般有如下三種情況:
1.函數預先要求你提供一個有固定空間的字符串,以供存儲函數的返回值。
2.函數的返回是一個以Null結尾的C字符串,而不是正規的VB字符串。
3.Win32API函數有時候會返回另一種類型的字符串。這種類型的字符串在單個緩沖區內保存了多個字符串值,每個值之間用Null隔開,結尾的是兩個Null,一個Null是最後一個字符串值的結尾符,另一個Null是整個字符串的結尾符。這其實就是我們通常在C中遇到的字符串數組。
第一種情況很好辦,只無原則預先定義好一個空間足夠大的字符串,然後把API函數的返回值賦於這個字符串就可以了。例如,如果你已經知道函數返回值最多不會走過256個字符,可以這樣編碼如下:
->DimsAPIReturnasstring
SAPIReturn=Space$(256)
SAPIReturn=API_Function(…)->
對於第二和第三種情況,就必須把返回的C字符串成標准的VB字符串。下面這個函數CStringToVBString把一個以Null結尾的C字符串成VB字符串。
->PublicFunctionCStringToVBString(psCStringAsString)Asstring
‘參數psCString是一個待轉換的C字符串
‘函數返回Null左邊所有的字符
dimsReturnasstring
dimiNullCharPosAsInteger
iNullCharPos=InStr(psCString,vbNullChar)
ifiNullCharPos>0then
sReturn=left(psCString,iNullCharPos-1)
else
sReturn=pscstring
endif
CStringToVBString=sReturn
Endfunction->
下面這個過程把一個含有多個C字符串的緩沖區轉換成一個字符串數組。
->PublicSubMultiCStringToStringArray(psMultiCStringAsString,psaStrings()AsString)
'參數psMultiCString是待轉換的多個C字符串
'參數psaStrings是返回的VB字符串數組,調用之前它必須是一個動態的空數組
'
DimiNullPosAsInteger
DimiPrevPosAsInteger
DimiIdxAsInteger
'初始化字符串數組
iIdx=0
ReDimpsaStrings(0ToiIdx 1)
psaStrings(iIdx 1)=""
Do
'
iNullPos=InStr(iPrevPos 1,psMultiCString,vbNullChar)
IfiNullPos>iPrevPos 1Then
'把找到的C字符串賦值給字符串數組
psaStrings(iIdx)=Mid$(psMultiCString,(iPrevPos 1),((iNullPos-1)-iPrevPos))
iIdx=iIdx 1
ReDimPreservepsaStrings(0ToiIdx)
iPrevPos=iNullPos
Else
'找到了兩個Null字符,去掉最後一個,然後退出
ReDimPreservepsaStrings(0ToiIdx-1)
ExitDo
EndIf
Loop
EndSub->
當調用Win32API函數時,使用這兩個簡單的函數,你可以消除很多冗余的代碼,加快開發步伐。
注意:
當你為API的返回值預先分配字符串的空間時,一定不要忘了空間內必須包含Null結束符。另外,建議你在使用API時,最好對每個變量都進行聲明,加上下面這句代碼:
->OptionExplicit->
五、小結 VB6中字節數組和字符串的相互轉換是編程中,尤其是新手使用中最為頭疼的問題。本文歸納了軟件開發過程中使用二者的典型情況及其應該注意的問題,供參考。不當之處還請讀者批評指正。->