2011-05-20 102 views
3

我需要使用qsBarcode的DLL文件http://www.qsbarcode.de/en/index.htm(這裏是下載鏈接http://www.qsbarcode.de/en/download/qsbar39.zip)。該DLL會將包含條形碼code39的位圖圖像解碼爲一個字符串。請幫助如何將C代碼轉換爲Delphi代碼(qsBarcode)

在他們的例子中只有VB和C的例子,但我需要在Delphi中使用它。 這裏是在C正式示例代碼:

#include <windows.h> 
#include <stdio.h> 

typedef int (WINAPI * CODE39_PROC)(char *, char *); 

int main(int argc, char* argv[]) 
{ 
    HINSTANCE  hinstLib; 
    CODE39_PROC  ProcAdd; 
    BOOL   fFreeResult; 

    char   cFileName[512] = "\0"; 
    char   cResult[512] = "\0"; 
    int    iReturn = 0; 


    if(argc < 2) return 0; //no bitmap filename in argv[1] 

    strcpy(cFileName,argv[1]); 

    hinstLib = LoadLibrary("qsBar39"); 
    if (hinstLib == NULL) return -1; //can't load lib 

    ProcAdd = (CODE39_PROC) GetProcAddress(hinstLib, "ReadCode39"); 
    if (NULL == ProcAdd) return -1; //can't access Proc 

    //dll Proc call 
    iReturn = (ProcAdd) (cFileName, cResult); 
    printf("%s", cResult); 

    fFreeResult = FreeLibrary(hinstLib); 

    return iReturn; 
} 

,這就是我試圖代碼德爾福

unit uRead; 

interface 

uses 
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
    Dialogs, StdCtrls, Mask, JvExMask, JvToolEdit; 

type 
    TDLLFunc = function(namafile: PChar; hasil:PChar):integer; 
    TForm2 = class(TForm) 
    JvFilenameEdit1: TJvFilenameEdit; 
    Edit1: TEdit; 
    Button1: TButton; 
    procedure Button1Click(Sender: TObject); 
    private 
    { Private declarations } 
    public 
    { Public declarations } 
    end; 

const 
    DLLFunc: TDLLFunc = nil; 

var 
    Form2: TForm2; 
    DLLHandle: THandle; 

implementation 

{$R *.dfm} 

procedure TForm2.Button1Click(Sender: TObject); 
var 
    feedback : integer; 
    hasil:PChar; 
begin 
    DLLHandle := LoadLibrary('qsBar39.dll'); 
    if (DLLHandle < HINSTANCE_ERROR) then 
    raise Exception.Create('library can not be loaded or not found. ' + SysErrorMessage(GetLastError)); 

    try 
    { load an address of required procedure} 
    @DLLFunc := GetProcAddress(DLLHandle, 'ReadCode39'); 

    {if procedure is found in the dll} 
    if Assigned(DLLFunc) then 
     feedback := DLLFunc(PChar(JvFilenameEdit1.Text), PChar(hasil)); 
    showmessage(hasil); 
    finally 
    {unload a library} 
    FreeLibrary(DLLHandle); 
    end; 

end; 

end. 

當我執行這個代碼和調試,hasil只包含#$11'½ 雖然它應該返回條形碼圖像中的一些字符(您可以在zip文件中獲取文件圖像)。 請幫助我,謝謝。


最新更新時間:

@ 500,謝謝,我已經把STDCALL

@dthorpe,謝謝,做

其實建議是偉大的,我的代碼應該運行良好,但我錯誤地把JvFilenameEdit1.text而不是JvFilenameEdit1.FileName,我的壞:)

再次感謝您的意見,所以這裏是工作代碼:

unit uRead; 

interface 

uses 
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, 
    Dialogs, StdCtrls, Mask, JvExMask, JvToolEdit; 

type 
    TDLLFunc = function(namafile: PAnsiChar; hasil:PAnsiChar):integer; stdcall; 
    TForm2 = class(TForm) 
    JvFilenameEdit1: TJvFilenameEdit; 
    Edit1: TEdit; 
    Button1: TButton; 
    procedure Button1Click(Sender: TObject); 
    private 
    { Private declarations } 
    public 
    { Public declarations } 
    end; 

const 
    DLLFunc: TDLLFunc = nil; 

var 
    Form2: TForm2; 
    DLLHandle: THandle; 

implementation 

{$R *.dfm} 

procedure TForm2.Button1Click(Sender: TObject); 
var 
    feedback : integer; 
    hasil: array [0..512] of char; 
begin 
    DLLHandle := LoadLibrary('qsBar39.dll'); 
    if (DLLHandle < HINSTANCE_ERROR) then 
    raise Exception.Create('library can not be loaded or not found. ' + SysErrorMessage(GetLastError)); 

    try 
    { load an address of required procedure} 
    @DLLFunc := GetProcAddress(DLLHandle, 'ReadCode39'); 

    {if procedure is found in the dll} 
    if Assigned(DLLFunc) then 
     feedback := DLLFunc(PAnsiChar(JvFilenameEdit1.FileName), @hasil); 

    edit1.Text := StrPas(@hasil); 

    finally 
    {unload a library} 
    FreeLibrary(DLLHandle); 
    end; 

end; 

end. 
+1

如果你用delphi 2009+(Unicode版本),那麼我認爲你需要在Delphi代碼 – ComputerSaysNo 2011-05-20 01:07:19

+0

喜與PAnsiChar更換PChar類型Dorin,我使用的是Delphi 2006,但我試圖使用PAnsiChar,謝謝 – Erwan 2011-05-20 03:46:30

+1

Erwan:不要將標題改爲(已解決)。將問題標記爲已回答。 – dthorpe 2011-05-20 06:35:45

回答

6

如果我是你,我會藉此機會將這個函數調用到更像Delphi的包裝器中。

function ReadCode39(FileName, Result: PAnsiChar): LongBool; stdcall; 
    external 'qsBar39'; 

function ReadCode(const FileName: string): string; 
var 
    cResult: array [0..512-1] of AnsiChar; 
begin 
    if not ReadCode39(PAnsiChar(AnsiString(FileName)), @cResult[0]) then 
    raise Exception.Create('ReadCode39 failed'); 
    Result := string(cResult); 
end; 

注:

  1. 我使用的是隱含的DLL導入(使用external),而不是一個明確的GetProcAddress。這大大減少了樣板代碼的數量。
  2. 我將C風格的整數代碼錯誤處理轉換爲Delphi異常。根據你的評論,我猜測一個非零返回值意味着成功。較早版本的C沒有布爾類型,並使用0表示false,並且每個非零值的計算結果都爲true。將其映射到Delphi布爾類型的自然方法是使用LongBool。這意味着您的調用代碼不需要擔心錯誤代碼。
  3. 所有與空終止字符串之間的轉換都是在一個例程中處理的,並且您的調用代碼不需要關注這些瑣事。
  4. 我已經編寫了代碼,以便它可以在ANSI和Unicode版本的Delphi之間移植。

這允許你調用代碼更清楚地寫着:

procedure TForm2.Button1Click(Sender: TObject); 
var 
    hasil: string; 
begin 
    hasil := ReadCode(JvFilenameEdit1.Text); 
    ShowMessage(hasil); 
end; 
+0

美麗的代碼大衛,謝謝,我得到錯誤信息「ReadCode39失敗,錯誤代碼1」,但是當我刪除iReturn檢查(2行)它工作很好,再次感謝。 – Erwan 2011-05-20 07:05:30

+0

@erwin是的我無法預測這個庫如何表示錯誤,但你大概有文檔。不要刪除檢查。相反,改變它來測試正確的價值! – 2011-05-20 07:18:49

+0

@erwin我已根據您的評論更新了代碼。我認爲0的返回碼意味着失敗,其他任何信號都表示成功。但我必須說,我猜測一點,你應該檢查這與文檔。 – 2011-05-20 08:02:12

3

堅持stdcall;指令在TDLLFunc聲明結束時告訴編譯器它正在使用WINAPI調用約定,正如Dorin指出的那樣,如果你使用的是基於Unicode的Delphi版本,你可能想使用PAnsiChar。

+0

thx @ 500,你能再次看到我的最新更新代碼 – Erwan 2011-05-20 04:05:03

2

除了在另一個答案中提到的stdcall之外,還需要爲傳遞給DLLFunc的pchar指針分配空間。請注意,在C代碼中,cResult var被定義爲char cResult[512];這意味着調用方爲512字符的char緩衝區保留空間並將該緩衝區的地址傳遞給DLL func。

你在Delphi代碼中沒有這樣做。

更改您的Delphi代碼來定義hasil爲char類型的數組:

var hasil: array [0..512] of char;

然後hasil的地址傳遞給DLLFunc電話:

DLLFunc(PChar(JvFilenameEdit1.Text), @hasil); 
+0

thx @dthorpe,你能再次看到我的上一次更新代碼嗎 – Erwan 2011-05-20 04:05:22

+0

不,你創建了一個PAnsiChar數組 - 一個指針數組。你需要一個char數組。將代碼更改爲我在答案中給出的內容。 – dthorpe 2011-05-20 06:33:39

+0

我編輯了我的帖子,兩個代碼都很好用,它是兩個PAnsiChar和Char之間的主要區別嗎?謝謝 – Erwan 2011-05-20 11:21:11