2008-10-01 19 views
7

J'ai une fonction dans une DLL native définie comme suit:maréchal C++ classe "chaîne" en C# P/Invoke

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

J'ai essayé de mettre cela dans P/Invoke Interop adjoint de Microsoft, mais il s'étrangle la classe "string" (que je pense est de MFC?). J'ai essayé de le marshaler comme une variété de différents types (C# String, char [], byte []) mais chaque fois que je reçois une exception NotSupportedException ou une exception Native Assembly (en fonction de marshaling j'ai essayé).

Comme on a déjà fait Interop Native/Managed où la classe de chaînes natives est utilisée? Y a-t-il un moyen de maréchal? Est-ce que je vais devoir écrire mon propre Marshaler?

+0

Bonne question; J'ai été surpris que ça ne fonctionne pas automatiquement. http://msdn.microsoft.com/en-us/library/1b4az623.aspx –

+0

J'ai été surpris aussi ... il n'y a pas de raison majeure que ça ne devrait pas ... mais il semble que STL ne va pas fonctionner avec ça ... Aussi ... Je voudrais juste changer la fonction pour utiliser WCHAR, mais ce n'est pas une DLL que je peux changer. –

Répondre

6

On dirait que vous essayez d'utiliser la classe de chaînes de la bibliothèque standard C++. Je doute que ce soit facile pour Maréchal. Mieux vaut rester avec un char * et Marshal comme StringBuilder. C'est ce que je fais habituellement. Vous devrez ajouter un wrapper qui génère la chaîne C++ pour vous.

+0

J'avais peur de ça ... des chiffres –

2

L'assistant d'interopérabilité PInvoke prend uniquement en charge C et non C++. Malheureusement, la classe MFC String (CString je crois?) Est C++ et ne fonctionnera pas avec l'assistant. Essayez plutôt d'utiliser les éléments suivants:

void SetPath(__in const WCHAR* path); 
0

Oui. Vous pouvez. En fait, non seulement std::string, std::wstring, n'importe quelle classe C++ standard ou vos propres classes peuvent être marshalées ou instanciées et appelées depuis C#/.NET. L'idée de base d'instancier un objet C++ à partir du monde .NET est d'allouer la taille exacte de l'objet C++ à partir de .NET, puis d'appeler le constructeur exporté à partir de la DLL C++ pour initialiser l'objet, alors vous pourrez Pour appeler l'une des fonctions pour accéder à cet objet C++, si l'une des méthodes implique d'autres classes C++, vous devrez également les placer dans une classe C#, pour les méthodes avec des types primitifs, vous pouvez simplement les appeler P/Invoke. Si vous avez seulement quelques méthodes à appeler, ce serait simple, le codage manuel ne prendra pas longtemps. Lorsque vous avez terminé avec l'objet C++, vous appelez la méthode destructor de l'objet C++, qui est également une fonction d'exportation. s'il n'en a pas, alors vous avez juste besoin de libérer votre mémoire de .NET.

Voici un exemple.

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); 
    } 
} 

Pour les détails, s'il vous plaît voir le lien ci-dessous,

C#/.NET PInvoke Interop SDK

(je suis l'auteur de l'outil SDK)

Une fois que vous avez la classe C# wrapper pour votre C++ Prêt pour la classe, il est facile d'implémenter ICustomMarshaler afin que vous puissiez marshaler l'objet C++ à partir de .NET.

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