Delphi - 从 DLL 修改变量
Delphi - modify variable from DLL
我想制作一个简单的程序,将 Edit1.Text 设置为“6”(例如,但使用 DLL - 这很重要)。这是代码:
单位:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Edit1: TEdit;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
a:integer;
implementation
procedure test; external 'lib.dll' name 'test';
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
test;
Edit1.Text:=Inttostr(a);
end;
end.
和 DLL 文件:
library lib;
uses
Winapi.Windows, System.SysUtils;
var
a:integer;
procedure test;
begin
a:=6;
end;
exports
test;
{$R *.res}
begin
end.
问题是,Edit1.Text 仍然是 0。你能帮帮我吗?
您有两个不同的变量,一个在 DLL 中,一个在可执行文件中。他们都被命名为 a
是偶然的。设置一个对另一个没有影响。
使 DLL 导出 return 值的函数:
function GetValue: Integer; stdcall;
begin
Result := 6;
end;
像这样导入:
function GetValue: Integer; stdcall; external dllname;
并这样称呼它:
Edit1.Text := IntToStr(GetValue);
毫无疑问,真正的代码会比 return 的价值 6
多,但这没问题。你可以return任何你喜欢的。它们的关键点是您使用函数 return 值将值从 DLL 传递到主机。
在您的原始代码的基础上再添加几个按钮,这里演示了您如何可以使用过程(或函数,如果您愿意)并让它们与DLL.
请注意,name
选项不是必需的,除非您希望 更改 函数的名称或使用重载 - 所以我已将其注释掉。
implementation
procedure test(var a : integer); external 'lib.dll' {name 'test'};
procedure test2(ptr_a : pinteger); external 'lib.dll';
procedure test3(ptr_a : pinteger); external 'lib.dll';
procedure test4(ptr_a : pinteger = nil); external 'lib.dll';
{$R *.dfm}
procedure TForm14.Button1Click(Sender: TObject);
begin
test(a);
Edit1.Text:=Inttostr(a);
end;
procedure TForm14.Button2Click(Sender: TObject);
begin
test2(@a);
Edit1.Text:=Inttostr(a);
end;
procedure TForm14.Button3Click(Sender: TObject);
begin
test3(@a);
Edit1.Text:=Inttostr(a);
end;
procedure TForm14.Button4Click(Sender: TObject);
begin
test4(@a);
test4;
Edit1.Text:=Inttostr(a);
end;
end.
...和图书馆正文...
var
local_a:integer;
local_Ptr_a:pinteger;
procedure test(var a : integer);
begin
a:=6;
end;
procedure test2(ptr_a : pinteger);
begin
inc(ptr_a^);
end;
procedure test3(ptr_a : pinteger);
begin
inc(local_a);
ptr_a^:=local_a;
end;
procedure test4(ptr_a : pinteger = nil);
begin
if ptr_a = nil then
inc(local_ptr_a^)
else
local_ptr_a := ptr_a;
end;
exports test;
exports test2;
exports test3;
exports test4;
{$R *.res}
begin
local_a := 4;
end.
所以 - 稍微解释一下。
第一个测试:使用可变参数 return 来自过程的值。没问题。
第二个测试:将接收变量的地址作为指针传递。我在这里添加了一点卷曲 - 增加了娱乐价值……价值。
第三个测试:这显示了如何使用 DLL 拥有的 local 值。 local 值由最后的 4
赋值初始化。该过程本身使用与第二个测试相同的机制来 return 从 DLL 的局部变量到主例程的变量的值。
注意 test3
分配给程序的变量(1 + 存储在 DLL 内存中的值,)因此按下按钮 3 实际上会改变 a
;所以按下按钮 1-2-2-3-2 将使用 3 中的值进行最后一次更改,而不是 prior-value-from-2.
最终测试:在这里我们可以变得更聪明一点。它使用可选参数机制来改变详细操作。
首先你用参数执行程序,参数是的地址(或指向[=60的指针=]) 适当类型的变量。该过程将该地址存储在 DLL 的内存区域中。
接下来您可以使用 无 参数执行该过程,它将递增存储指针指向的整数。纯粹为了方便起见,我在每次按下按钮时都建立了变量的地址,但是一旦存储了地址,该地址是几微秒前还是一周前设置的都没有关系,test4;
将递增该地址的整数值 - 无论它是什么。使用 test4(@b);
设置地址,然后 test4;
将递增 b
- 执行过程时最后指向的整数 和 一个参数。
执行 test4;
而没有在某个时间之前执行 test4(@something)
或者 某些东西 现在超出范围(比如可能是局部变量一个过程)很可能导致访问冲突。
效果不错:
在主单元中
implementation
procedure Test(Edit1: TEdit); stdcall; external 'dll_proj.dll';
在 DLL 中
exports Test;
Procedure Test(Object1: TEdit); stdcall;
var i:integer;
begin
for i:= 0 to 100 do
begin
Object1.Text:= IntToStr(i);
Application.Processmessages();
Sleep(100);
end;
end;
我想制作一个简单的程序,将 Edit1.Text 设置为“6”(例如,但使用 DLL - 这很重要)。这是代码: 单位:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.StdCtrls;
type
TForm1 = class(TForm)
Edit1: TEdit;
Button1: TButton;
procedure Button1Click(Sender: TObject);
private
{ Private declarations }
public
{ Public declarations }
end;
var
Form1: TForm1;
a:integer;
implementation
procedure test; external 'lib.dll' name 'test';
{$R *.dfm}
procedure TForm1.Button1Click(Sender: TObject);
begin
test;
Edit1.Text:=Inttostr(a);
end;
end.
和 DLL 文件:
library lib;
uses
Winapi.Windows, System.SysUtils;
var
a:integer;
procedure test;
begin
a:=6;
end;
exports
test;
{$R *.res}
begin
end.
问题是,Edit1.Text 仍然是 0。你能帮帮我吗?
您有两个不同的变量,一个在 DLL 中,一个在可执行文件中。他们都被命名为 a
是偶然的。设置一个对另一个没有影响。
使 DLL 导出 return 值的函数:
function GetValue: Integer; stdcall;
begin
Result := 6;
end;
像这样导入:
function GetValue: Integer; stdcall; external dllname;
并这样称呼它:
Edit1.Text := IntToStr(GetValue);
毫无疑问,真正的代码会比 return 的价值 6
多,但这没问题。你可以return任何你喜欢的。它们的关键点是您使用函数 return 值将值从 DLL 传递到主机。
在您的原始代码的基础上再添加几个按钮,这里演示了您如何可以使用过程(或函数,如果您愿意)并让它们与DLL.
请注意,name
选项不是必需的,除非您希望 更改 函数的名称或使用重载 - 所以我已将其注释掉。
implementation
procedure test(var a : integer); external 'lib.dll' {name 'test'};
procedure test2(ptr_a : pinteger); external 'lib.dll';
procedure test3(ptr_a : pinteger); external 'lib.dll';
procedure test4(ptr_a : pinteger = nil); external 'lib.dll';
{$R *.dfm}
procedure TForm14.Button1Click(Sender: TObject);
begin
test(a);
Edit1.Text:=Inttostr(a);
end;
procedure TForm14.Button2Click(Sender: TObject);
begin
test2(@a);
Edit1.Text:=Inttostr(a);
end;
procedure TForm14.Button3Click(Sender: TObject);
begin
test3(@a);
Edit1.Text:=Inttostr(a);
end;
procedure TForm14.Button4Click(Sender: TObject);
begin
test4(@a);
test4;
Edit1.Text:=Inttostr(a);
end;
end.
...和图书馆正文...
var
local_a:integer;
local_Ptr_a:pinteger;
procedure test(var a : integer);
begin
a:=6;
end;
procedure test2(ptr_a : pinteger);
begin
inc(ptr_a^);
end;
procedure test3(ptr_a : pinteger);
begin
inc(local_a);
ptr_a^:=local_a;
end;
procedure test4(ptr_a : pinteger = nil);
begin
if ptr_a = nil then
inc(local_ptr_a^)
else
local_ptr_a := ptr_a;
end;
exports test;
exports test2;
exports test3;
exports test4;
{$R *.res}
begin
local_a := 4;
end.
所以 - 稍微解释一下。
第一个测试:使用可变参数 return 来自过程的值。没问题。
第二个测试:将接收变量的地址作为指针传递。我在这里添加了一点卷曲 - 增加了娱乐价值……价值。
第三个测试:这显示了如何使用 DLL 拥有的 local 值。 local 值由最后的 4
赋值初始化。该过程本身使用与第二个测试相同的机制来 return 从 DLL 的局部变量到主例程的变量的值。
注意 test3
分配给程序的变量(1 + 存储在 DLL 内存中的值,)因此按下按钮 3 实际上会改变 a
;所以按下按钮 1-2-2-3-2 将使用 3 中的值进行最后一次更改,而不是 prior-value-from-2.
最终测试:在这里我们可以变得更聪明一点。它使用可选参数机制来改变详细操作。
首先你用参数执行程序,参数是的地址(或指向[=60的指针=]) 适当类型的变量。该过程将该地址存储在 DLL 的内存区域中。
接下来您可以使用 无 参数执行该过程,它将递增存储指针指向的整数。纯粹为了方便起见,我在每次按下按钮时都建立了变量的地址,但是一旦存储了地址,该地址是几微秒前还是一周前设置的都没有关系,test4;
将递增该地址的整数值 - 无论它是什么。使用 test4(@b);
设置地址,然后 test4;
将递增 b
- 执行过程时最后指向的整数 和 一个参数。
执行 test4;
而没有在某个时间之前执行 test4(@something)
或者 某些东西 现在超出范围(比如可能是局部变量一个过程)很可能导致访问冲突。
效果不错:
在主单元中
implementation
procedure Test(Edit1: TEdit); stdcall; external 'dll_proj.dll';
在 DLL 中
exports Test;
Procedure Test(Object1: TEdit); stdcall;
var i:integer;
begin
for i:= 0 to 100 do
begin
Object1.Text:= IntToStr(i);
Application.Processmessages();
Sleep(100);
end;
end;