Delphi - 从DLL修改变量

时间:2015-01-03 04:08:37

标签: delphi delphi-xe

我想创建一个简单的程序,将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.你能帮助我吗?

3 个答案:

答案 0 :(得分:1)

您有两个不同的变量,一个在DLL中,另一个在可执行文件中。他们都被命名为a是偶然的。设置一个对另一个没有影响。

使DLL导出一个返回值的函数:

function GetValue: Integer; stdcall;
begin
  Result := 6;
end;

像这样导入:

function GetValue: Integer; stdcall; external dllname;

并称之为:

Edit1.Text := IntToStr(GetValue);

毫无疑问,真正的代码所做的不仅仅是返回值6,但这没有问题。你可以退回任何你喜欢的东西。它们的关键点是使用函数返回值将值从DLL传递给主机。

答案 1 :(得分:0)

效果很好:

在MainUnit中

 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;

答案 2 :(得分:-2)

在您的原始代码的基础上添加更多按钮,这里演示了如何使用过程(或者您喜欢的功能)并让它们与 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.

所以 - 稍微解释一下。

首先测试:使用var-parameter从过程返回一个值。没问题。

第二次测试:将接收变量的地址作为指针传递。我在这里添加了一点卷曲 - 增加娱乐价值,......值。

第三项测试:显示如何使用 DLL 拥有的本地值。 local 值由最后4的赋值初始化。该过程本身使用与第二个测试相同的机制将DLL的局部变量中的值返回到主例程的变量。

注意test3分配给程序的变量(1 +存储在DLL内存中的值),因此按下button3实际上会改变a;所以按下按钮1-2-2-3-2将使用3中的值作为最后一次更改,而不是前一个值来自2。

最终测试:我们可以更聪明一点。它使用可选参数机制来改变详细操作。

首先,使用参数执行过程,作为地址(或指向的指针)相应类型的变量。该过程将该地址存储在DLL的内存区域中。

接下来,您可以使用 no 参数执行该过程,它将递增存储指针所指向的整数。纯粹为了方便起见,我已经在每个按钮上建立了变量的地址,但是一旦存储了地址,无论该地址是在几微秒前还是在一周内设置,test4;都会增加该地址的整数值 - 无论它是什么。使用test4(@b);设置地址,然后test4;将递增b - 使用参数执行过程时最后指向的整数。

执行test4;而没有在某个时间之前执行test4(@something)某些现在超出范围(可能是程序中的局部变量)非常可能会导致访问冲突。