转至繁体中文版     | 网站首页 | 图文教程 | 资源下载 | 站长博客 | 图片素材 | 武汉seo | 武汉网站优化 | 
最新公告:     敏韬网|教学资源学习资料永久免费分享站!  [mintao  2008年9月2日]        
您现在的位置: 学习笔记 >> 图文教程 >> 软件开发 >> VB.NET程序 >> 正文
使用 Visual Basic 通过 32 位 地址访问内存(中英对照)         ★★★★

使用 Visual Basic 通过 32 位 地址访问内存(中英对照)

作者:闵涛 文章来源:闵涛的学习笔记 点击数:2862 更新时间:2009/4/23 16:38:16

使用 Visual Basic 通过 32 位 地址访问内存

2001年7月6日

马尼拉,菲律宾

作者:Chris Vega [gwapo@models.com]

  当我们谈论“真的”指针和内存地址,我们大都会想到 Visual Basic 的局限性,比如,由于 VB 没有作为变量声明的指针数据类型,它不能直接访问内存。当某些场合需要一个变量的“地址”而不是它的值的时候,这一点混淆就显得特别明显。例如,那个变量位于内存(当前进程、其它进程或者动态链接库的虚拟空间)中的何处。

  是的,VB 确实“没有”指针变量,但是你是否曾试过将一个正规的 VB 数据类型转变为一个指针?你是否认为这是不可能的?好吧,还是再想一下,因为在 Visual Basic 中(从发行版本5开始),Microsoft 提供了一系列便利的函数以将你的正规变量转换为指针,它们是:

1] VarPtr - 返回一个变量或者数组元素的地址
   StrPtr - 返回字符串的地址

  Visual Basic 中除字符串以外的变量,都位于它的内存位置上,你可以通过调用 VarPtr 函数获取这个变量的地址。字符串实际上是作为 BSTR 储存的,这是一个指向“字符数组的指针”的指针,这样你就需要 StrPtr 以得到“字符数组的指针”的地址,而不是用 VarPtr 获得 BSTR 的地址。

范例:
 Dim ptrMyPointer As Long
 Dim intMyInteger As Integer
 Dim strMyString As String * 25

 '''' 这就是一个调用
 ptrMyPointer = VarPtr(intMyInteger)
 '''' 将内存中 intMyInteger 这个变量的32位地址赋予 ptrMyPointer

 strMyString = "变量的地址:" & Hex(ptrMyPointer)
 MsgBox strMyString


 '''' 这是另一个调用
 ptrMyPointer = StrPtr(strMyString)
 '''' 给出字符数组首元素的地址,例如,字符串的第一个字母。


2] VarPtrArray - 返回变量数组的地址
   VarPtrStringArray - 返回字符传数组的地址

  Visual Basic 中数组被包存在 SAFEARRAY 结构中,你需要使用 VarPtrArray 函数以获取数组的地址,但是在使用该函数之前,你必须手工把它从 msvbvm50.dll 中声明到 VB 程序中。

范例:

 '''' 对于 VB 5
 '''' ========
 Declare Function VarPtrArray Lib "msvbvm50.dll" Alias "VarPtr" (Var() as Any) As Long

 '''' 对于 VB 6
 '''' ========
 Declare Function VarPtrArray Lib "msvbvm60.dll" Alias "VarPtr" (Var() as Any) As Long

 '''' 调用

 Dim lngSafeArrayAddress As Long
 Dim lngArrayOfLongs(6) As Long
 Dim i As Long

 Randomize
 For i = 0 to 6
  lngArrayOfLongs = Int(Rnd * &HFFFF)
 Next

 lngSafeArrayAddress = VarPtrArray(lngArrayOfLongs())

 '''' 返回数组 lngArrayOfLongs 的安全地址,s of an Array , you
 '''' 你可以将这些地址用于快速排序或其它用途。


  事实上,VarPtrStringArray 更难以用于你的程序中,因为你需要创建一个类型库并手工将该类型库引用到 VB 程序中。要做一个类型库,你需要一个 MIDL 编译器,它是一个用于将 *.odl 文件编译成类型库的命令行工具。
  对于 VB5,创建一个文本文件并且保存为 VB5StrPtr.odl,加入以下内容:

----------开始剪切--------------------------------------------------
#define RTCALL _stdcall
[uuid(6E814F00-7439-11D2-98D2-00C04FAD90E7),lcid (0), version(5.0), helpstring("VarPtrStringArray Support for VB5")]
library PtrLib
{
 importlib ("stdole2.tlb");
 [dllname("msvbvm50.dll")]
 module ArrayPtr
   {
    [entry("VarPtr")]
    long RTCALL VarPtrStringArray([in] SAFEARRAY (BSTR) *Ptr);
   }
}
----------结束剪切-------------------------------------------------

  用以下命令编译: MIDL /t VB5StrPtr.odl

  对于 VB6,创建一个文本文件并且保存为 VB6StrPtr.odl,加入以下内容:

-----------开始剪切--------------------------------------------------
#define RTCALL _stdcall
[uuid(C6799410-4431-11d2-A7F1-00A0C91110C3),lcid (0), version(6.0), helpstring("VarPtrStringArray Support for VB6")]
library PtrLib
{
 importlib ("stdole2.tlb");
 [dllname("msvbvm60.dll")]
 module ArrayPtr
   {
    [entry("VarPtr")]
    long RTCALL VarPtrStringArray([in] SAFEARRAY (BSTR) *Ptr);
   }
}
----------结束剪切-------------------------------------------------

  用以下命令编译: MIDL /t VB6StrPtr.odl


  现在,你有了类型库,将该类型库引用到 VB 程序中,然后你可以用以下方式获取字符串数组:

Dim MyArrayOfStrings(3) As String
Dim AddressOfArray As Long
MyArrayOfStrings(0)="Chris"
MyArrayOfStrings(1)="Vega"
MyArrayOfStrings(2)="gwapo@models.com"

'''' 调用
AddressOfArray = VarPtrStringArray ( MyArrayOfStrings() )

'''' 给出数组首元素的地址,而且是该首元素的第一个字符,
'''' 例如,这里是字符“C”在内存中的地址


'''' *** 怎样?你没有 MIDL 编译器?或者你不愿麻烦自己创建类型库并手工引用?
'''' 这里有一种足够容易的简单方法。
'''' 因为 StrPtr 函数具有获得字符串地址的能力,而字符串数组的元素全部都是字符串,
'''' 所以你应该清楚了,你可以对数组的首元素进行这个调用

AddressOfArray = StrPtr ( MyArrayOfStrings(0) )

'''' 返回更上述方法完全相同的结果

 

3] ObjPtr - 返回一个对象的地址

  面向对象编程由众多对象组成,而这些对象和它的众多属性一起保存在内存中,作为一种结构化的布局。你需要调用 ObjPtr 函数来获取它的位置。

范例:
 '''' 你要知道 Form1 处于内存何处,本方法告诉你它在线程中的地址

 Dim objMyObject As New Form1
 MsgBox "Form1 位于:" & Hex( ObjPtr( objMyObject ) )

 

  好,到此为止你一定在想:无论如何,怎么才能把这些地址变成实际有用的东西呢?其实如果你这样想答案就很清楚了:地址是一个内存中的位置,而你的变量中保存的就是一个内存中的位置,并且有它本身在内存中的位置。搞糊涂了?我们让它简单一点,你可以简单的认为这个地址是保存数据的位置,数据是可读写的,而你需要通过这个地址来读写它。唔,Visual Basic 能够做这种事情吗?

  不能,如果你只是简单的考虑 Visual Basic 的能力的话,但是你的程序可以使用 API 函数。我现在谈到的 API 是从 KERNEL32.DLL 输出的运行库,名为 RtlMoveMemory 和 RtlCopyMemory。

  它太吸引人了。首先我们已经找到了通过把变量转变为指针来得到内存地址的方法,现在我们又有了读写这些地址所指内容的方法。但是只要将这两个声明中的任一个加入你的程序中,而不是全部,因为它们的功能是一样的。我建议使用第二个,因为它被所有的 Windows 系统支持,而 RtlCopyMemory 则不然。


 Private Declare Sub CopyMemory _
                     Lib "kernel32" Alias _
                     "RtlCopyMemory" _
                     (Destination As Any, _
                      Source As Any, _
                      ByVal length As Long)
 '''' RtlCopyMemory 将一块内存的内容复制到另一块中。

 '''' 或者

 Private Declare Sub CopyMemory _
                     Lib "kernel32" Alias _
                     "RtlMoveMemory" _
                     (Destination As Any, _
                      Source As Any, _
                      ByVal length As Long)

 '''' RtlMoveMemory 可以向前或向后移动内存,匹配的或不匹配的,
 '''' 以 4字节的块为单位,后面为所有保留的字节。

参数:

 Destination
  指向要移动的目标。

 Source
  指向要复制的内存。

 Length
  指定要复制的字节数。


  为了使它更容易使用,你可以把下面内容复制粘贴到 modMemory.bas 中:

------------开始剪切------------------------------------------------------------------

 Attribute VB_Name = "modMemory"
 '''' =============================================================================
 '''' 复制内存 API
 '''' =============================================================================
 Private Declare Sub CopyMemory _
                     Lib "kernel32" Alias _
                     "RtlMoveMemory" _
                     (Destination As Any, _
                      Source As Any, _
                      ByVal length As Long)
                    
 '''' =============================================================================
 '''' 数据长度
 '''' =============================================================================
 Public Enum e_BinaryData
     DefineByte = 1                          ''''  8 位数据
     DefineWord = 2                          '''' 16 位数据
     DefineDoubleWord = 4                    '''' 32 位数据
     DefineQuadWord = 8                      '''' 64 位数据
 End Enum

 '''' =============================================================================
 '''' 允许直接读 MemPointer 指向的内存
 '''' 用和 Asm 一样的字节数定义 (DB, DW, DD, DX)
 '''' =============================================================================
 Function ReadMem(ByVal MemPointer As Long, _
                  SizeInBytes As e_BinaryData)
     Select Case SizeInBytes
         Case DefineByte
             Dim DB As Byte
             CopyMemory DB, ByVal MemPointer, 1
            

[1] [2] [3] [4]  下一页


[VB.NET程序]通过短信猫发送短信  [C语言系列]使用C#实现ADSL自动拨号
[Web开发]狂人采集器规则使用详解  [电脑技术]windows7快捷键使用大全
[办公软件]PowerPoint模板使用经验之谈  [办公软件]如何在PowerPoint中使用(插入)Media Player控件播…
[办公软件]如何在PowerPoint中使用(插入、创建)书签及书签的…  [办公软件]如何在PowerPoint中插入(使用)条形码
[办公软件]PowerPoint通过对象播放视频电影  [办公软件]如何通过网页打开PPT
教程录入:mintao    责任编辑:mintao 
  • 上一篇教程:

  • 下一篇教程:
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
      注:本站部分文章源于互联网,版权归原作者所有!如有侵权,请原作者与本站联系,本站将立即删除! 本站文章除特别注明外均可转载,但需注明出处! [MinTao学以致用网]
      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)

    同类栏目
    · C语言系列  · VB.NET程序
    · JAVA开发  · Delphi程序
    · 脚本语言
    更多内容
    热门推荐 更多内容
  • 没有教程
  • 赞助链接
    更多内容
    闵涛博文 更多关于武汉SEO的内容
    500 - 内部服务器错误。

    500 - 内部服务器错误。

    您查找的资源存在问题,因而无法显示。

    | 设为首页 |加入收藏 | 联系站长 | 友情链接 | 版权申明 | 广告服务
    MinTao学以致用网

    Copyright @ 2007-2012 敏韬网(敏而好学,文韬武略--MinTao.Net)(学习笔记) Inc All Rights Reserved.
    闵涛 投放广告、内容合作请Q我! E_mail:admin@mintao.net(欢迎提供学习资源)

    站长:MinTao ICP备案号:鄂ICP备11006601号-18

    闵涛站盟:医药大全-武穴网A打造BCD……
    咸宁网络警察报警平台