Domanda

Ho questa funzione nella DLL Visual C ++

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

Sto cercando di importare questa funzione da C # con il seguente codice

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

Sto cercando di presentare questo in un MessageBox che ha sempre strani simboli alla fine della stringa. Qualche suggerimento su come superare questo problema?

È stato utile?

Soluzione

Sottolineerò nuovamente il fatto che il tuo codice C ++ non è valido. Si sta restituendo un puntatore a una variabile locale su un frame dello stack che non è più valido al ritorno della funzione. Che funzioni ora è solo un incidente. Non appena si chiama un'altra funzione, lo spazio dello stack verrà riutilizzato, corrompendo il contenuto del buffer. Ciò è garantito quando si chiama questo codice da C #, l'implementazione del marshaller P / Invoke sovrascriverà il frame dello stack e danneggerà il buffer.

A peggiorare le cose, il marshaller P / Invoke proverà a liberare il buffer. Supporrà che il buffer sia stato allocato da CoTaskMemAlloc () e chiamerà CoTaskMemFree () per rilasciare il buffer. Ciò fallirà silenziosamente su Windows XP e precedenti ma arresta in modo anomalo il programma su Vista e versioni successive.

Quale è una soluzione al tuo problema, usa CoTaskMemAlloc () per allocare il buffer invece di usare una variabile locale. La soluzione migliore a tutto tondo è quella di consentire al chiamante della funzione di passare il buffer, da riempire con la stringa. In questo modo, il chiamante può decidere come allocare il buffer e pulirlo come necessario. La firma della funzione dovrebbe apparire così:

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

Usa strcpy_s () per riempire in sicurezza il buffer ed evitare qualsiasi overflow del buffer. La corrispondente dichiarazione C # sarebbe quindi:

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

e chiamato così:

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

Altri suggerimenti

Dalla DLL si restituisce un array di caratteri, ad esempio un buffer, che si trova nello stack all'interno della funzione GetMessage, e quando viene eseguito il ritorno i dati vengono incasinati poiché il buffer viene espulso dallo stack ed è locale nello stack inoltre, da qui gli strani personaggi che stai vedendo. Esistono due modi per risolvere il problema, modificare la dichiarazione della variabile buffer in modo che sia un puntatore e eseguirne il malloc prima di restituirlo o dichiararlo come statico.

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.

o

static char buffer[250];

Puoi anche chiarire la variabile puntatore voce - è globale?

Spero che questo aiuti, I migliori saluti, Tom.

Prova a utilizzare StringBuilder per il tipo restituito e lascia fuori l'attributo CharSet:

[DllImport("mydll.dll")]
public static extern StringBuilder GetMessage(int id);
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top