Tutorial: Mit C++ eine DLL erstellen und in Purebasic nutzen

Hier kannst du häufig gestellte Fragen/Antworten und Tutorials lesen und schreiben.
Benutzeravatar
milan1612
Beiträge: 810
Registriert: 15.04.2007 17:58

Tutorial: Mit C++ eine DLL erstellen und in Purebasic nutzen

Beitrag von milan1612 »

Tutorial
Ich werde euch hier eine Anleitung geben, mit deren Hilfe ihr euch mit einem kostenlosen C++ Compiler
eigene DLLs kompilieren und sie dann in Purebasic benutzen könnt.

Compiler installieren
Okay, dann mal los. Als erstes müsst ihr euch natürlich den Compiler runterladen und installieren.
Verwenden werden wir den kostenlosen MinGW Compiler der auf dem bekannten GCC Compiler
für Linux basiert. Allerdings nehmen wir hierzu nicht das offizielle MinGW Paket, da dieses schon
ziemlich alt ist. Es gibt aber einen inoffiziellen Installer, der viel öfter aktualisiert wird.

Um den zu finden geht ihr auf http://www.tdragon.net/recentgcc. Scrollt etwas herunter und ihr
werdet unter "download" den Bundled Installer finden (in meinem Fall "tdm-mingw-1.905.0-4.4.0-2.exe").

Ladet diese Datei runter und führt sie aus. Klickt auf "Create" und wählt das Verzeichnis.
Dann müsst ihr den gewünschten Sourceforge Mirror Server auswählen. Bei der Komponentenwahl
behaltet einfach die Standardauswahl bei und klickt auf "Install".

Der Code
Nachdem wir also den Compiler installiert haben, brauchen wir jetzt noch Code den wir kompilieren wollen.

Nehmt am besten für den Anfang erst mal Notepad bis ihr die Grundzüge des Kompilier- und Linkablaufs
von C++ verinnerlicht habt. Danach könnt ihr dann eine der vielen IDEs verwenden, da wird vieles einfacher.

So, dann schreiben wir mal eine kleine DLL in C++. Hier ist der Code, ich werde gleich noch alles dazu erklären:

Code: Alles auswählen

#include <fstream>
#include <string>
using namespace std;

#define EXPORT extern "C" __declspec(dllexport)

EXPORT int CountLines(const char* filename) {
  ifstream file(filename);
  int lineCount = 1;
  string line;
  
  while(getline(file, line)) {
    lineCount++;
  }
  
  return lineCount;
}
Ich werde hier jetzt nicht den gesamten C++ Code erklären, das könnt ihr anderswo lernen. Wichtig ist hier
bloß wie ich die Funktion CountLines deklariert habe. Ich habe das Makro EXPORT definiert, welches zwei wichtige
Dinge festlegt. Das extern "C" sagt dem Compiler, dass er den Funktionsnamen nicht nach den C++ Regeln benennen soll.
So wird der Funktionsname, wie in C üblich, einfach so übernommen, und wir können später mit Purebasic einfacher
darauf zugreifen. Das __declspec(dllexport) sagt dem Compiler, dass er die Funktion exportieren soll, damit sie nach
außen hin sichtbar wird (wie das ProcedureDLL in Purebasic).

Okay, jetzt speichert die Datei in einem leicht von der Console aus zugänglichen Ordner (Ich nenne sie "dll.cpp").

Der Compiler
So, jetzt werden wir die Datei kompilieren. Geht ins Startmenu -> MinGW -> MinGW Command Prompt. Das sollte ein
Konsolenfenster öffnen. Wechselt in das Verzeichnis, in dem ihr die dll.cpp abgespeichert habt (mit "cd <Ordner>").

Jetzt führt ihr diese zwei Befehle aus:

Code: Alles auswählen

g++ -c dll.cpp
g++ -shared -o TestDll.dll dll.o
Der erste Befehl kompiliert eure Datei. Dabei kommt die Datei "dll.o" heraus, das ist die sogenannte Objektdatei. Darin
ist der eigentliche Maschinencode enthalten, allerdings sind die Abhängigkeiten noch nicht aufgelöst, das heißt die
Funktionen der Standard Bibliothek sind noch nicht dazu gelinkt. Das erledigt jetzt der zweite Befehl. Damit haben wir
unsere DLL endlich erhalten.

Purebasic
Um jetzt unsere neu erstellte DLL unter Purebasic verwenden zu können, müssen wir sie mit den Befehlen der Library
Bibliothek öffnen, und können dann auf die Funktionen zugreifen. Ich verwende hier Prototypen, falls ihr damit nichts
anfangen könnt, lest euch am besten die Seiten dazu in der Purebasic Hilfe durch. Hier ist der Code:

Code: Alles auswählen

;Der Prototyp für unsere Funktion in der DLL
PrototypeC ProtoCountLines(Filename.s)

;Die DLL öffnen
If Not OpenLibrary(0, "TestDll.dll")
  End
EndIf

;Eine globale Instanz unseres Prototypes, dem die Addresse der Funktion in der DLL zugewiesen wird
Global CountLines.ProtoCountLines = GetFunction(0, "CountLines")

;Einfach aufrufen, heraus kommen sollte die Anzahl der Zeilen unserers C++ Codes
Debug CountLines("dll.cpp")

;Library schliessen (macht Purebasic auch automatisch nach Beenden des Programms)
CloseLibrary(0)
Nachtrag
Mit der hier gezeigten Methode könnt ihr doch recht einfach DLLs in C++ schreiben. Wenn der Code aber dann
umfangreicher wird, empfiehlt es sich eine IDE zu nutzen. Ich schlage hierzu CodeBlocks vor (www.codeblocks.org).
CodeBlocks ist kostenlos, erkennt fast alle Compiler automatisch und hat alle wichtigen Eigenschaften einer IDE.

Wenn ihr noch Fragen habt, dann fragt einfach. Verbesserungsvorschläge und Kritik sind erwünscht.
Bin nur noch sehr selten hier, bitte nur noch per PN kontaktieren
Benutzeravatar
Josef Sniatecki
Beiträge: 657
Registriert: 02.06.2008 21:29
Kontaktdaten:

Beitrag von Josef Sniatecki »

Vielen Dank für dieses Tutorial. Programmiere immer mehr nebenbei mit
C++ und bin für jede Information dankbar.

Eine Frage habe ich aber noch:
Wenn ich Templates für Typen einer Funktion nutze, so kann ich mir
denken, dass der Export einer solchen Funktion nicht einfach ist. Möchte
ich z.B. folgende Funktion exportieren, dann müsste ich diese mehrmals
mit verschiedenen Namen und verschiedenen Typen definieren, oder?

Code: Alles auswählen

template <typename TYPE>
TYPE myMin(TYPE value, TYPE minimum){
  if(value < minimum){
    return(minimum);
  }else{
    return(value);
  }
}
PureBasic unterstützt ja die Typen Integer, Float usw. Nun müsste ich
"myMinI", "myMinF", "myMinD" usw. definieren. Gibt es in C++ die
Möglichkeit den Export von Template-Funktionen zu vereinfachen?
PB 4.61 | Windows Vista - 32Bit
Homepage

"Wahrlich es ist nicht das Wissen, sondern das Lernen, nicht das Besitzen sondern das Erwerben, nicht das Dasein, sondern das Hinkommen, was den grössten Genuss gewährt." - Carl Friedrich Gauß
estate
Beiträge: 110
Registriert: 10.09.2004 08:53
Wohnort: nähe Graz
Kontaktdaten:

Beitrag von estate »

Hallo,

vielen Dank fürs Tutorial.

Ich wollte noch hinzufügen, dass man wirklich minGW verwenden muss, mit einer anderen Version des g++ stürzt das Programm ab.
Benutzeravatar
milan1612
Beiträge: 810
Registriert: 15.04.2007 17:58

Beitrag von milan1612 »

Josef Sniatecki hat geschrieben:Vielen Dank für dieses Tutorial. Programmiere immer mehr nebenbei mit
C++ und bin für jede Information dankbar.

Eine Frage habe ich aber noch:
Wenn ich Templates für Typen einer Funktion nutze, so kann ich mir
denken, dass der Export einer solchen Funktion nicht einfach ist. Möchte
ich z.B. folgende Funktion exportieren, dann müsste ich diese mehrmals
mit verschiedenen Namen und verschiedenen Typen definieren, oder?

Code: Alles auswählen

template <typename TYPE>
TYPE myMin(TYPE value, TYPE minimum){
  if(value < minimum){
    return(minimum);
  }else{
    return(value);
  }
}
PureBasic unterstützt ja die Typen Integer, Float usw. Nun müsste ich
"myMinI", "myMinF", "myMinD" usw. definieren. Gibt es in C++ die
Möglichkeit den Export von Template-Funktionen zu vereinfachen?
Ja, Template Funktionen musst du selber spezialisieren (fuer einen Typ) und dann
erst exportieren. Templates zu exportieren funktioniert nicht mal wenn man die
DLL in C++ selbst benutzen will, die Funktionalitaet ist zwar im Standard enthalten,
allerdings ist dieses Feature so schwer zu implementieren, dass fast alle Compiler
Hersteller darauf verzichten und einfach alles ignorieren. :lol:

@estate
Danke :)
Bin nur noch sehr selten hier, bitte nur noch per PN kontaktieren
Antworten