我第一次调用DLL

Dri*_*t89 2 delphi dll

我变得疯了.

我是初学者,我想制作我的第一个DLL.我遵循了这个指南:

http://www.tutorialspoint.com/dll/dll_delphi_example.htm

我想设置一个关于程序版本的文本信息,并在我想要的时候阅读它,所以通过主应用程序将它显示给用户.这只是保持对DLL的信心的一个例子,我已经知道有很多其他方法可以实现这一点.

现在我试图从这样的DLL中读取变量"versione":

library Clientdll;


 uses SysUtils, Classes, Dialogs;

{$R *.res}


function Versione(var messaggio, versione: String):string; export; stdcall;
begin
  versione:='Nessun dato ricavato. Valore di chiamata alla DLL errato!';
  if messaggio='chiama' then  versione:='v4.0.0 build 31';
end;

exports versione;

begin
end.
Run Code Online (Sandbox Code Playgroud)

在主应用程序中我写了这个:

[...]

implementation

uses unit2;

{$R *.dfm}
function Versione(var messaggio, versione:string):string; stdcall; external 'Clientdll.dll'
Run Code Online (Sandbox Code Playgroud)

[...]

现在我说'好吧,我只是要调用DLL而这就是......'.所以:

procedure TForm1.Button1Click(Sender: TObject);
var x, y:string;
begin
 x:='chiama';
 Versione(x,y);
 showmessage(y);
end;
Run Code Online (Sandbox Code Playgroud)

我可以在对话框中阅读v4.0.0 build 31,但是当我按OK时我收到此错误:

"无效的指针操作".

有任何想法吗?

我试着谷歌,但我的英语很差,一些答案很难理解,也有翻译工具!

Ken*_*ite 6

不要String用作参数类型.在File->New->Other->Delphi Projects->DLL Wizard用于创建新DLL 时IDE生成的注释中清楚地解释了这一点:

{关于DLL内存管理的重要说明:如果您的DLL导出任何将字符串作为参数或函数结果传递的过程或函数,则ShareMem必须是库的USES子句和项目(选择项目 - 视图源)USES子句中的第一个单元.这适用于传递到DLL或从DLL传递的所有字符串 -即使是嵌套在记录和类中的字符串.ShareMem是BORLNDMM.DLL共享内存管理器的接口单元,必须与DLL一起部署.要避免使用BORLNDMM.DLL,请使用PChar或ShortString参数传递字符串信息.}

此外,使用Delphi字符串意味着您的DLL函数不能从其他语言(如C)调用.

您还应该期望调用应用程序为您提供放置结果的内存(以及一个长度参数,告诉您内存缓冲区的大小).

这是一个带有单个函数的Delphi dll的最小(相当无用)示例,以及一个调用它的测试应用程序.(正如我所说,DLL是没有意义的.任何实际的DLL都应该设计为将功能代码放在它自己的单元而不是项目文件中.)

示例DLL源:

library SimpleTest;

{ Important note about DLL memory management: ShareMem must be the
  first unit in your library's USES clause AND your project's (select
  Project-View Source) USES clause if your DLL exports any procedures or
  functions that pass strings as parameters or function results. This
  applies to all strings passed to and from your DLL--even those that
  are nested in records and classes. ShareMem is the interface unit to
  the BORLNDMM.DLL shared memory manager, which must be deployed along
  with your DLL. To avoid using BORLNDMM.DLL, pass string information
  using PChar or ShortString parameters. }

uses
  SysUtils,
  Classes;

{$R *.res}

// Parameters:
//   arg:    Argument that indicates whether this is a test or
//           something else, so we know which value to return
//   Buffer: The space in which to place the result
//   Len:    The length of the buffer provided
function TestDLL(const arg: PChar; const Buffer: PChar; 
  const Len: Integer): Boolean; stdcall;
begin
  // Make sure we use the Len parameter, so we don't overflow
  // the memory we were given. StrLCopy will copy a maximum of
  // Len characters, even if the length of the string provided
  // as the 'source' parameter is longer.
  if arg = 'Test' then
    StrLCopy(Buffer, 'Test result', Len)   
  else
    StrLCopy(Buffer, 'Non-test result', Len);
  Result := True;
end;

exports
  TestDll;

begin

end.
Run Code Online (Sandbox Code Playgroud)

调用它的测试应用程序的表单:

unit DLLTestForm;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;

var
  Form4: TForm4;

implementation

{$R *.dfm}

function TestDLL(const arg: PChar; const Buffer: PChar; const Len: Integer): Boolean; stdcall;
  external 'SimpleTest.dll';

procedure TForm4.Button1Click(Sender: TObject);
var
  Parm1: String;
  Parm2: String;
  BuffLen: Integer;
begin
  Parm1 := 'Test';
  // Length of buffer (including null terminator) for DLL call
  // Chosen arbitrarily - I know the DLL won't return more than 15 + the
  // null. I'm pretending I don't, though, and allowing extra space. The
  // DLL won't return more than 30 characters, even if it has more to say,
  // because it uses StrLCopy to limit the result to Len characters.
  BuffLen := 30;

  // Allocate space for return value
  SetLength(Parm2, BuffLen);

  // Call the DLL with `Test` arg
  if TestDLL(PChar(Parm1), PChar(Parm2), BuffLen) then
    ShowMessage(Parm2);

  // Call the DLL with a different parameter value
  Parm1 := 'Other';
  if TestDLL(PChar(Parm1), PChar(Parm2), BuffLen) then
    ShowMessage(Parm2);
end;

end.
Run Code Online (Sandbox Code Playgroud)