'当然少不了的CopyMemory,不用ANY的版本。 Declare Sub CopyMemory Lib "kernel32" Alias _ "RtlMoveMemory" (ByVal dest As Long, ByVal source As Long, _ ByVal numBytes As Long)
'嘿嘿,看下面是如何将CallWindowProc的声明做成Compare声明的。 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 ,还记得吧!这是标准的指针声明方法。
'声明需要比较的数组元素的结构 Public Type TEmployee Name As String Salary As Currency End Type
'再来看看我们的比较函数 '先按薪水比较,再按姓名比较 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
'先按姓名比较,再按薪水比较 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 最后再看看我们来看看我们最终的qsort的声明。
Sub qsort(ByVal ArrayPtr As Long, ByVal nCount As Long, _ ByVal nElemSize As Integer, ByVal pfnCompare As Long) 上面的ArrayPtr是需要排序数组的第一个元素的指针,nCount是数组的元素个数,nElemSize是每个元素大小,pfnCompare就是我们的比较函数指针。这个声明和C库函数里的qsort是极为相似的。
和C一样,我们完全可以将Basic的函数指针传递给Basic的qsort函数。
使用方式如下:
Dim Employees(1 To 10000) As TEmployee '假设下面的调用对Employees数组进行了赋值初始化。 Call InitArray() '现在就可以调用我们的qsort来进行排序了。 Call qsort(VarPtr(Employees(1)), UBound(Employees), _ LenB(Employees(1)), AddressOf CompareSalaryName) '或者先按姓名排,再按薪水排 Call qsort(VarPtr(Employees(1)), UBound(Employees), _ LenB(Employees(1)), AddressOf CompareNameSalary) 聪明的朋友们,你们是不是已经看出这里的奥妙了呢?作为一个测验,你能现在就给出在qsort里使用函数指针的方法吗?比如现在我们要通过调用函数指针来比较数组的第i个元素和第j个元素的大小。
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 '这里省略快速排序算法的具体实现,仅给出比较两个元素的方法。 If Compare(pfnCompare, ArrayPtr + (i - 1) * nElemSize, _ ArrayPtr + (j - 1) * nElemSize, 0, 0) > 0 Then '如果第i个元素比第j个元素大则用CopyMemory来交换这两个元素。 End IF End Sub 招式介绍完了,明白了吗?我再来简单地讲解一下上面Compare的意思,它非常巧妙地利用了CallWindowProc这个API。这个API需要五个参数,第一个参数就是一个普通的函数指针,这个API能够强马上回调这个函数指针,并将这个API的后四个Long型的参数传递给这个函数指针所指向的函数。这就是为什么我们的比较函数必须要有四个参数的原因,因为CallWindowProc这个API要求传递给的函数指针必须符合WndProc函数原形,WndProc的原形如下: