Ich möchte ein einfaches Beispiel für den Export einer Funktion aus einer C ++ - Windows-DLL.
Ich möchte den Header, die .cpp
Datei und die .def
Datei sehen (falls unbedingt erforderlich).
Ich möchte, dass der exportierte Name nicht dekoriert wird . Ich möchte die gängigste Anrufkonvention ( __stdcall
?) Verwenden . Ich möchte die Verwendung __declspec(dllexport)
und muss keine .def
Datei verwenden.
Beispielsweise:
//header
extern "C"
{
__declspec(dllexport) int __stdcall foo(long bar);
}
//cpp
int __stdcall foo(long bar)
{
return 0;
}
Ich versuche zu vermeiden, dass der Linker dem Namen Unterstriche und / oder Zahlen (Anzahl der Bytes?) Hinzufügt.
Ich bin damit einverstanden, dass ich nicht denselben Header unterstütze dllimport
und dllexport
verwende. Ich möchte keine Informationen zum Exportieren von C ++ - Klassenmethoden, sondern nur globale Funktionen im C-Stil.
AKTUALISIEREN
extern "C"
Wenn ich die Aufrufkonvention (und die Verwendung ) nicht einbeziehe, bekomme ich die Exportnamen, wie ich möchte, aber was bedeutet das? Bekomme ich unabhängig von der Standardaufrufkonvention was Pinvoke (.NET), deklariere (vb6) und GetProcAddress
würde es erwarten? (Ich denke, GetProcAddress
es würde vom Funktionszeiger abhängen, den der Aufrufer erstellt hat).
Ich möchte, dass diese DLL ohne Header-Datei verwendet wird, daher brauche ich nicht viel Fantasie #defines
, um den Header für einen Anrufer nutzbar zu machen.
Ich bin damit einverstanden, dass ich eine *.def
Datei verwenden muss.
quelle
extern C
die Dekoration entfernt wird, die die Parametertypen der Funktion beschreibt, aber nicht die Dekoration, die die Aufrufkonvention der Funktion beschreibt; b) Um alle Dekorationen zu entfernen , müssen Sie den (nicht dekorierten) Namen in einer DEF-Datei angeben.Antworten:
Wenn Sie einfache C-Exporte wünschen, verwenden Sie ein C-Projekt, nicht C ++. C ++ - DLLs basieren auf der Namensverwaltung für alle C ++ - Ismen (Namespaces usw.). Sie können Ihren Code als C kompilieren, indem Sie in Ihre Projekteinstellungen unter C / C ++ -> Erweitert gehen. Es gibt eine Option "Kompilieren als", die den Compiler-Schaltern / TP und / TC entspricht.
Wenn Sie weiterhin C ++ zum Schreiben der Interna Ihrer Bibliothek verwenden möchten, aber einige Funktionen exportieren möchten, die für die Verwendung außerhalb von C ++ nicht verwickelt sind, lesen Sie den zweiten Abschnitt unten.
Exportieren / Importieren von DLL-Bibliotheken in VC ++
Was Sie wirklich tun möchten, ist ein bedingtes Makro in einem Header zu definieren, das in allen Quelldateien Ihres DLL-Projekts enthalten ist:
Dann verwenden Sie für eine Funktion, die Sie exportieren möchten, Folgendes
LIBRARY_API
:Erstellen Sie in Ihrem Bibliothekserstellungsprojekt eine Definition. Dadurch
LIBRARY_EXPORTS
werden Ihre Funktionen für Ihren DLL-Build exportiert.Da
LIBRARY_EXPORTS
in einem Projekt, das die DLL verwendet, nicht definiert wird, werden stattdessen alle Funktionen importiert, wenn dieses Projekt die Header-Datei Ihrer Bibliothek enthält.Wenn Ihre Bibliothek plattformübergreifend sein soll, können Sie LIBRARY_API als nichts definieren, wenn Sie nicht unter Windows arbeiten:
Wenn Sie dllexport / dllimport verwenden, müssen Sie keine DEF-Dateien verwenden. Wenn Sie DEF-Dateien verwenden, müssen Sie dllexport / dllimport nicht verwenden. Die beiden Methoden erfüllen dieselbe Aufgabe auf unterschiedliche Weise. Ich glaube, dass dllexport / dllimport die empfohlene Methode unter den beiden ist.
Exportieren nicht entwirrter Funktionen aus einer C ++ - DLL für LoadLibrary / PInvoke
Wenn Sie dies benötigen, um LoadLibrary und GetProcAddress zu verwenden oder möglicherweise aus einer anderen Sprache zu importieren (z. B. PInvoke aus .NET oder FFI in Python / R usw.), können Sie
extern "C"
inline mit Ihrem dllexport den C ++ - Compiler anweisen, die Namen nicht zu entstellen. Und da wir GetProcAddress anstelle von dllimport verwenden, müssen wir den ifdef-Tanz nicht von oben ausführen, sondern nur einen einfachen dllexport:Der Code:
Und so sehen die Exporte mit Dumpbin / Exporten aus:
Dieser Code funktioniert also einwandfrei:
quelle
Für C ++:
Ich konfrontiere gerade das gleiche Problem und ich denke , es ist erwähnenswert , ein Problem aufkommt , wenn man beide verwenden
__stdcall
(oderWINAPI
) undextern "C"
:Wie Sie wissen,
extern "C"
wird die Dekoration entfernt, sodass anstelle von:Sie erhalten einen nicht dekorierten Symbolnamen:
Das
_stdcall
(= Makro WINAPI, das die aufrufende Konvention ändert) verziert jedoch auch Namen, sodass wir erhalten, wenn wir beide verwenden:und der Nutzen von
extern "C"
geht verloren, weil das Symbol verziert ist (mit _ @bytes)Dies ist besonders schwierig, wenn Sie sowohl auf x86- als auch auf x64-Plattformen abzielen.
Zwei Lösungen
Verwenden Sie eine Definitionsdatei. Dies zwingt Sie jedoch dazu, den Status der def-Datei beizubehalten.
Der einfachste Weg: Definieren Sie das Makro (siehe msdn ):
und fügen Sie dann das folgende Pragma in den Funktionskörper ein:
Vollständiges Beispiel:
Dadurch wird die Funktion für x86- und x64-Ziele nicht dekoriert exportiert, wobei die
__stdcall
Konvention für x86 beibehalten wird. Das__declspec(dllexport)
ist in diesem Fall nicht erforderlich.quelle
__FUNCTION__
Makro nur in Funktionen funktioniert.Ich hatte genau das gleiche Problem. Meine Lösung bestand darin, die Moduldefinitionsdatei (.def) zu verwenden, anstatt
__declspec(dllexport)
Exporte zu definieren ( http://msdn.microsoft.com/en-us/library/d91k01sh.aspx ). Ich habe keine Ahnung, warum das funktioniert, aber es funktioniertquelle
.def
Moduls export tut Arbeit, aber auf Kosten der Lage zu liefernextern
Definitionen in der Header - Datei für zB globale Daten in diesem Fall müssen Sie die Versorgungextern
Definition manuell in internen Anwendungen von diese Daten. (Ja, es gibt Zeiten, in denen Sie dies benötigen.) Es ist sowohl allgemein als auch speziell für plattformübergreifenden Code besser, einfach__declspec()
mit einem Makro zu verwenden, damit Sie die Daten normal weitergeben können.__stdcall
, dann__declspec(dllexport)
werden die Dekorationen nicht entfernt. Hinzufügen der Funktion zu einem.def
Testament jedoch.Ich denke, _naked könnte bekommen, was Sie wollen, aber es verhindert auch, dass der Compiler den Stapelverwaltungscode für die Funktion generiert. extern "C" bewirkt eine Namensdekoration im C-Stil. Entfernen Sie das und das sollte Ihre _s loswerden. Der Linker fügt keine Unterstriche hinzu, der Compiler jedoch. stdcall bewirkt, dass die Argumentstapelgröße angehängt wird.
Weitere Informationen finden Sie unter: http://en.wikipedia.org/wiki/X86_calling_conventions http://www.codeproject.com/KB/cpp/calling_conventions_demystified.aspx
Die größere Frage ist, warum Sie das tun wollen? Was ist los mit den verstümmelten Namen?
quelle