Pregunta

Tengo esta función en Visual C ++ DLL

char * __stdcall GetMessage(int id) {
char buffer[250];
.
.
.
strcpy(buffer, entry); // entry is a char * that has allocated 250 chars
return (char *)buffer;
}

estoy intentando importar esta función desde C # con el siguiente código

[DllImport("mydll.dll", CharSet=CharSet.Ansi)]
public static extern string GetMessage(int id);

Estoy intentando presentar esto en un MessageBox, siempre tiene símbolos extraños al final de la cadena. ¿Alguna sugerencia de cómo superar este problema?

¿Fue útil?

Solución

Volveré a enfatizar el hecho de que su código C ++ no es válido. Está devolviendo un puntero a una variable local en un marco de pila que ya no es válido cuando la función regresa. Que ahora funciona no es más que un accidente. Tan pronto como llame a otra función, el espacio de pila se reutilizará, corrompiendo el contenido del búfer. Se garantiza que esto sucederá cuando llame a este código desde C #, la implementación de marshaller P / Invoke sobrescribirá el marco de la pila y dañará el búfer.

Para empeorar las cosas, el invocador P / Invoke intentará liberar el búfer. Se asumirá que el búfer fue asignado por CoTaskMemAlloc () y se llama a CoTaskMemFree () para liberar el búfer. Eso fallará silenciosamente en Windows XP y versiones anteriores, pero bloqueará su programa en Vista y versiones posteriores.

Que es una solución a su problema, use CoTaskMemAlloc () para asignar el búfer en lugar de usar una variable local. La mejor solución es dejar que la persona que llama de la función pase el búfer, para que se llene con la cadena. De esa manera, el llamante puede decidir cómo asignar el búfer y limpiarlo según sea necesario. La firma de la función debería verse así:

extern "C" __declspec(dllexport)
void __stdcall GetMessage(int id, char* buffer, size_t bufferSize);

Use strcpy_s () para llenar de forma segura el búfer y evitar cualquier desbordamiento del búfer. La declaración de C # correspondiente sería entonces:

[DllImport("mydll.dll")]
private static extern void GetMessage(int id, StringBuilder buffer, int bufferSize);

y se llama así:

var sb = new StringBuilder(250);
GetMessage(id, sb, sb.Capacity);
string retval = sb.ToString();

Otros consejos

Desde la DLL está devolviendo una serie de caracteres, es decir, el búfer que está en la pila dentro de la función GetMessage, y cuando se ejecuta el retorno, los datos se desordenan ya que el búfer se extrae de la pila y es local a la pila También, de ahí los extraños personajes que estás viendo. Hay dos formas de solucionar este problema, cambiar la declaración de la variable del búfer para que sea un puntero y malloc antes de devolverla o declararla como estática.

char *buffer;
if (!(buffer = (char *)malloc((250 * sizeof(char)) + 1)){
   // Handle the out of memory condition
}
// Now the buffer has 250 + 1 for null terminating character.

Or

static char buffer[250];

También puede aclarar la variable de puntero de entrada, ¿es eso global?

Espero que esto ayude, Atentamente, Tom.

Intente usar un StringBuilder para el tipo de retorno y omita el atributo CharSet:

[DllImport("mydll.dll")]
public static extern StringBuilder GetMessage(int id);
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top