una extraer ejemplos caracteres cadena .net pinvoke marshalling access-violation

.net - extraer - ¿Por qué no puedo devolver una cadena char*de C++ a C#en una versión de lanzamiento?



string c# ejemplos (5)

El compilador de C ++ en modo Release está poniendo la constante en la página de datos, que está protegida; el intento de entregar esto a C # está causando problemas. En el modo de depuración, el compilador no está optimizando la constante en la página de datos, por lo que no hay problema de protección.

Estoy intentando llamar a la siguiente función C trivial desde C #:

SIMPLEDLL_API const char* ReturnString() { return "Returning a static string!"; }

Con la siguiente declaración P / Invoke (con o sin el atributo de retorno, no hace ninguna diferencia):

[DllImport("SimpleDll")] [return: MarshalAs(UnmanagedType.LPStr)] public static extern string ReturnString();

Funciona si la DLL es una compilación de depuración pero se bloquea en una compilación de la versión (AccessViolationException).

Estoy llamando a más de una docena de otras funciones simples y esta es la única que falla (aquí están las otras :)

[DllImport("SimpleDll")] public static extern int NextInt(); [DllImport("SimpleDll")] public static extern void SetNextInt(int x); [DllImport("SimpleDll")] public static extern int AddInts(int a, int b); [DllImport("SimpleDll")] public static extern int AddFourInts(int a, int b, int c, int d); [DllImport("SimpleDll")] public static extern double AddDoubles(double x, double y); [DllImport("SimpleDll")] public static extern IntPtr AddDoublesIndirect(ref double x, ref double y); [DllImport("SimpleDll")] [return: MarshalAs(UnmanagedType.U1)] public static extern char CharStringArgument([MarshalAs(UnmanagedType.LPStr)]string s); [DllImport("SimpleDll")] [return: MarshalAs(UnmanagedType.U2)] public static extern char WCharStringArgument([MarshalAs(UnmanagedType.LPWStr)]string s); [DllImport("SimpleDll")] [return: MarshalAs(UnmanagedType.LPWStr)] public static extern string ReturnWString(); [DllImport("SimpleDll")] [return: MarshalAs(UnmanagedType.BStr)] public static extern string ReturnBSTR(); [DllImport("SimpleDll")] public static extern System.Drawing.Point MakePoint(int x, int y); [DllImport("SimpleDll")] public static extern IntPtr MakePointIndirect(int x, int y); [DllImport("SimpleDll")] public static extern int GetPointY(System.Drawing.Point p); [DllImport("SimpleDll")] public static extern int GetPointYIndirect(ref System.Drawing.Point pp); [DllImport("SimpleDll")] public static extern int SumIntegers(ref int firstElem, int size);


En mi experiencia con P / Invoke, usualmente tiene 2 parámetros: 1. un búfer preasignado en, y 2, la longitud del búfer. El valor de retorno es la longitud de los datos devueltos (que no debe exceder la longitud original).

Por lo general, los lanzamientos de DEBUG no moverán la memoria tanto.

Por cierto, puedes pasar un StringBuilder asignado previamente, luego establecer sb.Lenght = el valor de retorno de la función C, entonces no tendrás un montón de nulos / 0 al final de tu cadena.


Me encontré con un problema similar y la especificación de "CharSet" pareció solucionarlo.

[DllImport("SimpleDll", CharSet = CharSet.Ansi)]

No estoy seguro de por qué esto sería diferente en depuración y lanzamiento.


O tal vez tratar de usar

[DllImport("SimpleDll")] public static extern IntPtr ReturnString();

y en su código de llamada, use la Clase Marshal

string ret = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(PInvoke.ReturnString());


También es posible hacer eso con un Marshaler personalizado:

class ConstCharPtrMarshaler : ICustomMarshaler { public object MarshalNativeToManaged(IntPtr pNativeData) { return Marshal.PtrToStringAnsi(pNativeData); } public IntPtr MarshalManagedToNative(object ManagedObj) { return IntPtr.Zero; } public void CleanUpNativeData(IntPtr pNativeData) { } public void CleanUpManagedData(object ManagedObj) { } public int GetNativeDataSize() { return IntPtr.Size; } static readonly ConstCharPtrMarshaler instance = new ConstCharPtrMarshaler(); public static ICustomMarshaler GetInstance(string cookie) { return instance; } }

Y úsalo así:

[DllImport("SimpleDll")] [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(ConstCharPtrMarshaler))] public static extern string ReturnString();