Recent

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

cdbc

  • Hero Member
  • *****
  • Posts: 2726
    • http://www.cdbc.dk
Re: how to use an external dll in lazarus
« Reply #15 on: October 30, 2009, 08:32:34 am »
Hi Ezzio.
The dll function returns a pchar as a result, hence

  vcaux:= string(vcrespsoc); { I assume 'vcrespsoc' is declared as a pchar, thus we can typecast it to a string }
  ShowMessage(vcrespsoc);

should work. The memory allocated for the result, is allocated within the dll. Pascal strings are pointers underneath it all, albeit smart ones.

HTH
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

ezzio

  • Newbie
  • Posts: 6
Re: how to use an external dll in lazarus
« Reply #16 on: October 30, 2009, 09:32:03 pm »
Hi Benny
I didn't know that I can "typecast" a variable (thanks)
vcrespsoc is declared as pchar
str is declared as string
I put in the software
...
  str:=string(vcrespsoc);
  //
  ShowMessage(str);
  cr:=copy(str,1,2);
  dcr:=copy(str,4,30);
end;
{this es the 'end' of procedure TForm1.Button1Click(Sender: TObject); }             

if I trace the code step by step, it works fine until i reach the 'end;'
where it raises the exception external SIGSEGV


cdbc

  • Hero Member
  • *****
  • Posts: 2726
    • http://www.cdbc.dk
Re: how to use an external dll in lazarus
« Reply #17 on: October 30, 2009, 11:30:20 pm »
Hi Ezzio.

Hmmmm..... The SIGSEGV (SIGnal SEGment Violation) is equivalent to AV (Access Violation) in Delphi.
Usually it means you're accessing memory, that does not belong to you or referencing a NIL pointer (or memory that has been freed), or overstepping bounds.
EXTERNAL might suggest a flaw in the dll, but if it is a released dll, it is not too likely (especially not when it comes to finance apps :o)

More likely, it has to do with your own variables, are they the right size for the values you put in them ?!?
Maybe you have to clone the result from dll, if you want to use it elsewhere, so that the memory doesn't get released prematurely.

'Str' is a local variable, it is no longer valid when method ends and goes out of scope.

It is hard for me to debug code on your computer, here from mine  ;)
(I don't know what 'cr' and 'dcr do' or are supposed to do)

Let me know how you progress...

Regards Benny
« Last Edit: October 30, 2009, 11:35:25 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

olsenweb

  • Newbie
  • Posts: 2
Re: how to use an external dll in lazarus
« Reply #18 on: December 03, 2009, 05:09:16 pm »
Dear all,
first of all "hello to everybody", this is my first post.

I'm pretty new to Lazarus and I've just start to programming with it and, immediately, I've found my first "big" problem and it is related to External SIGSEGV.

I've tried to use a library called PHP4App.dll that I use also in the past without problems.

Below the entire code

When I press the button the library's function was called and the message was showed without problems, after I press the "OK" button appear the external SIGSEGV error appear.

Another info: if I use functions that don't required the PChar values (like SaveToFile) everything gone fine  ::)
 
Any idea? :o

Code: [Select]
unit Unit1;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, FileUtil, LResources, Forms, Controls, Graphics, Dialogs,
  StdCtrls, dynlibs;

type

  { TForm1 }

  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;

var
  Form1: TForm1;

function  InitRequest : integer; stdcall;
procedure DoneRequest(RequestID : integer); stdcall;
procedure RegisterVariable(RequestID : integer; AName : PChar; AValue : PChar); stdcall;
function  ExecutePHP(RequestID : integer; FileName : PChar) : integer; stdcall;
function  ExecuteCode(RequestID : integer; ACode : PChar) : integer; stdcall;
function  GetResultText(RequestID : integer; Buffer : PChar; BufLen : integer) : integer; stdcall;
function  GetVariable(RequestID : integer; AName : PChar; Buffer : PChar; BufLen : integer) : integer; stdcall;
procedure SaveToFile(RequestID : integer; AFileName : PChar); stdcall;
function  GetVariableSize(RequestID : integer; AName : PChar) : integer; stdcall;
function  GetResultBufferSize(RequestID : integer) : integer; stdcall;


implementation

{ TForm1 }

function InitRequest: integer; stdcall; external 'php4app.dll';
procedure DoneRequest(RequestID : integer); stdcall; external 'php4app.dll';
procedure RegisterVariable(RequestID : integer; AName : PChar; AValue : PChar); stdcall; external 'php4app.dll';
function  ExecutePHP(RequestID : integer; FileName : PChar) : integer; stdcall; external 'php4app.dll';
function  ExecuteCode(RequestID : integer; ACode : PChar) : integer; stdcall; external 'php4app.dll';
function  GetResultText(RequestID : integer; Buffer : PChar; BufLen : integer) : integer; stdcall; external 'php4app.dll';
function  GetVariable(RequestID : integer; AName : PChar; Buffer : PChar; BufLen : integer) : integer; stdcall; external 'php4app.dll';
procedure SaveToFile(RequestID : integer; AFileName : PChar); stdcall; external 'php4app.dll';
function  GetVariableSize(RequestID : integer; AName : PChar) : integer; stdcall; external 'php4app.dll';
function  GetResultBufferSize(RequestID : integer) : integer; stdcall; external 'php4app.dll';


procedure TForm1.FormCreate(Sender: TObject);
begin


end;

procedure TForm1.Button1Click(Sender: TObject);
var
   id: integer;
   buffy: pchar;
   buflen: integer;
begin
  id := InitRequest();
  RegisterVariable(id, 'myvar', 'Test var ');
  ExecuteCode(id, '$myvar = $myvar.'' is passed'';');
  buflen := GetVariableSize(id, 'myvar');
  GetVariable(id, 'myvar', buffy, buflen +1);
  showmessage(buffy);
  DoneRequest(id);
end;

procedure TForm1.FormDestroy(Sender: TObject);


end;


initialization
  {$I unit1.lrs}

end.
       

theo

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1945
Re: how to use an external dll in lazarus
« Reply #19 on: December 03, 2009, 05:23:30 pm »
  buflen := GetVariableSize(id, 'myvar');
  GetVariable(id, 'myvar', buffy, buflen +1);

Shouldn't you probably allocate memory for the PChar?
like
buffy:=StrAlloc(buflen); //Prob. +1 ?
....
StrDispose(buffy);

olsenweb

  • Newbie
  • Posts: 2
Re: how to use an external dll in lazarus
« Reply #20 on: December 03, 2009, 05:32:09 pm »
  buflen := GetVariableSize(id, 'myvar');
  GetVariable(id, 'myvar', buffy, buflen +1);

Shouldn't you probably allocate memory for the PChar?
like
buffy:=StrAlloc(buflen); //Prob. +1 ?
....
StrDispose(buffy);


Unfortunately in most functions (like GetResultText) I can't know the buflen size until I execute the function the first time (seems to be stupid but you must run the same functions 2 times, first to know the buf lenght and the second to get the text)

But thanks to your suggestion I've found a solution, simple I assign an empty string to buffy before function call and everything gone fine

(sorry for my english :P)

theo

  • Global Moderator
  • Hero Member
  • *****
  • Posts: 1945
Re: how to use an external dll in lazarus
« Reply #21 on: December 03, 2009, 05:55:42 pm »
simple I assign an empty string to buffy before function call and everything gone fine

I would not rely on this.
Either the memory is allocated in the DLL or not.
If not, you have to allocate enough space and an empty string is not enough.
You might run into trouble sooner or later.

thierrybo

  • Full Member
  • ***
  • Posts: 146
Re: how to use an external dll in lazarus
« Reply #22 on: March 21, 2010, 11:23:45 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;

Maybe some answer in http://edn.embarcadero.com/article/10281 , hope this helps

excerpt:

Rule 4: var Parameters and Pointers

Some functions take a parameter that is a pointer to a type. If the type can never be passed as nil, then it should be changed to a var parameter and the type changed to the appropriate non-pointer type.

Consider the following C/C++ declaration from Winspool.h:

     
Code: [Select]
BOOL WINAPI EnumPrintersA( DWORD Flags, LPSTR Name, DWORD Level, LPBYTE pPrinterEnum, DWORD cbBuf, LPDWORD pcbNeeded, LPDWORD pcReturned );
Here is the Pascal translation of this type:

     
Code: [Select]
function EnumPrintersA(Flags: DWORD; Name: PAnsiChar; Level: DWORD; pPrinterEnum: Pointer; cbBuf: DWORD; var pcbNeeded, pcReturned: DWORD): BOOL; stdcall;

Notice that the last two parameters are passed as var parameters of type DWORD, even though they are declared as pointers to a DWORD in the original C/C++ header. If it were legal to call EnumPrintersA as follows, then the last two parameters would have to be declared in Pascal as pointers:
Code: [Select]
EnumPrintersA( 0, "SomeName", 0, nil, 0, nil, nil);

The problem is that in this evocation of the function, nil is being passed in the last two parameters. The compiler will obviously give a type mismatch if it is expecting a DWORD and gets a pointer value (nil) instead. Now, in this particular case, Microsoft does not allow you to pass nil in either of the last two parameters of this function. As a result, it is okay to declare the function as a DWORD passed by reference. Doing so will make the function easier for all Pascal programmers to call.

mas steindorff

  • Hero Member
  • *****
  • Posts: 571
Re: how to use an external dll in lazarus
« Reply #23 on: April 16, 2010, 06:50:20 pm »
FYI:
I don't know if it maters but the windows DLL's I've used want the strings as widestring as shown in this snpit
Code: [Select]
function TChkDsk.CheckDriveExists (const WDrive: WideString;
                           CheckInUse: boolean ; var WFormat: WideString): boolean ;
var
    FileSysName  : Array[0..MAX_PATH] of WChar;
    VolumeName   : Array[0..MAX_PATH] of WChar;
    maxcomlen, flags: longword;
    handle: THandle ;
    voldev: WideString ;
begin
    if (Length (WDrive) < 2) or (WDrive [2] <> ':') then  begin
        raise FmtChkException.Create('Invalid Drive Specification: ' + WDrive);
        exit ;
        end ;
// see if volume exists, get file system (FAT32, NTFS)
    if NOT GetVolumeInformationW (PWChar (WDrive), VolumeName, SizeOf(VolumeName) div 2,
                 Nil, maxcomlen, flags, FileSysName, SizeOf(FileSysName) div 2) then
        begin
        raise FmtChkException.Create('Drive Not Found: ' + WDrive);
        exit ;
        end ;
    WFormat := FileSysName ;
    doInfoEvent (WDrive + ' Volume Label: ' + VolumeName + ', File System: ' + FileSysName) ;

// try and get exclusive access to volume
    if CheckInUse then
       begin
       voldev := '\\.\' + WDrive [1] + ':' ;
       handle := CreateFileW (PWChar (voldev), Generic_Write, 0, nil, Open_Existing, 0, 0) ;
       if handle = INVALID_HANDLE_VALUE then
          begin
          raise FmtChkException.Create('Drive In Use: ' + WDrive);
          exit ;
          end ;
       CloseHandle (handle) ;
       end ;
    result := true ;
End;
windows 10 &11, Ubuntu 21+ IDE 3.4 general releases

 

TinyPortal © 2005-2018