Dll-Methode von C ++ nach C # exportieren. Warum brauche ich: "extern" C ""

8

In meiner DLL gibt es eine Methode, die ich exportieren möchte.

// Werke:

%Vor%

// Funktioniert nicht

%Vor%

C ++ Export:

%Vor%

C # importieren:

%Vor%

Warum brauche ich das externe "C" ?

    
Pedro77 16.12.2011, 13:33
quelle

4 Antworten

11

Der Hauptgrund besteht darin, zu verhindern, dass der C ++ - Name-Mangler den Namen der Funktion verändert.

Versuchen Sie, es ohne extern "C" zu exportieren, und untersuchen Sie die resultierende DLL in Dependency Walker, und Sie werden einen anderen Namen für die exportierte Funktion sehen.

    
David Heffernan 16.12.2011, 13:35
quelle
20

Dies liegt an der Namensänderung durch C ++.

extern "C" gegen kein externes "C"

Als Beispiel hier ist, was CFF Explorer für eine Exporttabelle einer DLL zeigt. Der erste wurde mit borlands C ++ Compiler erstellt. Die zweite wurde mit msvc erstellt.

%Vor% %Vor%

Die ersten 2 Funktionen createDevice und createDeviceEx enthalten die extern "C" Signatur in ihrem Prototyp, während die anderen nicht. Beachten Sie den Unterschied in der Codierung, wenn C ++ Mangling verwendet wird. Der Unterschied geht tatsächlich tiefer als das.

ABI & amp; Standardisierung

Wie in den anderen Antworten erläutert, gibt der C ++ - Standard nicht ein A bstract an B inary I Benutzeroberfläche . Das bedeutet, dass die Anbieter, die ihre Tools entwerfen, ziemlich genau das tun können, was sie wollen, wenn es darum geht, wie Funktionsaufrufe gehandhabt werden und wie Überlastung unter der Haube funktioniert - solange es das erwartete Verhalten gemäß dem Standard aufweist / p>

Mit all diesen verschiedenen Codierungsschemata gibt es keine Möglichkeit, dass eine andere Sprache mit Modulen arbeiten kann, die mit C ++ kompiliert wurden. Heck-Module, die mit einem C ++ - Compiler kompiliert wurden, funktionieren wahrscheinlich nicht mit einem anderen! Compiler-Anbieter können ihre Codierung zwischen den Versionen nach eigenem Ermessen ändern.

Darüber hinaus bedeutet kein gebräuchliches ABI, dass es keinen allgemein üblichen Weg gibt, diese Funktionen / Methoden aufzurufen. Zum Beispiel könnte ein Compiler seine Argumente auf dem Stack übergeben, während ein anderer Compiler sie auf dem Register weitergibt. Man könnte Argumente von links nach rechts weitergeben, während eine andere umgekehrt werden könnte. Wenn nur einer dieser Aspekte nicht genau zwischen dem Anrufer und dem Angerufenen übereinstimmt, stürzt Ihre App ab ... wenn Sie Glück haben. Anstatt sich damit zu befassen, sagen die Anbieter einfach nein, indem sie einen Erstellungsfehler mit den verschiedenen Kodierungen erzwingen.

OTOH, während C auch kein standardisiertes ABI hat, ist C eine viel einfachere Sprache, mit der verglichen werden kann. Die meisten C-Compiler-Anbieter handhaben Funktionserstellung und Aufrufmechanismus in ähnlicher Weise. Daher gibt es eine Art "de-facto" -Standard, selbst wenn eine ABI nicht explizit im Standard spezifiziert ist. Mit dieser Gemeinsamkeit macht es anderen Sprachen viel leichter, mit Modulen zu kommunizieren, die mit C kompiliert wurden.

Beispiel: Eine __stdcall Dekoration in einer Funktionssignatur entspricht einer bestimmten Aufrufkonvention. Argumente werden von rechts nach links geschoben und der Angerufene ist dafür verantwortlich, den Stapel danach zu reinigen. __cdecl ist ähnlich, aber es versteht sich, dass der Aufrufer für das Löschen des Stapels zuständig ist.

Die untere Zeile

Wenn das fragliche Modul mit Sprachen außerhalb von C ++ kompatibel sein muss, ist es am besten, es angemessen zu dekorieren und als C-API verfügbar zu machen. Beachten Sie, dass Sie dabei etwas Flexibilität aufgeben. Insbesondere können Sie diese Funktionen nicht überladen, da der Compiler keine eindeutigen Symbole mehr für jede Überladung mit Namen Mangling generieren kann.

Wenn die Interoperabilität für das fragliche Modul nicht wichtig ist, wird es nur mit demselben Werkzeug verwendet, mit dem es gebaut wurde, und dann die extern "C" Dekoration von Ihren Prototypen weglassen.

    
greatwolf 16.12.2011 13:36
quelle
1

Der Compiler Ihre exportierten Namen, um Informationen über Klasse und Signatur aufzunehmen. extern "C" sagt dem Compiler, dies nicht zu tun.

    
Anders Tornblad 16.12.2011 13:37
quelle
0

Ich habe das mit einer Funktion mit 1 Parameter versucht und Sie müssen

verwenden
  

[DllImportAttribute ("was auch immer.Dll", CallingConvention = CallingConvention. Cdecl )]

für den Import in C # zu arbeiten. Stdcall-Anweisung funktioniert nur (in der dargestellten Situation, nicht allgemein) für Funktionen ohne Parameter, die void zurückgeben. Getestet in vs2012 Express-Ausgabe.

  

Als eine Randnotiz kann der Dependency Walker von Ссылка

heruntergeladen werden
    
Pifcnt 20.06.2013 13:21
quelle

Tags und Links