Kreuz und quer durch C++, alles ist dabei ...
-
Der aus dem Westen ... schrieb:
Problem ist: ich weiss nicht mal, WIE aus meinem schnöden Code eine binäre DLL wird.
Eine DLL erstellst du in Visual Studio, indem du einfach bei dem Projekt den gewünschten "Konfigurationstyp" angibst. Das geht bei den Eigenschaften des Projekts unter "Allgemein" - jedenfalls bei VS 2005, das ich gerade vor mir habe.
Du musst allerdings nicht nur dafür sorgen, dass deine Klassen und Funktionen aus der DLL exportiert werden (mit __declspec(dllexport)), sondern dass andere Binaries diese auch wieder importieren (mit __declspec(dllimport)). Die Klassen und Funktionen müssen also verschieden deklariert sein, je nachdem, ob sie beim Bauen der DLL selbst oder beim Bauen eines anderen Binaries gelesen werden.
Ich verwende dazu eine Lösung, die mit VS und MinGW funktioniert:
// --- MyClass.hpp #ifdef MYDLL_EXPORTS #undef EXPORT_IMPORT #define EXPORT_IMPORT __declspec(dllexport) #else #undef EXPORT_IMPORT #define EXPORT_IMPORT __declspec(dllimport) #endif class EXPORT_IMPORT MyClass { // ... }; void EXPORT_IMPORT myFunction();Jetzt muss in den Einstellungen zum Projekt, das MyDll.dll baut noch das Makro MYDLL_EXPORTS definiert sein (und in den importierenden Binaries ist es natürlich nicht definiert!). Dann klappts auch mit der DLL.
Der aus dem Westen ... schrieb:
4. Ich weiss auch nicht. Vielleicht mag ich es nicht, die Werkzeuge fremder MEnschen zu nutzen, deren Code ich (noch nicht) verstehe. Solange ich jedoch nicht den Durchblick habe, werde ich schön die Finger davon lassen.
Diese Einstellung ist für Anfänger vielleicht lobenswert. Da lernt man halt was. Allerdings führt sie auch dazu, dass du viele Dinge halt nicht verwenden kannst, die andere schon sehr gut erledigt haben. Zum Beispiel hindert es dich daran, die STL zu verwenden. Oder Boost. Oder sonst eine Library.
Vielleicht solltest du diese Haltung noch einmal überdenken?
Stefan.
-
Mo-mo-mo-mo-moment! Wie ist das zu verstehen?
Also erst mal ein neues Projekt, Anwendungstyp DLL. So war's doch, oder?
Da ich eine neue DLL ohne alte Funktionen erstellen will, muss ich dllexport verwenden, da so neue Funktionen hinzugefügt werden.
Zuerst Header erstellen, Deklarationen hinzufügen (damit man auf die Liste zugreifen kann), dann Funktionen definieren und ein Schutzmakro einbinden. Anschliessend kompilieren.
Korrigiere mich, wenn ich falsch liege. Aber was ich da hingeschrieben habe, ist sozusagen MEIN EIGENER Maschinencode. Einfache Anweisungen, das ist meine Art zu denken.
Und was die STL angeht: Ich habe vor, ein guter - ich meine ein WIRKLICH guter - Programmierer zu werden. Aber wenn ich nur den einfachen Weg gehe und mich nie mit der Interna der STL einlasse, werde ich es auch zu nichts bringen. Dazu will ich auch sagen, dass ich erst 18 bin und vor einem Jahr mit C++ angefangen habe, und ich habe die Befürchtung, dass ich den Anschluss verpassen könnte, DESHALB nehme ich den harten Weg und beschäftige mich mit Speicherverwaltung, dynamischen Arrays und komplexen Listen (denn komplexen ist die ganze Matrix schon). Und nur, wenn ich ABSOLUT nicht klarkomme (wie zum Beispiel mit selbstprogrammierten streams), greife ich auf Hilfe von Ausserhalb zu.
-
Der aus dem Westen ... schrieb:
Also erst mal ein neues Projekt, Anwendungstyp DLL. So war's doch, oder?
Ja.
Der aus dem Westen ... schrieb:
Da ich eine neue DLL ohne alte Funktionen erstellen will, muss ich dllexport verwenden, da so neue Funktionen hinzugefügt werden.
Das verstehe ich nicht ganz. Du musst Funktionen usw. als "dllexport" deklarieren, damit sie von außerhalb der DLL verfügbar werden. Sonst kannst du die DLL ja gar nicht benutzen. War es das, was du meintest?
Der aus dem Westen ... schrieb:
Zuerst Header erstellen, Deklarationen hinzufügen (damit man auf die Liste zugreifen kann), dann Funktionen definieren und ein Schutzmakro einbinden. Anschliessend kompilieren.
Im Prinzip ja. Bitte beachte aber, dass im Falle von Templates *kein* "dllexport" verwendet werden darf. Hier sind ja die Definitionen bereits im Header vorhanden und es wird überhaupt kein Code für die DLL erzeugt.
Der aus dem Westen ... schrieb:
Und was die STL angeht: Ich habe vor, ein guter - ich meine ein WIRKLICH guter - Programmierer zu werden. Aber wenn ich nur den einfachen Weg gehe und mich nie mit der Interna der STL einlasse, werde ich es auch zu nichts bringen. Dazu will ich auch sagen, dass ich erst 18 bin und vor einem Jahr mit C++ angefangen habe, und ich habe die Befürchtung, dass ich den Anschluss verpassen könnte, DESHALB nehme ich den harten Weg und beschäftige mich mit Speicherverwaltung, dynamischen Arrays und komplexen Listen (denn komplexen ist die ganze Matrix schon). Und nur, wenn ich ABSOLUT nicht klarkomme (wie zum Beispiel mit selbstprogrammierten streams), greife ich auf Hilfe von Ausserhalb zu.
Ich möchte dich keineswegs davon abbringen, Dinge verstehen zu wollen, die du verwendest! Und Algorithmen und Datenstrukturen zu verstehen, gehört sicherlich dazu, ein guter Programmierer zu sein.
Bloß klang dein Beitrag so, als wolltest du gar nichts verwenden, das du nicht vorher verstanden hast. Und das erschien mir ein Bischen zu viel des Guten. Mehr wollte ich gar nicht sagen. Ein guter Programmierer versteht sich nämlich auch auf die Kunst, gute Dinge wieder zu verwenden. Damit er sein Ziel nicht aus den Augen verliert...
Stefan.
-
DStefan schrieb:
Das verstehe ich nicht ganz. Du musst Funktionen usw. als "dllexport" deklarieren, damit sie von außerhalb der DLL verfügbar werden. Sonst kannst du die DLL ja gar nicht benutzen. War es das, was du meintest?
Bingo! Genau das. In der Header muss die Deklaration + __declspec(dllexport) stehen. Im DLL-Projekt muss dann die Header eingebunden sein, dann kann man die Funktionen definieren, oder?
DStefan schrieb:
Im Prinzip ja. Bitte beachte aber, dass im Falle von Templates *kein* "dllexport" verwendet werden darf. Hier sind ja die Definitionen bereits im Header vorhanden und es wird überhaupt kein Code für die DLL erzeugt.
Für Templates fällt die DLL ins Wasser. Aber was ist mit statischen Bibliotheken?
DStefan schrieb:
Ich möchte dich keineswegs davon abbringen, Dinge verstehen zu wollen, die du verwendest! Und Algorithmen und Datenstrukturen zu verstehen, gehört sicherlich dazu, ein guter Programmierer zu sein.
Bloß klang dein Beitrag so, als wolltest du gar nichts verwenden, das du nicht vorher verstanden hast. Und das erschien mir ein Bischen zu viel des Guten. Mehr wollte ich gar nicht sagen. Ein guter Programmierer versteht sich nämlich auch auf die Kunst, gute Dinge wieder zu verwenden. Damit er sein Ziel nicht aus den Augen verliert...
Klar, sonst wären Vererbung, Templates und RTTI wohl verschwendet, oder?
-
Der aus dem Westen ... schrieb:
Für Templates fällt die DLL ins Wasser. Aber was ist mit statischen Bibliotheken?
Dieselbe Antwort. DLLs enthalten fertig übersetzten Code, der unmittelbar ausgeführt wird, wenn man die jeweilige Funktion aufruft.
Im Falle von Templates (und so lange dein Compiler nicht das Keyword "export" unterstützt) wird der Code eines Templates am Ort der Verwendung/Instanziierung erzeugt. Das ist nicht ganz dasselbe wie inline aber so ähnlich.
Also kann man aus Templates keine DLLs erzeugen.
Stefan.
-
Aber mein Compiler unterstützt "export". Nur weiss ich nicht, was mir das bringt.
-
Aber mein Compiler unterstützt "export".
Aus deinem Post kann man erkennen, dass du Visual C++ nutzt und das unterstützt export nicht!
-
Stimmt. Da habe ich einen Anweisung verwechselt.
Also, entweder bin ich zu blöd dafür, oder mein Compiler hasst mich (was gut sein kann, da er sich immer aufhängt, wenn ich mit der rechten Maustaste klicke), um DLLs zu erstellen. Ich habe eine Klasse, die ... aber seht selbst:
// Headerdatei SimpleClassDLL.h // #pragma once #ifndef _SIMPLECLASSDLL_H #define _SIMPLECLASSDLL_H #include <iostream> using std::cout; using std::endl; class CSimpleClass { public: void __declspec(dllexport) Hello(); void __declspec(dllexport) Bye(); }; #endif // Quellcodedatei SimpleClassDLL.cpp // #include "SimpleClassDLL.h" void CSimpleClass::Hello() { cout<<"Hallo!"<<endl; } void CSimpleClass::Bye() { cout<<"Auf Wiedersehen!"<<endl; }Hier existeren zwei Dateien: SimpleClassDLL.h, die die Deklaration der Klasse vornimmt, und SimpleClassDLL.cpp, die die beiden einzigen Funktionen der Klasse definiert. Ich kompiliere meinen Code und heraus kommt eine DLL von ungefähr 37 KB Größe. Dann will ich meine Funktionen in einem anderen Projekt unterbringen. Dazu kopiere ich den Header der Klasse und die DLL in den Projektodner und binde dann die Headerdatei ein:
// Ein anderes Projekt, Main.cpp // #include "SimpleClassDLL.h" int main() { CSimpleClass SC; SC.Hello(); SC.Bye(); cin.get(); return 0; }Hier wird die neue Klasse eingebunden, eine Instanz erstellt und die beiden Funktionen der Klasse aufgerufen. Nein, das heisst, sie SOLLEN aufgerufen werden, aber mein Linker quaselt was von wegen "nichtaufgelöstem extenem Symbol" (es heisst immer, Laufzeitfehler seien die schlimmsten Fehler, aber ich denke, Linkerfehler können einen in den Wahnsinn treiben). Kann mir jemand verraten, was ich falsch mache?
-
1. Du musst die gesamte Klasse exportieren (dllexport nach "class").
2. Du musst in dem Projekt, welches die DLL benutzt die Klasse auch wieder IMportieren - wie Du das am besten machst, ohne zwei Header für dieselbe Klasse zu erzeugen, hat DStefan schön beschrieben.
3. Beim Erstellungsprozess der DLL wird eine LIB-Datei erzeugt. Diese musst Du beim nutzenden Projekt einbinden, damit die undefined references des Linkers befriedigt werden.
-
Also ...
Erstens:
class __declspec(dllexport) CSimpleClass{/*...*/};Zweitens (nach der Erstellung der DLL):
class __declspec(dllimport) CSimpleClass{/*...*/};Drittens: Die .LIB mitkopieren. Richtig?
-
1./2. Ja, wobei Du die Datei nicht ändern musst. Lies den Beitrag von DStefan nochmal

3. Ja, und in den Projektoptionen bei "zusätzliche Linkerabhängigkeiten" eintragen, oder (ein MSVC-Konstrukt), in die Headerdatei folgendes schreiben:
#pragma comment(lib,"dllname.lib")
-
Den habe ich bereits gelesen :D.
OK, wird noch heute ausprobiert.
-
Davon abgesehen: Alles was mit Bibliothekten etc. zu tun hat, ist kein ANSI C++ (Der Thread gehört eher in "MFC (Visual C++)"). Es gibt keine dll & ähnliches in ANSI C++.