OMG!内存操作真危险

版权声明:可以任意转载,转载时请务必以链接形式标明如下文章原始出处和作者信息及本声明

作者:xixi

出处:http://blog.csdn.net/slowgrace/archive/2009/04/24/4105426.aspx

这篇文章里提到把API参数声明为ANY和声明为LONG的区别。昨天在这个帖子里试了试,还真是那么回事。感谢myjian耐心解释。

话说有个API函数RtlMoveMemory,我们可以有以下两种声明:

Private Declare Sub copyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByVal Destination As Long,ByVal Source As Long,ByVal Length As Long)
Private Declare Sub copyMemory Lib "kernel32" Alias "RtlMoveMemory" (Destination As Any,Source As Any,ByVal Length As Long)

然后我们用下面的测试代码

Option Explicit

Private Type MyStruct
x
As Byte
y
As Byte
z
As Long
End Type

Private Sub Form_Load()
Dim t As MyStruct
With t
.x
= 12
.y
= 34
.z
= &H5678 '在内存中存放为 &H78 &H56 &H00 &H00
End With

Dim p As Long
Dim b As Byte
p
= VarPtr(t)

Call copyMemory(b,ByVal p + 2,1)
Debug.Print Hex(b)

Call copyMemory(b,ByVal p + 4,1)
Debug.Print Hex(b)
End Sub

这段代码大致的意思,是要验证VB6中结构的高字节对齐存储方式

如果用第一种声明就会导致内存溢出(我昨天尝试的后果是ACCESS死掉重启),用第二种就不会。主要是下面这个语句

Call copyMemory(b,ByVal p + 2,1)

这个语句的第二个参数是为了把P变量内的值(也就是变量t的内存地址)+2之后的那个"值"传进去,而不是P这个变量的地址,所以要加上BYVAL,因为声明里认是ByRef。而当声明里面不是声明为ByRef As Any而是ByVal As Long时,这个调用就可以是p+2了,可以省去ByVal说明。

而这个语句的第一个参数是要把变量b的地址传过去,如果使用ByVal as Long式声明的话,这样传进去的就是b的值(当时是0),向着0这个地址复制数据,当然会出错了。实际上,如果用ByVal as Long式声明的话,应该传vatPtr(b)才对。

相关文章

Format[$] ( expr [ , fmt ] ) format 返回变体型 format$ 强...
VB6或者ASP 格式化时间为 MM/dd/yyyy 格式,竟然没有好的办...
在项目中添加如下代码:新建窗口来显示异常信息。 Namespace...
转了这一篇文章,原来一直想用C#做k3的插件开发,vb没有C#用...
Sub 分列() ‘以空格为分隔符,连续空格只算1个。对所选...
  窗体代码 1 Private Sub Text1_OLEDragDrop(Data As Dat...