Maresciallo C ++ classe "stringa" in C # P / Invoke
-
03-07-2019 - |
Domanda
Ho una funzione in una DLL nativa definita come segue:
#include <string>
void SetPath(string path);
Ho provato a inserirlo in P / Invoke Interop Assistant di Microsoft, ma si soffoca sulla stringa "quot" " classe (che penso provenga dall'MFC?).
Ho provato a eseguirne il marshalling come una varietà di tipi diversi (stringa C #, char [], byte []) ma ogni volta ricevo NotSupportedException o un'eccezione di assembly nativo (a seconda di quale marshalling ho provato).
Come qualcuno ha mai fatto l'interoperabilità nativa / gestita in cui viene utilizzata la classe di stringhe nativa? C'è un modo per maresciallo questo? Dovrò scrivere il mio Marshaler?
Soluzione
Sembra che tu stia provando a usare la classe di stringhe della libreria standard C ++. Dubito che sarà facile per il maresciallo. Meglio restare con un char * e Marshal come StringBuilder. Questo è quello che faccio di solito. Dovrai aggiungere un wrapper che genera la stringa C ++ per te.
Altri suggerimenti
L'assistente di interoperabilità di PInvoke supporta solo C e C ++. Sfortunatamente la classe String MFC (CString credo?) È C ++ e non funzionerà attraverso l'assistente. Prova invece a utilizzare quanto segue
void SetPath(__in const WCHAR* path);
Sì. Puoi. In realtà, non solo std :: string
, std :: wstring
, qualsiasi classe C ++ standard o le tue classi possono essere sottoposte a marshalling o istanziate e chiamate da C # /. NET.
L'idea di base di creare un'istanza di un oggetto C ++ dal mondo .NET è quella di allocare le dimensioni esatte dell'oggetto C ++ da .NET, quindi chiamare il costruttore che viene esportato dalla DLL C ++ per inizializzare l'oggetto, quindi si sarà in grado di chiama una delle funzioni per accedere a quell'oggetto C ++, se uno qualsiasi dei metodi coinvolge altre classi C ++, dovrai anche avvolgerli in una classe C #, per i metodi con tipi primitivi, puoi semplicemente P / Invocarli. Se hai solo pochi metodi da chiamare, sarebbe semplice, la codifica manuale non richiederà molto tempo. Quando hai finito con l'oggetto C ++, chiami il metodo distruttore dell'oggetto C ++, che è anche una funzione di esportazione. se non ne ha uno, è sufficiente liberare la memoria da .NET.
Ecco un esempio.
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);
}
}
Per i dettagli, consultare il link seguente,
C # /. NET PInvoke Interop SDK
(Sono l'autore dello strumento SDK)
Una volta pronta la classe wrapper C # per la classe C ++, è facile implementare ICustomMarshaler
in modo da poter eseguire il marshalling dell'oggetto C ++ da .NET.
http://msdn.microsoft.com/ it-it / library / system.runtime.interopservices.icustommarshaler.aspx