Pergunta

Eu tenho essa função no 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;
}

Estou tentando importar esta função a partir de C # com o seguinte código

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

Eu estou tentando apresentar isso em um MessageBox sempre tem símbolos estranhos no final da cadeia. Todas as sugestões como superar este problema?

Foi útil?

Solução

Eu vou voltar a sublinhar o fato de que seu código de C ++ é inválido. Você está retornando um ponteiro para uma variável local em um quadro de pilha que já não é válida quando é a função retorna. Que ele funciona agora é meramente um acidente. Assim que você chamar uma outra função, o espaço de pilha serão reutilizados, corrompendo o conteúdo do buffer. Isto é garantido para acontecer quando você chamar esse código de C #, a implementação marshaller P / Invoke irá substituir o quadro de pilha e corromper a memória intermédia.

Para piorar a situação, o / marshaller Invoke P vai tentar libertar o buffer. Ele assumirá que o buffer foi alocado pelo CoTaskMemAlloc () e CoTaskMemFree call () para liberar o buffer. Que irá falhar silenciosamente no Windows XP e versões anteriores, mas travar o seu programa no Vista e para cima.

O que é uma solução para o seu problema, o uso CoTaskMemAlloc () para alocar o buffer em vez de usar uma variável local. A solução totalmente melhor é para permitir que o chamador da função passar o tampão, para ser preenchido com a cadeia. Dessa forma, o chamador pode decidir como alocar o buffer e limpá-lo conforme necessário. A assinatura da função deve ficar assim:

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

Use strcpy_s () para preencher com segurança o tampão e evitar qualquer estouro de buffer. A C # declaração correspondente seria então:

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

e chamou assim:

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

Outras dicas

A partir da DLL você está retornando um array de caracteres ie tampão que está na pilha dentro da função GetMessage, e quando o retorno é executado os dados é confuso desde o buffer é retirado da pilha e é local para a pilha também, portanto, os caracteres estranhos que você está vendo. Há duas maneiras que você pode corrigir isso, altere a declaração de variável buffer para ser de um ponteiro e malloc-lo antes de devolvê-lo ou declará-lo como um estático.

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.

ou

static char buffer[250];

Também pode-lo a esclarecer variável ponteiro de entrada - é que a Global

?

Espero que isso ajude, Cumprimentos, Tom.

Tente usar um StringBuilder para o tipo de retorno e deixar de fora o atributo CharSet:

[DllImport("mydll.dll")]
public static extern StringBuilder GetMessage(int id);
Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top