VBGood网站全文搜索 Google

搜索VBGood全站网页(全文搜索)
首页 - 经验之谈 - 在VB 中调用动态连接库(四)
发表评论(0)作者:不详, 平台:VB6.0+Win98, 阅读:11415, 日期:2002-06-04
   Function GetCharByte(ByVal OneChar As Integer, ByVal IsHighByte As Boolean) As Byte 注释: 该函数获得一个字符的高字节或低字节
If IsHighByte Then
If OneChar >= 0 Then
GetCharByte = CByte(OneChar \ 256)
注释:右移8位,得到高字节
Else
GetCharByte = CByte((OneChar
And &H7FFF) \ 256) Or &H80
End If
Exit Function
Else
GetCharByte = CByte(OneChar And &HFF)
注释:屏蔽掉高字节,得到低字节
Exit Function
End If
End Function

Sub StrToByte(StrToChange As String, ByteArray() As Byte)
注释:该函数将一个字符串转换成字节数组
Dim LowBound, UpBound As Integer
Dim i, count, length As Integer
Dim OneChar As Integer

count = 0
length = Len(StrToChange)
LowBound = LBound(ByteArray)
UpBound = UBound(ByteArray)

For i = LowBound To UpBound
ByteArray(i) = 0 注释:初始化字节数组
Next

For i = LowBound To UpBound
count = count + 1
If count <= length Then
OneChar = Asc(Mid(StrToChange, count, 1))

If (OneChar > 255) Or (OneChar < 0) Then
注释:该字符是非ASCII字符
ByteArray(i) = GetCharByte(OneChar, True) 注释:得到高字节
i = i + 1
If i <= UpBound Then ByteArray(i)
= GetCharByte(OneChar, False)
注释:得到低字节
Else
注释:该字符是ASCII字符
ByteArray(i) = OneChar
End If
Else
Exit For
End If
Next
End Sub

Sub ChangeStrAryToByte(StrAry()
As String, ByteAry() As Byte)
注释:将字符串数组转换成字节数组
Dim LowBound, UpBound As Integer
Dim i, count, StartPos, MaxLen As Integer
Dim TmpByte() As Byte

LowBound = LBound(StrAry)
UpBound = UBound(StrAry)
count = 0
ReDim ByteAry(0)

For i = LowBound To UpBound
MaxLen = LenB(StrAry(i))
ReDim TmpByte(MaxLen + 1)
ReDim Preserve ByteAry(count + MaxLen + 1)
Call StrToByte(StrAry(i), TmpByte) 注释:转换一个字符串
StartPos = count
Do
ByteAry(count) = TmpByte(count - StartPos)
count = count + 1
If ByteAry(count - 1) = 0 Then Exit Do
Loop 注释:将每一个字符串对应
的字节数组按顺序填入结果数组中
ReDim Preserve ByteAry(count - 1)
Next i
End Sub



  下面看一个转换的例子:

DimResultAry()asByte
DimSomeStr(2)asString
SomeStr(0)="测试1"
SomeStr(1)="测试222"
SomeStr(2)="测试33"
CallChangeStrAryToByte
(SomeStr,ResultAry)注释:转换字符串数组


  当转换完成以后,查看字节数组ResultAry,其中包含了21个元素,依次是:178,226,202,212,49,0,178,226,202,212,50,50,50,0,178,226,202,212,51,51,0。其中,[178,226]是"测"的字节码,[202,112]是"试"的字节码,49,50,51 分别为字符1、2、3的ASCII码。可见,经过转换后,字符串数组中的各个元素按顺序放在了字节数组中,相互间以终止符0分隔。

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

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

  用户自定义类型在VB中是一种重要的数据类型,它为编程者提供了很大的灵活性,使开发人员可以根据需要构造自己的数据结构。它相当于C/C++中的结构类型(structure)。在VB中,允许程序员以传址的方式将自定义数据类型参数传入动态库,DLL过程也可以将修改后的参数返回VB程序。但是,在VB中仍然不支持以传值的方式传递用户自定义类型参数。

  传递用户自定义类型参数时,必须确保VB中的数据类型的成员与动态库中的结构成员是一一对应的,所占空间也必须严格一致。这里所说的一一对应,不仅是指VB 中的所有结构成员在动态库的结构中都必须有对应的元素,而且它们在数据结构中定义的顺序也必须严格一致,这是VB中使用的"数据结构成员对齐方式"决定的。在VB 中,数据结构使用双字对齐方式(4-byte alignment),因此,在用户自己生成用于VB 调用的动态连接库时,也必须把编译选项"structure member alignment" 设为4字节(如前文所述)。

  所谓结构成员对齐方式是指一个数据结构内部,其成员的排列方式。譬如,在VB中,其对齐方式是4字节,这就好象在一个数据结构内部分成了很多个4字节大小的小单元,如果相邻 两个或多个数据成员的大小可以放在一个单元中,那么就放在一起;否则这些小单元中可能 会出现未用的空字节。我们来看下面一个数据类型:


Type TestType
m1 as Integer
m2 as Byte
m3 as Long
End Type


  它的三个成员的大小加起来是2+1+4=7。但是,由于m1和m2的字节总长度是3,小于4,它 们就存放于一个单元中;但该单元剩下的一个字节不足以放下一个Long型的成员m3,于是m3 就被放在下一个单元中,它们之间就有了一个未用的空字节;因此,整个结构所占实际长度是8 字节。同理,如果将m3和m2的位置交换一下,它所占的尺寸就变成了9字节。可见,成员在结构 中的声明顺序也是非常重要的。

  通常,当一个用户自定义类型中不包含字符串时,向动态连接库中传递该类型的参数是没有什么问题的。如果只传递一个自定义类型变量,则既可以传递该变量名,也可以传递该变 量的第一个成员,它们的效果是一样的,都是将该变量的地址传进了动态库;同样,如果要传递一个自定义类型的数组,则既可以传递该数组的第一个元素,也可以传递第一个元素的第一个成员。但是,如果用户自定义类型中包含字符串类型时,又该如何与动态连接库传递参数呢?答案是令人遗憾的:在VB中,你无法将一个包含字符串成员的用户自定义类型变量或数 组安全、正确地传入动态库中。如果你这样做了,即使某次侥幸得到了正确的结果,在其背后也隐藏着许多致命的危险。因此,如果一定要在用户自定义类型中包含字符串变量,并且该类型的变量又要作为参数传入动态库时,你最好修改类型定义,把其中的字符串成员用相应的字节数组类型替换掉(转换方法可参见前文),这样就可以在VB 和动态库间传递这种类型的参数了。

  另外,在VB 中还可以把一个函数的指针传递到动态库中,方法也并不复杂。但笔者强烈建议最好不要这么做,因为这样一来VB 应用程序就几乎完全丧失了它所应有的安全性。如果 确实需要传递函数指针的话,那么还是编一个C/C++ 的程序来完成这项工作吧。

  总之,在VB中调用DLL过程是一个比较复杂的问题,编程人员必须很好地把握,才能达到既提高了程序效率,开拓了程序功能,又不降低程序安全性的目的。另外需要特别指出的一点是,在本文中提到的所有动态连接库,都是指没有使用自动化(OLE Automation)技术的动态库,Windows API和大多数用户自编的动态连接库都是这种类型的。对于使用了OLE Automation技术的动态连接库,其参数传递的方式有所不同,读者可以参阅有关OLE 技术的书籍,在此不再涉及。