2011-05-20 110 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