请帮助如何将C代码转换为Delphi代码(qsBarcode)

发布于 2024-11-08 21:30:25 字数 4076 浏览 4 评论 0原文

我需要使用 qsBarcode http://www.qsbarcode.de/en/index 中的 DLL 文件。 htm (这里是下载链接 http://www.qsbarcode.de/ en/download/qsbar39.zip)。该 dll 会将包含条形码 code39 的位图图像解码为字符串。

在他们的示例中只有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;
}

这就是我尝试在 Delphi 中编写的代码

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.

I need to use a DLL file from qsBarcode http://www.qsbarcode.de/en/index.htm (here is the download link http://www.qsbarcode.de/en/download/qsbar39.zip). The dll will decode a bitmap image that contain barcode code39 into a string.

In their example there are only VB and C example, but I need to use it in Delphi.
here is the official example code in 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;
}

and this is what I try to code in Delphi

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.

When I execute this code and debug, hasil only contains #$11'½
while it should return some character in the barcode image (you can get the file image in the zip file).
Please help me, thank you.


latest update:

@500, thanks, I have put stdcall

@dthorpe, thanks, done

Actually the advice is great, my code is supposed to running well, but I've mistakenly put JvFilenameEdit1.text instead of JvFilenameEdit1.FileName, my bad :)

Thank you again for the advice, so here is the working code:

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

二智少女猫性小仙女 2024-11-15 21:30:25

如果我是你,我会利用这个机会将这个函数调用包装在一个更像 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;

If I were you I would take the opportunity to wrap this function call up in a more Delphi like wrapper.

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;

Notes:

  1. I'm using an implicit DLL import (using external) rather than an explicit GetProcAddress. This reduces the amount of boilerplate code considerably.
  2. I'm converting the C style integer code error handling into a Delphi exception. Based on your comment I'm guessing that a non-zero return value means success. Older versions of C do not have a boolean type and use 0 to mean false and every non-zero value evaluates as true. The natural way to map this to a Delphi boolean type is with LongBool. This means that your calling code doesn't need to worry about error codes.
  3. All the conversion to and from null-terminated strings is handled in one routine and your calling code again need not concern itself over such trivia.
  4. I've written the code so that it is portable between both ANSI and Unicode versions of Delphi.

This allows your calling code to read much more clearly:

procedure TForm2.Button1Click(Sender: TObject);
var
  hasil: string;
begin
  hasil := ReadCode(JvFilenameEdit1.Text);
  ShowMessage(hasil);
end;
不及他 2024-11-15 21:30:25

坚持stdcall; TDLLFunc 声明末尾的指令告诉编译器它正在使用 WINAPI 调用约定,并且正如 Dorin 指出的那样,如果您使用基于 unicode 的 Delphi 版本,您可能需要使用 PAnsiChar。

Stick a stdcall; directive at the end of your TDLLFunc declaration to tell the compiler that it's using the WINAPI calling convention, and, as Dorin points out, if you're using a unicode-based version of Delphi you probably want to use PAnsiChar.

℉服软 2024-11-15 21:30:25

除了另一个答案中提到的 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);

In addition to the stdcall mentioned in another answer, you also need to allocate space for the pchar pointers you're passing into the DLLFunc. Notice that in the C code the cResult var is defined as char cResult[512]; That means the caller is reserving space for a char buffer of 512 chars and passing the address of that buffer to the DLL func.

You're not doing the equivalent in your Delphi code.

Change your Delphi code to define hasil as an array of char:

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

then pass the address of hasil to the DLLFunc call:

DLLFunc(PChar(JvFilenameEdit1.Text), @hasil);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文