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;