指针似乎是C/C++的代名词,其实VB中也有指针。
在VB中不允许定义指针类型的变量,也没有内建的用地址对内存进行操作的方法,所以从某种意义上来说,VB是没有指针的。
到底有没有指针,关键看如何理解指针这个概念,《C程序设计语言》一书中是这样定义的:指针是能够存放一个地址的一组存储单元(通常是2个或4个字节)。所以如果我们能在VB中定义一个变量,该变量存放的是一个内存地址,那么我们可以认为这就是指针。
VB中有三种指针。第一种是变量的内存地址,第二种是字符串、对象、数组的地址(这些变量有两个指针:一个是变量的,一个是数据的),第三种是函数指针。每种指针获取的方式都不尽相同。
可以使用VarPtr函数来获取任意非数组变量的地址,相当于C语言中的地址运算符&:
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal Destination As Any, ByVal Source As Any, ByVal Length As Long)
Sub Main()
Dim n1 As Long
Dim n2 As Long
n1 = 123456
CopyMemory VarPtr(n2), VarPtr(n1), 4
Debug.Print n2
End Sub
可以用StrPtr函数来获取指向字符串变量中字符串数据的指针,与VarPtr不同,StrPtr获取的是指向实际数据的指针,而不是指向变量本身的指针:
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal Destination As Any, ByVal Source As Any, ByVal Length As Long)
Sub Main()
Dim s1 As String
Dim s2 As String
s1 = "http://manongku.com"
s2 = String$(Len(s1), 0)
CopyMemory StrPtr(s2), StrPtr(s1), LenB(s1)
Debug.Print s2
End Sub
用VarPtr也可以实现相同的效果,只不过比较麻烦:
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal Destination As Any, ByVal Source As Any, ByVal Length As Long)
Sub Main()
Dim s1 As String, s2 As String
Dim p1 As Long, p2 As Long
s1 = "http://manongku.com"
s2 = String$(Len(s1), 0)
CopyMemory VarPtr(p1), VarPtr(s1), 4
CopyMemory VarPtr(p2), VarPtr(s2), 4
CopyMemory p2, p1, LenB(s1)
Debug.Print s2
End Sub
而ObjPtr函数可以获取指向对象的指针:
Sub Main()
Dim o1 As Object, o2 As Object
Set o1 = New Collection
Set o2 = o1
Debug.Print VarPtr(o1); VarPtr(o2)
Debug.Print ObjPtr(o1); ObjPtr(o2)
End Sub
最后,可以使用VB的AddressOf操作符来获取标准模块(.bas)中任意函数的地址,AddressOf最初是设计用来为Win32 API提供回调函数的:
Public Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal Destination As Any, ByVal Source As Any, ByVal Length As Long)
Public Declare Function EnumSystemCodePages Lib "kernel32" Alias "EnumSystemCodePagesW" (ByVal lpCodePageEnumProc As Long, ByVal dwFlags As Long) As Long
Const CP_INSTALLED = &H1&
Function EnumCodePagesProc(ByVal lpCodePageString As Long) As Long
Dim buffer As String
buffer = String$(256, 0)
CopyMemory StrPtr(buffer), lpCodePageString, LenB(buffer)
buffer = Left$(buffer, InStr(buffer, vbNullChar) - 1)
Debug.Print buffer
EnumCodePagesProc = 1&
End Function
Sub Main()
Call EnumSystemCodePages(AddressOf EnumCodePagesProc, CP_INSTALLED)
End Sub
运行结果:
10000
10001
10002
10003
10004
10005
10006
10007
10008
10010
10017
10021
10029
10079
10081
10082
1026
1047
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1250
1251
1252
1253
1254
1255
1256
1257
1258
1361
20000
20001
20002
20003
20004
20005
20105
20106
20107
20108
20127
20261
20269
20273
20277
20278
20280
20284
20285
20290
20297
20420
20423
20424
20833
20838
20866
20871
20880
20905
20924
20932
20936
20949
21025
21027
21866
28591
28592
28593
28594
28595
28596
28597
28598
28599
28603
28605
37
38598
437
500
50220
50221
50222
50225
50227
50229
51949
52936
54936
55000
55001
55002
55003
55004
57002
57003
57004
57005
57006
57007
57008
57009
57010
57011
708
720
737
775
850
852
855
857
858
860
861
862
863
864
865
866
869
870
874
875
932
936
949
950
65000
65001
指针是把双刃剑,使用时一定要万分小心,不然很容易导致VB崩溃。