2012-01-19 7 views
5

Tengo la siguiente cabecera de la función en un DLL nativa:Mariscal de un unsigned char * Función de regresar de una DLL, en C#

unsigned char* Version_String() 

Estoy tratando de llamarlo desde un proyecto de C#, he intentado la siguiente llamada (según lo encontrado en otras preguntas similares aquí):

[DllImport("BSL430.dll", CharSet=CharSet.Ansi)] 
public extern static UIntPtr Version_String(); 

Y me siguen dando la siguiente excepción:

Intento de leer o escribir prot memoria ect. Esto a menudo es una indicación de que otra memoria está corrupta.

El siguiente intento fue el siguiente y me da la misma excepción:

[DllImport("BSL430.dll", CharSet=CharSet.Ansi)] 
[return : MarshalAs(UnmanagedType.LPStr)] 
public extern static string Version_String(); 

Me parece que no puede conseguir alrededor de este problema. ¡Cualquier ayuda sería muy apreciada!

Editar: miradas

no puedo dar el código DLL aquí, ya que cae bajo un acuerdo de confidencialidad, pero la función que estoy llamando como este:

unsigned char versionString[50]; 

__declspec(dllexport) unsigned char* Version_String() 
{ 
    if(check_hardware_stuff()) 
    { 
     strcpy((char *) versionString, "version_string_bla_bla"); 
     versionString[5] = stuff; 
    } 
    else if (other_check()) 
    { 
     //will return empty string, that should be filled with '\0' 
    } 
    else 
    { 
     strcpy((char *) versionString, "ERROR"); 
    } 
    return versionString; 
} 

estoy No me gusta especialmente la implementación de DLL, pero necesito usarla "tal como está". Obtengo la excepción cuando trato de llamar al VersionString(), independientemente de lo que haga con el valor devuelto.

+0

Tal vez esté usando una convención de llamadas incorrecta (http://msdn.microsoft.com/en-us/library/system.runtime.interopservices.callingconvention.aspx)? – svick

+0

¿Su dll se compiló con la opción de juego de caracteres MultiByte? –

+1

Utilice el depurador para averiguar dónde se bloquea el código nativo. Project + Properties, Debug, marque "Habilitar la depuración del código no administrado". Establezca un punto de interrupción en la función en el archivo de código fuente C. –

Respuesta

8

actualización

Después de haber visto la cuestión actualizada, los diversos comentarios, y el código de su función nativa, parece probable que la excepción se lanza cuando se llama check_hardware_stuff(). Es lo suficientemente simple para depurar. Reemplazaría su función con una como esta:

unsigned char versionString [50];

__declspec(dllexport) unsigned char* Version_String() 
{ 
    strcpy(versionString, "testing"); 
    return versionString; 
} 

Si éste tampoco funciona entonces mi conjetura es que el error se eleva en el DllMain de su DLL. Depure eso al poner la función anterior en un archivo DLL simple que no hace nada más.

Respuesta original

convención de llamada es el problema más obvio. Es probable que su código nativo use cdecl, pero el valor predeterminado p/invoke es stdcall. Cambiar su p/invocar la firma que ser así:

[DllImport("BSL430.dll", CallingConvention=CallingConvention.Cdecl)] 
public extern static IntPtr Version_String(); 

Se puede omitir el parámetro de forma segura CharSet ya que ninguno de los parámetros tiene texto porque está tratando el valor devuelto como un puntero.

Editar: Hans señala correctamente en los comentarios que, dado que no hay parámetros, el desajuste de la convención de llamadas no importa. Entonces este no es el problema.

Llame Marshal.PtrToStringAnsi para convertir a una cadena .net.

string version = Marshal.PtrToStringAnsi(Version_String()); 

Desde PtrToStringAnsi espera un parámetro IntPtr Yo recomendaría que utilice IntPtr como el tipo de retorno de ustedes p/invocar la firma.

Todo esto supone que la memoria devuelta por su función nativa se asigna y libera en la DLL nativa. Si se asigna un montón y espera que la persona que llama lo desasigne, entonces tiene un pequeño problema. ¿Cómo desasigna la memoria de C# ya que no tiene acceso al montón de la DLL nativa?

La solución simple es usar el montón COM compartido para asignar la memoria. Llame al CoTaskMemAlloc para asignar el búfer para la cadena. A continuación, declare que el valor de retorno es del tipo string y el marshaller p/invoke desasignará con el asignador COM.

[DllImport("BSL430.dll", CallingConvention=CallingConvention.Cdecl)] 
public extern static string Version_String(); 
... 
string version = Version_String(); 

Por supuesto, esto solo se aplica si devuelve la memoria asignada que usted espera que la persona que llama desasigne.

+0

Gracias por la pronta respuesta. Probé el código, pero sigo recibiendo las mismas excepciones. Observé el código DLL, y por lo que puedo decir, la cadena se declara globalmente como una matriz de tamaño fijo: 'unsigned char versionString [50];'. Por lo que sé, no se requieren más asignaciones en este caso, ¿verdad? – andreiscurei

+1

No puede ser CallingConvention, la función no toma ningún argumento. –

+0

¿En qué momento obtienes la excepción? ¿Cuándo se llama al DLL o cuando se hace algo con el valor que se devuelve? –

Cuestiones relacionadas