C++ Bibliothek in Lazarus einbinden

Für alles, was in den übrigen Lazarusthemen keinen Platz, aber mit Lazarus zutun hat.

C++ Bibliothek in Lazarus einbinden

Beitragvon Mojo » 26. Jul 2017, 08:37 C++ Bibliothek in Lazarus einbinden

Hallo,

ich bin gerade dabei mein Lazarus Programm (Win32 GUI) zu debuggen, weil es plötzlich (ab Version Lazarus 1.6.2, Zur Zeit 1.6.4) nicht mehr die Bibliotheksfunktionen der externen C++ dll einbindet und direkt nach dem kompilieren bzw externen Aufruf abstürzt. Ob es etwas mit der Lazarus Version zu tun hat, möchte ich hier herausfinden. Der Absturz wird mit der Fehlermeldung: "Die Anwendung konnte nicht korrekt gestartet werden (0xc000007b). ...." begleitet und die GUI öffnet sich nicht.

Die Bibliothek (DLL) wird von einem MinGW Compiler auf Netbeans 8.2 (mit GCC 6) mit den Compileroptionen "-static-libgcc -static-libstdc++ -DHAVE_STRUCT_TIMESPEC" im Standard C++14 umgesetzt. Die zu exportierenden DLL Funktionen werden mit folgendem Syntax exportiert:

Code: Alles auswählen
#ifdef __cplusplus
extern "C" {
#endif
 
int32_t extern_nsifun(const char* password, int32_tcall_id);
const char* extern_getversion(); 
int32_textern_testfun(int32_t i);
 
#ifdef __cplusplus
}
#endif


Auf der Lazarus-Seite versuche ich die Funktionen statisch einzubinden und zwar im UNIT Teil "interface". Die Einbindung geht wie folgt:
const DLL_NAME='liblibfraes.dll';
Code: Alles auswählen
function extern_nsifun(password:Pchar;call_id:int32):int32; cdecl; external DLL_NAME; 
function extern_getversion:Pchar; cdecl; external DLL_NAME; 
function extern_testfun(ii:int32):int32; cdecl; external DLL_NAME;
 


Gibt es einen anderen Weg an die Funktionen zu kommen - Stichwort dynamisches einbinden, da bin ich mir noch unsicher ? Gibt es eine spezielle Compiler-Einstellung, dich ich übersehen habe? Hat es was mit der Versionierung von Lazarus zu tun?

ich bitte um Antwort, da ich hier nicht weiter komme...

Viele Grüße, Mojo
Mojo
 
Beiträge: 7
Registriert: 26. Jul 2017, 07:34

Beitragvon theo » 26. Jul 2017, 09:22 Re: C++ Bibliothek in Lazarus einbinden

Kann FPC jetzt mit C++? Ich dachte das geht gar nicht ohne Interface Lib?
ftp://ftp.freepascal.org/pub/fpc/docs-p ... Pascal.pdf
theo
 
Beiträge: 7879
Registriert: 11. Sep 2006, 18:01

Beitragvon mse » 26. Jul 2017, 09:28 Re: C++ Bibliothek in Lazarus einbinden

Solange reine C Funktionen aufgerufen werden schon.
@Mojo:
Versuche herauszufinden, wie die Funktionen tatsächlich heissen (Stichwort "Name mangling") und gib den Namen in der "name" Klausel an.
https://www.freepascal.org/docs-html/cu ... 890007.1.1
Marco kann sicher mehr dazu sagen.
Edit:
Das passt vielleicht auch zum Thema:
https://answers.microsoft.com/en-us/win ... 111?auth=1
As mentioned in several links in a Google search, this error is most likely a result of a 32-bit (x86) executable trying to load a 64-bit (x64) DLL.

Gibt es einen anderen Weg an die Funktionen zu kommen - Stichwort dynamisches einbinden, da bin ich mir noch unsicher ?

https://www.freepascal.org/docs-html/cu ... index.html
mse
 
Beiträge: 1676
Registriert: 16. Okt 2008, 09:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.4.2,git master FPC 3.0,fixes_3_0) | 
CPU-Target: x86,x64,ARM
Nach oben

Beitragvon Mojo » 26. Jul 2017, 10:32 Re: C++ Bibliothek in Lazarus einbinden

Hallo mse,

Danke für Deine schnelle Antwort.

Ich habe über pexports den direkten Namen der Funktion herausgelesen. Über das C-interface wird der korrekte Name exportiert: extern_testfun.

Ich habe den statischen Aufruf um den name-Zusatz ergänzt (und die typen C=long, Lazarus=longint ersetzt) - Leider ohne Erfolg: Den Index konte ich noch nicht herausfinden.

Code: Alles auswählen
function extern_testfun(ii:longint):longint; cdecl; external DLL_NAME name 'extern_testfun';


Des weiteren habe ich konkret für ein 32 Bit Umgebung die DLL ausgegeben. (Ich benutze Windows 8 64bit)

Ich habe das LazarusProjekt mal mit der betreffenden Test - DLL angehängt um das Problem zu verdeutlichen. Vllt hat ja noch jemand eine zündende Idee? Die Testfunktion soll nichts anderes machen, als den übergebenen longint-Wert als Rückgabewert wieder herauszugeben - also eigentlich simpel.

Code: Alles auswählen
long extern_testfun(long i){
    return(i);
}


Viele Grüße,
Mojo

DLL_TEST.zip
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.
Mojo
 
Beiträge: 7
Registriert: 26. Jul 2017, 07:34

Beitragvon mse » 26. Jul 2017, 12:12 Re: C++ Bibliothek in Lazarus einbinden

Ich würde versuchen, die Funktion mit mit den Funktionen aus dynlibs zu laden.
https://www.freepascal.org/docs-html/cu ... index.html
(loadlibrary(), getprocedureaddress()) und die Fehlermeldungen auszuwerten (getlasterror()).
mse
 
Beiträge: 1676
Registriert: 16. Okt 2008, 09:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.4.2,git master FPC 3.0,fixes_3_0) | 
CPU-Target: x86,x64,ARM
Nach oben

Beitragvon mse » 26. Jul 2017, 12:27 Re: C++ Bibliothek in Lazarus einbinden

Linux "nm" findet in libtest.dll
Code: Alles auswählen
 
6ea414b0 T _extern_testfun
6ea414f8 t __GLOBAL__sub_I_extern_testfun
 

Marco kann sicher Licht ins Dunkel bringen.
mse
 
Beiträge: 1676
Registriert: 16. Okt 2008, 09:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.4.2,git master FPC 3.0,fixes_3_0) | 
CPU-Target: x86,x64,ARM
Nach oben

Beitragvon Mojo » 26. Jul 2017, 12:57 Re: C++ Bibliothek in Lazarus einbinden

Hallo mse,

ich habe mal beide Varianten ausprobiert: "_extern_testfun" und "__GLOBAL__sub_I_extern_testfun" - es kam wieder die gleiche Fehlermeldung :( . Interessant, dass pexports und nm unterschiedliche exportfunktionen anzeigen - siehe Anhang.

Kannst du mir ein Beispiel geben, wie ich die Funktion per loadlibrary aufrufen und benutzen kann? :?:

Vielen Dank und Grüße, Mojo

dlltest.jpg
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.
Mojo
 
Beiträge: 7
Registriert: 26. Jul 2017, 07:34

Beitragvon mse » 26. Jul 2017, 13:32 Re: C++ Bibliothek in Lazarus einbinden

https://www.freepascal.org/docs-html/cu ... brary.html
https://www.freepascal.org/docs-html/cu ... dress.html
Code: Alles auswählen
 
uses
 dynlibs,ctypes,windows;
 
var
 extern_testfun: function(ii: clong): clong cdecl;
 handle: tlibhandle;
 
[...]
 
 handle:= loadlibrary('libtest.dll');
 if handle = 0 then begin
  writeln('loadlibrary error: ',getlasterror());
 end
 else begin
  writeln('loadlibrary OK');
  extern_testfun:= getprocedureaddress(handle,'extern_testfun');
  if assigned(extern_testfun) then begin
   writeln('getprocedureaddress OK');
   if extern_testfun(123) = 123 then begin
    writeln('extern_testfun OK');
   end;
  end
  else begin
   writeln('getprocedureaddress error: ',getlasterror());
  end;
 end;
 

(ungeprüft).
mse
 
Beiträge: 1676
Registriert: 16. Okt 2008, 09:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.4.2,git master FPC 3.0,fixes_3_0) | 
CPU-Target: x86,x64,ARM
Nach oben

Beitragvon Mojo » 26. Jul 2017, 14:24 Re: C++ Bibliothek in Lazarus einbinden

Hallo mse,

Danke für deinen CODE.

Ich habe den Code mal probiert und bekomme die Bibliothek nichtgeladen - ich bekomme immer einen dynlibs.NILHANDLE zurück - kann ich mir nicht erklären :(
DLL_TEST2.jpg


Ich habe das Projekt und den Code begefügt zur kontrolle. Woran kann das liegen, dass ich die Bibliothek nicht geladen bekomme?

DLL_TEST_dynlib.ZIP


Code: Alles auswählen
Procedure TForm1.test_extern_testfun;
 
type Textern_testfun = function(ii: clong): clong; cdecl;
 
var MyHandle : TLibHandle = dynlibs.NilHandle;
    MyFunc   : Textern_testfun;
 
begin
 MyHandle:= loadlibrary(pchar('libtest.dll'));
 if MyHandle = dynlibs.NilHandle then begin
  memo1.lines.add('loadlibrary error: dynlib.Nilhandle');
 end
 else begin
   memo1.lines.add('loadlibrary OK');
   MyFunc := Textern_testfun(getprocedureaddress(MyHandle,'extern_testfun'));
   if assigned(MyFunc) then
    begin
    memo1.lines.add('getprocedureaddress OK');
    if MyFunc(123) = 123 then
     begin
      memo1.lines.add('extern_testfun OK');
     end;
    end
  else begin
    memo1.lines.add('Funktion nicht gefunden ');
  end;
 end;
FreeLibrary(MyHandle);
end;   


Viele Grüße, Mojo
Du hast keine ausreichende Berechtigung, um die Dateianhänge dieses Beitrags anzusehen.
Mojo
 
Beiträge: 7
Registriert: 26. Jul 2017, 07:34

Beitragvon mse » 26. Jul 2017, 14:46 Re: C++ Bibliothek in Lazarus einbinden

Ich habe hier im Moment kein Windows. Was bringt getlasterror()?
Um die FPC Version von getprocedureaddress() aufzurufen muss die unit Reihenfolge geändert werden, sorry:
Code: Alles auswählen
 
uses
 windows,dynlibs,ctypes;
 
mse
 
Beiträge: 1676
Registriert: 16. Okt 2008, 09:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.4.2,git master FPC 3.0,fixes_3_0) | 
CPU-Target: x86,x64,ARM
Nach oben

Beitragvon Mojo » 26. Jul 2017, 15:02 Re: C++ Bibliothek in Lazarus einbinden

getlasterror() bringt direkt nach loadlibrary(...) einen Wert von 193 - was auch immer das zu bedeuten hat.
Mojo
 
Beiträge: 7
Registriert: 26. Jul 2017, 07:34

Beitragvon Thandor » 26. Jul 2017, 15:05 Re: C++ Bibliothek in Lazarus einbinden

Probiere mal spaßeshalber "stdcall;" statt "cdecl;"
Thandor
 
Beiträge: 101
Registriert: 30. Jan 2010, 18:17
Wohnort: Berlin
OS, Lazarus, FPC: Windows 10 64Bit/ lazarus 1.6 mit FPC 3.0.0 (32Bit) | 
CPU-Target: 64Bit
Nach oben

Beitragvon mse » 26. Jul 2017, 15:07 Re: C++ Bibliothek in Lazarus einbinden

https://msdn.microsoft.com/en-us/librar ... 82(v=vs.85).aspx
Code: Alles auswählen
 
ERROR_BAD_EXE_FORMAT
    193 (0xC1)
    %1 is not a valid Win32 application.
 

Kannst du denn die DLL in einer anderen nicht FPC Windows Applikation verwenden?
mse
 
Beiträge: 1676
Registriert: 16. Okt 2008, 09:22
OS, Lazarus, FPC: Linux,Windows,FreeBSD,(MSEide+MSEgui 4.4.2,git master FPC 3.0,fixes_3_0) | 
CPU-Target: x86,x64,ARM
Nach oben

Beitragvon Mojo » 26. Jul 2017, 15:19 Re: C++ Bibliothek in Lazarus einbinden

stdcall bringt auch nix - ich versuche mal die DLL in einem anderen Format auszugeben.
Mojo
 
Beiträge: 7
Registriert: 26. Jul 2017, 07:34

Beitragvon Mojo » 26. Jul 2017, 16:05 Re: C++ Bibliothek in Lazarus einbinden

Also - geht nun.

Ich würde mal Licht ins Dunkle bringen: Der Fehler lag im GCC Compiler, der die DLL rausgegeben hat. Auf einem 64Bit System sollte man auch den Compiler für win64 installieren 8) . Warum der Compiler trozdem funktioniert hat weiß ich nicht. Nunmehr geht das Projekt mit einem GCC-7-WIN64 und gibt eine für Lazarus 1.6.4 FPC3.0.2 eine lesbare DLL aus, welche sowohl dynamisch als auch statisch eingebunden werden kann.

DLL statisch einbinden funktioniert mit folgendem Syntax:

Code: Alles auswählen
uses ctypes
...
Const DLL_NAME = 'libtest.dll';
 
// externe Funktionen deklarieren
function extern_testfun(ii:clong):clong; cdecl; external DLL_NAME name 'extern_testfun';


DLL dynamisch einbinden funktioniert mit folgendem Syntax:
Code: Alles auswählen
uses windows,dynlibs,ctypes;
...
Procedure TForm1.test_extern_testfun;
 
type Textern_testfun = function(ii: clong): clong; cdecl;
 
var MyHandle : TLibHandle = dynlibs.NilHandle;
    MyFunc   : Textern_testfun;
begin
  MyHandle:= loadlibrary(PChar('libtest.dll'));
  memo1.lines.add(inttostr(getlasterror()));
  if MyHandle = dynlibs.NilHandle then begin
  memo1.lines.add('loadlibrary error: dynlib.Nilhandle');
 end
 else begin
   memo1.lines.add('loadlibrary OK');
   MyFunc := Textern_testfun(getprocedureaddress(MyHandle,'extern_testfun'));
   if assigned(MyFunc) then
    begin
    memo1.lines.add('getprocedureaddress OK');
    if MyFunc(123) = 123 then
     begin
      memo1.lines.add('extern_testfun OK');
     end;
    end
  else begin
    memo1.lines.add('Funktion nicht gefunden ');
  end;
 end;
FreeLibrary(MyHandle);
end;


beides setzt in C++ ein C-Interface für die zu exportierenden Funktionen voraus, damit diese im Export der DLL lesbar sind, d.h. Ihre Namen so sind, wie sie programmiert wurden.
BSP:
Code: Alles auswählen
 
#define PRECTYPE1 long
#define DllExport  __declspec(dllexport)
#ifdef __cplusplus
extern "C" {
#endif
 
DllExport PRECTYPE1 extern_testfun(PRECTYPE1 i); //Testfunktion
 
#ifdef __cplusplus
}
#endif
 


An alle die mitgeholfen haben: vielen Dank dafür!

Viele Grüße, Mojo
Mojo
 
Beiträge: 7
Registriert: 26. Jul 2017, 07:34

» Weitere Beiträge siehe nächste Seite »
Nächste

Zurück zu Sonstiges



Wer ist online?

Mitglieder in diesem Forum: 0 Mitglieder und 3 Gäste

porpoises-institution
accuracy-worried