Erstellen von Dynamic Link Libraries (*.*.dll) mit Microsoft Visual C++ 2008 Express Editions

Inhalt:
- Allgemeines
- Erstellen des Projekts
- DllMain und _declspec
- Funktionen und Klassen
- Wie Verwende ich die DLL in meinem Projekt
- Zusammenfassung
- Referenzquellen

Allgemeines
In diesem Artikel wollen wir uns mit dem erstellen einer Dynamic Link Library in Microsoft Visual C++ 2008 Express Editions widmen.
Doch davor sollten wir uns erst mit den Vorzügen und dem Zweck solcher Dateien beschäftigen. Er besteht darin, viel Verwendeten Code in eine seperate Datei, auf der Festplatte auszulagern, die dann nur einmal in den Arbeittspeicher geladen werden muss. Dies Verkleinert die Größe der .exe und bringt noch weitere Vorteile mit sich.

Erstellen des Projekts
Fangen wir einmal an mit dem Erstellen unseres Übungsprojekts. Ich war so frei, und habe ihm den Namen “Dll Win32″ gegeben. Als Projekttyp sollte man Win32-Anwendung angeben, dann geht es weiter zum nächsten Dialog. Hier bestätigen wir erst einmal mit Weiter, und dann müssen wir Folgendes umstellen.

Diese Einstellungen sollten geändert werden

Diese Einstellungen sollten geändert werden

1 – Den Anwendungstyp: Hier sollte (wie sich erahnen lässt) DLL ausgewählt werden.
2 – Bei Leeres Projekt einen Haken setzen: In diesem Übungsprojekt benötigen wir keine Vorkompilierten Header.

Nun müssen wir noch die Quellcode-Dateien zu unserem Projekt hinzufügen. Ich verwende DLLmain.cpp und DLLmain.hpp, der Name ist aber egal.
Jetzt kann es endlich Losgehen. ;)
Zuerst füllen wir die DLLmain.hpp mit folgendem Code:

// Includes
#include <windows.h>

Ausserdem inkludieren wir in der DLLmain.cpp noch die DLLmain.hpp.

DllMain und _declspec
Der Einsprungpunkt in die DLL, diese Funktion wird unter anderem Aufgerufen, beim Starten und Beenden. Anders als die WinMain Funktion, an die sie vom Namen her erinnert, ist sie aber optional, d.h. Man muss sie nicht unbedingt inplementieren.
Die DllMain Funktion sollte einen Funktionsheader im Folgenden Format haben:

BOOL WINAPI DllMain (HINSTANCE Instance, DWORD Reason, LPVOID Reserved)

Zu den Parametern:
Instance     -> Das Handle dieser DLL
Reason        -> Der Grund, bzw. das Ereigniss, aufgrund dessen diese Funktion aufgerufen wurde. hier ist eine genaue Auflistung zu Finden, welche Werte dieses Parameter annehmen kann, und was diese Bedeuten.
Reserved     -> Ziemlich unwichtig, siehe obigen Link für die möglichen Werte.
Doch was soll unsere Funkton zurückgeben ? TRUE wenn alles in Ordnung war, und FALSE, wenn es Fehler gab. Dabei sei erwähnt, dass der Rückgabewert nur von Bedeutung sind, wenn Reason DLL_PROCESS_ATTACH ist. Ansonsten wird er nicht weiter beachtet.
Wer Zwischenzeitlich einmal kompiliert hat, wird sich wundern, dass ein Fenster auftaucht “Ausführbare Datei für Debugsitzung”. Wir können diesen Dialog jetzt zwar noch getrost abbrechen, aber ich werde doch erwähnen, wofür er da ist.
Nehmen wir einmal an, Sie schreiben eine Engine, und lagern diese in eine DLL aus. Paralell dazu entwickeln Sie gleich noch ein Spiel, mit dieser Engine. Da man eine Dll ja nicht einfach ausführen kann, müsste man nun jedes mal, wenn man eine Änderung in der Engine gemacht hat erst wieder das Spiel, welches die Engine Verwendet, starten. Man kann sich vorstellen, das dies ziemlich umständlich ist. Bei diesem Dialog kann man nun einfach die .exe seines Spiels eintragen, und dann wird nach abschluss des Erstellens und Linkens automatisch das Spiel mit der neuen Engine-DLL gestartet. Geschickt, nicht ?

Funktionen und Klassen
Und jetzt werden wir unsere Erste (unspektakuläre) Funktion in unserer DLL implementieren. Doch davor müssen wir uns noch über etwas anderes Gedanken machen: Wie sagen wir dem Compiler, dass er die Funktion exportieren soll ? Nun, dafür gibt es _declspec. Nun werden wir uns ein schickes Makro erstellen, dass uns einiges an Arbeit erspart:

#ifdef DLLWIN32_EXPORTS
#define DLL _declspec (dllexport)
#else
#define DLL _declspec (dllimport)
#endif

_declspec (dllexport) weist den Compiler an, das darauffolgende Symbol zu exportieren, _declspec (dllimport) das Folgende Symbol zu importieren.
WICHTIG: Der Name des Makros (DLLWIN32_EXPORTS) ist keineswegs zufällig gewählt. Standardmässig erstellt MSVCPP beim kreieren des Projekts diese Präprozessordefinition, und zwar mit dem Namen des Projekts. (Leerzeichen werden einfach Weggelassen, alles wird Groß geschrieben.).
Will man dies Ändern, so kann man in den Projekteinstellungen unter Konfigurationseigenschaften -> C++ -> Präprozessor -> Präprozessordefinitionen den Namen der definition ändern.

Nun zur eigentlichen Funktion, wir schreiben sie so in die DLLmain.hpp:

bool DLL MyFirstDllFunction ()
{
 MessageBox (NULL, TEXT ("Hat geklappt"), TEXT("MyFirstDllFunction"), NULL);

 return true;
}

-> Das DLL Makro sollte bei Funktionen vor dem Funktionsheader stehen.
Wenn man die Funktion auf .hpp (prototyp) und .cpp (implementierung) aufteilt, sollte man vor beide Funktionsheader Das Makro Schreiben.

Bei Klassen sieht die Sache nicht viel anderst aus:

class DLL MyTestClass
{
...
};

Wie Verwende ich die DLL in meinem Projekt
Was nutzt uns nun aber unsere DLL, wenn ich sie nicht benutzen kann? Also fangen wir an: Wer mittlerweile das DLL-Projekt kompiliert hat, wird feststellen, dass in seinem Debug/Release Ordner sich unter anderem folgende Dateien vorfinden: DLL Win32.dll DLL Win32.lib
Um die DLL zu testen, habe ich einfach eine Konsolenanwendung erstellt, und den üblichen Code der Main Funktion hinzugefügt. Um nun unsere DLL verwenden zu können müssen wir 3 Dinge tun: 1. Unsere DLLmain.hpp inkludieren 2. Unter Konfigurationseigenschaften -> Linker -> Eingabe -> Zusätzliche Abhängigkeiten DLL Win32.lib eintragen. 3. Die .dll in die Working Directory kopieren
Jetzt können wir einfach die Funktion aus der DLL im Code verwenden.

#include <iostream>
#include "DLLmain.hpp"

int main ()
{
 MyFirstDllFunction ();

 return 0;
}

Zusammenfassung
In diesem Tutorial haben wir gelernt, wie wir eine DLL erstellen und verwenden.

Referenzquellen
http://support.microsoft.com/kb/132044/de
http://msdn.microsoft.com/de-de/library/a90k134d%28VS.80%29.aspx
http://msdn.microsoft.com/en-us/library/ms682583%28VS.85%29.aspx