Bibliothek erstellen
-
Hi, ich möchte mehrere Klassen zu einer Bibliothek zusammenfassen die ich dann in anderen Programmen verwenden kann. Vorgegangen bin ich nach diesen Link:
http://msdn.microsoft.com/en-us/library/ms235636%28v=VS.100%29.aspx
Ich habe also das Win32-DLL-Projekt erstellt, alle .h und .cpp Dateien hinzugefügt und anstatt z.B.
class Button {...
class __declspec(dllexport) Button {...
geschrieben.
Kompilieren funktioniert soweit, allerdings frage ich mich wie ich das ganze nun in einer Anwendung implementiere. Reicht es die .dll, .lib Datei und sämtliche Headerdateien einzubinden?
-
Schlauer wäre ein Makro im Header:
#ifdef MY_DLL_BUILD #define MY_DLL_EXPORT __declspec(dllexport) #else #define MY_DLL_EXPORT __declspec(dllimport) #endif class MY_DLL_EXPORT MyClass { // .. } int MY_DLL_EXPORT MyFunction { // ... }
Jetzt definierst Du MY_DLL_EXPORT im Projekt der DLL unter Präprozessor. Es braucht nichts in der "Client Anwendung" beim bauen definiert werden.
So brauchst Du das nicht jedesmal von export auf import ändern.
lg
-
Was genau meinst du mit implementieren?
Du machst ja ein neues Projekt auf, aus dem die dll dann später kompiliert wird.
So un da hast ja deine Header-Dateien und deine Quelldateien.
Und in den Quelldateien is ja deine Implementierung.So und dann kannste in deinem Projekt einfach die Header-Datei einbinden und dem Linker sagen wo die dll liegt, dann linkst am besten noch die .lib die dazu erstellt wurde rein, dann musste nicht mehr machen, sonst musst du ja die Bibliothek noch reinladen usw...
Aber vor die Klasse selbst musst du eigentlich soweit ich weiß gar nicht das __declspec( dllexport ) schreiben.
Lg freeG
-
fr33g schrieb:
Aber vor die Klasse selbst musst du eigentlich soweit ich weiß gar nicht das __declspec( dllexport ) schreiben.
Lg freeGDoch, wenn es exportiert werden soll schon. Zumindest bin ich es so gewohnt, dass es nötig ist. Zumindest bei C++. Für C reicht da auch eine .def Datei, aber is ja das C++ Forum. Aber ja, das einbinden des Headers und der Lib reicht, solange das makro wie von mir o.g. genutzt wird. Sonst gibts Linkerfehler ob des statischen dllexport.
Bin kein so guter Erklärbär, bitte um Verzeihung wenns nicht 100% verständlich ist.
lg
-
UnbekannterNr.42 schrieb:
fr33g schrieb:
Aber vor die Klasse selbst musst du eigentlich soweit ich weiß gar nicht das __declspec( dllexport ) schreiben.
Lg freeGDoch, wenn es exportiert werden soll schon. Zumindest bin ich es so gewohnt, dass es nötig ist. Zumindest bei C++. Für C reicht da auch eine .def Datei, aber is ja das C++ Forum. Aber ja, das einbinden des Headers und der Lib reicht, solange das makro wie von mir o.g. genutzt wird. Sonst gibts Linkerfehler ob des statischen dllexport.
Bin kein so guter Erklärbär, bitte um Verzeihung wenns nicht 100% verständlich ist.
lgMhh ich hab mir erst vorgestern ne Bibliothek gemacht, und diese hab ich so erstellt wie ich es beschrieben hab und sie funktioniert tadellos
Vielleicht kann da mal jemand das kurz erläutern der noch ein bisschen mehr ahnung hat wie ich
Lg freeG
-
UnbekannterNr.42 schrieb:
Schlauer wäre ein Makro im Header:
#ifdef MY_DLL_BUILD #define MY_DLL_EXPORT __declspec(dllexport) #else #define MY_DLL_EXPORT __declspec(dllimport) #endif class MY_DLL_EXPORT MyClass { // .. } int MY_DLL_EXPORT MyFunction { // ... }
Jetzt definierst Du MY_DLL_EXPORT im Projekt der DLL unter Präprozessor. Es braucht nichts in der "Client Anwendung" beim bauen definiert werden.
So brauchst Du das nicht jedesmal von export auf import ändern.
lgDanke für den Tipp.
Noch eine Frage. Was wenn ich nicht möchte, dass alle Variablen oder Funktionen einer Klasse sichtbar sind, da diese nur intern verwendet werden, also von anderen Funktionen der Klasse? Kann ich diese für den Nutzer der DLL unsichtbar machen bzw. muss ich dann eine modifizierte Headerdatei zur Verfügung stellen?
-
Und wo muss ich denn in Visual Studio den Pfad ändern damit die DLL gefunden wird? Ich habe schon unter "Configuration Properties -> VC++ Directories" alle Möglichkeiten durchprobiert. Auch das Hinzufügen unter "Linker -> General -> Additional Library Directories" war nicht erfolgreich. Kopiere ich die DLL direct in den Ordner mit der Anwendung geht es.
-
Eine variable die nur die klasse intern
nutzt sprich nur für die implementierung gedacht ist, gehört in den privat bereich.Du gibst unter den eigenschaftendes projektes bei zusätzliche bibliotheken( ich glaub so heißt das, genaue bezeichnung bzw menüführung kann ich dir leider erst morgen sagen ) den pfad der dll an und bei zusätzliche incldepfade den der headerdatei. Bei zusättliche abhängigkeiten die lib.
Lg freeG
-
Der User sieht dann aber immernoch im Header dass es diese Variable gibt. Ist es möglich für den Import der dll eine andere Header Datei zur Verfügung zu stellen (wo ich die Variable einfach weg lasse), als für den export?
Mir ist auch noch nicht ganz klar wozu die lib-Datei ist. Brauche ich mit dieser überhaupt Headerdateien mitliefern?Wie baut man denn am besten eine solche Programmbibliothek von der Ordnerstruktur auf, damit die Implementierung in anderen Anwendungen einfach ist? Im Moment habe ich einen Hauptordner in dem sich weiter verschachelt weitere Subordner befinden. Die .cpp und .h Datei einer Klasse befindet sich jeweils im selben Ordner.
Ist es sinnvoller einen Ordner include für alle .h Dateien und einen für alle .cpp dateien zu erstellen?
-
Der User sieht dann aber immernoch im Header dass es diese Variable gibt. Ist es möglich für den Import der dll eine andere Header Datei zur Verfügung zu stellen (wo ich die Variable einfach weg lasse), als für den export?
Nein, unterschiedliche header führen zu undefinierten verhalten.
sprich, es kann funktionieren, muss aber nicht. Schlimmstenfalls passiert folgendes: mit den Compilerflags funktioniert es, mit denen nicht.wo(als welche position) der compiler in der vtable z.b. anlegt, iss ihm ueberlassen, aber die art und weisse wie die methoden am header definiert sind, hat einfluss drauf.
Eigentlich solltest du sowas nicht brauchen, aber dazu spaeter ....Für solche faelle gibt es Proxy klassen !
man definiert sowas fuer ne Lib z.b.:
foo.h
class fooImpl; #include memory class foo { public: foo(); ~foo(); void myfoomethod(); private: const std::autoptr<fooImpl> mPimpl; };
foo.cpp
#include<foo.h> // steht meist in nem extra verzeichnis wegen dem exportierens #include"fooImpl.h" // implementatiomsklasse brauchen wir foo::foo():mPimpl(new fooImpl) { } foo::~foo() { } void foo::myfoomethod() { mPimpl->myfoomethod(); }
fooImpl.h
class fooImpl { public: fooImpl(); ~fooImpl(); void myfoomethod(); private: void mySecretMethod(); /// und noch vieles andere mehr };
fooImpl.cpp
fooImpl::fooImpl() { } fooImpl::~fooImpl() { } void fooImpl::myfoomethod() { /// ganz wildes tun was keiner mitbekommen soll /// und unter anderem auch die secret methode aufrufen mySecretMethod(); } void fooImpl::mySecretMethod() { /// und hier die ganz geheimen dinge tun ... }
Exportieren musst nur foo.h, also von der secret methode bekaem eh keiner was mit!
Das macht man aber hoffentlich nur bei statischen libs ... zumindest unter windows. keine ahnung unter linux geht das wahrscheinlich auch bei den dynamischen(.so) meist gut.
Machen sollt man sowas sowieso bei Biblios, siehe Pimpl-Idom. Hat nicht nur vorteile wegens der Security.
Da windows dlls + Klassendefinitionen so seine Problemchen hat, ist es auf Dauer praktisch so wenig wie moglich implementationsdetails ueber dll schnittstellen zu schicken. Ein binaerinkompatibles Flag setzen und dir zerreists deine schnittstelle zwische exe und dll, wenn du da implementierungsdetails rueberschickst !
Deswegen: ProtokollKlassen verwenden: die haben die wenigsten Abhaengigkeiten.
Protokollklassen sind pure abstract klassen. Das sind eigentlich nur noch benamste vtables. Was dann schiefgehen kann sind nur noch Benamsung(name mergling), vtables generation selber, und parameterausrichtung.
namemergling kann man abschalten, parameterausrichtung kann man vorschreiben (__declspec(dllexport) macht auch sowas) und vtables werden ueber generationen von compilern meist eh gleich bleiben. Nur so erhaelt man stabile Dll interfaces, wenn man unbedingt klassen exportieren will (c++ interfaces).Also bei dlls und klassen, immer schoen von nem Interface ableiten, und nur mit dem interface ausserhalb arbeiten!
Ciao ...
-
Was ich noch nicht verstehe ist z.B. der Aufruf
class fooImpl;
. Was bewirkt dieser? Mich haben diese Aufrufe schon bei den wxwidgets-library-headern verwundert. Ist das so eine Art extern definition wie bei Variablen?
Wenn ich dich richtig verstanden habe wären also Protokollklassen die ideale Lösung? Ich erstelle also von jeder (abstrakten) Klasse eine weitere abgeleitete "Interface-Klasse" die dann nach außen für den User sichtbar ist und alle private definitions der abstracten Klasse nicht mehr beinhaltet.
Nur muss ich doch wenn ich eine Klasse von einer anderen ableite deren Header includen. Müsste diesen also auch zur Verfügung stellen, was ich ja nicht möchte da dann wieder die private definitions sichtbar wären.
-
Student83 schrieb:
Was ich noch nicht verstehe ist z.B. der Aufruf
class fooImpl;
. Was bewirkt dieser?
Das ist kein Aufruf, sondern eine Vorwärtsdeklaration. Diese wird primär dazu benutzt, Abhängigkeiten zu verringern. Wenn der vollständige Typ nicht bekannt sein muss (Referenz-/Zeigervariable auf ihn, Vorkommen als Parameter und Rückgabetyp einer Funktion, etc.), kann dessen Deklaration verwendet werden. Damit kann man sich oft etliche
#include
s sparen, was sich zumindest positiv auf die Kompilierzeit auswirkt, aber oft sogar notwendig ist.
-
Ich erstelle also von jeder (abstrakten) Klasse eine weitere abgeleitete "Interface-Klasse" die dann nach außen für den User sichtbar ist und alle private definitions der abstracten Klasse nicht mehr beinhaltet.
Nein, Du hasst doch die abstracte Klasse, also das Interface.
deine interne Implementierung kennt das Interface klar, aber auch die Implementierung, logisch.
Deine externe Anwendungen kennen nur noch das Interface! Das heisst die haben Null ahnung was dahinter steckt ... und genau das willst du doch erreichen oder ?Beispiel:
foo_if.hclass IFoo { protected: // abhaengig davon, ob man das expliziete Loeschen von zeigern auf interfaces zulassen will, Ich halts fuer schlecht, daher protected ! virtual ~IFoo(){} public: /// Hier die Methoden die deine Klasse zur verfügung stellen soll: virtual void myMethod() = 0; }
fuer deine Interne Implementierung, kannst ja nun ne FooImpl Schreiben, die von IFoo ableitet ! Die FooImpl muss natuerlich IFoo kennen, was ja kein problem ist.
Jetzt kommt das Schöne an der Geschichte:
Ueber irgendwelche Zugriffsfunktionen gibst an deinen Anwender nur noch IFoo, meist als Zeiger nach aussen !
Und der Anwender muss nur das Interface kennen :also der kann dann sowas machen:
/// irgendwie das Interface bekommen: IFoo * pFoo = getFoo(); /// kann auch anders nach aussen gegeben werden ... /// Und mit dem Interface kann er nur das machen, was ihm im interface erlaubst ! /// in obigen falle kann er nur myMethod() aufrufen pFoo->myMethod();
Der Anwender von IFoo muss nur IFoo kennen, und die datentypen die IFoo verwendet halt, klar ...
von der Impl sieht er gar nix !Und Du erreichst eine sauebere Trennen zwischen Protokoll/Schnittstelle und Implementation!
wenn Du mit IFoo ned hinkommst, weisst das dein Interface ned genau genug definiert war !
In grossen Projecten, mit mehreren Modulen und mehreren beteiligen Programmierern/Firmen ... iss das auf c++ Ebene die saubere Variante, Verhalten und Funktionalitaet vorzuschreiben.
Meist existiert das Interface dann weit weit bevor die Implementierung existiert. Das Interface selber iss meist auch noch versioniert.
Und Du erreichst ein Highlight der Objectorientierten programmierung -> du kannst den Anwendern eines Interfaces unterschiedliche Implementierungen unterschieben, ohne das die Anwender ihre Module neucompilieren muessen, saubere Interfaces mal vorrausgesetzt.Ciao ...
-
fr33g schrieb:
UnbekannterNr.42 schrieb:
fr33g schrieb:
Aber vor die Klasse selbst musst du eigentlich soweit ich weiß gar nicht das __declspec( dllexport ) schreiben.
Lg freeGDoch, wenn es exportiert werden soll schon. Zumindest bin ich es so gewohnt, dass es nötig ist. Zumindest bei C++. Für C reicht da auch eine .def Datei, aber is ja das C++ Forum. Aber ja, das einbinden des Headers und der Lib reicht, solange das makro wie von mir o.g. genutzt wird. Sonst gibts Linkerfehler ob des statischen dllexport.
Bin kein so guter Erklärbär, bitte um Verzeihung wenns nicht 100% verständlich ist.
lgMhh ich hab mir erst vorgestern ne Bibliothek gemacht, und diese hab ich so erstellt wie ich es beschrieben hab und sie funktioniert tadellos
Vielleicht kann da mal jemand das kurz erläutern der noch ein bisschen mehr ahnung hat wie ich
Lg freeGKönnte vielleicht jemand mal dazu Stellung beziehen in welchen Fällen dies nötig ist?
Und vielleicht könnte mir kurz jemand erläutern für was __declspec( dllimport ) ist, weil das ist mir leider noch nicht so ganz klar.
Lg freeG
-
Bei .dll ist das nötig unter Win32. Das dllexport bedeutet, dass die Klasse oder Funktion nach aussen exportiert werden soll, sichtbar ist und in der Importlibrary dafür Symbole angelegt werden. Tut man das nicht, gibts einen Linkerfehler, da die Klasse/Funktion nicht in der Importlibrary der .dll zu finden sind. Bindet man nun den Header der .dll in ein Client-Projekt ein, darf da natürlich nicht export stehen, sondern import da wir es importieren möchten.
Deswegen auch das Makro.
http://msdn.microsoft.com/en-us/library/3y1sfaz2.aspx
http://msdn.microsoft.com/en-us/library/81h27t8c.aspxIch kenne die Generierung von .dll unter Win32 auch nicht anders und der erste Post sprach ja von einer .dll. Bei einer reinen statischen Library oder einer DLL in C oder wo einzelne Funktionen als extern "C" deklariert werden inkl. def Datei ist das nicht nötig afaik.
HTH
rya.
-
macht eigentlich 2 DInge:
Es setzt "storage" informationen, also legt fest, wie die Funktionen / Methoden binaer ausgerichtet sind. Notwendig, damit Aufrufer und Implementeur auch binaer kompatibel zueinander sind.
Aehnliche Dinge machen __stdcall, __cdecl, __fastcall etc, und entsprechende vordefinierte Kombinationen von denen ... WINAPI z.b.
es setzt marker fuer den linker, wenn eine dll gebaut wird. "Normal" braucht man beim M$ Linker keine .def datei, wenn man die dll funktionen exportieren will, sondern er erkennt die Marker und erstellt die exporttabelle daraus.
Ciao ...