2011-07-01 73 views
0

我的DLL可能會發送多個結果/返回值來執行一次拍攝。我仍然不明白如何使回調函數,使DLL可以與主機應用程序通信。調用具有多個返回值的DLL函數

這裏的情景:

應用:

type 
    TCheckFile = function(const Filename, var Info, Status: string): Boolean; stdcall; 

var 
    CheckFile: TCheckFile; 
    DLLHandle: THandle; 

Procedure Test; 
var 
Info,Status : string; 
begin 
.... 
// load the DLL 
DLLHandle := LoadLibrary('test.dll'); 
    if DLLHandle <> 0 then 
    begin 
     @CheckFile := GetProcAddress(DLLHandle, 'CheckFile'); 
     if Assigned(CheckFile) then 
     beep 
     else 
     exit; 
    end; 

// use the function from DLL 
if Assigned(CheckFile) then 
    begin 
    if CheckFile(Filename, Info, Status) then 
    begin 
    AddtoListView(Filename, Info, Status); 
    end; 
    end; 
... 
end; 

DLL:

function CheckFile(const Filename, var Info,Status: string): Boolean; stdcall; 
    var 
    Info, Status: string; 
    begin 
    if IsTheRightFile(Filename, Info,Status) then 
    begin 
     result := true; 
     exit; 
    end 
    else 
    begin 
     if IsZipFile then 
     begin 
     // call function to extract the file 
     ExtractZip(Filaname); 
     // check all extracted file 
     for i := 0 to ExtractedFileList.count do 
     begin 
      IsTheRightFile(ExtractedFile, Info, Status) then 
      // how to send the Filename, Info and Status to exe ?? // << edited 
      // SendIpcMessage('checkengine', pchar('◦test'), length('◦test') * SizeOf(char)); error! 
      // "AddtoListView(Filename, Info);" ??? 
     end; 
     end; 
    end; 
    end; 

其實我還是從代碼中得到一個錯誤之上。所以在我的情況下,我需要你的幫助來解釋和確定從DLL發送數據到appp的正確方式是什麼。

+0

GetProcAddress的(DLLHandle, 'CheckFile'); - 它是否會返回有效的句柄?你沒有忘記在進口部分指定你的dll功能嗎? – heximal

+0

你的意思是'Info'和'Status'而不是'Info'和'Filename'?因爲'Filename'是'const'並且不能被表達。要修改'Info'和'Status',你需要在你的DLL函數中爲它設置一個值。請注意,如果不在'uses'子句中使用'ShareMem',那麼傳遞字符串可能會導致問題。 –

+0

@heximal:是的,它返回一個有效的句柄。我相信導入/導出功能沒有問題。我試圖在DLL中使用虛擬函數。 – user

回答

3

你說得對,但我能看到的最明顯的問題是使用string變量。這些是分配的堆,因爲你有兩個單獨的內存管理器,你將在一個堆上分配(在DLL中),然後在不同的堆上釋放(在應用程序中)。

有幾個選項。一種選擇是共享內存管理器,但我不推薦這麼做,原因有很多。不用進入它們,你可以在評論中聲明,你希望非Delphi應用程序能夠使用你的DLL,這將阻止使用共享內存管理器。

另一種選擇是強制調用應用程序爲該字符串分配內存,然後讓您的DLL複製到該內存中。這工作正常,但有點勞動密集型。

相反,我會使用一個字符串類型,可以在一個模塊中分配,但在不同的模塊中釋放。 COM BSTR就是這樣一種類型,用德爾菲術語,這是WideString。更改代碼以使用WideString用於任何導出的功能。


我還將簡化導入/導出過程並使用隱式動態鏈接。

DLL

function CheckFile(
    const Filename: WideString; 
    var Info, Status: WideString 
): Boolean; stdcall; 

應用

function CheckFile(
    const Filename: WideString; 
    var Info, Status: WideString 
): Boolean; stdcall; external 'test.dll'; 

procedure Test(const FileName: string); 
var 
    Info, Status: WideString; 
begin 
    if CheckFile(Filename, Info, Status) then 
    AddtoListView(Filename, Info); 
end; 
+0

我使用FastMM。我還需要關注嗎? – user

+0

@user確實如此,因爲您將擁有FastMM分配器的兩個實例。雖然您可以共享內存管理器,但您的DLL的其他潛在客戶端又如何?我強烈建議避免導出由專用分配器分配的內存。你可以用WideString來完成它,因爲它依賴共享的COM分配器。 –

+0

在我的情況下,我需要一個靜態鏈接。我會嘗試WideString。在我看來,我只需要使用WideString作爲導出的參數(= string),並且在其他函數中使用字符串是可以的,對吧?在DLL中播放對我來說是一種新東西。 – user

相關問題