Marshal C ++ & # 8220; string & # 8221; clase en C # P / Invoke
-
03-07-2019 - |
Pregunta
Tengo una función en una DLL nativa definida de la siguiente manera:
#include <string>
void SetPath(string path);
Intenté poner esto en el Asistente de interoperabilidad P / Invoke de Microsoft, pero se ahoga en la cadena " " clase (que creo que es de MFC?).
He intentado calcularlo como una variedad de tipos diferentes (C # String, char [], byte []) pero cada vez que obtengo una NotSupportedException o una Excepción de ensamblaje nativo (dependiendo de lo que intenté calcular).
¿Como cualquier persona que haya hecho Interop nativa / administrada donde se usa la clase de cadena nativa? ¿Hay alguna manera de marchar esto? ¿Voy a tener que escribir mi propio Marshaler?
Solución
Parece que estás intentando usar la clase de cadena de la biblioteca estándar de C ++. Dudo que sea fácil para el mariscal. Mejor seguir con un char * y Marshal como StringBuilder. Eso es lo que suelo hacer. Tendrá que agregar un contenedor que genere la cadena de C ++ para usted.
Otros consejos
El asistente de interoperabilidad PInvoke solo admite C no C ++. Desafortunadamente, la clase de cadena MFC (CString, ¿creo?) Es C ++ y no funcionará a través del asistente. En su lugar, intente usar lo siguiente
void SetPath(__in const WCHAR* path);
Sí. Usted puede. En realidad, no solo std :: string
, std :: wstring
, cualquier clase de C ++ estándar o sus propias clases se pueden calcular y crear instancias y llamar desde C # / .NET.
La idea básica de crear una instancia de un objeto C ++ desde el mundo .NET es asignar el tamaño exacto del objeto C ++ desde .NET, luego llamar al constructor que se exporta desde la DLL de C ++ para inicializar el objeto, luego podrá llame a cualquiera de las funciones para acceder a ese objeto de C ++, si alguno de los métodos involucra otras clases de C ++, también tendrá que envolverlos en una clase de C #, para los métodos con tipos primitivos, simplemente puede P / Invocarlos. Si solo tiene algunos métodos para llamar, sería sencillo, la codificación manual no tomará mucho tiempo. Cuando haya terminado con el objeto C ++, llame al método destructor del objeto C ++, que también es una función de exportación. si no tiene uno, solo necesita liberar su memoria de .NET.
Aquí hay un ejemplo.
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);
}
}
Para más detalles, consulte el siguiente enlace,
C # /. NET PInvoke Interop SDK
(Soy el autor de la herramienta SDK)
Una vez que tenga preparada la clase de envoltorio de C # para su clase de C ++, es fácil implementar ICustomMarshaler
para poder ordenar el objeto de C ++ desde .NET.
http://msdn.microsoft.com/ en-us / library / system.runtime.interopservices.icustommarshaler.aspx