现在的位置: 首页 > 精选转贴 > 正文

浅谈 VarPtr、StrPtr 和 ObjPtr 函数的用法

2014年07月21日 精选转贴 ⁄ 共 2243字 ⁄ 字号 暂无评论 ⁄ 阅读 2,103 次

 

一、发展历史

 

在 Basic 语言演变成 QBasic,然后到 Visual Basic 之前,VarPtr 函数就已经存在了。开始,这个函数存在于 VB 运行库 1.0 版中。通过声明可以调用这个函数:

Declare Function VarPtr Lib "vbrun100.dll" (Var As Any) As Long

 数年之后,vbrun100.dll 变成了 msvbvm50.dll,但该函数的入口点却还在那儿。为了获取变量的地址,只须将变量名传递给该函数就行了。例如:

Dim l As Long 
Debug.Print VarPtr(l)

 类似地,为了获取字符串的指针,而非保存字符串的变量的指针,只须在变量名前加上 ByVal 即可。如:

Debug.Print VarPtr(s),VarPtr(ByVal s)

在VB3之前,用这种方法来获取字符串缓冲的指针是非常普遍的。但在VB4却遇到了一点麻烦。

 

ANSI/UNIDCODE问题

这种差异是如何影响 VarPtr 函数的呢?当一个字符串传递给 VarPtr 函数时,函数执行后所返回的地址是保存临时ANSI 字符串的临时 ANSI 字符串 或变量的地址。换句话说,这个地址并不是你声明的变量的真正地址。因此,对于字符串变量以及包括字符串的结构来讲,这个函数一点用也没有。

 

VB5来解决问题

为了能VarPtr能重新发挥作用,VB5 加入了三个针对 VBA 类型库的入口点。这些入口点为 VarPtr 函数提供了内置的声明。这三个函数的作用是:

VarPtr:返回变量地址

StrPtr:返回真正的 UNICODE 字符串缓冲区的地址

ObjPtr:返回任何对象变量引用的地址

 

二、下面是这三个函数的具体用法:

 

1、StrPtr

该函数主要用来产生高效的 UNICODE API 调用。在 VB4,UNICODE 形式的 API 函数的调用必须借助于 Byte 数组,例如:

Declare Sub MyUnicodeCall Lib "MyUnicodeDll.dll" (pStr as Byte)
Sub MakeCall(MyStr As String)
    Dim bTmp() As Byte
    bTmp = MyStr & vbNullChar
    MyUnicodeCall bTmp(0)
    MyStr = bTmp
    MyStr = Left(MyStr, Len(MyStr) - 1)
End Sub

如果使用 StrPtr,上面的代码精简为:

Declare Sub MyUnicodeCall Lib "MyUnicodeDll.dll" (pStr as Byte)
Sub MakeCall(MyStr As String)
    MyUnicodeCall StrPtr(MyStr)
End Sub

VarPtr/StrPtr/ObjPtr 的执行速度非常非常快,因此调用 UNICODE 函数所赞成有系统负担实际上小于调用相对应的ANSI函数。因为前者不需进行转换。

StrPtr 还能用于优化 ANSI API 函数的调用。在调用时使用 StrConv 和 StrPtr 就能避免将一个字符串变量多资传递给函数以及为每个调用而执行转换操作所造成的系统负担。例如原来的:

Declare Sub MyAnsiCall Lib "MyAnsiDll.dll" (ByVal pStr As String)
MyAnsiCall MyStr

现在变为:

Declare Sub MyAnsiCall Lib "MyAnsiDll.dll" (ByVal pStr As Long)
MyStr = StrConv(MyStr, vbFromUnicode)
MyAnsiCall StrPtr(MyStr)
MyStr = StrConv(MyStr, vbUnicode) '并不总是要求

StrPtr 还是唯一能直观地告诉你空字符串和 null 字符串的不同的方法。对于 null 字符串(vbNullString),StrPtr 的返回值为 0,而对于空字符串,函数的返回值为非零。

2、VarPtr

该函数能与要求包含有UNICODE字符串的结构的API调用一起使用。如果将一个 MyUDTVariable 变量(一个自定义类型的变量)传递给一个由 ByRef UDTParam As MyUDT定义的参数,就会发生 ANSI/UNICODE 之间的转换。但是,如果将 VarPtr(MyUDTVariable) 传递给由 ByVal UDTParam As Long 定义的参数,则不会发生这样的转换。

有一点需要特别注意,在VB中指针的算法非常重要。此外,你必须计算元素的大小,因为VB不会帮你完成这项工作。你还必须处理缺乏无符号长整型数据类型的问题。下面的函数实现了无符号算法

Function UnsingedAdd(ByVal Start As Long, ByVal Incr As Long) As Long    
    Const SignBit As Long = &H80000000    
    UnsignedAdd = (Start Xor SignBit) + Incr Xor SignBit
End Function

3、ObjPtr

该函数返回由对象变量引用的接口指针。由于大多数对象都支持多重接口,因此搞清楚地址对应的是对象的哪一个接口就非常重要了。通常个函数用来放在集合中的 对象。通过创建基于对象地址的关键字,你就可以在不需要启遍历整个集合中所有元素的情况下,轻松地将对象从集合中删除。在许多情况下,对象地址是唯一可靠 的能作为关键字的东西,示例如下:

ObjCol.Add MyObj1, CStr(ObjPtr(MyObj1))
'.....
ObjCol.Remove CStr(ObjPtr(MyObj1))

给我留言

您必须 [ 登录 ] 才能发表留言!