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.
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:
external
) rather than an explicit GetProcAddress
. This reduces the amount of boilerplate code considerably. LongBool
. This means that your calling code doesn't need to worry about error codes. 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;
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.
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);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.