Recent

Author Topic: how to use an external dll in lazarus  (Read 65674 times)

ezzio

  • Newbie
  • Posts: 6
how to use an external dll in lazarus
« on: October 22, 2009, 10:51:56 pm »
Hi
 I am new using lazarus and I know that this must be a really simple question but I don't know how to use an dll in lazarus

I have a dll (written in C++ I guess but not sure)

What I did is: i declare a function

 dllpurchase: function( var termid:string ): pchar; cdecl;

this function is included in the dll

When I execute the program, it raised an execption:
raised exception class 'External: SIGSEGV'

The question is how to declare and use and function from an external dll?

thanks

Marc

  • Administrator
  • Hero Member
  • *
  • Posts: 2680
Re: how to use an external dll in lazarus
« Reply #1 on: October 22, 2009, 11:46:07 pm »
what is the C declaration of the function ? I'm almost sure it does not pass a pascal managed string.
//--
{$I stdsig.inc}
//-I still can't read someones mind
//-Bugs reported here will be forgotten. Use the bug tracker

ezzio

  • Newbie
  • Posts: 6
Re: how to use an external dll in lazarus
« Reply #2 on: October 23, 2009, 12:11:07 am »
I do not have the source code of the dll, therefore I don't know the C declaration of the function

Any way, I thougth that the word 'cdecl' in the funtion would solve this issue, isn't it true?

Ñuño_Martínez

  • Hero Member
  • *****
  • Posts: 1226
    • Burdjia
Re: how to use an external dll in lazarus
« Reply #3 on: October 23, 2009, 10:36:17 am »
CDECL just tells the compiler that the function/procedure uses "C-style calling convention" which is quite different than the "Pascal-style calling convention".

C hasn't strings so you can't use "STRING" in your Pascal declaration. The inners of Pascal's STRING are more complex than simple character arrays. Even you can't assume that ANSISTRING are C-style strings because it may include internal stuff used for code optimization that make it no compatible with C-style strings.

All parameters on C are passed by value (reference parameters are actually pointer wrappers) so you can't use "VAR" in your Pascal declaration.
« Last Edit: October 23, 2009, 10:38:53 am by Ñuño_Martínez »
Are you interested in game programming? Join the Pascal Game Development community!
Also visit the Game Development Portal

bflm

  • Jr. Member
  • **
  • Posts: 54
    • Free Pascal Random Bits
Re: how to use an external dll in lazarus
« Reply #4 on: October 23, 2009, 12:35:56 pm »
All parameters on C are passed by value (reference parameters are actually pointer wrappers) so you can't use "VAR" in your Pascal declaration.

If the C function parameter is a pointer to some type, than you can IMO do both variants:
Code: [Select]
type
  P = ^T;
procedure SomeExternalCFunc(Arg: P); cdecl; external ...
procedure SomeExternalCFunc2(var Arg: T); cdecl; external ...

EMTR

  • New Member
  • *
  • Posts: 20
Re: how to use an external dll in lazarus
« Reply #5 on: October 23, 2009, 01:36:06 pm »
Im having the same problem - I have a dll and an executable - both written in Delphi 7. The dll compiles and builds, I've set the host to the exe (which is the Delphi built EXE, I haven't converted it to Lazarus) - I'm compiling against the Delphi syntax.

I then run the app and place some breakpoints in my dll - I should now be able to step into the DLL when I click a button the app AND DEBUG! (yey! - if only Lazarus let me)... This is pretty much how its done in Delphi 7 I think... Anyway I'm having problems.

So Lazarus allows me to place a breakpoint with a "?" in the source for my DLL. I hit run and the breakpoint changes to an "X" (ie its been disabled)

I assume this is because its not got the debug symbols; the debug output window states "The first problem I have is that I get a spurious message in the debug output - "No source file named OSLO.lpr in loaded symbols." - OSLO.lpr is the dll project. I've tried adding {$D+} and {$LOCALSYMBOLS} to no avail.

So how do I include the debug symbols so Lazarus allows me to that I don't have to keep setting the same breakpoints (I'm looking at 10 entry points and its a nightmare to keep setting them again and again)

My current work around is to allow an exception to occur (then Lazarus has found the symbols) then reset the breakpoints (again!) click the button in the application again. When I do this I can step into the dll code (Yey! at last!) however the code executes correctly and appears to get all the way through the dll code - Then I get a message "EXE raised exception class 'External: SIGSEGV'." Put simply... HELP!??!

So what have I done wrong?!? Why is Lazarus such a pain. (Thats rhetorical).

Phil

  • Hero Member
  • *****
  • Posts: 2737
Re: how to use an external dll in lazarus
« Reply #6 on: October 23, 2009, 03:59:18 pm »
To debug a DLL that you've just ported, I would suggest compiling its code into a standalone executable. That will be easier to debug. After you have the DLL's code working, then put the code into a DLL. If you're still having problems, then you pretty much know that it's either in parameter passing or calling convention and not in the DLL code itself.

Don't try to make it harder than it is.

Thanks.

-Phil

cdbc

  • Hero Member
  • *****
  • Posts: 2726
    • http://www.cdbc.dk
Re: how to use an external dll in lazarus
« Reply #7 on: October 24, 2009, 07:37:21 pm »
Hi Ezzio.
Here are some codesnippets I have used with success...
Code: [Select]
1)
uses
  Classes,Sysutils,Lresources,Forms,Controls,Graphics,Dialogs,Buttons,StdCtrls,
  bom_mbs,
  dynlibs,   <<--- Important
  bcStrings,
  bcGraphics,
  bcDebug,
  uIterator,
  uConfig, Menus, ComCtrls, ExtCtrls, Grids, ExtDlgs, SynEdit;

type
  { function prototypes }
  TInputQuery = function (Caption,Text: pchar): pchar; cdecl;
  TShowMbsPreview = function (aProj_Id: integer;aDbPath: pchar): boolean; cdecl;
  
  { TfmMain }
  TfmMain = class(Tform)
    ...
  private
    { dynamically linking }
    hLib: TlibHandle;
    InputQuery: TInputQuery;
    ShowMbsPreview: TShowMbsPreview;
  public
    ...
2)
procedure Tfmmain.Formcreate(Sender: Tobject);
begin
  ...
  if fileexists('libPrint.dll') then begin { just a sanity check, could extend this }
    hLib:= LoadLibrary('libPrint.dll');
    if hLib <> 0 then begin
      pointer(InputQuery):= GetProcedureAddress(hLib,'InputQuery');
      pointer(ShowMbsPreview):= GetProcedureAddress(hLib,'ShowMbsPreview');
    end;
  end;
end;

3)
procedure Tfmmain.Formdestroy(Sender: Tobject);
begin
  ...
  pointer(ShowMbsPreview):= nil; { reset library addresses just in case :o) }
  pointer(InputQuery):= nil; { reset library addresses }
  if hLib <> 0 then UnloadLibrary(hLib); { release library }
  hLib:= 0; { again sanity }
end;

4)
{ file.print projekt }
procedure Tfmmain.Menuitem15click(Sender: Tobject);
begin
 ShowMbsPreview(fProjects.Entries[fCurrIdx].Id,pchar(AppConfig.DatabasePath));
end;

{ another approach, taken from Lame_Enc, this goes in 'interface' section of unit }

function beInitStream(var pbeConfig: TBE_CONFIG; var dwSample: LongWord; var dwBufferSize: LongWord; var phbeStream: THBE_STREAM ): BE_Err; cdecl; external 'Lame_enc.dll';


  stdcall calling convention is used in the windows api,
  cdecl calling convention is used by both "C" and "C++",
I normally try "cdecl" first, if it is NOT WinApi.

Hope this can help you on the way, if not let me know and we'll have another look  ;)

Regards Benny
« Last Edit: October 24, 2009, 07:55:15 pm by cdbc »
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE6/QT6 -> FPC Release -> Lazarus Release &  FPC Main -> Lazarus Main

ezzio

  • Newbie
  • Posts: 6
Re: how to use an external dll in lazarus
« Reply #8 on: October 26, 2009, 04:14:50 am »
Thank you Benny
I followed your code and I was able to compile and link the project, but when I execute it, it shows and error that says that the project raised exception class 'External SIGSEGV'
and stop
Thanks again for your example code

Marc

  • Administrator
  • Hero Member
  • *
  • Posts: 2680
Re: how to use an external dll in lazarus
« Reply #9 on: October 26, 2009, 11:42:50 am »
What I did is: i declare a function

 dllpurchase: function( var termid:string ): pchar; cdecl;


Still no answer to this. Why do you think dllpurchase expects a string as parameter ?
//--
{$I stdsig.inc}
//-I still can't read someones mind
//-Bugs reported here will be forgotten. Use the bug tracker

ezzio

  • Newbie
  • Posts: 6
Re: how to use an external dll in lazarus
« Reply #10 on: October 26, 2009, 07:12:19 pm »
Sorry Marc
To be honest, I didn't undestand what you mean by your question until now, I understood that you was asking me for the source code (which I don't have)

the definition of the function dllpurchase is :

char * dllpurchase(char* termid, int autmedia, int auttype, char *cardnumber, char
*amount, char *expdate, char *track, char *tax, char *tip, char *cash, int seccode,
int secresp, char *secdata, int avs, char *postalcode, char *address, char *invoice);


I supposed that "char* termid" in C was equivalent to the string type in Pascal

Thank you for your help

cdbc

  • Hero Member
  • *****
  • Posts: 2726
    • http://www.cdbc.dk
Re: how to use an external dll in lazarus
« Reply #11 on: October 26, 2009, 08:00:25 pm »
Hi again.
Well, to be exact, 'char*' is a pointer to a char (or an array of chars), aka, pchar in pascal. If function expects pchar parameters, you can typecast a string into a pchar -> pchar(SomeString), then you don't have to bother with memory allocation.

dllpurchase: function(termid: pchar ): pchar; cdecl;

Result:= dllPurchase(pchar(SomeString));

If the error persists you may have to post us your source, that we can have a look, the more eyes, the merrier...

Regards Benny
If it ain't broke, don't fix it ;)
PCLinuxOS(rolling release) 64bit -> KDE6/QT6 -> FPC Release -> Lazarus Release &  FPC Main -> Lazarus Main

Marc

  • Administrator
  • Hero Member
  • *
  • Posts: 2680
Re: how to use an external dll in lazarus
« Reply #12 on: October 26, 2009, 08:03:59 pm »

the definition of the function dllpurchase is :

char * dllpurchase(char* termid, int autmedia, int auttype, char *cardnumber, char
*amount, char *expdate, char *track, char *tax, char *tip, char *cash, int seccode,
int secresp, char *secdata, int avs, char *postalcode, char *address, char *invoice);


I supposed that "char* termid" in C was equivalent to the string type in Pascal

the c char and the pascal sting are used smilar, but its datatype is completely different and cannot be used for passing data to c dlls

the external declaration has to match exactly, so you cannot alter or skip parameters.
(add ctypes to your uses clause)

Code: [Select]
function dllpurchase(termid: pchar; autmedia, auttype: cint; cardnumber, amount, expdate, track, tax, tip, cash: pchar; seccode, secresp: cint; secdata:pchar; avs: cint; postalcode, address, invoice:pchar): pchar;
//--
{$I stdsig.inc}
//-I still can't read someones mind
//-Bugs reported here will be forgotten. Use the bug tracker

Ñuño_Martínez

  • Hero Member
  • *****
  • Posts: 1226
    • Burdjia
Re: how to use an external dll in lazarus
« Reply #13 on: October 27, 2009, 11:40:31 am »
All parameters on C are passed by value (reference parameters are actually pointer wrappers) so you can't use "VAR" in your Pascal declaration.

If the C function parameter is a pointer to some type, than you can IMO do both variants:
Code: [Select]
type
  P = ^T;
procedure SomeExternalCFunc(Arg: P); cdecl; external ...
procedure SomeExternalCFunc2(var Arg: T); cdecl; external ...
May be, but IMO it's dangerous. I mean, may be VAR uses some kind of "magic" to optimize callings. My recommendation:

Code: [Select]
TYPE
  PT = ^T;
PROCEDURE _SomeExternalCFunc_ (Arg: PT); CDECL; EXTERNAL ...
PROCEDURE SomeExternalCFunc (VAR Arg: T);
BEGIN
  _SomeExternalCFunc_ (@Arg);
END;
Are you interested in game programming? Join the Pascal Game Development community!
Also visit the Game Development Portal

ezzio

  • Newbie
  • Posts: 6
Re: how to use an external dll in lazarus
« Reply #14 on: October 30, 2009, 07:23:16 am »
Thanks to everybody for your help
Following your indications I finally get de dll to work, but it happen something strage:


I made a form and put a button in it (button1)
the code in button1click is :
procedure TForm1.Button1Click(Sender: TObject);
var
vcaux, str: string;
begin
  vctermid  := '00000015';
  vnautmedia := 1;
  vnauttype := 1;
  vccardnumber := '1234567812345678';
  vcamount  := '000000100.00';
  vcexpdate := '1002';
  vctrack   := '';
  vctax     := '';
  vctip     := '';
  vccash    := '';
  vnseccode := 1;
  vnsecresp := 1;
  vcsecdata := '';
  vnavs     := 1;
  vcpostalcode := '';
  vcaddress := '';
  vcinvoice := '';

  vcrespsoc := dllpurchase(PChar(vctermid), vnautmedia, vnauttype,
    PChar(vccardnumber), PChar(vcamount), PChar(vcexpdate),
    PChar(vctrack), PChar(vctax), PChar(vctip), PChar(vccash),
    vnseccode, vnsecresp, PChar(vcsecdata),
    vnavs, PChar(vcpostalcode), PChar(vcaddress),
    PChar(vcinvoice));
  //vcaux:=vcrespsoc;
  //ShowMessage(vcrespsoc);
end;           

If I execute the code just like i put here, the program works, but i I "uncomment" at least one of the last 2 lines , the software raises an exception SIGSEGV
Why I can not even assign the value of vcrespsoc to another variable ?

 

TinyPortal © 2005-2018