Nicht verwaltete DLLs in C ++

8

Ich habe viele Tutorials / Artikel zu nicht verwalteten DLLs in C ++ gelesen. Für das Leben von mir kann ich das Konzept jedoch nicht begreifen. Ich bin leicht verwirrt durch die scheinbare Uneinigkeit darüber, ob es eine Header-Datei benötigt, wie man es exportiert, ob ich eine .lib-Datei brauche und was Sie haben.

Also, nehmen wir an, ich habe nur eine Funktion wie folgt:

%Vor%

Wenn ich den eigentlichen Code ignoriere, was benötige ich, um diese einfache Funktion selbst in eine DLL zu bringen, die ich dann aufrufen kann? Füge ich einfach __dllexport oder was auch immer es ist in die erste Zeile oder benötige ich einen Header? Ich bin perplex von all dem.

    
Peter C. 25.10.2008, 07:04
quelle

4 Antworten

15

Ich kann das nicht genug betonen, der C ++ - Compiler sieht keine Header-Dateien, nach dem Präprozessor gibt es nur eine große Quelldatei (auch Kompilierungseinheit genannt). Sie benötigen also keinen Header, um diese Funktion von einer DLL zu exportieren. Was Sie brauchen, ist eine Form der bedingten Kompilierung, um die Funktion in der DLL, die Sie kompilieren, zu exportieren und sie in den Client-Code zu importieren.

Normalerweise wird dies mit einer Kombination von Makros und Header-Dateien gemacht. Sie erstellen einen Makro mit dem Namen MYIMPORTEXPORT, und durch die Verwendung von bedingten Makroanweisungen können Sie ihn wie __declspec (dllexport) in der DLL und __declspec (dllimport) im Clientcode verwenden.

in der Datei MYIMPORTEXPORT.h

%Vor%

in der Datei MyHeader.h

%Vor%

in dll .cpp-Datei

%Vor%

in der Client-Code-CPP-Datei

%Vor%

Natürlich müssen Sie dem Linker auch signalisieren, dass Sie eine DLL mit dem / DLL-Option .

Der Build-Prozess erstellt auch eine .lib-Datei, das ist eine statische lib - in diesem Fall Stub genannt - mit der der Client-Code eine Verbindung herstellen muss, als würde er mit einer echten statischen lib verlinken. Automatically wird die DLL geladen, wenn der Client-Code ausgeführt wird. Natürlich muss die DLL vom Betriebssystem durch ihren Lookup-Mechanismus gefunden werden, was bedeutet, dass Sie die DLL nicht irgendwo, sondern an einem bestimmten Ort ablegen können. Hier ist mehr dazu.

Ein sehr praktisches Werkzeug, um zu sehen, ob Sie die korrekte Funktion aus der DLL exportiert haben, und ob der Client-Code korrekt importiert, ist dumpbin . Führen Sie es mit / EXPORTS bzw. / IMPORTS aus.

    
QBziZ 25.10.2008, 07:27
quelle
6

QBziZ 'Antwort ist richtig genug. Siehe Nicht verwaltete DLLs in C ++

Um es zu vervollständigen: Wenn Sie in C ++ ein Symbol verwenden müssen, müssen Sie dem Compiler mitteilen, dass es existiert, und oft auch seinen Prototyp .

In anderen Sprachen wird der Compiler nur die Bibliothek selbst erkunden und das Symbol et voilà finden.

In C ++ müssen Sie den Compiler informieren.

Siehe einen C / C ++ - Header als Buch-Inhaltsverzeichnis

Der beste Weg ist es, den benötigten Code an einer Stelle zu platzieren. Die "Schnittstelle", wenn Sie möchten. Dies geschieht normalerweise in einer Header-Datei namens Header, da dies normalerweise keine unabhängige Quelldatei ist. Der Header ist nur eine Datei, deren Ziel es ist, in echte Quelldateien eingefügt (d. H. Kopiert / eingefügt durch den Präprozessor).

Im Wesentlichen scheint es, dass Sie zweimal ein Symbol deklarieren müssen (Funktion, Klasse, was auch immer). Was im Vergleich zu anderen Sprachen fast eine Häresie ist.

Sie sollten es als ein Buch mit einer Übersichtstabelle oder einem Index sehen. In der Tabelle haben Sie alle Kapitel. Im Text haben Sie die Kapitel und deren Inhalt.

Und manchmal bist du nur glücklich, dass du die Kapitelliste hast.

In C ++ ist dies der Header.

Was ist mit der DLL?

Also zurück zum DLL-Problem: Das Ziel einer DLL ist es, Symbole zu exportieren, die Ihr Code verwenden wird.

Also müssen Sie in C ++ - Art den Code bei der Kompilierung exportieren (dh in Windows zB __declspec) und eine Tabelle mit exportierten Daten "veröffentlichen" (dh "public" - Header haben, die den Code enthalten) exportierte Deklarationen).

    
paercebal 25.10.2008 08:55
quelle
1

Checkliste für den Export von Funktionen:

  • Ist die Anrufkonvention für den Anrufer geeignet? (Dies bestimmt, wie Parameter und Ergebnisse übergeben werden und wer für das Bereinigen des Stapels verantwortlich ist). Sie sollten Ihre Aufrufkonvention explizit angeben.
  • Unter welchem ​​Namen wird das Symbol exportiert? C ++ muss normalerweise die Namen von Symbolen, z. um zwischen verschiedenen Überlastungen zu unterscheiden.
  • Sagen Sie dem Linker, dass die Funktion als DLL-Export sichtbar gemacht werden soll

Auf MSVC:

  • __stdcall (was Pascal-Aufrufkonvention ist) ist die typische Aufrufkonvention für exportierte Symbole - unterstützt von den meisten Clients, denke ich.
  • extern "C" ermöglicht es Ihnen, das Symbol C-style ohne Name Mangling
  • zu exportieren
  • Verwenden Sie __declspec(dllexport) , um ein zu exportierendes Symbol zu markieren, oder verknüpfen Sie eine separate .def-Datei, in der die zu exportierenden Symbole aufgelistet sind. Mit einer .def-Datei können Sie auch nur nach Ordnungszahl (nicht nach Namen) exportieren und den Namen des exportierten Symbols ändern.
peterchen 25.10.2008 09:42
quelle
0

Sie müssen die Funktion entweder mit __declspec( dllexport ) exportieren oder die Funktion zu einer Moduldefinitionsdatei (.def) hinzufügen. Dann kompiliere das Projekt als DLL.

Auf der Client-Seite haben Sie zwei Möglichkeiten. Verwenden Sie eine Importbibliothek (.lib), die beim Kompilieren der DLL generiert wird. Durch einfaches Verknüpfen mit Ihrem Client-Projekt mit dieser Bibliothek erhalten Sie Zugriff auf die aus der DLL exportierten Funktionen. Und Sie benötigen eine Header-Datei, weil der Compiler die Signatur Ihrer Funktion kennen muss - dass er int zurückgibt und einen int übernimmt. Zur Erinnerung: Sie müssen eine Verknüpfung mit einer Importbibliothek (.lib) und einer Headerdatei herstellen, die den Header Ihrer Funktion enthält.

Sie können die DLL auch dynamisch laden, indem Sie WinAPI call LoadLibrary und dann GetProcAddress verwenden, um einen Zeiger auf die Funktion zu erhalten. Der Zeiger auf Funktion muss den richtigen Typ haben, damit der Compiler ihm die korrekten Parameter geben kann und die richtige Aufrufkonvention verwendet wird.

    
Roman Plášil 25.10.2008 07:29
quelle

Tags und Links