工具软件   办公软件   操作系统   网络安全   设计在线   程序开发   教程宝典   软件下载   软件论坛
您的位置:软件 > 开发者网络 > 开发工具 > 开发专栏 > VB > 正文
真没想到VB也可以这样用之指针技术
[文章信息]
作者:adambear
时间:2005-02-17
出处:BLOG
责任编辑:方舟
[文章导读]
若想成为VB里的东方不败,熟习VB《葵花宝典》,掌握VB指针技术,乃是不二的法门
advertisement
热点推荐
· 禁止QQ登录的方法
· 给你的XML文件做个数字签名
· ImageReady制作“焰火”小动画
· Java加密和数字签名编程快速入门
· 在VB6中用命令行为模式控制GUI动作
[正文]

上一页  1 2 3 4 5  下一页

  三、 程咬金的三板斧

  是的,程序二基本上就已经让我们看到VB指针技术的模样了。总结一下,在VB里用指针技术我们需要掌握三样东西:CopyMemory,VarPtr/StrPtr/ObjPtr, AdressOf. 三把斧头,程咬金的三板斧,在VB里Hack的工具。

  1、CopyMemory

  关于CopyMemory和Bruce McKinney大师的传奇,MSDN的Knowledge Base中就有文章介绍,你可以搜索"ID: Q129947"的文章。正是这位大师给32位的VB带来了这个可以移动内存的API,也正是有了这个API,我们才能利用指针完成我们原来想都不敢想的一些工作,感谢Bruce McKinney为我们带来了VB的指针革命。

  如CopyMemory的声明,它是定义在Kernel32.dll中的RtlMoveMemory这个API,32位C函数库中的memcpy就是这个API的包装,如MSDN文档中所言,它的功能是将从Source指针所指处开始的长度为Length的内存拷贝到Destination所指的内存处。它不会管我们的程序有没有读写该内存所应有的权限,一但它想读写被系统所保护的内存时,我们就会得到著名的Access Violation Fault(内存越权访问错误),甚至会引起更著名的general protection (GP) fault(通用保护错误) 。所以,在进行本系列文章里的实验时,请注意随时保存你的程序文件,在VB集成环境中将"工具"->"选项"中的"环境"选项卡里的"启动程序时"设为"保存改变",并记住在"立即"窗口中执行危险代码之前一定要保存我们的工作成果。

  2、VatPtr/StrPtr/ObjPtr

  它们是VB提供给我们的好宝贝,它们是VBA函数库中的隐藏函数。为什么要隐藏?因为VB开发小组,不鼓励我们用指针嘛。

  实际上这三个函数在VB运行时库MSVBVM60.DLL(或MSVBVM50.DLL)中是同一个函数VarPtr(可参见我在本系列第一篇文章里介绍的方法)。

  其库型库定义如下:

[entry("VarPtr"), hidden]
long _stdcall VarPtr([in] void* Ptr);
[entry("VarPtr"), hidden]
long _stdcall StrPtr([in] BSTR Ptr);
[entry("VarPtr"), hidden]
long _stdcall ObjPtr([in] IUnknown* Ptr);

  即然它们是VB运行时库中的同一个函数,我们也可以在VB里用API方式重新声明这几个函数,如下:

Private Declare Function ObjPtr Lib "MSVBVM60" Alias "VarPtr" (var As Object) As Long
Private Declare Function VarPtr Lib "MSVBVM60" (var As Any) As Long

  (没有StrPtr,是因为VB对字符串处理方式有点不同,这方面的问题太多,我将在另一篇文章中详谈。顺便提一下,听说VB.NET里没有这几个函数,但只要还能调用API,我们就可以试试上面的几个声明,这样在VB.NET里我们一样可以进行指针操作。但是请注意,如果通过API调用来使用VarPtr,整个程序二SwapPtr将比原来使用内置VarPtr函数时慢6倍。)

  如果你喜欢刨根问底,那么下面就是VarPtr函数在C和汇编语言里的样子:

  在C里样子是这样的:

long VarPtr(void* pv){
 return (long)pv;
}

  所对就的汇编代码就两行:

mov eax,dword ptr [esp+4]
ret 4 '弹出栈里参数的值并返回。

  之所以让大家了解VarPtr的具体实现,是想告诉大家它的开销并不大,因为它们不过两条指令,即使加上参数赋值、压栈和调用指令,整个获取指针的过程也就六条指令。当然,同样的功能在C语言里,由于语言的直接支持,仅需要一条指令即可。但在VB里,它已经算是最快的函数了,所以我们完全不用担心使用VarPtr会让我们失去效率!速度是使用指针技术的根本要求。

  一句话,VarPtr返回的是变量所在处的内存地址,也可以说返回了指向变量内存位置的指针,它是我们在VB里处理指针最重要的武器之一。

  3、ByVal和ByRef

  ByVal传递的参数值,而ByRef传递的参数的地址。在这里,我们不用去区别传指针/传地址/传引用的不同,在VB里,它们根本就是一个东西的三种不同说法,即使VB的文档里也有地方在混用这些术语(但在C++里的确要区分指针和引用)

  初次接触上面的程序二SwapPtr的朋友,一定要搞清在里面的CopyMemory调用中,在什么地方要加ByVal,什么地方不加(不加ByVal就是使用VB缺省的ByRef),准确的理解传值和传地址(指针)的区别,是在VB里正确使用指针的基础。

  现在一个最简单的实验来看这个问题,如下面的程序三:

  【程序三】:

'体会ByVal和ByRef
Sub TestCopyMemory()
 Dim k As Long
 k = 5
 Note: CopyMemory ByVal VarPtr(k), 40000, 4
 Debug.Print k
End Sub

  上面标号Note处的语句的目的,是将k赋值为40000,等同于语句k=40000,你可以在"立即"窗口试验一下,会发现k的值的确成了40000。
实际上上面这个语句,翻译成白话,就是从保存常数40000的临时变量处拷贝4个字节到变量k所在的内存中。

  现在我们来改变一个Note处的语句,若改成下面的语句:

Note2: CopyMemory ByVal VarPtr(k), ByVal 40000, 4

  这句话的意思就成了,从地址40000拷贝4个字节到变量k所在的内存中。由于地址40000所在的内存我们无权访问,操作系统会给我们一个Access Violation内存越权访问错误,告诉我们"试图读取位置0x00009c40处内存时出错,该内存不能为'Read'"。

  我们再改成如下的语句看看。

Note3: CopyMemory VarPtr(k), 40000, 4

  这句话的意思就成了,从保存常数40000的临时变量处拷贝4个字节到到保存变量k所在内存地址值的临时变量处。这不会出出内存越权访问错误,但k的值并没有变。

  我们可以把程序改改以更清楚的休现这种区别,如下面的程序四:

  【程序四】:

'看看我们的东西被拷贝到哪儿去了
Sub TestCopyMemory()
 Dim i As Long, k As Long
 k = 5
 i = VarPtr(k)
 NOTE4: CopyMemory i, 40000, 4
 Debug.Print k
 Debug.Print i
 i = VarPtr(k)
 NOTE5: CopyMemory ByVal i, 40000, 4
 Debug.Print k
End Sub

  程序输出:

5
40000
40000

  由于NOTE4处使用缺省的ByVal,传递的是i的地址(也就是指向i的指针),所以常量40000拷贝到了变量i里,因此i的值成了40000,而k的值却没有变化。但是,在NOTE4前有:i=VarPtr(k),本意是要把i本身做为一个指针来使用。这时,我们必须如NOTE5那样用ByVal来传递指针i,由于i是指向变量k的指针,所以最后常量40000被拷贝了变量k里。

  希望你已经理解了这种区别,在后面问题的讨论中,我还会再谈到它。


上一页  1 2 3 4 5  下一页

发表评论推荐给朋友我想参加相关培训打印我对此感兴趣订阅电子杂志
相关内容焦点新闻
  • 在VB6中用命令行为模式控制GUI动作
  • VB设计Win2000下截获IP数据包程序
  • 真没想到VB也可以这样用之VB能做什么
  • 用VB编写异步多线程下载程序
  • 适合Visual Basic初学者的10个小技巧
  • 民营家电商排队造手机 设备商全面杀入
  • 英特尔澄清杨旭任职传闻 官方没宣布此消息
  • 国资委河北密制联通拆分方案
  • 垃圾邮件害人害企害国 清除垃圾邮件不手软
  • 中兴携手阿尔卡特 全球逐鹿CDMA
  • 用友总裁王文京:誓将ERP变成“大众消费”
  • 香港消费者委员会:数码相机最贵未必最好
  • 外电称中兴正评估西门子手机业务 或能并购
  • Advertisement