Mit Lazarus erzeugte dll von C++ aus aufrufen

Für allgemeine Fragen zur Programmierung, welche nicht! direkt mit Lazarus zu tun haben.
Antworten
KreuzBlick
Beiträge: 24
Registriert: Fr 3. Mai 2019, 17:45
OS, Lazarus, FPC: Win8.1 (L 2.0.10 FPC 3.0.4)
CPU-Target: 32Bit
Wohnort: Saarland

Mit Lazarus erzeugte dll von C++ aus aufrufen

Beitrag von KreuzBlick »

Hallo,
da ich hier schon oft kompetente Hilfe bekam, erlaube ich mir mal wieder eine Frage zu stellen, die allerdings über Lazarus hinausgeht. Mir ist inzwischen klar, wie man dlls mit Hilfe von Lazarus aufruft. Jetzt will ich es umgekehrt machen.
Konkret: Ich erzeuge mit Lazarus eine dll. Folgendes Beispiel habe ich in den Weiten des Netzes gefunden:

Code: Alles auswählen

library dlltest;

{$mode objfpc}{$H+}

uses
  Classes
  { you can add units after this };

function Addieren(x, y: Byte): Word; stdcall;
begin
  Result := x + y;
end;

function Subtrahieren(x, y: Byte): ShortInt; stdcall;
begin
  Result := x - y;
end;

exports
  Addieren index 1,
  Subtrahieren index 2;

begin
end.
Die dll stellt zwei Funktionen zur Verfügung, Addieren und Subtrahieren.
Die will ich jetzt in einem möglichst einfachen C++-Programm ohne weiteren Überbau verwenden, um den Mechanismus zu verstehen. Meine Suche im Internet endet in der Regel bei völlig komplexen Beispielen, die ich dann nicht verstehe. Gibt es dafür auch eine einfache Lösung?
Auch für einen Link, wo das ganze einfach erklärt wird, bin ich natürlich dankbar.

Edit: Rechtschreibfehler in der Überschrift.
Zuletzt geändert von KreuzBlick am Sa 1. Aug 2020, 13:50, insgesamt 2-mal geändert.
Viele Grüße
Gerold

Benutzeravatar
theo
Beiträge: 8413
Registriert: Mo 11. Sep 2006, 19:01

Re: Mit Lazarus erzeugte dll vom C++ aus aufrufen

Beitrag von theo »

Ich denke das geht bei dem einfachen Beispiel von C++ aus genau gleich wie mit einer C Library. Das hier ist aber kein C++ Forum.
Warum willst du das überhaupt machen?
Der umgekehrte Weg ist sinnvoller, da man so mit Freepascal Betriebssystems- und andere, große Bibliotheken verwenden kann, die oft in C bzw. C++ geschrieben sind.

KreuzBlick
Beiträge: 24
Registriert: Fr 3. Mai 2019, 17:45
OS, Lazarus, FPC: Win8.1 (L 2.0.10 FPC 3.0.4)
CPU-Target: 32Bit
Wohnort: Saarland

Re: Mit Lazarus erzeugte dll von C++ aus aufrufen

Beitrag von KreuzBlick »

Ich denke auch, dass da zwischen C und C++ kein großer Unterschied ist.
Die Beispiele, die ich gefunden habe, gehen aber alle davon aus, dass die von C aufgerufene dll auch in C erzeugt worden ist. Ich will die dll aber mit Lazarus erzeugen.
Der Grund, warum ich das machen will, ist ganz einfach. Ich kenne mich mit Lazarus viel besser aus als mit C/C++. In einem bestehenden C/C++ Projekt will ich Erweiterungen mit Lazarus schreiben und diese dann in eine dll packen. Dann muss ich die exportierten Funktionen natürlich irgendwie aufrufen.
Es ist mir klar, dass das hier das "falsche" Forum dafür ist. Aber vielleicht hat das ja schon mal jemand gemacht und kann mir einen kleinen Tipp oder Link geben.
Viele Grüße
Gerold

Benutzeravatar
theo
Beiträge: 8413
Registriert: Mo 11. Sep 2006, 19:01

Re: Mit Lazarus erzeugte dll von C++ aus aufrufen

Beitrag von theo »

KreuzBlick hat geschrieben:
Sa 1. Aug 2020, 13:47
Ich denke auch, dass da zwischen C und C++ kein großer Unterschied ist.
Das meinte ich nicht, ich meinte, dass du eine Freepascal DLL mit einfachen Typen, wie in deinem obigen Beispiel, genau gleich importieren kannst, wie eine C DLL.
Wie du das mit deinem C++ Tool machst, ist aber tatsächlich keine Frage für dieses Forum.

PascalDragon
Beiträge: 55
Registriert: Mi 3. Jun 2020, 07:18
OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
CPU-Target: Aarch64 bis Z80 ;)
Wohnort: München

Re: Mit Lazarus erzeugte dll von C++ aus aufrufen

Beitrag von PascalDragon »

KreuzBlick hat geschrieben:
Fr 31. Jul 2020, 18:18

Code: Alles auswählen

library dlltest;

{$mode objfpc}{$H+}

uses
  Classes
  { you can add units after this };

function Addieren(x, y: Byte): Word; stdcall;
begin
  Result := x + y;
end;

function Subtrahieren(x, y: Byte): ShortInt; stdcall;
begin
  Result := x - y;
end;

exports
  Addieren index 1,
  Subtrahieren index 2;

begin
end.
Die dll stellt zwei Funktionen zur Verfügung, Addieren und Subtrahieren.
Erstmal Anmerkungen für den Pascal Code:
  • Verwende cdecl statt stdcall
  • Nimm die Typen aus der Unit ctypes (zum Beispiel cuint8 statt Byte), dann kannst du das nämlich leichter mit dem Header für C/C++ abstimmen (siehe unten)
  • Lass die index Direktiven weg; Ordinale Importe werden soooo selten gebraucht, dass man das auch einfach vergessen kann
KreuzBlick hat geschrieben:
Fr 31. Jul 2020, 18:18
Die will ich jetzt in einem möglichst einfachen C++-Programm ohne weiteren Überbau verwenden, um den Mechanismus zu verstehen. Meine Suche im Internet endet in der Regel bei völlig komplexen Beispielen, die ich dann nicht verstehe. Gibt es dafür auch eine einfache Lösung?
Auch für einen Link, wo das ganze einfach erklärt wird, bin ich natürlich dankbar.
Als erstes brauchst du einen Header für deine Bibliothek. Sowas hier zum Beispiel:

Code: Alles auswählen

#include <stdint.h>

#ifdef __cplusplus
extern "C" {
#endif

extern uint16_t Addieren(uint8_t a, uint8_t b);
extern int16_t Subtrahieren(uint8_t a, uint8_t b);

#ifdef __cplusplus
}
#endif
Unter *nix musst du dem Programm dann mitteilen, wo es deine Bibliothek finden kann. In meinem Beispiel: ich habe die Library nach bin kompliert, mein Quellcode ist in src und mein aktuellen Verzeichnis ist das Überverzeichnis von beiden. Dann geht es einfach so:

Code: Alles auswählen

gcc -o bin/tdlltest -Lbin -ldlltest ./src/tdlltest.c
-L ist der Suchpfad für Bibliotheken, -l ist eine Bibliothek die gelinkt wird (der Linker erweitert das dann zu libdlltest.so)

Unter Windows musst du eine Importbibliothek generieren. Eigentlich kann dir FPC dabei helfen, aber irgendwie habe ich das gerade nicht zu laufen gebracht, also musst du manuell eine Definitionsdatei (hier dlltest.def) erstellen:

Code: Alles auswählen

LIBRARY dlltest
EXPORTS
  Addieren
  Subtrahieren
Das hier ist für x86_64. Für i386 musst du entweder die Exporte in der Bibliothek ändern auf Addieren name 'Addieren' (das führt aber dazu, dass du unter *nix Probleme bekommst) oder in der Definitionsdatei _Addieren angeben, da unter Win32 für cdecl Funktionen ein _ voran gestellt wird (es empfiehlt sich dann zwei Definitionsdateien zu haben).

Aus der Definitionsdatei erzeugst du nun eine Importbibliothek (musst du jedes Mal wachen, wenn sich die Exporte der Bibliothek ändern (also eine Funktion kommt hinzu oder fällt weg), aber nicht, wenn sich nur der Code ändert):

Code: Alles auswählen

lib /machine:x64 /def:dlltest.def /out:dlltest.lib
Die finale Binary kannst du nun entweder in Visual Studio generien (dabei die lib Datei als Linkereingabe angeben) oder über die Kommandozeile (für das aktuelle Beispiel musst du die x64 Umgebung von Visual Studio gestartet haben):

Code: Alles auswählen

cl src\tdlltest.c /link bin\dlltest.lib
Ich hoffe das hilft dir weiter.
FPC Compiler Entwickler

KreuzBlick
Beiträge: 24
Registriert: Fr 3. Mai 2019, 17:45
OS, Lazarus, FPC: Win8.1 (L 2.0.10 FPC 3.0.4)
CPU-Target: 32Bit
Wohnort: Saarland

Re: Mit Lazarus erzeugte dll von C++ aus aufrufen

Beitrag von KreuzBlick »

Hallo PascalDragon,

erstmal vielen Dank für die Mühe. Das muss ich jetzt alles mal in Ruhe ausprobieren.
Viele Grüße
Gerold

Socke
Lazarusforum e. V.
Beiträge: 2780
Registriert: Di 22. Jul 2008, 19:27
OS, Lazarus, FPC: Lazarus: SVN; FPC: svn; Win 10/Linux/Raspbian/openSUSE
CPU-Target: 32bit x86 armhf
Wohnort: Köln
Kontaktdaten:

Re: Mit Lazarus erzeugte dll von C++ aus aufrufen

Beitrag von Socke »

Unter https://macpgmr.github.io/MacXPlatform/ ... nLibs.html habe ich noch ein sehr schöne Zusammenfassung für verschiedene Sprachen gefunden, darunter auch C und C++
MfG Socke
Ein Gedicht braucht keinen Reim//Ich pack’ hier trotzdem einen rein

PascalDragon
Beiträge: 55
Registriert: Mi 3. Jun 2020, 07:18
OS, Lazarus, FPC: L 2.0.8, FPC Trunk, OS Win/Linux
CPU-Target: Aarch64 bis Z80 ;)
Wohnort: München

Re: Mit Lazarus erzeugte dll von C++ aus aufrufen

Beitrag von PascalDragon »

Der Punkt bei „What about stdcall?” ist nicht ganz korrekt: Natürlich unterstützt Visual Studio auch cdecl, es ist sogar die Standardcallingconvention und die Namen, die FPC für cdecl-Funktionen generiert sind auch kompatibel damit (mit „_” vorneweg für Win32 und ohne für Win64). Und man kann dekorierte Namen auch abschalten (egal welcher C++-Compiler), in dem man den Code in extern "C" { … } packt, wie ich das in meinem Beispiel gemacht habe.
FPC Compiler Entwickler

Antworten