Dll multilangage, genre api, sans sharemem, avec pointeur et buffer

{

Si vous préférez le Delphi au Français, le code est dessous !

ShareMemne sera pas utilisée (L'aide en ligne précise qu'elle estnécessairedans la close uses de l'exe, ce qui peut être délicat quandl'EDI d'unautre langage n'a pas de close uses).

Le passage d'Integer et detype énumérés ne semble pas poser deproblèmes, mais en ce qui concerneles String, c'est une autre histoire.

Comme on n'utilise pas ShareMem, le choix se reporte sur les pointeurs.

Le problème est de s'assurer que les pointeurs continuent de pointer sur quelque-chose.

En effet, l'erreur classique consiste à renvoyer un pointeur sur une variable locale à la fonction...

Renvoyerun pointeur sur une variable globale de la dll est une méthodequifonctionne dans certains cas, mais cela me parait très risqué engénéral.

Laconclusion est que les pointeurs doivent pointer sur deschaînesdéfinies dans l'exe, et donc que l'on peut parfaitementtransmettretous les paramètres de type PChar comme const.

Parce que même si la chaîne qui se trouve à l'adresse change, l'adresse ne change pas.

Unproblème possible est que la chaîne renvoyée n'est pas forcément delamême taille que la chaîne qui a initialisé le pointeur, ou quelamémoire allouée pour contenir le résultat soit insuffisante.

Et comme de par hasard, vous constaterez que je me rapproche bizarrement de quelque chose de connu...

Les API utilisent des buffers pour renvoyer des String, dont la taille est aussi spécifiée dans les paramètres...

Evidement,si la chaîne est initialisée avec des espaces, elle seraterminée par un0 terminale et la dll peut donc facilement récupérer lataille de lachaine tampon.

Mais il est certainement plus rapide d'allouer (New et Dispose sous Delphi), et non d'initialiser.

Cependant, la syntaxe des API, comme celle que je présente, est assez contraignante.

Il faut spécifier une taille de buffer, et il n'est pas toujours évident de prévoir la longueur de ce que la dll vat renvoyer.

Lamémoire est très mal exploitée: une partie est allouée sansêtreutilement utilisée (Si le tampon fait 1000 caractères et la chaînearenvoyer en fait 2, vous saisissez la perte).

Et la fonction nerenvoie pas la chaine comme résultat, mais commeparamètre ce qui obligeà attendre la ligne suivante pour l'utiliser.

Evidement, on peut faire passer le même pointeur que celui de l'argument tampon comme résultat de la fonction.

Apparement,ça marche en VB et en Delphi, mais perso, je préfère fairerenvoyer unlong, comme les API, et de m'en servir comme code d'erreur.

(Même pour les routines qui renvoient de long, j'ai décidé d'utiliser un buffer).

En contrepartie, j'alourdis l'utilisation de mes fonctions, alors ne suivez pas forcément mon exemple...

J'ai déclaré les arguments comme String dans les déclaration d'appel sous Delphi (De même que sous VB).

Celapermet de définir des valeurs par défaut pour les chaînes, etpermetdonc plus de souplesse lors de l'emploi d'arguments optionnels.

On fait passer des paramètres string const qui sont en fait modifiés, lol.

ce tuto sera remis a niveau très régulièrement (du moins pendant quelque mois après le 12.08.05).

J'ai bien sûr automatisé le système de conversion 'déclaration dans l'interface de la dll' -> 'Déclaration dans l'exe'.
}

//C'est juste l'API InputQuery encapsullée de manière a ce qu'elle renvoie une chaîne vide si l'utilisateur clique sur annuler.
//Je n'ai pas encore implémenté l'utilisation de lpEX qui sera une chaîne de paramètre pour la dll.
//nSize n'est pas encore utilisée non plus (Je crois qu'il empèchera une faille manifique de type Buffer Overflow).
//Il ne faut pas oublier la close external.

//Routine de la dll:

functionEXsup_InputQuery(constlpBuffer: PChar; const nSize: Integer; constlpEX: PChar; constlpPrompt: PChar; const lpCaption: PChar; constlpDefaultText: PChar):Integer; stdcall;
var
bolResult: Boolean;
strText: String;
I: Integer;
begin
strText:= lpDefaultText;
bolResult:= InputQuery(lpCaption, lpPrompt, strText);
if bolResult = false then strText:= '';
EY_PCharOutput(lpBuffer, nSize, PChar(strText));
Result:= 0;
end;

//Routine de la dll de remplissage du buffer:

function EY_PCharOutput(const lpBuffer: PChar; const nSize: Integer; const lpOutput: PChar): Integer;
var
I: Integer;
strOutput: String;
begin
strOutput:= String(lpOutput);
I:= -1;
for I:= 0 to Length(strOutput) - 1 do
lpBuffer[I * := lpOutput[I];
lpBuffer[Length(strOutput) * := #0;
end;

//Déclaration d'appel de l'exe Delphi:

functionEXsup_InputQuery(const lpBuffer: String; const nSize: Integer; constlpEX: String; constlpPrompt: String= ''; const lpCaption: String= '';const lpDefaultText:String= ''): Integer; stdcall; external'EX_Support.dll';

//Emploi dans l'exe Delphi:

type
TStr1000 = array[0..1000 * of Char;

procedure TfrmMain.btnTest1Click(Sender: TObject);
var
lpBuffer: ^TStr1000;
begin
New(lpBuffer);
EXsup_InputQuery(String(lpBuffer), 1000, lpEX, 'Prompt', 'Caption', '123456');

MessageBox(PChar(lpBuffer), 'Caption');

Dispose(lpBuffer);
end;

//Déclaration de l'exe VB6:

PublicDeclareFunction EXsup_InputQuery Lib "EX_Support.dll" (ByVal lpBufferAsString, ByVal nSize As Long, ByVal lpEX As String, OptionalByVallpPrompt As String = Empty, Optional ByVal lpCaption As String =Empty,Optional ByVal lpDefaultText As String = Empty) As Long

//Emploi dans l'exe VB6:

Private Sub Command1_Click()
Dim strEX As String
Dim strBuffer As String

strBuffer=" "
strEX = "AA"
Call EX_Support.EXsup_InputQuery(strBuffer, 1000, strEX, "Prompt", "Caption", "151")
MsgBox strBuffer
End Sub

Adresse d'origine

A voir également
Ce document intitulé « Dll multilangage, genre api, sans sharemem, avec pointeur et buffer » issu de CodeS SourceS (codes-sources.commentcamarche.net) est mis à disposition sous les termes de la licence Creative Commons. Vous pouvez copier, modifier des copies de cette page, dans les conditions fixées par la licence, tant que cette note apparaît clairement.
Rejoignez-nous