Marshal C ++ & # 8220; string & # 8221; classe en C # P / Invoke
-
03-07-2019 - |
Question
J'ai une fonction dans une DLL native définie comme suit:
#include <string>
void SetPath(string path);
J'ai essayé de mettre cela dans l'assistant d'interopérabilité P / Invoke de Microsoft, mais cela étouffe la & string; chaîne " classe (qui, je pense est de MFC?).
J'ai essayé de le marshaler sous différents types (C # String, char [], byte []), mais à chaque fois je reçois une exception NotSupportedException ou Native Assembly Exception (selon le marshaling que j'ai essayé).
Comme quelqu'un a déjà fait Native / Managed Interop où la classe de chaîne native est utilisée? Y at-il un moyen de Marshal cela? Est-ce que je vais devoir écrire mon propre Marshaler?
La solution
On dirait que vous essayez d'utiliser la classe de chaîne de bibliothèque standard C ++. Je doute que ce sera facile à marshal. Mieux vaut s'en tenir à un caractère * et à Marshal en tant que StringBuilder. C'est ce que je fais d'habitude. Vous devrez ajouter un wrapper qui génère la chaîne C ++ pour vous.
Autres conseils
L’assistant d’interopérabilité PInvoke ne prend en charge que le C, pas le C ++. Malheureusement, la classe MFC String (CString, je crois?) Est en C ++ et ne fonctionnera pas avec l'assistant. Essayez plutôt d'utiliser ce qui suit
void SetPath(__in const WCHAR* path);
Oui. Vous pouvez. En réalité, il ne suffit pas de std :: string
, std :: wstring
, toute classe C ++ standard ou vos propres classes peuvent être marshalées ou instanciées et appelées à partir de C # / .NET.
L'idée de base pour instancier un objet C ++ à partir d'un monde .NET consiste à 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, puis vous pourrez appelez 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 envelopper dans une classe C #; pour les méthodes avec des types primitifs, vous pouvez simplement les invoquer / les appeler. Si vous n'avez que 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, il vous suffira 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 plus de détails, consultez le lien ci-dessous,
.C # /. Kit de développement logiciel d'interopérabilité NET PInvoke
(Je suis l'auteur de l'outil SDK)
Une fois que vous avez prêt la classe wrapper C # pour votre classe C ++, il est facile d'implémenter ICustomMarshaler
afin de pouvoir marshaler l'objet C ++ à partir de .NET.
http://msdn.microsoft.com/ en-us / library / system.runtime.interopservices.icustommarshaler.aspx