Delphi是一种基于Pascal的面向对象的可视化
程序设计工具,功能强大,编译速度极快,
性能非常卓越。但是在Delphi中,却不像C语言一样能方便地利用函数指针,对已知地址
的函数进行调用。
如在Windows环境中用C语言编程,经常碰到如下形式的函数调用:
FARPROC lpGetversion;
lpGetversion=GetProcAddress(hinst,"getVersion");
(*lpGetversion)();
而在Delphi中,对用GetProcAddress获得的32位函数地址,如果采用类似C语言的
形式调用函数指针,便会在编译时碰到错误,根本无法通过。如:
例1 直接地址调用,错误是91号;
lpGetversion; { error 91 ″:=″ expected}
例2 带空参数直接地址调用,错误是91号;
lpGetversion(); { error 91 ″:=″ expected}
例3 间接地址调用,错误是43号;
lpGetversion^; { error 43 iiiegal assignment}例4 带空参数间接地址调用,错误是43号;
(lpGetversion^)(); { error 43 iiiegal assignment}
在Windows系统的编程实践中,如钩子(HOOK)函数的编写和某些未公开的函数的
调用等,必须用函数指针来调用函数,那么该怎么调用呢?
答案是必须采用嵌入式汇编语言来调用函数指针,因为在Delphi的Help中,明确指
出:The only use for procedural pointer is to pass it to an assembly language routine or to use it in
a inline statement。所以,如果我们获得了DLL中的函数地址,想利用它来调用该函数,只
需在程序中插入一小段很简单的汇编
程序,就能调用了。举例如下:
var {声明函数指针lpGetVersion}
lpGetVersion :TFARPROC;
lpGetVersion:=getProcAddress(GetModuleHandle(′kernel′),′getversion'');
if lpGetVersion=nil then exit; {获得模块kernel 中的函数getVersion的指针lpGetVersion}
.
asm {用汇编形式调用函数getVersion}
call lpGetVersion {不用; 用; 也可以}
end;
现举一个简单的例子,在按钮上单击一下,利用汇编语言调用getversion函数得到
Windows和DOS 的版本号:
unit Getveru;
interface
uses
SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
Forms, Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Button1: TButton;
Label1: TLabel;
Label2: TLabel;
Label3: TLabel;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{R *.DFM}
procedure TForm1.Button1Click(Sender: TObject);
var
lpGetVersion:TFARPROC;
version:longint;
versionLowWord:word;
versionHighWord:word;
begin
lpGetVersion:=getprocAddress(GetModuleHandle
(′