VB6拾遗:虚幻的指针

标签: , , , , ,

指针似乎是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 = "https://demon.tw"
    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 = "https://demon.tw"
    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

指针是把双刃剑,使用时一定要万分小心,不然很容易导致VB崩溃。

赞赏

微信赞赏支付宝赞赏

随机文章:

  1. Windows 7关闭共享后怎样去掉图标上的小锁
  2. JavaScript里的sprintf函数
  3. VBSCript 之 GenerateSDDL 函数
  4. 用JavaScript实现PHP的basename函数
  5. 文件夹拒绝访问且文件夹显示为空的解决方法

一条评论 发表在“VB6拾遗:虚幻的指针”上

  1. prophetk说道:

    太有用了 老实说前段时间我也在想这个 不过不是在VB上实现 是在VBS DX1.0上调用API函数时

留下回复