2014-02-15 89 views
2

我变得疯了。我第一次打电话给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. 

在主应用程序,我已经写:

[...]

implementation 

uses unit2; 

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

[...]

现在我说 'OK,我只是调用DLL,这一切......'。所以:

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

我可以读V4.0.0在对话框中建立31,但是当我按OK我已经收到此错误:

“无效的指针操作”。

任何想法?

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

+1

如果使用'文件 - >新建 - >其它 - > DLL wizard'到创建你的DLL shell,IDE会插入一个非常重要的注释:“{关于DLL内存管理的重要注意事项:** ShareMem必须是库的USES子句中的第一个单元,并且你的项目(选择Project-View Source)USES子句,如果你的DLL导出任何传递字符串的过程或函数作为参数或函数结果环传递给你的DLL ** ... **为了避免使用BORLNDMM.DLL,使用PChar或ShortString参数传递字符串信息。**}“不要使用** string **参数。 –

+0

你说得对。谢谢!但是现在,当我尝试退出应用程序时收到异常: 运行时错误217在0041470C – Drift89

+0

请参阅下面的答案。 –

回答

6

请勿使用String作为参数类型。这是在注释清楚解释说,当你使用File->New->Other->Delphi Projects->DLL Wizard创建一个新的DLL IDE生成:

{ 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. }

此外,采用Delphi字符串意味着你的DLL函数不是从其他语言如C

调用

您还应该期待调用应用程序为您提供放置结果的内存(以及一个指示内存缓冲区有多大的长度参数)。

这是一个Delphi函数的简单(完全没用)的例子,它带有一个函数,还有一个调用它的测试应用程序。 (正如我所说的,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. 

形式的测试应用程序调用它:

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. 
+0

感谢您的帮助。我试过你的代码,它工作正常。我在这个恶魔的DDL开头:D – Drift89

+0

这是一个很好的答案。如果你想要便宜又简单的方法,你可以使用WideString并利用共享的COM堆。但不要将WideString用作函数返回值。必须out或var参数。 –

+0

@DavidHeffernan为什么'WideString'不能用作函数返回值? –