Obtenir la valeur de retour de chaîne à partir de DLL C en Delphi

J’ai une ancienne DLL écrite en C qui contient une fonction qui renvoie une chaîne et je dois accéder à cette fonction à partir de Delphi. La seule information que j’ai sur la DLL est le VB déclare pour accéder à la fonction:

Public Declare Fonction DecryptStr Lib “strlib” (Str As Ssortingng) As Ssortingng

J’ai essayé ce qui suit sans succès:

Déclaration:

function DecryptStr(s: PChar): PChar; cdecl; external 'strlib.dll'; 

Usage:

 var p1, p2 : pchar; begin GetMem( p1, 255 ); StrPCopy( p2, 'some ssortingng to decrypt' ); p1 := DecryptStr( p2 ); end; 

Cela bloque régulièrement la DLL avec une violation d’access. Je suis à perte.

Aucune suggestion ?

Pensez à réécrire votre code de test comme suit:

 var p1, p2 : pchar; begin GetMem( p1, 255 ); // initialize GetMem( p2, 255 ); StrPLCopy( p2, 'some ssortingng to decrypt', 255 ); // prevent buffer overrun StrPLCopy( p1, DecryptStr( p2 ), 255); // make a copy since dll will free its internal buffer end; 

Si vous échouez toujours dans un appel à DecryptStr, lisez attentivement http://support.microsoft.com/kb/187912 .

p2 n’est pas initialisé. StrPCopy copie la chaîne dans un emplacement de mémoire aléatoire. Et très probablement la convention d’appel est stdcall.

Je devine ici, mais êtes-vous sûr que c’est cdecl? Si le VB déclare ne le mentionne pas, je suppose que c’est en fait une fonction STDCALL (STDCALL est assez courant sous Windows, car la quasi-totalité de son API native l’utilise). Appeler une fonction d’une convention d’appel comme s’il s’agissait d’une autre convention d’appel peut vraiment gâcher la stack, entraînant généralement un crash.

Assurez-vous également que la chaîne est ANSI (LPSTR / LPCSTR) ou UNICODE (LPWSTR / LPCWSTR). Je ne connais pas VB ou Delphi, donc je ne sais pas ce que chacun utilise par défaut.

Comme Jozz le dit, p2 (où vous copiez votre chaîne) n’est jamais initialisé dans votre exemple.

Essayez ceci à la place.

 var p1, p2 : pchar; begin GetMem( p2, 255 ); // allocate memory for 'some ssortingng...' StrPCopy( p2, 'some ssortingng to decrypt' ); p1 := DecryptStr( p2 ); end; 

En outre, la mémoire que vous avez allouée en appelant Getmem (p1, …) aurait été perdue, car p1 a été écrasé par la fonction return de DecryptStr.

Cependant, je serais un peu préoccupé par le contenu exact de DecryptStr et par le propriétaire de la mémoire désignée par p1. S’il renvoie un pointeur à la mémoire allouée par la DLL, vous devrez faire attention à la manière dont cette mémoire est libérée.

Je suis d’accord avec CesarB, essayez de le déclarer avec la directive stdcall comme:

 function DecryptStr(s: PChar): PChar; stdcall; external 'strlib.dll'; 

si cela ne fonctionne pas, postez la déclaration VB ici.

Le meilleur moyen dans ce genre de situation est de déboguer votre programme et de vérifier la stack avant et après l’exécution du rappel. Comment savoir, cela pourrait même être un bogue dans la DLL externe?

De cette façon, vous verrez assez facilement comment corriger cela.

La DLL a-t-elle été écrite dans Borland C ou C ++ Builder par hasard avec l’intention d’être utilisée avec Delphi? Dans ce cas, il aurait pu être compilé en utilisant une directive pascal.

Les suggestions selon lesquelles les chaînes doivent être “initialisées” semblent être correctes. En effet, C exigera que la chaîne en cours de transmission soit terminée par un caractère null. Vérifiez que le caractère dans la mémoire tampon juste après la fin du texte est nul (# 0).

Pourquoi pensez-vous que la chaîne transmise a une longueur exacte de 255 caractères? Vous devez allouer Longueur (p1) + 1 octet – pour les caractères dans p1 et un caractère # 0 à la fin.

En outre, votre exemple de code semble confus quant à l’utilisation de p1 et p2. Il semble que p1 soit le tampon transmis à la DLL C que vous allouez et p2 à la chaîne renvoyée allouée par la DLL. Mais alors le code serait (notez l’utilisation de p1 et p2)

 var p1, p2 : pchar; begin GetMem( p1, 255 ); StrPCopy( p1, 'some ssortingng to decrypt' ); p2 := DecryptStr( p1 ); end; 

De meilleurs noms de variables vous aideraient à rendre cela plus clair.

Je laisse tomber dans ma solution car je me suis un peu échappé contre elle et je ne l’ai pas trouvée dans les réponses.

La fonction C ++ ressemble à ceci:

 int __stdcall DoSomething(char * _name); 

Pour que cela fonctionne avec Delphi, je déclare la fonction suivante

 function DoSomething(name: PAnsiChar): integer; stdcall; external 'somedll.dll'; 

Et puis, quand je passe l’appel, j’ai une fonction qui ressemble à ceci:

 var s: PAnsiChar; begin GetMem(s, 255); DoSomething(s); // s now contains the value returned from the C DLL end; 

J’ai essayé d’utiliser PChar au lieu de PAnsiChar mais tout ce que j’obtiens en retour est un déchet. De même, si je déclare la fonction dans Delphi avec le paramètre défini sur var , j’obtiens une exception lorsque je tente de la lire.

J’espère que cela aide quelqu’un ..