一个VB数组指针类

一个VB数组指针类       顾名思义了,这个代码就是将指定的内存地址绑定到一个VB数组,即COM中的SafeArray上。所谓绑定,是指在使用该内存地址之前,并不需要申请相应的本地内存缓冲区,也不需要进行内存复制,只是根据该地址凭空构造一个VB数组,并将数组的真实数据地址指向该地址。当然,该类的功能完全可以用CopyMemory函数直接代替。为什么又写了这个类呢?主要还是为了进一步展示VB中数组的内幕,同…

        顾名思义了,这个代码就是将指定的内存地址绑定到一个VB数组,即COM中的SafeArray上。所谓绑定,是指在使用该内存地址之前,并不需要申请相应的本地内存缓冲区,也不需要进行内存复制,只是根据该地址凭空构造一个VB数组,并将数组的真实数据地址指向该地址。当然,该类的功能完全可以用CopyMemory函数直接代替。为什么又写了这个类呢?主要还是为了进一步展示VB中数组的内幕,同时避免在进行大块内存操作时的内存复制,节省内存占用,加快运行速度。该类在VB进行内存搜索等方面的应用上有较好的性能表现。当然,在类中也使用了CopyMemory,但只用来构造数组而已,并没有作大量的数据调动。

好了,废话少好,言归正转,先建一个名为VbArrayPtr的类,代码如下: 

代码如下:

Option Explicit

‘自定义的数组类型枚举
Public Enum vbArray_Type
    vbArrayByte = vbByte Or vbArray             ‘1Bytes
    vbArrayInteger = vbInteger Or vbArray       ‘2Bytes
    vbArrayLong = vbLong Or vbArray             ‘4Bytes
    vbArrayCurrency = vbCurrency Or vbArray     ‘8Bytes
End Enum

Private Type SAFEARRAYBOUND
    cElements As Long                           ‘这一维有多少个元素?
    lLbound As Long                             ‘它的索引从几开始?
End Type
Private Const MAX_DIMS = 0                      ‘数组最大维数为1维(下标为0)
Private Type SAFEARRAY                          ‘安全数组结构定义
    cDims As Integer                            ‘维数
    fFeatures As Integer                        ‘标志
    cbElements As Long                          ‘单个元素的字节数
    clocks As Long                              ‘锁定计数
    pvData As Long                              ‘指向数组元素的指针
    rgsabound(MAX_DIMS) As SAFEARRAYBOUND       ‘定义维数边界
End Type

Private Declare Function VarPtrArray Lib “msvbvm60.dll” Alias “VarPtr” (ptr() As Any) As Long
Private Declare Sub CopyMemory Lib “kernel32” Alias “RtlMoveMemory” (Destination As Any, Source As Any, ByVal Length As Long)
Private Declare Function GetCurrentProcess Lib “kernel32” () As Long

Private Const FADF_AUTO = &H1                   ‘在栈上创建数组
Private Const FADF_STATIC = &H2                 ‘在堆上创建数组
Private Const FADF_EMBEDDED = &H4               ‘在结构中创建
Private Const FADF_FIXEDSIZE = &H10             ‘不能改变数组大小
Private Const FADF_RECORD = &H20                ‘记录容器
Private Const FADF_HAVEIID = &H40               ‘有IID 身份标记 数组
Private Const FADF_HAVEVARTYPE = &H80           ‘VT 类型数组
Private Const FADF_BSTR = &H100                 ‘BSTR数组
Private Const FADF_UNKNOWN = &H200              ‘IUnknown* 数组
Private Const FADF_DISPATCH = &H400             ‘IDispatch* 数组
Private Const FADF_VARIANT = &H800              ‘VARIANTs数组
Private Const FADF_RESERVED = &HF0E8            ‘保留,将来使用
 
Private Type MEMORY_BASIC_INFORMATION
     BaseAddress As Long
     AllocationBase As Long
     AllocationProtect As Long
     RegionSize As Long
     State As Long
     Protect As Long
     lType As Long
End Type
Private Declare Function VirtualQueryEx Lib “kernel32” (ByVal hProcess As Long, lpAddress As Any, lpBuffer As MEMORY_BASIC_INFORMATION, ByVal dwLength As Long) As Long
Private Const PAGE_READONLY = &H2               ‘只读属性,如果试图进行写操作,将引发访问违规。如果系统区分只读、执行两种属性,那么试图在该区域执行代码也将引发访问违规
Private Const PAGE_READWRITE = &H4              ‘允许读写
Private Const PAGE_EXECUTE_READ = &H20          ‘允许读和执行代码
Private Const PAGE_EXECUTE_READWRITE = &O40     ‘允许读和执行代码

Dim m_pvArray() As Variant                      ‘通用指针数组
Dim m_nCountRef As Long                         ‘引用计数

‘将一个VB一维数组绑定指定的内存地址上
Public Function Bind(ByVal lpMemoryAddress As Long, dwBytes As Long, Optional ByVal vtType As vbArray_Type = vbByte) As Variant
    Dim SA As SAFEARRAY
   
    ‘置默认返回值为Empty
    Bind = Empty
   
    ‘判断字节数是否合法
    If dwBytes <= 0 Then Exit Function
   
    ‘判断内存是否可读
    Dim hProcess As Long
    Dim MBI As MEMORY_BASIC_INFORMATION
    Dim MBI_SIZE As Long
    MBI_SIZE = Len(MBI)
    hProcess = GetCurrentProcess()
    If VirtualQueryEx(hProcess, lpMemoryAddress, MBI, MBI_SIZE) <> MBI_SIZE Then ‘函数运行失败
        Exit Function
    End If
    If Not (((MBI.Protect And PAGE_READONLY) = PAGE_READONLY) Or ((MBI.Protect And PAGE_READWRITE) = PAGE_READWRITE) Or ((MBI.Protect And PAGE_EXECUTE_READ) = PAGE_EXECUTE_READ) Or ((MBI.Protect And PAGE_EXECUTE_READWRITE) = PAGE_EXECUTE_READWRITE)) Then
        Exit Function
    End If
   
    ‘构造一个一维数组
    Dim cbElem As Long
    cbElem = Switch(vtType = vbArrayByte, 1, vtType = vbArrayInteger, 2, vtType = vbArrayLong, 4, vtType = vbArrayCurrency, 8)
    SA.cDims = 1
    SA.fFeatures = FADF_AUTO Or FADF_EMBEDDED Or FADF_FIXEDSIZE
    SA.cbElements = cbElem
    SA.clocks = 0
    SA.pvData = lpMemoryAddress                        ‘真实数组(非安全数组结构)的地址(可用VarPtr(数组首个成员变量)获取)或指定内址地址,注意:绝对不能使用VarPtrArray获取地址
    SA.rgsabound(0).cElements = dwBytes / cbElem       ‘按数组单个元素的大小对齐
    SA.rgsabound(0).lLbound = 0
   
    ‘设置pV的数据类型为安全数组
    m_nCountRef = m_nCountRef + 1
    If m_nCountRef > UBound(m_pvArray) Then
        ReDim Preserve m_pvArray(UBound(m_pvArray) + 10)          ‘以10递增扩展VARIANT类型的指针数组
    End If
   
    ‘绑定数组到一个VARIANT变量上
    Dim pSV As Long
    Dim pSA As Long
    pSA = VarPtr(SA)
    pSV = VarPtr(m_pvArray(m_nCountRef))
    CopyMemory ByVal pSV, vtType, 2
    CopyMemory ByVal pSV + 8, pSA, 4
  
    Bind = m_pvArray(m_nCountRef)
End Function

‘此函数释放未被使用的m_pV数组的成员变量,并减少引用计数
Public Function UnBind(ByRef pvSA As Variant) As Boolean
    Dim lpMemoryAddress As Long
   
    On Error GoTo ErrHandle
    If (VarType(pvSA) And vbArray) = vbArray Then           ‘说明参数为数组
        ‘获得数组的下标和维数
       
        lpMemoryAddress = VarPtr(pvSA(0))
    Else
        If VarType(pvSA) = vbLong Then                      ‘说明参数为地址
        End If
    End If
ErrHandle:
End Function

Private Sub Class_Initialize()
    m_nCountRef = 0
    ReDim m_pvArray(1 To 10)                                  ‘为了减少内存调整,预定义10个VARIANT类型的指针
End Sub

Private Sub Class_Terminate()
    Dim i As Long
    Dim pSV As Long

    pSV = VarPtr(m_pvArray(1))
    For i = 1 To m_nCountRef
        CopyMemory ByVal pSV + 8 + (i – 1) * 16, 0&, 4
    Next
    Erase m_pvArray
End Sub

调用代码:

Option Explicit

Sub main()
    Dim s As String
    Dim vbptr As New VbArrayPtr
    Dim p As Variant
    Dim i As Integer
   
    s = “我爱你中国”
    p = vbptr.Bind(StrPtr(s), LenB(StrConv(s, vbFromUnicode)), vbArrayInteger)
    For i = 0 To UBound(p)
        Debug.Print p(i)
    Next
    vbptr.UnBind (p)
   
End Sub

        如果用ReadProcessMemory取得的内存指针,亦可直接用vbptr.Bind绑定到一个数组即可,不用再将该指针指向的内容复制到本地,速度自然加快了不少。

摘自:一个VB数组指针类

相关参考


VB中的指针技术

一个VB数组指针类

VB Environ系统环境变量函数大全

变量、常数和数据类型及过程概述

VB小技巧:字符变量中双引号的输入

深入了解VB中的变量和指针


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/34195.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注