Novembre 2024 | Lun | Mar | Mer | Jeu | Ven | Sam | Dim |
---|
| | | | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | | Calendrier |
|
|
| Aide avec codage de DLL en Delphi | |
| | Auteur | Message |
---|
Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Aide avec codage de DLL en Delphi Mer 18 Mar 2015 - 1:39 | |
| @Jack Je pense que la question qui suit, s'adressera uniquement à Jack, bien que le sujet soit ouvert à tous. Depuis des années, je code KGF.dll, en Delphi 6 Personal Edition. J'ai bien intégré les contraintes liées à l'interfaçage avec Panoramic, c'est du moins ce que je pense. Et pourtant, je rencontre de sporadiques violations de mémoire, en cours d'exécution, et souvent en sortie du programme qui ne veut pas se terminer proprement. ET depuis deux jours, j'arrive enfin à le reproduire systématiquement, avec un code très réduit. J'hésite à placer ce post dans la rubrique des bugs, car j'ai tendance à toujours chercher le problème entre mes mains et mon écran, mais j'ai un doute.... Voilà la situation. J'ai fait une minuscule DLL nommée KGF_GRID.dll qui contient une seule fonction: SetGridSeparators, qui a deux paramètres. Voici le fichier KGF_GRID.dpr: - Code:
-
library KGF_GRID;
uses Classes, Controls, StrUtils, Grids, Types, Graphics, Dialogs, Windows;
var SG_line_separator, SG_cell_separator: string; SG_ColorCol, SG_ColorRow: integer; SG_color: TColor;
{$R *.res}
function SetGridSeparators(sepcel, seplin: pstring):integer; stdcall; export; begin SG_line_separator := seplin^; SG_cell_separator := sepcel^; showmessage('['+SG_cell_separator+'] ['+SG_line_separator+']'); result := 0; end;
exports SetGridSeparators ;
begin end.
Et voici le code Panoramic qui va avec: - Code:
-
' demo_GetSelectedGridText.bas label clic dim res%, sepcel$, seplin$
grid 1 : top 1,100 : left 1,10 grid_write 1,2,2,"aaa" grid_write 1,2,3,"bbb" grid_write 1,3,3,"ccc" on_click 1,clic
dll_on "KGF_GRID.dll" end
exit: res% = dll_call1("KillProcessByHandle",handle(0)) message str$(res%) return
clic:
' paramétrer les séparateurs (ce sont d'ailleurs les valeurs par défaut) sepcel$ = "" seplin$ = chr$(13)+chr$(10) ' >>>>>>>>> la ligne suivante provoque le problème: <<<<<<<<<<<<< res% = dll_call2("SetGridSeparators",adr(sepcel$),adr(seplin$)) message str$(res%) return
Il faut sélectionner un rectangle de cellules avec la souris, ou simplement cliquer dans le GRID. Il y aura deux messages: un venant de la DLL, l'autre du programme Panoramic (juste pour contrôler). Après quelques tentatives (2, 3 ouun peu plus), il y a ceci: " /> suivi de: " /> Souvent, il faut tuer le process par le gestionnaire des tâches. Alors, j'ai fait un programme Delphi créant un TStringGrid, chargeant la DLL dynamiquement et appelant la même fonction. Et là, pas de problème ! La fonction s'exécute normalement, autant de fois qu'on veut, et en sortie, pas de crash, pas besoin d'utiliser la TaskManager pour arrêter le programme. Voici le fichier Test_KGF_GRID.dpr: - Code:
-
program Test_KGF_GRID;
uses Forms, Test_KGF_GRID_Unit1 in 'Test_KGF_GRID_Unit1.pas' {Form1};
{$R *.res}
begin Application.Initialize; Application.CreateForm(TForm1, Form1); Application.Run; end.
Voici Test_KGF_GRID_unit1.dfm: - Code:
-
object Form1: TForm1 Left = 198 Top = 117 Width = 928 Height = 480 Caption = 'Text_KGF_GRID' Color = clBtnFace Font.Charset = DEFAULT_CHARSET Font.Color = clWindowText Font.Height = -11 Font.Name = 'MS Sans Serif' Font.Style = [] OldCreateOrder = False OnCreate = FormCreate PixelsPerInch = 96 TextHeight = 13 object StringGrid1: TStringGrid Left = 120 Top = 80 Width = 320 Height = 120 TabOrder = 0 OnClick = StringGrid1Click end end
et Test_KGF_GRID_unit1.pas: - Code:
-
unit Test_KGF_GRID_Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, Grids;
type TForm1 = class(TForm) StringGrid1: TStringGrid; procedure FormCreate(Sender: TObject); procedure StringGrid1Click(Sender: TObject); private { Déclarations privées } public { Déclarations publiques } end;
type TSetGridSeparators = function(sepcel, seplin: pstring):integer; stdcall;
var Form1: TForm1; dllHandle : cardinal; SetGridSeparators : TSetGridSeparators;
implementation
{$R *.dfm}
procedure TForm1.FormCreate(Sender: TObject); begin StringGrid1.Cells[2,2] := 'aaa'; StringGrid1.Cells[2,3] := 'bbb'; StringGrid1.Cells[3,3] := 'ccc';
// dllHandle := LoadLibrary('KGF.dll'); dllHandle := LoadLibrary('KGF_GRID.dll'); if dllHandle <> 0 then begin @SetGridSeparators := GetProcAddress(dllHandle, 'SetGridSeparators') ; if not Assigned (SetGridSeparators) then begin ShowMessage('"SetGridSeparators" function not found') ; FreeLibrary(dllHandle) ; application.Terminate; end; end else begin ShowMessage('KGF_GRID.dll not found / not loaded') ; application.Terminate; end; end;
procedure TForm1.StringGrid1Click(Sender: TObject); var seplin,sepcel: string; res: integer; begin seplin := #13#10; sepcel := '\'; res := SetGridSeparators(@sepcel,@seplin) ; //call the function showmessage(inttostr(res)); end;
end.
ainsi que Test_KGF_GRID.dof (généré automatiquement, juste pour info): - Code:
-
[FileVersion] Version=6.0 [Compiler] A=8 B=0 C=1 D=1 E=0 F=0 G=1 H=1 I=1 J=0 K=0 L=1 M=0 N=1 O=1 P=1 Q=0 R=0 S=0 T=0 U=0 V=1 W=0 X=1 Y=1 Z=1 ShowHints=1 ShowWarnings=1 UnitAliases=WinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; [Linker] MapFile=0 OutputObjs=0 ConsoleApp=1 DebugInfo=0 RemoteSymbols=0 MinStackSize=16384 MaxStackSize=1048576 ImageBase=4194304 ExeDescription= [Directories] OutputDir= UnitOutputDir= PackageDLLOutputDir= PackageDCPOutputDir= SearchPath= Packages= Conditionals= DebugSourceDirs= UsePackages=0 [Parameters] RunParams= HostApplication= Launcher= UseLauncher=0 DebugCWD= [Version Info] IncludeVerInfo=0 AutoIncBuild=0 MajorVer=1 MinorVer=0 Release=0 Build=0 Debug=0 PreRelease=0 Special=0 Private=0 DLL=0 Locale=1036 CodePage=1252 [Version Info Keys] CompanyName= FileDescription= FileVersion=1.0.0.0 InternalName= LegalCopyright= LegalTrademarks= OriginalFilename= ProductName= ProductVersion=1.0.0.0 Comments=
et Test_KGF_GRID.cfg (généré, juste pour info): - Code:
-
-$A8 -$B- -$C+ -$D+ -$E- -$F- -$G+ -$H+ -$I+ -$J- -$K- -$L+ -$M- -$N+ -$O+ -$P+ -$Q- -$R- -$S- -$T- -$U- -$V+ -$W- -$X+ -$YD -$Z1 -cg -AWinTypes=Windows;WinProcs=Windows;DbiTypes=BDE;DbiProcs=BDE;DbiErrs=BDE; -H+ -W+ -M -$M16384,1048576 -K$00400000 -LE"c:\program files (x86)\borland\delphi6\Projects\Bpl" -LN"c:\program files (x86)\borland\delphi6\Projects\Bpl"
Alors, ma question est: Pourquoi ça marche avec Delphi/Delphi, mais pas avec Panoramic/Delphi ? Qu'est-ce que j'ai raté au niveau de l'utilisation de l'interface Panoramic vers DLL ? Ou y aurait-il un problème dans Panoramic au niveau du chargement dynamique d'une DLL ? Ca fait des mois que je me bats avec ce problème sporadique, et depuis 2 jours, c'est devenu systématique. Et j'ai réussi à le reproduire avec ce code réduit au minimum. Je ne vois pas comment aller plus loin tout seul. Pourrais-tu m'aider, Jack ? | |
| | | Jicehel
Nombre de messages : 5947 Age : 52 Localisation : 77500 Date d'inscription : 18/04/2011
| Sujet: Re: Aide avec codage de DLL en Delphi Mer 18 Mar 2015 - 8:09 | |
| Puisque ça aide à faire des dll (peut être même qu'un jour je me lancerais dans l'aventure aussi )pour ajouter les compléments à Panoramic dont nous avons besoin pour faire ce que nous avons en tête, c'est forcément utile. J'espère que vous trouverez la solution. | |
| | | Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Re: Aide avec codage de DLL en Delphi Jeu 19 Mar 2015 - 18:45 | |
| Jack, si tu avais l'occasion de regarder ce petit code, ça m'arrangerait. Je suis bloqué à ce niveau. Je sais que tu es loin et que tu ne disposes pas de tout ce qu'il faut, là où tu es. Mais donne-moi stp une petite info pour confirmer que tu as bien vu ce problème.
J'attends la solution de cet aspect pour donner accès aux fonctions de gestion des GRID par DLL. En-dehors de ce que j'ai déjà publié (retourner les indices du rectangle de cellules sélectionné, retourner une chaîne de caractères contenant toutes les cellules sélectionnées et remplacer d'un coup toutes les cellules d'un rectangle de cellules), j'ai fait des fonctions qui marchent bien: activer/désactiver le mode édition pour pouvoir saisir directement dans un GRID, et choisir la couleur de fond d'une ligne, d'une colonne et/ou d'une cellule, pour autant d'éléments qu'on veut. Je pense que ça peut être utile. | |
| | | Jack Admin
Nombre de messages : 2395 Date d'inscription : 28/05/2007
| Sujet: Re: Aide avec codage de DLL en Delphi Ven 20 Mar 2015 - 10:35 | |
| Je n'ai pas tout mon "attirail" pour regarder en détail ce qui se passe, mais dès que je le peux, je décortiquerai ton code. En fait, je te répond maintenant, même si ma réponse n'est pas complète, pour que tu ne t'imagine pas que je délaisse ton problème. A la lecture des différents codes que tu proposes, une chose me chagrine. Dans KGF_GRID.dpr, tu fais: - Code:
-
SG_line_separator := seplin^; SG_cell_separator := sepcel^; alors que SG_line_separator et SG_cell_separator sont du type String Delphi, et que seplin et sepcel sont des PString Delphi. Je suis d'accord avec le fait que seplin et sepcel sont des pointeurs sur des strings, mais je ne vois pas comment, on peut récupérer de cette façon correctement un string qui n'est pas codé en "zero-terminal", c'est à dire qui n'est pas terminé par un 0. Dans l'appel en Panoramic : res% = dll_call2("SetGridSeparators",adr(sepcel$),adr(seplin$)) adr(string) donne certes, l'adresse d'un string, mais pas d'un string "zero-terminal". en Panoramic, faire adr(string) revient à faire integer(addr(string)) en Delphi, ce qui est différent de ton deuxième exemple où "ça marche". integer(addr(string)) est sans doute différent de @string. J'ai compilé ton exemple Test_KGF_GRID.dpr pour obtenir Test_KGF_GRID.dll et quand j'exécute demo_GetSelectedGridText.bas, j'obtiens : - à l'exécution un message correct affichant sepcel$ et seplin$ - à la fermeture, un message d'erreur : The instruction at "0x013934ce" referenced memory at "0x01437e8". The memory could not be "read". Click OK to terminate the program Puis : Runtime error 216 at 013934CE, c'est à dire sur l'instruction qui veut lire en mémoire en dehors du domaine de l'application. En conclusion (provisoire), je pense que le problème vient du fait que ces 3 instructions ne sont pas cohérentes (je n'ose pas dire compatibles) : integer(addr(string)) @string string := pstring^ _________________ username : panoramic@jack-panoramic password : panoramic123 | |
| | | Klaus
Nombre de messages : 12331 Age : 75 Localisation : Ile de France Date d'inscription : 29/12/2009
| Sujet: Re: Aide avec codage de DLL en Delphi Ven 20 Mar 2015 - 11:40 | |
| Merci beaucoup d'avoir regardé mon problème, Jack. Tu dis: - Citation :
- Je suis d'accord avec le fait que seplin et sepcel sont des pointeurs sur des strings, mais je ne vois pas comment, on peut récupérer de cette façon correctement un string qui n'est pas codé en "zero-terminal", c'est à dire qui n'est pas terminé par un 0.
Mais en réalité, il y a toujours un byte ZERO après le texte des strings qui sont passés par adr(s$). JE ne sais évidemment pas comment c'est réalisé en interne, par Panoramic, mais vu par la DLL, je constate que ce sont toujours des strings ASCIZ. Au début, je faisais une gymnastique complexe à l'aide d'un pointeur, pour récupérer les données. Mais un traçage avec affichage de la valeur des bytes récupérés le montre parfaitement. Dailleurs, comme Panoramic ne passe que l'adresse, comment saurais-je la fin du string s'il n'y avait pas de ZERO derrière ? Heureusement que ça marche comme ça ! Et j'utilise cette technique depuis des années, dans des dizaines de fonctions. Quelques exemples: toutes les fonctions utilisant un nom de fichier, un libellé, une URL, ... Mais, cette discussion m'a fait réfléchir à l'usage d'un PSTRING. En effet, par la ligne - Code:
-
SG_line_separator := seplin^; Delphi copie simplement l'adresse et non les données elles-mêmes. Et lorsque les données changent, le pointer copié devient invalide, d'où le crash. Il suffit de faire - Code:
-
SG_line_separator := trim(seplin^); par exemple, pour que les données elles-mêmes sont copiées, et comme par miracle, tout fonctionne. Je te suis très reconnaissant d'avoir étudié mon code. J'étais mentalement totalement bloqué sur ce probème, et tu m'as donné l'indication indispensable pour dépasser cela, en suscitant une réflexion sur le sens de PSTRING. Je produirai dans la journée une version corrigée de KGF.dll qui n'aura plus de problème. Et, progressivement, je vais sécuriser toutes les fonctions de KGF.dll, de cette manière, si elles utilisent PSTRING en paramètre. | |
| | | papydall
Nombre de messages : 7017 Age : 74 Localisation : Moknine (Tunisie) Entre la chaise et le clavier Date d'inscription : 03/03/2012
| Sujet: Re: Aide avec codage de DLL en Delphi Ven 20 Mar 2015 - 12:30 | |
| Quand un Klaus rencontre un Jack, ça donne des KJ (Kilojoules) Comme le J (joule) est une unité qui quantifie l’énergie, le travail, on profite de ces kilos d’énergie et de travail. Merci Klaus. Merci Jack. - Spoiler:
| |
| | | Yannick
Nombre de messages : 8635 Age : 53 Localisation : Bretagne Date d'inscription : 15/02/2010
| Sujet: re Ven 20 Mar 2015 - 21:38 | |
| Génial ! | |
| | | Contenu sponsorisé
| Sujet: Re: Aide avec codage de DLL en Delphi | |
| |
| | | | Aide avec codage de DLL en Delphi | |
|
Sujets similaires | |
|
| Permission de ce forum: | Vous ne pouvez pas répondre aux sujets dans ce forum
| |
| |
| |