怎样把过程(方法)当作参数? 和 DLL 函数的调用 (50分)

  • 主题发起人 onlyonekgx
  • 开始时间
O

onlyonekgx

Unregistered / Unconfirmed
GUEST, unregistred user!
怎样把过程(方法)当作参数? 谢谢!

DLL中的函数可以这样导出:
exports
Function1 index 1,
Function2 index 2;
一般我们都是按名称来调用,
如何按 Index 号来调用 DLL 中的函数呢?
 
以下也许会对你有所帮助:

过程类型

Object Pascal 的另一个独特功能是可定义过程类型。过程类型属于语言的高级功能,Delphi 程序员不会经常用到它。因为后面章节要讨论相关的内容(尤其是“方法指针” Delphi 用得特别多),这里不妨先了解一下。如果你是初学者,可以先跳过这部分,当学到一定程度后再回过头阅读这部分。

Pascal 中的过程类型与C语言中的函数指针相似。过程类型的声明只需要参数列表;如果是函数,再加个返回值。例如声明一个过程类型,该类型带一个通过引用传递的整型参数:

Type
IntProc = procedure (var Num: Integer);

这个过程类型与任何参数完全相同的例程兼容(或用C语言行话来说,具有相同的函数特征)。下面是一个兼容例程:

procedure DoubleTheValue (var Value: Integer);
begin
Value := Value * 2;
end;

注意:在16位Delphi中,如果要将例程用作过程类型的实际值,必须用far指令声明该例程。

过程类型能用于两种不同的目的:声明过程类型的变量;或者把过程类型(也就是函数指针)作为参数传递给另一例程。利用上面给定的类型和过程声明,你可以写出下面的代码:

var
IP: IntProc;
X: Integer;
begin
IP := DoubleTheValue;
X := 5;
IP (X);
end;

这段代码与下列代码等效:

var
X: Integer;
begin
X := 5;
DoubleTheValue (X);
end;

上面第一段代码明显要复杂一些,那么我们为什么要用它呢?因为在某些情况下,调用什么样的函数需要在实际中决定,此时程序类型就很有用。这里不可能建立一个复杂的例子来说明这个问题,不过可以探究一下简单点的例子,该例名为 ProcType。该例比前面所举的例子都复杂,更接近实际应用。

如图 6.3 所示,新建一个工程,在上面放两个 radio 按钮和一个 push 按钮。例中有两个过程,一个过程使参数的值加倍,与前面的 DoubleTheValue 过程相似;另一个过程使参数的值变成三倍,因此命名为 TripleTheValue

图 6.3: 例 ProcType 窗体


procedure TripleTheValue (var Value: Integer);
begin
Value := Value * 3;
ShowMessage ('Value tripled: ' + IntToStr (Value));
end;

两个过程都有结果显示,让我们知道他们已被调用。这是一个简单的程序调试技巧,你可以用它来检测某一代码段是否或何时被执行,而不用在代码中加断点。

当用户按Apply 按钮,程序会根据 radio 按钮状态选择执行的过程。实际上,当窗体中有两个 radio 按钮时,你只能选择一个,因此你只需要在 Apply 按钮的 OnClick 事件中添加代码检测 radio 按钮的值,就能实现程序要求。不过为了演示过程类型的使用,我舍近求远选择了麻烦但有趣的方法:只要用户选中其中一个 radio 按钮,按钮对应的过程就会存入过程变量:

procedure TForm1.DoubleRadioButtonClick(Sender: TObject);
begin
IP := DoubleTheValue;
end;

当用户按Apply 按钮,程序就执行过程变量保存的过程:

procedure TForm1.ApplyButtonClick(Sender: TObject);
begin
IP (X);
end;

为了使三个不同的函数能访问 IP 和 X 变量,需要使变量在整个窗体单元中可见,因此不能声明为局部变量(在一个方法中声明)。一个解决办法是,把这些变量放在窗体声明中:

type
TForm1 = class(TForm)
...
private
{ Private declarations }
IP: IntProc;
X: Integer;
end;

学完下一章,你会更清楚地了解这段代码的意思,目前只要能知道怎样添加过程类型定义、怎样修改相应的代码就行了。为了用适当的值初始化上面代码中的两个变量,你可以调用窗体的 OnCreate 事件(激活窗体后,在 Object Inspector 中选择这一事件,或者双击窗体)。此外最好仔细看一看上例完整的源代码。
 
以下是乱弹。看看代码。实在想不到这样做有什么好处。

type
TTest = function(const s: string): integer;

function Test(const s: string='0'): integer;
begin
try
result := StrToInt(s);
except
result := 0;
end;
end;

function TestEx(s: string; t: TTest): boolean;
begin
if t(s)=0 then
result := false
else
result := true;
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
if TestEx('1',Test) then
showmessage('1');
if TestEx('a',Test) then
showmessage('0');
end;
 
这就是所谓的回调函数(过程)。
 
呵呵,那你干吗要通过index  调用呢?
 
1.dll中的回调函数:
举个例子:

DLL中:
type
TCallBackFunc = procedure(x,y: integer);stdcall;

var
CallBackFunc: TCallBackFunc;

//赋值接口
procedure SetCallBackFunc(Func: TCallBackFunc);stdcall;
begin
CallBackFunc := Func;
end;

DLL中调用:
if assigned(CallBackFunc) then CallBackFunc(CommonData.MousePos.x,CommonData.MousePos.y);
---------------------------
外部调用程序:

type
TCallBackFunc = procedure(x,y: integer);stdcall;

procedure SetCallBackFunc(Func: TCallBackFunc);stdcall; external '../mousehook.dll';

procedure MyCallBack(x,y: integer);stdcall;
begin
Form1.Caption := format('%d:%d',[x,y]);
end;

//赋值
SetCallBackFunc(MyCallBack);

2.按 Index 号来调用 DLL 中的函数
举个例子:
function SHFindComputer(pidlRoot: PItemIDList; pidlSavedSearch: PItemIDList): Boolean;
stdcall; external 'Shell32.dll' index 91;
 
不好意思,我说的是动态调用
怎么通过 index 来调用,
我想通过 index 号来遍历 DLL
中的所有导出函数
 
FARPROC GetProcAddress(
HMODULE hModule, // handle to DLL module
LPCSTR lpProcName // name of function
);

Parameters
hModule
Handle to the DLL module that contains the function. The LoadLibrary or
GetModuleHandle function returns this handle.
lpProcName
Pointer to a null-terminated string containing the function name, or specifies
~~~~~~~~~~~~
the function's ordinal value. If this parameter is an ordinal value, it must
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
be in the low-order word; the high-order word must be zero.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 
to 楼主
您能把DLL调用的一个例程发给我吗?我调用DLL里的子窗体时,子窗体接收不到TAB与Enter键!
能帮我解决吗?
DinkySoft@163.com
 
多人接受答案了。
 
顶部