2014-02-15 85 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'不能用作函數返回值? –