VB.NET字符串数组全面分析

开发 后端
这里介绍当需要把一个VB.NET字符串数组整个传入动态连接库时,情况就变得复杂多了,用传递简单数据类型数组的方式来传递VB.NET字符串数组是行不通的。

VB.NET有很多值得学习的地方,这里我们主要介绍VB.NET字符串数组,包括介绍将VB.NET字符串数组转换成字节数组等方面。

大部分的DLL过程(包括Windows 95 API中的所有过程)使用LPSTR类型字符串,这是指向标准的以null结束的C语言字符串的指针,它也被称为ASCIIZ字符串。LPSTR 没有前缀。下图显示了一个指向ASCIIZ字符串的LPSTR。

如果DLL过程需要一个LPSTR(指向以null结束的字符串的指针)作为参数,可以在 VB 中将一个字符串以传值的方式传递给它。因为指向BSTR的指针实际指向以null值结束的字符串的第一个数据字节,所以对于DLL过程来说,它就是一个 LPSTR。这样传入动态连接库的字符串,DLL过程也可以对它进行修改,尽管它是以传值方式传入的。只有当DLL过程需要一个指向LPSTR的指针时,才以传址的方式传入字符串,这时DLL过程得到的是一个指向字符串指针的指针(相当于C/C++中的char**),而不是通常所用的字符串的首地址(相当于C/C++中的char*)。

当需要把一个VB.NET字符串数组整个传入动态连接库时,情况就变得复杂多了,用传递简单数据类型数组的方式来传递VB.NET字符串数组是行不通的。当我们以传值的方式将一个VB.NET字符串数组的第一个元素传进动态连接库时,DLL过程得到的实际上是该元素压入堆栈段后的地址,而不是数据段中整个数组的首地址。也就是说,这时DLL过程只能得到数组的第一个元素,而无法访问整个数组。而以传址方式传入第一个元素时,DLL过程只能得到指向该元素在堆栈段中地址的指针,同样无法访问整个数组。这不能不说是VB的一个不足。因此,在程序设计中,如果确实需要将整个VB.NET字符串数组传入动态库,就必须采取其它方法。

我们知道,在VB中,有一种Byte数据类型。每个Byte型变量占一个字节,不含符号位,因 此所能表示的范围为0到255。这种数据类型是专门用于存放二进制数据的。为了将整个VB.NET字符串数组传进动态库,可以用字节数组来保存字符串。由于Byte是一种简单数据类型,因此字节数组的传递是非常简单的。首先,需要把一个字符串正确地转变成一个字节数组。这要涉及一 些字符集的知识。Windows 95和VB使用不同的字符集,Windows 95 API使用的是ANSI或DBCS 字符集,而VB使用的则是Unicode字符集。所谓ANSI字符集,是指每个字符都用一个字节表示,因此最多只能有28=256个不同的字符,这对于英语来说已经足够了,但不能完全支持其它语言。DBCS字符集支持很多不同的东亚语言,如汉语、日语和朝鲜语,它使用数字0-255表示ASCII 字符,其它大于255或小于0的数字表明该字符属于非拉丁字符集;在DBCS中,ASCII字符的长度是一个字节,而汉语、日语和其它东亚字符的长度是2个字节。而Unicode字符集则完全用两个字节表示一个字符,因此最多可以表示216=65536个不同字符。也就是说,ANSI字符集中所有的字符都只占一个字节,DBCS字符集中ASCII字符占一个字节,汉字占两个字节,Unicode 字符集中每个字符都占两个字节。由于VB与WindowsAPI使用的字符集不同,因此在进行字符串到字节数组的转换时,当用Asc函数取得一个字符的字节码后,需要判断它是否是一个ASCII 字符;如果是ASCII字符,则在转换后的字节数组中就只占一个字节,否则要占两个字节。

下面给出了转换函数:GetChar Byte得到一个字符的高字节或低字节,它的第一个参数是一个字符的ASCII码,第二个参数是标志取高字节还是低字节;StrToByte按DBCS或ANSI格式将一个字符串转换成一个字节数组,第一个参数是待转换的字符串,第二个参数是转换后的一个定长字节数组,若该数组长度不足以存放整个字符串,则截去超长的部分;ChangeStrAryToByte 利用前两个函数将VB.NET字符串数组转换成字节数组,第一个参数是定长的VB.NET字符串数组,其中每个元素都是一个字符串(各个元素包含的字符数可以不同),第二个参数是一个变长的字节数组, 保存转换后的结果。

  1. Function GetCharByte(ByVal OneChar As Integer, 
    ByVal IsHighByte As Boolean) As Byte 
  2. ' 该函数获得一个字符的高字节或低字节  
  3. If IsHighByte Then  
  4. If OneChar >= 0 Then  
  5. GetCharByte = CByte(OneChar \ 256)  
  6. '右移8位,得到高字节  
  7. Else  
  8. GetCharByte = CByte((OneChar  
  9. And &H7FFF) \ 256) Or &H80  
  10. End If  
  11. Exit Function  
  12. Else  
  13. GetCharByte = CByte(OneChar And &HFF)  
  14. '屏蔽掉高字节,得到低字节  
  15. Exit Function  
  16. End If  
  17. End Function  
  18. Sub StrToByte(StrToChange As String, ByteArray() As Byte)  
  19. '该函数将一个字符串转换成字节数组  
  20. Dim LowBound, UpBound As Integer  
  21. Dim i, count, length As Integer  
  22. Dim OneChar As Integer  
  23. count = 0 
  24. length = Len(StrToChange)  
  25. LowBound = LBound(ByteArray)  
  26. UpBound = UBound(ByteArray)  
  27. For i = LowBound To UpBound  
  28. ByteArray(i) = 0 '初始化字节数组  
  29. Next  
  30. For i = LowBound To UpBound  
  31. countcount = count + 1  
  32. If count <= length Then  
  33. OneChar = Asc(Mid(StrToChange, count, 1))  
  34. If (OneChar > 255) Or (OneChar < 0) Then  
  35. '该字符是非ASCII字符  
  36. ByteArray(i) = GetCharByte(OneChar, True) '得到高字节  
  37. ii = i + 1  
  38. If i <= UpBound Then ByteArray(i)  
  39. = GetCharByte(OneChar, False)  
  40. '得到低字节  
  41. Else  
  42. '该字符是ASCII字符  
  43. ByteArray(i) = OneCha  
  44. End If  
  45. Else  
  46. Exit For  
  47. End If  
  48. Next  
  49. End Sub  
  50.  
  51. Sub ChangeStrAryToByte(StrAry()  
  52. As String, ByteAry() As Byte)  
  53. '将字符串数组转换成字节数组  
  54. Dim LowBound, UpBound As Integer  
  55. Dim i, count, StartPos, MaxLen As Integer  
  56. Dim TmpByte() As Byte  
  57. LowBound = LBound(StrAry)  
  58. UpBound = UBound(StrAry)  
  59. count = 0 
  60. ReDim ByteAry(0)  
  61. For i = LowBound To UpBound  
  62. MaxLen = LenB(StrAry(i))  
  63. ReDim TmpByte(MaxLen + 1)  
  64. ReDim Preserve ByteAry(count + MaxLen + 1)  
  65. Call StrToByte(StrAry(i), TmpByte) '转换一个字符串  
  66. StartPos = count 
  67. Do  
  68. ByteAry(count) = TmpByte(count - StartPos)  
  69. countcount = count + 1  
  70. If ByteAry(count - 1) = 0 Then Exit Do Loop   
  71. '将每一个字符串对应的字节数组按顺序填入结果数组中  
  72. ReDim Preserve ByteAry(count - 1)  
  73. Next i  
  74. End Sub 

这样,VB.NET字符串数组就全部转换成了字节数组,然后只要将字节数组的第一个元素以传址的方式传入动态连接库,DLL过程就可以正确地访问数组中的所有字符串了。但是,使用这种方法,当DLL过程处理结束返回VB时,VB得到的仍然是字节数组。如果需要在VB中再次得到该字节数组表示的字符串,还要把整个字节数组重新以0为分割符分成多个子数组(每个子数组都对应原来字符串数组中的一个元素),然后使用VB函数StrConv将每个子数组转换成字符串(转换时第二个参数选vbUnicode),就可以显示或进行其它操作了。例如,其中一个子数组的名字是SubAry,则函数StrConv(SubAry,vbUnicode)就返回了它所对应的字符串。

总之,VB应用程序和动态库间字符串参数的传递是一个比较复杂的过程,使用时要非常谨慎。同时应尽可能避免传递字符串数组类型的参数,因为这很容易引起下标越界、堆栈溢出等严重错误。

【编辑推荐】

  1. VB.NET使用Alias子句简介
  2. 详细描述VB调用动态连接库
  3. 叙述VB.NET创建控件数组
  4. 浅析VB.NET绘制GDI图形的方法
  5. VB.NET Declare语句学习笔记
责任编辑:佚名 来源: weaseek
相关推荐

2009-10-27 09:45:03

VB.NET数组

2009-10-28 10:04:53

VB.NET XmlW

2009-10-15 10:57:16

VB.NET Text

2009-10-29 15:16:02

VB.NET文件传送

2009-10-14 15:20:21

VB.NET窗体指针

2009-11-04 10:54:53

VB.NET MOVE

2009-11-02 15:57:36

VB.NET WEB

2010-01-13 15:12:04

VB.NET字符串合并

2009-11-10 12:06:17

VB.NET字符串函数

2010-01-08 15:11:22

VB.NET字符串转义

2009-10-14 15:44:04

VB.NET字节数组

2010-01-11 13:42:20

VB.NET字符串加密

2009-10-28 17:44:31

VB.NET语言

2009-11-02 14:48:45

VB.NET HOOK

2009-10-15 11:42:05

VB.Net赋值语句

2009-11-10 16:46:52

VB.NET指针应用

2009-10-26 14:06:03

2009-11-02 17:12:01

VB和VB.NET

2009-10-21 09:10:52

VB.NET压缩

2009-10-15 17:50:48

VB.NET调用API
点赞
收藏

51CTO技术栈公众号