选择显示字体大小

visual basic变态用法之函数指针

一、函数指针

addressof得到一个vb内部的函数指针,我们可以将这个函数指针传递给需要回调这个函数的api,它的作用就是让外部的程序可以调用vb内部的函数。

但是vb里函数指针的应用,远不象c里应用那么广泛,因为vb文档里仅介绍了如何将函数指针传递给api以实现回调,并没指出函数指针诸多神奇的功能,因为vb是不鼓励使用指针的,函数指针也不例外。

首先让我们对函数指针的使用方式来分个类。

1、回调。这是最基本也是最重要的功能。比如vb文档里介绍过的子类派生技术,它的核心就是两个api:setwindowlong和callwindowproc。

我们可以使setwindowlong这个api来将原来的窗口函数指针换成自己的函数指针,并将原来的窗口函数指针保存下来。这样窗口消息就可以发到我们自己的函数里来,并且我们随时可以用callwindowproc来调用前面保存下来的窗口指针,以调用原来的窗口函数。这样,我们可以在不破坏原有窗口功能的前提下处理钩入的消息。

具体的处理,我们应该很熟悉了,vb文档也讲得很清楚了。这里需要注意的就是callwindowproc这个api,在后面我们将看到它的妙用。

在这里我们称回调为让"外部调用内部的函数指针"。

2、程序内部使用。比如在c里我们可以将c函数指针作为参数传递给一个需要函数指针的c函数,如后面还要讲到的c库函数qsort,它的声明如下:

#define int (__cdecl *compare)(const void *elem1, const void *elem2)
void qsort(void *base, size_t num, size_t width,
compare pfncompare);

它需要一个compare类型函数指针,用来比较两个变量大小的,这样排序函数可以调用这个函数指针来比较不同类型的变量,所以qsort可以对不同类型的变量数组进行排序。

我们姑且称这种应用为"从内部调用内部的函数指针"。

3、调用外部的函数

也许你会问,用api不就是调用外部的函数吗?是的,但有时候我们还是需要直接获取外部函数的指针。比如通过loadlibrary动态加载dll,然后再通过getprocaddress得到我们需要的函数入口指针,然后再通过这个函数指针来调用外部的函数,这种动态载入dll的技术可以让我们更灵活的调用外部函数。

我们称这种方式为"从内部调用外部的函数指针"

4、不用说,就是我们也可控制"从外部调用外部的函数指针"。不是没有,比如我们可以加载多个dll,将其中一个dll中的函数指针传到另一个dll里的函数内。

上面所分的"内"和"外"都是相对而言(dll实际上还是在进程内),这样分类有助于以后我们谈问题,请记住我上面的分类,因为以后的文章也会用到这个分类来分析问题。

函数指针的使用不外乎上面四种方式。但在实际使用中却是灵活多变的。比如在c++里继承和多态,在com里的接口,都是一种叫vtable的函数指针表的巧妙应用。使用函数指针,可以使程序的处理方式更加高效、灵活。

vb文档里除了介绍过第一方式外,对其它方式都没有介绍,并且还明确指出不支持“basic 到 basic”的函数指针(也就是上面说的第二种方式),实际上,通过一定的hack,上面四种方式均可以实现。今天,我们就来看看如何来实现第二种方式,因为实现它相对来说比较简单,我们先从简单的入手。至于如何在vb内调用外部的函数指针,如何在vb里通过处理vtable接口函数指针跳转表来实现各种函数指针的巧妙应用,由于这将涉及com内部原理,我将另文详述。

其实vb的文档并没有说错,vb的确不支持“basic 到 basic”的函数指针,但是我们可以绕个弯子来实现,那就是先从"basic到api",然后再用第一种方式"外部调用内部的函数指针"来从"api到basic",这样就达到了第二种方式从"basic 到 basic"的目的,这种技术我们可以称之为"强制回调",只有vb里才会有这种古怪的技术。

说得有点绕口,但是仔细想想窗口子类派生技术里callwindowproc,我们可以用callwindowproc来强制外部的操作系统调用我们原来的保存的窗口函数指针,同样我们也完全可以用它来强制调用我们内部的函数指针。

呵呵,前面说过要少讲原理多讲招式,现在我们就来开始学习招式吧!

考虑我们在vb里来实现和c里一样支持多关键字比较的qsort。完整的源代码见本文配套代码,此处仅给出函数指针应用相关的代码。

'当然少不了的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是极为相似的。


 


关键字 本文所属关键字

相关 与本文相关文章

分类 所有文章关键字导航

源码编程相关

Java   Asp   PHP   .Net   XML   C/C++   CGI   VB   Jsp   J2ee   J2se   J2me   EJB   Servlet   Tomcat   Resin   Struts   Weblogic   Eclipse   ANT   GUI   JMS   Web servise   IDEA   Webphere   Hibernate   Spring   Jboss   Applet   Swing   Socket   Javamail   Perl   Ajax   P2P   安全   模式   框架   测试   开源   游戏

SQL数据库相关

My-SQL   Ms-SQL   Access   DB2   Oracle   Sybase   SQLserver   索引   存储过程   加密   数据库   分页   视图  

手机无线相关

3G   Wap   CDMA   GRPS   GSM   IVR   彩信   短信   无线   增值业务

网页设计制作相关

HTML   CSS   网页配色   网页特效   Javascript   VBscript   Dreamweaver   Frontpage   JS   Web   网站设计

网站建设推广相关

建站经验   网站优化   网站排名   推广   Alexa

操作系统/服务器相关

Windows XP   Windows 2000   Windows 2003   Windows Me   Windows 9.x   Linux   UNIX   注册表   操作系统   服务器   应用服务器

图形图像多媒体相关

Photoshop   Fireworks   Flash   Coreldraw   Illustrator   Freehand   Photoimpact   多媒体   图形图像

标准 网站致力的规范

Valid CSS!

无不良内容,无不良广告,无恶意代码

Valid XHTML 1.0 Transitional

creativecommons