Delphi是一种基于Pascal的面向对象的可视化程序设计工具,功能强大,编译速度极快,
性能非常卓越。但是在Delphi中,却不像c语言一样能方便地利用函数指针,对已知地址
的函数进行调用。
如在Windows环境中用C语言编程,经常碰到如下形式的函数调用:
…
FARPROC lpGetversion;
http://www.gaodaima.com/?p=65738Delphi的嵌入式汇编语言与Windows函数调用_Delphi
…
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
(′kernel′), ′getversion′);
{GETVERSION 函数在模块 KERNEL中}
{lpGetVersion 存放GETVERSION 的地址}
if lpgetVersion=nil then exit;
label1.caption:=intTostr(selectorof(lpgetversion))
+’:’ +intTostr(offsetof(lpgetversion));{取32位地址的高16位用selectorof}
{取32位地址的低16位用offsetof }
asm {嵌入式汇编语言标记}
call lpgetversion
mov versionLowWord,ax
{ax寄存器放Windows版本号}
mov versionHighWord,dx
{dx寄存器放DOS版本号}
end;
label2.caption:=′Windows Version ′+
intTostr(lobyte(versionLowWord))
+′.′+intTostr(hibyte(versionLowWord)); {取16位 2进制数 的低8位用lowbyte}
{取16位 2进制数 的高8位用hibyte}
label3.caption:=′MS-DOS Version ′+
intTostr(hibyte(versionHighWord))
+′.′+intTostr(lobyte(versionHighWord));
end;
end
欢迎大家阅读《Delphi的嵌入式汇编语言与Windows函数调用_Delphi》,跪求各位点评,若觉得好的话请收藏本文,by 搞代码