2009-10-07 5 views
8

Hoffentlich ist dies eine hirnlos einfache Frage, aber es zeigt meine fehlende Expertise mit C++. Ich bin ein C# -Programmierer und habe mit P/Invoke in der Vergangenheit umfangreiche Arbeit mit C++/C-DLLs anderer Leute geleistet. Dieses Mal habe ich mich jedoch entschieden, selbst eine Wrapper-C++ - DLL (unmanaged) zu schreiben und meine Wrapper-DLL von C# anzurufen.Wie richtet man eine C++ - Funktion ein, damit sie von p/invoke verwendet werden kann?

Das Problem, auf das ich sofort hinlaufe, ist, dass ich keine C++ - Funktion definieren kann, die von p/invoke gefunden werden kann. Ich weiß nicht, was die Syntax für das ist, aber hier ist, was ich bisher versucht:

extern bool __cdecl TestFunc() 
{ 
    return true; 
} 

Ursprünglich einfach das ich hatte, aber es hat nicht funktioniert entweder:

bool TestFunc() 
{ 
    return true; 
} 

Und dann auf der C# Seite, ich habe:

public const string InterfaceLibrary = @"Plugins\TestDLL.dll"; 

    [DllImport(InterfaceLibrary, CallingConvention = CallingConvention.Cdecl, 
     EntryPoint = "TestFunc"), SuppressUnmanagedCodeSecurity] 
    internal static extern bool TestFunc(); 

Alles kompiliert, aber wenn ich diese C# p/aufrufen Aufruf ausführen, erhalte ich eine System.EntryPointNotFoundException: Nicht imstande, einen Einstiegspunkt namens ‚TestFunc‘ in DLL zu finden ' Plugins \ TestDLL.dll '.

Sicher muss dies etwas unglaublich einfach auf dem C++ Ende sein, dass ich einfach nicht die Syntax dafür kenne.

Antwort

12

Sie wollen als __declspec(export)extern "C" als auch verwenden, etwa so:

extern "C" _declspec(dllexport) bool TestFunc() 
{ 
    return true; 
} 

Für vollständige Details siehe MSDN on Marshalling Types.

+0

Perfekt, das ist es! Ich hatte auch versucht, in der Vergangenheit nur extern "C" zu haben, aber das hat nicht funktioniert. Es schlägt fehl, bis die _declspec (dllexport) hinzugefügt wird. – x4000

1

Sie müssen diese Funktion mit extern "C" verfügbar machen, sonst wird der Name verstümmelt.

1

Der C++ - Compiler ändert die Namen Ihrer Funktionen, um Informationen zu den Parametern und Rückgabetypen einzubeziehen. Dies wird Name Mangling genannt. Auf der anderen Seite, der C-Compiler nicht Ihre Funktionsnamen.

Sie können die C++ Compiler sagen, als C-Compiler extern "C" mit arbeiten:

extern "C" __declspec(dllexport) bool TestFunc { return true; } 

aufrufen Funktionen von C# mit P/Invoke, müssen Sie Ihre Namen nicht verstümmelt werden. Daher können Sie C-Funktionen tatsächlich in C# exportieren. Wenn Sie möchten, dass die Funktionalität in C++ implementiert wird, können Sie eine C-Funktion schreiben, die nur die C++ - Funktion aufruft, die die Funktionalität implementiert.

6

Erweitern Reeds richtige Antwort.

Ein anderes Problem, mit dem Sie beim Aussetzen einer C++ - Funktion über PInvoke umgehen können, ist die Verwendung ungültiger Typen. PInvoke kann wirklich nur das Marshalling von primitiven Typen und einfachen alten Datenstruktur-/Klassentypen unterstützen.

Angenommen, TestFunc hatte die folgende Signatur

void TestFunc(std::string input); 

Auch extern "C" Hinzufügen und __declspec(dllexport) würde nicht ausreichen, um die C++ Funktion zu belichten. Stattdessen müssten Sie eine Hilfsfunktion erstellen, die nur PInvoke-kompatible Typen verfügbar macht und dann in die Hauptfunktion aufgerufen wird.Zum Beispiel

void TestFunc(const std::string& input) { ... } 

extern "C" _declspec(dllexport) void TestFuncWrapper(char* pInput) { 
    std::string input(pInput); 
    TestFunc(input); 
} 
+0

Ja, es ist genau diese Art von Grund, dass ich eine Wrapper-C++ - DLL schreibe, anstatt zu versuchen, alle Funktionen aufzurufen, die ich direkt benötige. Mein Ziel ist es, eine einfachere Schnittstelle für P/Invoke zu erstellen, während die gesamte erforderliche Komplexität mit Rückrufen und komplexen Typen usw. auf C++ - Seite verbleibt. Gute Argumente! – x4000

+0

@ x4000, habe ich genau den gleichen Ansatz vor. Außer einer neuen DLL habe ich die Wrapper-Funktionen der gleichen DLL hinzugefügt. Mehr DLLs wären sauberer gewesen. – JaredPar

+0

Die ursprüngliche DLL, die ich verpacke, ist von einer dritten Partei, also war das für mich keine Option. Aber Sie haben Recht, ich denke, es ist in vielerlei Hinsicht sauberer, die Wrapper von den Inhalten zu trennen, die wenn möglich eingepackt werden. – x4000

1

etwas tun gefällt das:

#define EXPORT extern "C" __declspec(dllexport) 

Und dann jede Funktion mit dem EXPORT Schlüsselwort deklarieren, zum Beispiel eine C++ Funktion

BOOL getString(TCHAR* string, DWORD size); 

würde

EXPORT BOOL getString(TCHAR* string, DWORD size); 

dann der Spaß Teil: Gehen Sie zu Ihrer VS-Konsole und geben:

dumpbin /EXPORTS <PATH_TO_GENERATED_DLL> 

und you'l finden Sie in die verstümmelten Namen und Ordnungs aller Ihrer leicht exportierten Funktionen, dann ist es nur eine Sache o pInvoking sie

0

Bau alle Projekte mit Win32-Plattform und entsprechendes Bit (z. B. x86 oder x64) Build-Option.

Verwandte Themen