Du bist nicht angemeldet.

Stilllegung des Forums
Das Forum wurde am 05.06.2023 nach über 20 Jahren stillgelegt (weitere Informationen und ein kleiner Rückblick).
Registrierungen, Anmeldungen und Postings sind nicht mehr möglich. Öffentliche Inhalte sind weiterhin zugänglich.
Das Team von spieleprogrammierer.de bedankt sich bei der Community für die vielen schönen Jahre.
Wenn du eine deutschsprachige Spieleentwickler-Community suchst, schau doch mal im Discord und auf ZFX vorbei!

Werbeanzeige

hanhau

Treue Seele

  • »hanhau« ist der Autor dieses Themas

Beiträge: 80

Wohnort: St. Pölten, Österreich

Beruf: schueler

  • Private Nachricht senden

1

14.11.2015, 18:41

[C++][MSVS 2015] Probleme beim C++ DLL erstellen

Guten Abend,

Ich möchte eine C++-DLL erstellen, ich bin aber irgendwie verwirrt:

-> Ich kann kompilieren, allerdings wenn ich die DLL verwende, taucht C2001 auf.
-> Was hat es mit dem _declspec(dllimport/dllexport) auf sich ?

Mein Projekt umfasst .cpp und .hpp Dateien und hat als Ausgabe eine .lib und .dll Datei.
Ich linke im Demoprojekt gegen die .lib und #includere "Header.hpp".

Ich habe zuvor mit MinGW gearbeitet und dort nur statische libs gebaut und
je mehr ich im Internet über .dlls erstellen unter MSVS lese, umso mehr kenne ich*
mich nicht aus :dash:

Vielleicht kann mir jemand die Schritte erläutern wie was gehört ?

Ich wäre sehr dankbar !
Oft denke ich an sie, niemals habe ich sie gefragt, niemals etwas gesagt,
nur verzweifelt am PC gesessen und dabei die Zeit vergessen, sie ist weg.

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

2

14.11.2015, 21:59

-> Ich kann kompilieren, allerdings wenn ich die DLL verwende, taucht C2001 auf.

Zeig doch mal die genaue Fehlermeldung und den Code, in dem der Fehler auftritt.

Mein Projekt umfasst .cpp und .hpp Dateien und hat als Ausgabe eine .lib und .dll Datei.
Ich linke im Demoprojekt gegen die .lib und #includere "Header.hpp".

klingt soweit richtig


-> Was hat es mit dem _declspec(dllimport/dllexport) auf sich ?

Der Unterschied zwischen einer statischen und einer dynamischen Library liegt darin, wie die Library gelinked wird. Eine statische Library wird während der Erzeugung einer Binary gelinked, indem die benötigten Teile der Library selbst zum Teil der Binary gemacht werden. Um Dinge aus einer statischen Library zu verwenden, generiert der Compiler Maschinencode einfach so, als wären diese Dinge Teil der Binary, da sie es am Ende ja werden. Eine dynamische Library ist dagegen eine eigenständige Binary, die erst während der Ausführung geladen wird. Die Adressen der Dinge in der dynamischen Library sind zum Zeitpunkt der Erzeugung der Binary, die die Library verwendet, nicht bekannt. Um Dinge aus einer dynamischen Library zu verwenden, muss der Compiler also Maschinencode generieren, der die entsprechenden Dinge nicht direkt, sondern indirekt anspricht. Jede Binary hat dazu eine sog. Import Address Table (IAT), eine Tabelle, in die beim Laden der Binary die Adressen der benötigten Dinge aus der DLL eingetraten werden. Der Maschinencode in der Binary verwendet Dinge aus der DLL, indem er erst die Adresse im entsprechenden Eintrag der IAT nachschlägt und dann das Ding über diese Adresse anspricht.

Komplementär zur IAT, muss eine Binary, deren Inhalte dynamisch gelinked werden können sollen (also z.B. eine DLL), eine Export Table (ET) haben, die zu jedem Ding in der Library, das von außen erreichbar sein soll, die Adresse enthält, sodass diese beim Laden nachgeschlagen und in die IAT der verwendenden Binary eingetragen werden kann.

Je nach Betriebssystem und Compiler varriieren die Mechanismen, nach denen all das genau abgewickelt wird, die Grundidee ist aber immer die gleiche. Im Falle von Windows und MSVC gibt es zusätzlich auch noch mehrere Vorgehensweisen, die am Ende alle das gleiche erreichen, was vermutlich der Grund für die scheinbare Widersprüchlichkeit dessen, was du im Internet dazu so gefunden hast, ist. Die wohl einfachste und definitiv am häufigsten angetroffene Form ist die mit __declspec() und dllexport bzw. dllimport.

Um ein Ding wie beispielsweise eine Funktion f() im Code verwenden zu können, muss dieses Ding zuvor deklariert worden sein. Eine Deklaration wie

C-/C++-Quelltext

1
void f();

sagt dem Compiler, dass es irgendwo anders eine Funktion f() gibt und der Compiler generiert Maschinencode, der diese Funktion verwendet, als wäre sie Teil der Binary. Der Linker sucht beim Erzeugen der Binary aus den Object Files und statischen Libraries dann nach dieser Funkion f, sorgt dafür, dass die Funktion Teil der fertigen Binary wird und ersetzt das Symbol f durch die Adresse, die die Funktion in der fertigen Binary haben wird (wenn die Funktion nirgendwo zu finden ist, meldet sich der Linker mit seiner wohl berühmtesten Form der Beschwerde zu Wort: "nichtaufgelöstes externes Symbol f").

Um ein Ding wie beispielsweise eine Funktion f(), die sich in einer DLL befindet, verwenden zu können, muss der Compiler, wie oben besprochen, Code generieren, der die Funktion f nicht direkt, sondern indirekt über die IAT anspricht. Um ihm dies mitzuteilen, deklarierst du die Funktion im Code, der die DLL verwenden soll, mit dem __declspec(dllimport) Attribut:

C-/C++-Quelltext

1
__declspec(dllimport) void f();

Dies führt dazu, dass der Compiler Code generiert, der diese Funktion über die IAT anspricht.

Auf der anderen Seite, im Code der DLL, muss die Funktion f entsprechend markiert werden, damit sie vom Linker in die ET der DLL aufgenommen wird, sodass sie beim Laden einer Binary, die die DLL verwendet, in der DLL gefunden werden und in die IAT eingetragen kann. Dies erreichst du, indem du die Definition der Funktion mit dem __declspec(dllexport) Attribut versiehst:

C-/C++-Quelltext

1
2
3
4
5
__declspec(dllexport)
void f()
{
  // ...
}

Die .lib Datei, die beim Erzeugen einer DLL standardmäßig miterzeugt wird, enthält effektiv Code und Informationen, die dafür sorgen, dass der Linker beim Erzeugen der die DLL verwendenden Binary die entsprechenden Einträge in der IAT erzeugt.

Dieser Beitrag wurde bereits 5 mal editiert, zuletzt von »dot« (14.11.2015, 22:25)


hanhau

Treue Seele

  • »hanhau« ist der Autor dieses Themas

Beiträge: 80

Wohnort: St. Pölten, Österreich

Beruf: schueler

  • Private Nachricht senden

3

18.11.2015, 17:47

Ich kann mich nicht genug für die Antwort bedanken ! :)
for(;;) std::cout << "DANKE !" << std::endl;
Oft denke ich an sie, niemals habe ich sie gefragt, niemals etwas gesagt,
nur verzweifelt am PC gesessen und dabei die Zeit vergessen, sie ist weg.

dot

Supermoderator

Beiträge: 9 757

Wohnort: Graz

  • Private Nachricht senden

4

18.11.2015, 18:55

you're welcome^^

Hast du nun zum Laufen gebracht, was auch immer du genau machen wolltest?

hanhau

Treue Seele

  • »hanhau« ist der Autor dieses Themas

Beiträge: 80

Wohnort: St. Pölten, Österreich

Beruf: schueler

  • Private Nachricht senden

5

18.11.2015, 19:57

Ja klar :)
Oft denke ich an sie, niemals habe ich sie gefragt, niemals etwas gesagt,
nur verzweifelt am PC gesessen und dabei die Zeit vergessen, sie ist weg.

Werbeanzeige