Question

J'ai cette fonction dans la 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;
}

J'essaie d'importer cette fonction à partir de C # avec le code suivant

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

J'essaie de présenter ceci dans un MessageBox qui contient toujours des symboles étranges à la fin de la chaîne. Des suggestions pour surmonter ce problème?

Était-ce utile?

La solution

Je soulignerai à nouveau le fait que votre code C ++ n'est pas valide. Vous renvoyez un pointeur sur une variable locale sur un cadre de pile qui n'est plus valide au retour de la fonction. Que cela fonctionne maintenant est simplement un accident. Dès que vous appelez une autre fonction, l'espace de la pile sera réutilisé, ce qui altérera le contenu de la mémoire tampon. Cela se produira sûrement lorsque vous appelez ce code à partir de C #, l'implémentation de marshaller P / Invoke écrasera le cadre de la pile et corrompra le tampon.

Pour aggraver les choses, le commissaire d’invitation P / Invoke tentera de libérer le tampon. Il supposera que la mémoire tampon a été allouée par CoTaskMemAlloc () et appelle CoTaskMemFree () pour libérer le tampon. Cela échouera silencieusement sous Windows XP et versions antérieures, mais plantera votre programme sous Vista et versions ultérieures.

Quelle que soit la solution à votre problème, utilisez CoTaskMemAlloc () pour allouer le tampon au lieu d’utiliser une variable locale. La meilleure solution consiste à laisser l’appelant de la fonction passer le tampon, pour qu’il soit rempli avec la chaîne. Ainsi, l’appelant peut décider de l’affectation de la mémoire tampon et de la nettoyer si nécessaire. La signature de la fonction doit ressembler à ceci:

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

Utilisez strcpy_s () pour remplir le tampon en toute sécurité et éviter tout débordement de tampon. La déclaration C # correspondante serait alors:

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

et appelé comme ceci:

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

Autres conseils

A partir de la DLL, vous renvoyez un tableau de caractères, c'est-à-dire un tampon qui se trouve dans la pile de la fonction GetMessage. Lorsque le retour est exécuté, les données sont altérées, car le tampon est extrait de la pile et est local à la pile. aussi, d'où les personnages étranges que vous voyez. Vous pouvez résoudre ce problème de deux manières: changez la déclaration de la variable buffer en un pointeur et colocalisez-la avant de la renvoyer ou déclarez-la en tant que statique.

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];

Pouvez-vous également préciser la variable du pointeur d'entrée - est-ce global?

J'espère que ça aide, Meilleures salutations, Tom.

Essayez d’utiliser un StringBuilder pour le type de retour et laissez l’attribut CharSet:

[DllImport("mydll.dll")]
public static extern StringBuilder GetMessage(int id);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top