![](/icons/46511yi.gif)
、
![](/icons/46511hanshu.gif)
指针
AddressOf得到
![](/icons/46511yi.gif)
个VB内部
![](/icons/46511de.gif)
![](/icons/46511hanshu.gif)
指针
![](/icons/46511dou.gif)
我们可以将这个
![](/icons/46511hanshu.gif)
指针传递给需要回调这个
![](/icons/46511hanshu.gif)
![](/icons/46511de.gif)
API
![](/icons/46511dou.gif)
它
![](/icons/46511de.gif)
作用就是让外部
![](/icons/46511de.gif)
![](/icons/46511chengxu.gif)
可以
![](/icons/46511diaoyong.gif)
VB内部
![](/icons/46511de.gif)
![](/icons/46511hanshu.gif)
但是VB里
![](/icons/46511hanshu.gif)
指针
![](/icons/46511de.gif)
应用
![](/icons/46511dou.gif)
远不象C里应用那么广泛
![](/icons/46511dou.gif)
![](/icons/46511yinwei.gif)
VB文档里仅介绍了如何将
![](/icons/46511hanshu.gif)
指针传递给API以实现回调
![](/icons/46511dou.gif)
并没指出
![](/icons/46511hanshu.gif)
指针诸多神奇
![](/icons/46511de.gif)
功能
![](/icons/46511dou.gif)
![](/icons/46511yinwei.gif)
VB是不鼓励使用指针
![](/icons/46511de.gif)
![](/icons/46511dou.gif)
![](/icons/46511hanshu.gif)
指针也不例外
首先让我们对
![](/icons/46511hanshu.gif)
指针
![](/icons/46511de.gif)
使用方式来分个类
1、回调
![](/icons/46511dou2.gif)
这是最基本也是最重要
![](/icons/46511de.gif)
功能
![](/icons/46511dou2.gif)
比如VB文档里介绍过
![](/icons/46511de.gif)
子类派生技术
![](/icons/46511dou.gif)
它
![](/icons/46511de.gif)
核心就是两个API:SetWindowLong和CallWindowProc
我们可以使SetWindowLong这个API来将原来
![](/icons/46511de.gif)
窗口
![](/icons/46511hanshu.gif)
指针换成自己
![](/icons/46511de.gif)
![](/icons/46511hanshu.gif)
指针
![](/icons/46511dou.gif)
并将原来
![](/icons/46511de.gif)
窗口
![](/icons/46511hanshu.gif)
指针保存下来
![](/icons/46511dou2.gif)
这样窗口消息就可以发到我们自己
![](/icons/46511de.gif)
![](/icons/46511hanshu.gif)
里来
![](/icons/46511dou.gif)
并且我们随时可以用CallWindowProc来
![](/icons/46511diaoyong.gif)
前面保存下来
![](/icons/46511de.gif)
窗口指针
![](/icons/46511dou.gif)
以
![](/icons/46511diaoyong.gif)
原来
![](/icons/46511de.gif)
窗口
![](/icons/46511hanshu.gif)
![](/icons/46511dou2.gif)
这样
![](/icons/46511dou.gif)
我们可以在不破坏原有窗口功能
![](/icons/46511de.gif)
前提下处理钩入
![](/icons/46511de.gif)
消息
具体
![](/icons/46511de.gif)
处理
![](/icons/46511dou.gif)
我们应该很熟悉了
![](/icons/46511dou.gif)
VB文档也讲得很清楚了
![](/icons/46511dou2.gif)
这里需要注意
![](/icons/46511de.gif)
就是CallWindowProc这个API
![](/icons/46511dou.gif)
在后面我们将看到它
![](/icons/46511de.gif)
妙用
在这里我们称回调为让\"外部
![](/icons/46511diaoyong.gif)
内部
![](/icons/46511de.gif)
![](/icons/46511hanshu.gif)
指针\"
2、
![](/icons/46511chengxu.gif)
内部使用
![](/icons/46511dou2.gif)
比如在C里我们可以将C
![](/icons/46511hanshu.gif)
指针作为参数传递给
![](/icons/46511yi.gif)
个需要
![](/icons/46511hanshu.gif)
指针
![](/icons/46511de.gif)
C
![](/icons/46511hanshu.gif)
![](/icons/46511dou.gif)
如后面还要讲到
![](/icons/46511de.gif)
C库
![](/icons/46511hanshu.gif)
qsort
![](/icons/46511dou.gif)
它
![](/icons/46511de.gif)
声明如下:
#
![](/icons/46511int.gif)
(__cdecl *COMPARE)(const void *elem1, const void *elem2)
void qsort(void *base, size_t num, size_t width,
COMPARE pfnCompare);
它需要
![](/icons/46511yi.gif)
个COMPARE类型
![](/icons/46511hanshu.gif)
指针
![](/icons/46511dou.gif)
用来比较两个变量大小
![](/icons/46511de.gif)
![](/icons/46511dou.gif)
这样排序
![](/icons/46511hanshu.gif)
可以
![](/icons/46511diaoyong.gif)
这个
![](/icons/46511hanshu.gif)
指针来比较区别类型
![](/icons/46511de.gif)
变量
![](/icons/46511dou.gif)
所以qsort可以对区别类型
![](/icons/46511de.gif)
变量
![](/icons/46511shuzu.gif)
进行排序
我们姑且称这种应用为\"从内部
![](/icons/46511diaoyong.gif)
内部
![](/icons/46511de.gif)
![](/icons/46511hanshu.gif)
指针\"
3、
![](/icons/46511diaoyong.gif)
外部
![](/icons/46511de.gif)
也许你会问
![](/icons/46511dou.gif)
用API不就是
![](/icons/46511diaoyong.gif)
外部
![](/icons/46511de.gif)
![](/icons/46511hanshu.gif)
吗?是
![](/icons/46511de.gif)
![](/icons/46511dou.gif)
但有时候我们还是需要直接获取外部
![](/icons/46511hanshu.gif)
![](/icons/46511de.gif)
指针
![](/icons/46511dou2.gif)
比如通过LoadLibrary动态加载DLL
![](/icons/46511dou.gif)
然后再通过GetProcAddress得到我们需要
![](/icons/46511de.gif)
![](/icons/46511hanshu.gif)
入口指针
![](/icons/46511dou.gif)
然后再通过这个
![](/icons/46511hanshu.gif)
指针来
![](/icons/46511diaoyong.gif)
外部
![](/icons/46511de.gif)
![](/icons/46511hanshu.gif)
![](/icons/46511dou.gif)
这种动态载入DLL
![](/icons/46511de.gif)
技术可以让我们更灵活
![](/icons/46511de.gif)
![](/icons/46511diaoyong.gif)
外部
![](/icons/46511hanshu.gif)
我们称这种方式为\"从内部
![](/icons/46511diaoyong.gif)
外部
![](/icons/46511de.gif)
![](/icons/46511hanshu.gif)
指针\"
4、不用说
![](/icons/46511dou.gif)
就是我们也可控制\"从外部
![](/icons/46511diaoyong.gif)
外部
![](/icons/46511de.gif)
![](/icons/46511hanshu.gif)
指针\"
![](/icons/46511dou2.gif)
不是没有
![](/icons/46511dou.gif)
比如我们可以加载多个DLL
![](/icons/46511dou.gif)
将其中
![](/icons/46511yi.gif)
个DLL中
![](/icons/46511de.gif)
![](/icons/46511hanshu.gif)
指针传到另
![](/icons/46511yi.gif)
个DLL里
![](/icons/46511de.gif)
![](/icons/46511hanshu.gif)
内
上面所分
![](/icons/46511de.gif)
\"内\"和\"外\"都是相对而言(DLL实际上还是在进程内)
![](/icons/46511dou.gif)
这样分类有助于以后我们谈问题
![](/icons/46511dou.gif)
请记住我上面
![](/icons/46511de.gif)
分类
![](/icons/46511dou.gif)
![](/icons/46511yinwei.gif)
以后
![](/icons/46511de.gif)
文章也会用到这个分类来分析问题
![](/icons/46511hanshu.gif)
指针
![](/icons/46511de.gif)
使用不外乎上面 4种方式
![](/icons/46511dou2.gif)
但在实际使用中却是灵活多变
![](/icons/46511de.gif)
![](/icons/46511dou2.gif)
比如在C
![](/icons/46511jiajia.gif)
里继承和多态
![](/icons/46511dou.gif)
在COM里
![](/icons/46511de.gif)
接口
![](/icons/46511dou.gif)
都是
![](/icons/46511yi.gif)
种叫vTable
![](/icons/46511de.gif)
![](/icons/46511hanshu.gif)
指针表
![](/icons/46511de.gif)
巧妙应用
![](/icons/46511dou2.gif)
使用
![](/icons/46511hanshu.gif)
指针
![](/icons/46511dou.gif)
可以使
![](/icons/46511chengxu.gif)
![](/icons/46511de.gif)
处理方式更加高效、灵活
VB文档里除了介绍过第
![](/icons/46511yi.gif)
方式外
![](/icons/46511dou.gif)
对其它方式都没有介绍
![](/icons/46511dou.gif)
并且还明确指出不支持“Basic 到 Basic”
![](/icons/46511de.gif)
![](/icons/46511hanshu.gif)
指针(也就是上面说
![](/icons/46511de.gif)
第 2种方式)
![](/icons/46511dou.gif)
实际上
![](/icons/46511dou.gif)
通过
![](/icons/46511yi.gif)
定
![](/icons/46511de.gif)
HACK
![](/icons/46511dou.gif)
上面 4种方式均可以实现
![](/icons/46511dou2.gif)
今天
![](/icons/46511dou.gif)
我们就来看看如何来实现第 2种方式
![](/icons/46511dou.gif)
![](/icons/46511yinwei.gif)
实现它相对来说比较简单
![](/icons/46511dou.gif)
我们先从简单
![](/icons/46511de.gif)
入手
![](/icons/46511dou2.gif)
至于如何在VB内
![](/icons/46511diaoyong.gif)
外部
![](/icons/46511de.gif)
![](/icons/46511hanshu.gif)
指针
![](/icons/46511dou.gif)
如何在VB里通过处理vTable接口
![](/icons/46511hanshu.gif)
指针跳转表来实现各种
![](/icons/46511hanshu.gif)
指针
![](/icons/46511de.gif)
巧妙应用
![](/icons/46511dou.gif)
由于这将涉及COM内部原理
![](/icons/46511dou.gif)
我将另文详述
其实VB
![](/icons/46511de.gif)
文档并没有说错
![](/icons/46511dou.gif)
VB
![](/icons/46511de.gif)
确不支持“Basic 到 Basic”
![](/icons/46511de.gif)
![](/icons/46511hanshu.gif)
指针
![](/icons/46511dou.gif)
但是我们可以绕个弯子来实现
![](/icons/46511dou.gif)
那就是先从\"Basic到API\"
![](/icons/46511dou.gif)
然后再用第
![](/icons/46511yi.gif)
种方式\"外部
![](/icons/46511diaoyong.gif)
内部
![](/icons/46511de.gif)
![](/icons/46511hanshu.gif)
指针\"来从\"API到BASIC\"
![](/icons/46511dou.gif)
这样就达到了第 2种方式从\"Basic 到 Basic\"
![](/icons/46511de.gif)
目
![](/icons/46511de.gif)
![](/icons/46511dou.gif)
这种技术我们可以称的为\"强制回调\"
![](/icons/46511dou.gif)
只有VB里才会有这种古怪
![](/icons/46511de.gif)
技术
说得有点绕口
![](/icons/46511dou.gif)
但是仔细想想窗口子类派生技术里CallWindowProc
![](/icons/46511dou.gif)
我们可以用CallWindowProc来强制外部
![](/icons/46511de.gif)
操作系统
![](/icons/46511diaoyong.gif)
我们原来
![](/icons/46511de.gif)
保存
![](/icons/46511de.gif)
窗口
![](/icons/46511hanshu.gif)
指针
![](/icons/46511dou.gif)
同样我们也完全可以用它来强制
![](/icons/46511diaoyong.gif)
我们内部
![](/icons/46511de.gif)
![](/icons/46511hanshu.gif)
指针
呵呵
![](/icons/46511dou.gif)
前面说过要少讲原理多讲招式
![](/icons/46511dou.gif)
现在我们就来开始学习招式吧!
考虑我们在VB里来实现和C里
![](/icons/46511yi.gif)
样支持多关键字比较
![](/icons/46511de.gif)
qsort
![](/icons/46511dou2.gif)
完整
![](/icons/46511de.gif)
源代码见本文配套代码
![](/icons/46511dou.gif)
此处仅给出
![](/icons/46511hanshu.gif)
指针应用相关
![](/icons/46511de.gif)
代码
\'当然少不了
![](/icons/46511de.gif)
CopyMemory
![](/icons/46511dou.gif)
不用ANY
![](/icons/46511de.gif)
版本
Declare Sub CopyMemory Lib \"kernel32\" Alias _
\"RtlMoveMemory\" (ByVal dest As Long, ByVal source As Long, _
ByVal numBytes As Long)
\'嘿嘿
![](/icons/46511dou.gif)
看下面是如何将CallWindowProc
![](/icons/46511de.gif)
声明做成Compare声明
![](/icons/46511de.gif)
Declare Function Compare Lib \"user32\" Alias _
\"CallWindowProcA\" (ByVal pfnCompare As Long, ByVal pElem1 As Long, _
ByVal pElem2 As Long, ByVal unused1 As Long, _
ByVal unused2 As Long) As Integer
\'注:ByVal xxxxx As Long
![](/icons/46511dou.gif)
还记得吧!这是标准
![](/icons/46511de.gif)
指针声明思路方法
\'声明需要比较
![](/icons/46511de.gif)
![](/icons/46511shuzu.gif)
元素
![](/icons/46511de.gif)
结构
Public Type TEmployee
Name As String
Salary As Currency
End Type
\'再来看看我们
![](/icons/46511de.gif)
比较
\'先按薪水比较
![](/icons/46511dou.gif)
再按姓名比较
Function CompareSalaryName(Elem1 As TEmployee, _
Elem2 As TEmployee, _
unused1 As Long, _
unused2 As Long) As Integer
Dim Ret As Integer
Ret = Sgn(Elem1.Salary - Elem2.Salary)
If Ret = 0 Then
Ret = StrComp(Elem1.Name, Elem2.Name, vbTextCompare)
End If
CompareSalaryName = Ret
End Function
\'先按姓名比较
![](/icons/46511dou.gif)
再按薪水比较
Function CompareNameSalary(Elem1 As TEmployee, _
Elem2 As TEmployee, _
unused1 As Long, _
unused2 As Long) As Integer
Dim Ret As Integer
Ret = StrComp(Elem1.Name, Elem2.Name, vbTextCompare)
If Ret = 0 Then
Ret = Sgn(Elem1.Salary - Elem2.Salary)
End If
CompareNameSalary = Ret
End Function
最后再看看我们来看看我们最终
![](/icons/46511de.gif)
qsort
![](/icons/46511de.gif)
声明
Sub qsort(ByVal ArrayPtr As Long, ByVal nCount As Long, _
ByVal nElemSize As Integer, ByVal pfnCompare As Long)
上面
![](/icons/46511de.gif)
ArrayPtr是需要排序
![](/icons/46511shuzu.gif)
![](/icons/46511de.gif)
第
![](/icons/46511yi.gif)
个元素
![](/icons/46511de.gif)
指针
![](/icons/46511dou.gif)
nCount是
![](/icons/46511shuzu.gif)
![](/icons/46511de.gif)
元素个数
![](/icons/46511dou.gif)
nElemSize是每个元素大小
![](/icons/46511dou.gif)
pfnCompare就是我们
![](/icons/46511de.gif)
比较
![](/icons/46511hanshu.gif)
指针
![](/icons/46511dou2.gif)
这个声明和C库
![](/icons/46511hanshu.gif)
里
![](/icons/46511de.gif)
qsort是极为相似
![](/icons/46511de.gif)
和C
![](/icons/46511yi.gif)
样
![](/icons/46511dou.gif)
我们完全可以将Basic
![](/icons/46511de.gif)
![](/icons/46511hanshu.gif)
指针传递给Basic
![](/icons/46511de.gif)
qsort
![](/icons/46511hanshu.gif)
使用方式如下:
Dim Employees(1 To 10000) As TEmployee
\'假设下面
![](/icons/46511de.gif)
![](/icons/46511diaoyong.gif)
对Employees
![](/icons/46511shuzu.gif)
进行了赋值
![](/icons/46511chushi.gif)
化
Call InitArray
\'现在就可以
![](/icons/46511diaoyong.gif)
我们
![](/icons/46511de.gif)
qsort来进行排序了
Call qsort(VarPtr(Employees(1)), UBound(Employees), _
LenB(Employees(1)), AddressOf CompareSalaryName)
\'或者先按姓名排
![](/icons/46511dou.gif)
再按薪水排
Call qsort(VarPtr(Employees(1)), UBound(Employees), _
LenB(Employees(1)), AddressOf CompareNameSalary)
聪明
![](/icons/46511de.gif)
朋友们
![](/icons/46511dou.gif)
你们是不是已经看出这里
![](/icons/46511de.gif)
奥妙了呢?作为
![](/icons/46511yi.gif)
个测验
![](/icons/46511dou.gif)
你能现在就给出在qsort里使用
![](/icons/46511hanshu.gif)
指针
![](/icons/46511de.gif)
思路方法吗?比如现在我们要通过
![](/icons/46511diaoyong.gif)
![](/icons/46511hanshu.gif)
指针来比较
![](/icons/46511shuzu.gif)
![](/icons/46511de.gif)
第i个元素和第j个元素
![](/icons/46511de.gif)
大小
没错
![](/icons/46511dou.gif)
当然要使用前面声明
![](/icons/46511de.gif)
Compare(其实就是CallWindowProc)这个API来进行强制回调
具体
![](/icons/46511de.gif)
实现如下:
Sub qsort(ByVal ArrayPtr As Long, ByVal nCount As Long, _
ByVal nElemSize As Integer, ByVal pfnCompare As Long)
Dim i As Long, j As Long
\'这里省略快速排序算法
![](/icons/46511de.gif)
具体实现
![](/icons/46511dou.gif)
仅给出比较两个元素
![](/icons/46511de.gif)
思路方法
If Compare(pfnCompare, ArrayPtr + (i - 1) * nElemSize, _
ArrayPtr + (j - 1) * nElemSize, 0, 0) > 0 Then
\'如果第i个元素比第j个元素大则用CopyMemory来交换这两个元素
End IF
End Sub
招式介绍完了
![](/icons/46511dou.gif)
明白了吗?我再来简单地讲解
![](/icons/46511yi.gif)
下上面Compare
![](/icons/46511de.gif)
意思
![](/icons/46511dou.gif)
它非常巧妙地利用了CallWindowProc这个API
![](/icons/46511dou2.gif)
这个API需要 5个参数
![](/icons/46511dou.gif)
第
![](/icons/46511yi.gif)
个参数就是
![](/icons/46511yi.gif)
个普通
![](/icons/46511de.gif)
![](/icons/46511hanshu.gif)
指针
![](/icons/46511dou.gif)
这个API能够强马上回调这个
![](/icons/46511hanshu.gif)
指针
![](/icons/46511dou.gif)
并将这个API
![](/icons/46511de.gif)
后 4个Long型
![](/icons/46511de.gif)
参数传递给这个
![](/icons/46511hanshu.gif)
指针所指向
![](/icons/46511de.gif)
![](/icons/46511hanshu.gif)
![](/icons/46511dou2.gif)
这就是为什么我们
![](/icons/46511de.gif)
比较
![](/icons/46511hanshu.gif)
必须要有 4个参数
![](/icons/46511de.gif)
原因
![](/icons/46511dou.gif)
![](/icons/46511yinwei.gif)
CallWindowProc这个API要求传递给
![](/icons/46511de.gif)
![](/icons/46511hanshu.gif)
指针必须符合WndProc
![](/icons/46511hanshu.gif)
原形
![](/icons/46511dou.gif)
WndProc
![](/icons/46511de.gif)
原形如下:
LRESULT (CALLBACK* WNDPROC) (HWND, UINT, WPARAM, LPARAM);
上面
![](/icons/46511de.gif)
LRESULT、HWND、UINT、WPARAM、LPARAM都可以对应于VB里
![](/icons/46511de.gif)
Long型
![](/icons/46511dou.gif)
这真是太好了
![](/icons/46511dou.gif)
![](/icons/46511yinwei.gif)
Long型可以用来作指针嘛!
再来看看工作流程
![](/icons/46511dou.gif)
当我们用AddressOf CompareSalaryName做为
![](/icons/46511hanshu.gif)
指针参数来
![](/icons/46511diaoyong.gif)
qsort时
![](/icons/46511dou.gif)
qsort
![](/icons/46511de.gif)
形参pfnCompare被赋值成了实参CompareSalaryName
![](/icons/46511de.gif)
![](/icons/46511hanshu.gif)
指针
![](/icons/46511dou2.gif)
这时
![](/icons/46511dou.gif)
![](/icons/46511diaoyong.gif)
Compare来强制回调pfnCompare
![](/icons/46511dou.gif)
就相当于
![](/icons/46511diaoyong.gif)
了如下
![](/icons/46511de.gif)
VB语句:
Call CompareSalaryName(ArrayPtr + (i - 1) * nElemSize, _
ArrayPtr + (j - 1) * nElemSize, 0, 0)
这不会引起参数类型不符
![](/icons/46511cuowu.gif)
吗?CompareSalaryName
![](/icons/46511de.gif)
前两个参数不是TEmployee类型吗?
![](/icons/46511de.gif)
确
![](/icons/46511dou.gif)
在VB里这样
![](/icons/46511diaoyong.gif)
是不行
![](/icons/46511de.gif)
![](/icons/46511dou.gif)
![](/icons/46511yinwei.gif)
VB
![](/icons/46511de.gif)
类型检查不会允许这样
![](/icons/46511de.gif)
![](/icons/46511diaoyong.gif)
![](/icons/46511dou2.gif)
但是
![](/icons/46511dou.gif)
实际上这个
![](/icons/46511diaoyong.gif)
是API进行
![](/icons/46511de.gif)
回调
![](/icons/46511dou.gif)
而VB不可能去检查API回调
![](/icons/46511de.gif)
![](/icons/46511hanshu.gif)
![](/icons/46511de.gif)
参数类型是
![](/icons/46511yi.gif)
个普通
![](/icons/46511de.gif)
Long数值类型还是
![](/icons/46511yi.gif)
个结构指针
![](/icons/46511dou.gif)
所以也可以说我们绕过了VB对
![](/icons/46511hanshu.gif)
参数
![](/icons/46511de.gif)
类型检查
![](/icons/46511dou.gif)
我们可以将这个Long型参数声明成任何类型
![](/icons/46511de.gif)
指针
![](/icons/46511dou.gif)
我们声明成什么
![](/icons/46511dou.gif)
VB就认为是什么
![](/icons/46511dou2.gif)
所以
![](/icons/46511dou.gif)
我们要小心地使用这种技术
![](/icons/46511dou.gif)
如上面最终会传递给CompareSalaryName
![](/icons/46511hanshu.gif)
![](/icons/46511de.gif)
参数\"ArrayPtr + (i - 1) * nElemSize\"只不过是
![](/icons/46511yi.gif)
个地址
![](/icons/46511dou.gif)
VB不会对这个地址进行检查
![](/icons/46511dou.gif)
它总是将这个地址当做
![](/icons/46511yi.gif)
个TEmployee类型
![](/icons/46511de.gif)
指针
![](/icons/46511dou.gif)
如果不小心用成了\"ArrayPtr + i * nElemSize\"
![](/icons/46511dou.gif)
那么当i是最后
![](/icons/46511yi.gif)
个元素时
![](/icons/46511dou.gif)
我们就会引起内存越权访问
![](/icons/46511cuowu.gif)
![](/icons/46511dou.gif)
所以我们要和在C里处理指针
![](/icons/46511yi.gif)
样注意边界问题
![](/icons/46511hanshu.gif)
指针
![](/icons/46511de.gif)
巧妙应用这里已经可见
![](/icons/46511yi.gif)
斑了
![](/icons/46511dou.gif)
但是这里介绍
![](/icons/46511de.gif)
思路方法还有很大
![](/icons/46511de.gif)
局限性
![](/icons/46511dou.gif)
我们
![](/icons/46511de.gif)
![](/icons/46511hanshu.gif)
必须要有 4个参数
![](/icons/46511dou.gif)
更干净
![](/icons/46511de.gif)
做法还是在VC或Delphi里写
![](/icons/46511yi.gif)
个DLL
![](/icons/46511dou.gif)
做出更加符合要求
![](/icons/46511de.gif)
API来实现和CallWindowProc相似
![](/icons/46511de.gif)
功能
![](/icons/46511dou2.gif)
我跟踪过CallWindowProc
![](/icons/46511de.gif)
内部实现
![](/icons/46511dou.gif)
它要做许多和窗口消息相关
![](/icons/46511de.gif)
工作
![](/icons/46511dou.gif)
这些工作在我们这个应用中是多余
![](/icons/46511de.gif)
![](/icons/46511dou2.gif)
其实实现强制回调API只需要将后几个参数压栈
![](/icons/46511dou.gif)
再call第
![](/icons/46511yi.gif)
个参数就行了
![](/icons/46511dou.gif)
不过几条汇编指令而已
正是
![](/icons/46511yinwei.gif)
CallWindowProc
![](/icons/46511de.gif)
局限性
![](/icons/46511dou.gif)
我们不能够用它来
![](/icons/46511diaoyong.gif)
外部
![](/icons/46511de.gif)
![](/icons/46511hanshu.gif)
指针
![](/icons/46511dou.gif)
以实现上面说
![](/icons/46511de.gif)
第 3种
![](/icons/46511hanshu.gif)
指针
![](/icons/46511diaoyong.gif)
方式
![](/icons/46511dou2.gif)
要实现第 3种方式
![](/icons/46511dou.gif)
Matt Curland大师提供了
![](/icons/46511yi.gif)
个噩梦
![](/icons/46511yi.gif)
般
![](/icons/46511de.gif)
HACK方式
![](/icons/46511dou.gif)
我们要在VB里凭空构造
![](/icons/46511yi.gif)
个IUnknown接口
![](/icons/46511dou.gif)
在IUnknown接口
![](/icons/46511de.gif)
vTable原有
![](/icons/46511de.gif)
3个入口后再加入
![](/icons/46511yi.gif)
个新入口
![](/icons/46511dou.gif)
在新入口里插入机器代码
![](/icons/46511dou.gif)
这个机器代码要处理掉this指针
![](/icons/46511dou.gif)
最后才能
![](/icons/46511diaoyong.gif)
到我们给
![](/icons/46511de.gif)
![](/icons/46511hanshu.gif)
指针
![](/icons/46511dou.gif)
这个
![](/icons/46511hanshu.gif)
指针无论是内部
![](/icons/46511de.gif)
还是外部
![](/icons/46511de.gif)
都
![](/icons/46511yi.gif)
样没问题
![](/icons/46511dou2.gif)
在我们深入讨论COM内部原理时我会再来谈这个思路方法
另外
![](/icons/46511dou.gif)
排序算法是个见仁见智
![](/icons/46511de.gif)
问题
![](/icons/46511dou.gif)
我本来想
![](/icons/46511dou.gif)
在本文提供
![](/icons/46511yi.gif)
个最通用性能最好
![](/icons/46511de.gif)
算法
![](/icons/46511dou.gif)
这种想法虽好
![](/icons/46511dou.gif)
但是不可能有在任何情况下都“最好”
![](/icons/46511de.gif)
算法
![](/icons/46511dou2.gif)
本文提供
![](/icons/46511de.gif)
用各种指针技术来实现
![](/icons/46511de.gif)
快速排序思路方法
![](/icons/46511dou.gif)
应该比用对象技术来实现同样功能快不少
![](/icons/46511dou.gif)
内存占用也少得多
![](/icons/46511dou2.gif)
可是就是这个已经经过了我不少优化
![](/icons/46511de.gif)
快速排序算法
![](/icons/46511dou.gif)
还是比不了ShellSort
![](/icons/46511dou.gif)
![](/icons/46511yinwei.gif)
ShellSort实现上简单
![](/icons/46511dou2.gif)
从算法
![](/icons/46511de.gif)
理论上来讲qsort应该比ShellSort平均性能好
![](/icons/46511dou.gif)
但是在VB里这不
![](/icons/46511yi.gif)
定(可见本文配套代码
![](/icons/46511dou.gif)
里面也提供了VBPJ
![](/icons/46511yi.gif)
篇专栏
![](/icons/46511de.gif)
配套代码ShellSort
![](/icons/46511dou.gif)
非常得棒
![](/icons/46511dou.gif)
本文
![](/icons/46511de.gif)
思想就取自这个ShellSort)
但是应当指出无论是这里
![](/icons/46511de.gif)
快速排序还是ShellSort
![](/icons/46511dou.gif)
都还可以大大改进
![](/icons/46511dou.gif)
![](/icons/46511yinwei.gif)
它们在实现上需要大量使用CopyMemroy来拷贝数据(这是VB里使用指针
![](/icons/46511de.gif)
缺点的
![](/icons/46511yi.gif)
)
![](/icons/46511dou2.gif)
其实
![](/icons/46511dou.gif)
我们还有更好
![](/icons/46511de.gif)
思路方法
![](/icons/46511dou.gif)
那就是Hack
![](/icons/46511yi.gif)
下VB
![](/icons/46511de.gif)
![](/icons/46511shuzu.gif)
结构
![](/icons/46511dou.gif)
也就是COM自动化里
![](/icons/46511de.gif)
SafeArray
![](/icons/46511dou.gif)
我们可以
![](/icons/46511yi.gif)
次性
![](/icons/46511de.gif)
将SafeArray里
![](/icons/46511de.gif)
各个
![](/icons/46511shuzu.gif)
元素
![](/icons/46511de.gif)
指针放到
![](/icons/46511yi.gif)
个long型
![](/icons/46511shuzu.gif)
里
![](/icons/46511dou.gif)
我们无需CopyMemroy
![](/icons/46511dou.gif)
我们仅需交换Long型
![](/icons/46511shuzu.gif)
里
![](/icons/46511de.gif)
元素就可以达到实时地交换SafeArray
![](/icons/46511shuzu.gif)
元素指针
![](/icons/46511de.gif)
目
![](/icons/46511de.gif)
![](/icons/46511dou.gif)
数据并没有移动
![](/icons/46511dou.gif)
移动
![](/icons/46511de.gif)
仅仅是指针
![](/icons/46511dou.gif)
可以想象这有快多
延伸阅读
- 2010-12-9-- 函数指针,ASP GetRef 函数指针试探
- 2011-6-11-- 指针数组,php数组指针探究
- 2010-12-9-- php数组函数,PHP array_flip() 删除重复数组元素专用函数
- 2010-12-9-- 函数指针数组,约瑟夫环问题的PHP实现 使用PHP数组内部指针操作函数
- 2010-12-9-- php数组函数,php不用内置函数对数组排序的两个算法代码
- 2010-12-9-- php数组函数,支持数组的ADDSLASHES的php函数
- 2010-12-9-- php数组函数,PHP array_push 数组函数
- 2011-6-12-- 指针数组,php数组指针探究二
- 2011-1-4-- c语言函数指针,关于C/C++函数指针
- 2010-12-9-- php数组函数,asp 数组 重复删除函数(脚本之家增强版)
最新评论