问题描述
.dll文件产生/终止线程,每一秒产生一个随机数,然后用回调函数显示在edit上
考点
- 计时器控件
Timer1: TTimer;
procedure TForm1.Timer1Timer(Sender: TObject);
可以控制刷新时间、是否开始,事件中,选择OnTimer后面的空白处,双击。进去后写定时器到点触发后的代码
- 随机函数
//指定范围的随机数函数
function Rand(min,max:Integer):Integer;
begin
randomize;//初始化
Result:=random(max) mod (max-min+1)+min;
end;
//调用
Rand(100,1000);
显示结果是100~1000之间的随机数
- 调用函数作为另一个函数的参数
type
TFunc = function(): String of object;
TFunc1 = procedure(a: Integer) of object;
add(f: TFunc)
- 回调函数
procedure TForm1.abc;
begin
showmessage('这是回调函数测试');
end;
procedure TForm1.Button1Click(Sender: TObject);
begin
myTest(abc);
end;
function TForm1.myTest(f:TFunc):string;
begin
f();
end;
- DLL文件生成
function MyDllFunc(x:integer):integer;stdcall;
begin
Result := x*x;
end;
exports
MyDllFunc ;
静态调用
implementation
{$R *.dfm}
function MyDllFunc(x:integer):integer;stdcall;
external 'Project2.dll'
procedure TForm1.Button1Click(Sender: TObject);
begin
Edit2.Text := inttostr(MyDllFunc(strToint(Edit1.Text)));
end;
动态调用
implementation
{$R *.dfm}
type
Test = function (x:integer):Integer; stdcall;
procedure TForm1.Button1Click(Sender: TObject);
var
myDiaoYong:TmyDiaoYong;
begin
MyTest:=Test(GetProcAddress(Loadlibrary('Project2.dll') ,'MyDllFunc') );
Edit2.Text := inttostr(MyTest (strToint(Edit1.Text)));
FreeLibrary(Loadlibrary('Project2.dll') ;
end;
end.
- 线程创建
线程唤醒和挂起、构造以及执行函数的重写 - 类库使用
这里用到的—TThread线程类,是一个基类 ,而有一些类以及是继承类,比如TList,线程队列类,就像是一个已经写好的线程池
无论是基类还是一个继承类,再使用的时候:
如果需要添加新成员,就继承过来,创建一个继承类,再使用的时候就要创建对象了,创建对象的时候只是一个声明,对象是需要实例化的
1)创建继承类(类型)
需要注意的是,继承过来的类里,如果有抽象函数就需要重写的,就好比这个线程类里的exec函数,就必须重写
2)建类对象
3)对象需要实例化
解题过程
- 主程序
(1)edit
(2)bottom——start按钮
(3)回调函数——display - .dll文件
(1)线程开启/关闭函数
(2)线程执行函数——随机数产生
(3)回调处理函数——把产生的随机数作为参数传给回调函数 - 描述
按下start按钮后 , 产生线程,线程每一秒产生一个随机数,并且在edit上显示出来,由于线程的产生和随机数的产生是在.dll内,不能直接使用控件,只能把产生的随机数传出来给主程序显示,传出来的方式有两种,一个是通过普通函数传出,在主程序内还要不断的扫描是否有值传出;另外一种就是使用回调函数,把显示程序函数的地址传给回调处理函数,在.dll内就可以使用显示程序函数了,也避免了一直扫描。也就是说,.dll中什么时候产生随机数,就什么时候调用显示函数
代码实现
.dll
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls; //把常用部分加进来
type //在type下的都是类型
MyThread = class(TThread) //线程类:TTread,继承这个类,产生这个类的对象从而使用它
procedure Execute; override; //线程执行函数,把要重写的放进类里来 ,重写
end;
//导出函数——声明后加stdcall
PointToFunc = function (num : Integer) : Integer;//(这只是个类型)函数指针类型(要和回调函数相同)
function CreateThread(StartFlag : BOOL) : Integer; stdcall; //线程开启/关闭函数
function CallBack(Func : PointToFunc) : Integer; stdcall; //回调处理函数——把回调函数的地址传进来。
var //上面的是类型,这里才是定义对象
thread : MyThread; //创建类对象
CallFunc : PointToFunc; //函数指针对象
implementation
procedure MyThread.Execute; //MYThread的函数,要加类
var
num : Integer;
begin
while not Suspended do //挂起标志,在TTheard内的
begin
Randomize;
num := Trunc(Random(100)); //随机数产生
CallFunc(num); //调用回调函数 CallFunc(num) --> Func(num) --->dispaly(num)
Sleep(1000);
end;
end;
function CreateThread(StartFlag : BOOL) : Integer; stdcall;
begin
if thread = nil then
thread := MyThread.Create(True);//实例化
if StartFlag = True then
begin
thread.Resume; //唤醒线程
end
else
begin
thread.Suspend; //挂起线程
end;
end;
function CallBack(Func : PointToFunc) : Integer; stdcall;
begin
CallFunc := Func; //地址传递
end;
end.
.pas
unit Unit1;
interface
uses
Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls;
type
TForm1 = class(TForm)
Edit: TEdit;
Start: TButton;
procedure FormCreate(Sender: TObject);
procedure StartClick(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
StartFlag : BOOL; //按键标志:true :打开 false : 关闭
end;
//导入动态库中的函数 ——加external '*.dll(库名)' name '新名'
PointToFunc = function (num : Integer) : Integer;
function CreateThread(StartFlag : BOOL) : Integer; stdcall;external 'randomthread.dll' name 'CreateThread';
function CallBack(Func : PointToFunc) : Integer; stdcall;external 'randomthread.dll' name 'CallBack';
function display(num : Integer) : Integer;
var
Form1: TForm1;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject);
begin
StartFlag := True;
CallBack(display); //一开始就导入回调函数的地址 ,函数名可以就直接当地址传入
end;
procedure TForm1.StartClick(Sender: TObject);
begin
if StartFlag = True then
begin
CreateThread(True);
StartFlag := False; //按键切换
end
else
begin
CreateThread(False);
StartFlag := True;
end;
end;
function display(num : Integer) : Integer;
begin
Form1.Edit.Text := IntToStr(num); //显示 ,因为是全局的,所以要加上
end;
end.