出处: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)才对。
原文链接:https://www.f2er.com/vb/263099.html