考考大家认识这三个函数么 VarPtr,ObjPtr和StrPtr
vb吧
全部回复
仅看楼主
level 7
偶然见遇到了,查完资料才知道的,大家都认识么?呵呵
2006年02月20日 12点02分 1
level 0
愿闻其详
2006年02月20日 12点02分 2
level 3
快告诉俺们吧!馋死了!!!
2006年02月20日 13点02分 3
level 7
呵呵,卖个关子先明天顺便把我找的文章一起贴上来
2006年02月20日 14点02分 5
level 7
  一是效率,这是一种态度一种追求,在VB里也一样;  二是不能不用,因为操作系统是C写的,它时刻都在提醒我们它需要指针;  三是突破限制,VB想照料我们的一切,VB给了我们很强的类型检查,VB象我们老妈一样,对我们关心到有时我们会受不了,想偶尔不听妈妈的话吗?你需要指针!  但由于缺少官方的技术支持,在VB里,指针变得很神秘。因此在C里一些基本的技术,在VB里就变得比较困难。本文的目的就是要提供给大家一种简单的方法,来将C处理指针的技术拿到VB里来,并告诉你什么是可行的,什么可行但必须要小心的,什么是可能但不可行的,什么是根本就不可能的。 三、 程咬金的三板斧   是的,程序二基本上就已经让我们看到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 LongPrivate 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会让我们失去效率!速度是使用指针技术的根本要求。
2006年02月21日 01点02分 7
level 7
  本文配套代码中的LinkedList里有完全用指针实现的链表,它是使用HeapAlloc从堆栈中动态分配内存,另有一个调用FindFirstUrlCacheEntry这个API来操作IE的Cache的小程序IECache,它使用了VirtualAlloc来动态分配内存。但实际上这都不是必须的,VB已经为我们提供了标准的动态内存分配的方法,那就是:  对象、字符串和字节数组  限于篇幅,关于对象的技术这里不讲,LinkedList的源代码里有用对象实现的链表,你可以参考。  字符串可以用Space$函数来动态分配,VB的文档里就有详细的说明。  关于字节数组,这里要讲讲,它非常有用。我们可用Redim来动态改变它的大小,并将指向它第一个元素的指针传给需要指针的API,如下:dim ab() As Byte , ret As long'传递Null值API会返回它所需要的缓冲区的长度。ret = SomeApiNeedsBuffer(vbNullString)'动态分配足够大小的内存缓冲区ReDim ab(ret) As Byte'再次把指针传给API,此时传字节数组第一个元素的指针。SomeApiNeedsBuffer(ByVal VarPtr(ab(1)))   在本文配套程序中的IECache中,我也提供了用字节数组来实现动态分配缓冲区的版本,比用VirtualAlloc来实现更安全更简单。  2、突破限制  下面是一个突破VB类型检查来实现特殊功能的经典应用,出自Bruce Mckinney的《HardCore Visual Basic》一书。  将一个Long长整数的低16位作为Interger型提取出来,  【程序七】'标准的方法,也是高效的方法,但不容易理解。Function LoWord(ByVal dw As Long) As Integer  If dw And &H8000& Then   LoWord = dw Or &HFFFF0000  Else   LoWord = dw And &HFFFF&  End IfEnd Function   【程序八】'用指针来做效率虽不高,但思想清楚。Function LoWord(ByVal dw As Long) As Integer  CopyMemory ByVal VarPtr(LoWord), ByVal VarPtr(dw), 2End Function   3、对数组进行批量操作  用指针进行大批量数组数据的移动,从效率上考虑是很有必要的,看下面的两个程序,它们功能都是将数组的前一半数据移到后一半中:  【程序九】:'标准的移动数组的做法Private Sub ShitArray(ab() As MyType) Dim i As Long, n As Long n = CLng(UBound(ab) / 2) For i = 1 To n  Value(n + i) = Value(i)  Value(i).data = 0 NextEnd Sub  【程序十】:'用指针的做法Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _(ByVal dest As Long, ByVal source As Long, ByVal bytes As Long)Private Declare Sub ZeroMemory Lib "kernel32" Alias "RtlZeroMemory" _(ByVal dest As Long, ByVal numbytes As Long)Private Declare Sub FillMemory Lib "kernel32" Alias "RtlFillMemory" _(ByVal dest As Long, ByVal Length As Long, ByVal Fill As Byte)Private Sub ShitArrayByPtr(ab() As MyTpye) Dim n As Long n = CLng(UBound(ab) / 2) Dim nLenth As Long nLenth = Len(Value(1)) 'DebugBreak CopyMemory ByVal VarPtr(Value(1 + n)), ByVal VarPtr(Value(1)), n * nLenth ZeroMemory ByVal VarPtr(Value(1)), n * nLenthEnd Sub   当数组较大,移动操作较多(比如用数组实现HashTable)时程序十比程序九性能上要好得多。  程序十中又介绍两个在指针操作中会用到的API: ZeroMemory是用来将内存清零;FillMemory用同一个字节来填充内存。当然,这两个API的功能,也完全可以用CopyMemory来完成。象在C里一样,作为一个好习惯,在VB里我们也可以明确的用ZeroMemory来对数组进行初始化,用FillMemory在不立即使用的内存中填入怪值,这有利于调试。  4、最后的一点  当然,VB指针的应用决不止这些,还有什么应用就要靠自己去摸索了。对于对象指针和字符串指针的应用我会另写文章来谈,做为本文的结束和下一篇文章《VB字符串全攻略》的开始,我在这里给出交换两个字符串的最快的方法:  【程序十一】'交换两个字符串最快的方法Private Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" _ (Destination As Any, Source As Any, ByVal Length As Long) Sub SwapStrPtr3(sA As String, sB As String) Dim lTmp As Long Dim pTmp As Long, psA As Long, psB As Long pTmp = StrPtr(sA): psA = VarPtr(sA): psB = VarPtr(sB) CopyMemory ByVal psA, ByVal psB, 4 CopyMemory ByVal psB, pTmp, 4End Sub   对不起,为了一点点效率,又用了Any!关于StrPtr,下一篇文章我会来谈。  自己来试试吧!欲练神功,赶快行动!
2006年02月21日 01点02分 12
level 0
这么好的东东咋现在才发出来啊,不错啊
2006年02月21日 09点02分 13
level 1
多谢分享,顶了、、
2006年02月23日 11点02分 14
level 1
好东西....顶死你~~~~
2006年08月05日 01点08分 15
level 1

2006年08月05日 09点08分 16
level 0
我今天又长了见识了!可是个好玩意啊!
2006年08月05日 11点08分 17
level 1
好东西,收藏先
2006年09月25日 03点09分 18
level 1
是啊,好东西!建议大家收藏!
2006年09月25日 04点09分 19
level 1
先收藏,虽然看不懂!
2006年09月25日 04点09分 20
level 0
vb的字符串格式与C的存储方式不兼容,vb都是用Unicode表示字符串的,而且字符串首位字节不是字符串的开始,所以vb中取字符串的指针必须用StrPtr。楼住还漏掉一个取函数的地址 AddressOf,例如:OldLong = SetWindowLong(Me.hWnd, GWL_WNDPROC, AddressOf Func1)
2006年09月26日 17点09分 21
level 0
好东西一起\分享
2010年05月17日 04点05分 22
level 1
找的就是这个
2010年06月14日 07点06分 23
level 1
回复21楼
4、AddressOf
     它用来得到一个指向VB函数入口地址的指针,不过这个指针只能传递给API使用,以使得API能回调VB函数。
     本文不准备详细讨论函数指针,关于它的使用请参考VB文档。
麻烦您仔细看清楚了再回帖
2010年06月14日 08点06分 24
level 12
我很认识= =.
24#:不一定啊 给过程也可以的。我就准备用AsmCode一个跳转地址的
2010年06月14日 09点06分 25
1 2 尾页