2008-10-01 5 views
7

Ich habe eine Funktion in einer nativen DLL wie folgt definiert:Marshal C++ "string" Klasse in C# P/Invoke

#include <string> 
void SetPath(string path); 

Ich habe versucht, diese P/Invoke Interop Assistant in Microsoft zu setzen, aber es Drosseln auf die "string" -Klasse (die ich denke, ist von MFC?).

Ich habe versucht, es als eine Vielzahl von verschiedenen Typen (C# String, Char [], Byte []) Marsling aber jedes Mal, wenn ich entweder NotSupportedException oder eine native Assembly Exception (je nachdem, was Marshalling versuchte ich).

Wie jeder jemals gemacht Native/Managed Interop, wo die native String-Klasse verwendet wird? Gibt es irgendeinen Weg, dies zu marschieren? Muss ich meinen eigenen Marshaler schreiben?

+0

Große Frage; Ich war überrascht, dass es nicht automatisch funktioniert. http://msdn.microsoft.com/en-us/library/1b4az623.aspx –

+0

Ich war auch überrascht ... es gibt keinen wichtigen Grund sollte es nicht ... aber es scheint, dass STL wird nicht damit arbeiten ... Auch ... Ich würde nur die Funktion ändern, um WCHAR zu verwenden, aber es ist keine DLL, die ich ändern kann. –

Antwort

6

Sieht aus, als ob Sie versuchen, die C++ - Standardbibliothekszeichenfolgenklasse zu verwenden. Ich bezweifle, dass das für Marshal einfach sein wird. Besser mit einem Char * und Marshal als StringBuilder zu bleiben. Das mache ich normalerweise. Sie müssen einen Wrapper hinzufügen, der die C++ - Zeichenfolge für Sie generiert.

+0

Ich hatte Angst davor ... Zahlen –

2

Der PInvoke-Interop-Assistent unterstützt nur C nicht C++. Leider ist die MFC-String-Klasse (CString, glaube ich?) C++ und funktioniert nicht über den Assistenten. Versuchen Sie stattdessen, folgendes zu verwenden:

void SetPath(__in const WCHAR* path); 
0

Ja. Sie können. Tatsächlich können nicht nur std::string, std::wstring, eine beliebige Standard-C++ - Klasse oder eigene Klassen gemarshallt oder instanziiert und von C# /. NET aufgerufen werden. Die Grundidee, ein C++ - Objekt aus der .NET-Welt instanziieren, besteht darin, die exakte Größe des C++ - Objekts aus .NET zuzuordnen und dann den Konstruktor aufzurufen, der aus der C++ - DLL exportiert wird, um das Objekt zu initialisieren, dann können Sie das tun Um eine der Funktionen aufzurufen, um auf dieses C++ - Objekt zuzugreifen, müssen Sie, wenn eine der Methoden andere C++ - Klassen enthält, diese in eine C# -Klasse einbetten. Bei Methoden mit primitiven Typen können Sie sie einfach P/Invoice aufrufen. Wenn Sie nur wenige Methoden zum Anrufen haben, wäre es einfach, manuelle Codierung dauert nicht lange. Wenn Sie mit dem C++ - Objekt fertig sind, rufen Sie die Destruktor-Methode des C++ - Objekts auf, das ebenfalls eine Exportfunktion ist. Wenn es keine hat, müssen Sie nur Ihren Speicher von .NET befreien.

Hier ist ein Beispiel.

public class SampleClass : IDisposable 
{  
    [DllImport("YourDll.dll", EntryPoint="ConstructorOfYourClass", CharSet=CharSet.Ansi,   CallingConvention=CallingConvention.ThisCall)] 
    public extern static void SampleClassConstructor(IntPtr thisObject); 

    [DllImport("YourDll.dll", EntryPoint="DoSomething", CharSet=CharSet.Ansi,  CallingConvention=CallingConvention.ThisCall)] 
    public extern static void DoSomething(IntPtr thisObject); 

    [DllImport("YourDll.dll", EntryPoint="DoSomethingElse", CharSet=CharSet.Ansi,  CallingConvention=CallingConvention.ThisCall)] 
    public extern static void DoSomething(IntPtr thisObject, int x); 

    IntPtr ptr; 

    public SampleClass(int sizeOfYourCppClass) 
    { 
     this.ptr = Marshal.AllocHGlobal(sizeOfYourCppClass); 
     SampleClassConstructor(this.ptr); 
    } 

    public void DoSomething() 
    { 
     DoSomething(this.ptr); 
    } 

    public void DoSomethingElse(int x) 
    { 
     DoSomethingElse(this.ptr, x); 
    } 

    public void Dispose() 
    { 
     Marshal.FreeHGlobal(this.ptr); 
    } 
} 

Für Einzelheiten finden Sie auf den folgenden Link,

C#/.NET PInvoke Interop SDK

(ich bin der Autor des SDK-Tool)

Sobald Sie den C# Wrapper-Klasse für Ihre C haben ++ Klasse bereit, es ist einfach, ICustomMarshaler zu implementieren, damit Sie das C++ - Objekt von .NET marshalieren können.

http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.icustommarshaler.aspx