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 = ""
    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 = ""
    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. 利用 WindowsInstaller.Installer 對象計算文件 MD5 hash 值
  2. 再談Msxml2.XMLHTTP、Msxml2.ServerXMLHTTP與緩存
  3. Microsoft Platform SDK Febrary 2003版下載
  4. BAT批處理編輯器Visual Bat
  5. OpenWrt使用crontab執行計劃任務

一條評論 發表在“VB6拾遺:虛幻的指針”上

  1. prophetk說道:

    太有用了 老實說前段時間我也在想這個 不過不是在VB上實現 是在VBS DX1.0上調用API函數時

留下回複