Bonjour à tous,
J'explique la chose ;-) Nous avons créés plusieurs applications en Delphi qui se basent toutes sur une DLL (API) écrite en C++ Builder.
Après un petit audit de nos codes sources, nous avons constatés qu'il y avait un léger soucis avec les TList que nous employons et qui transitaient entre les applications et la DLL. Le fait est que nous pensions qu'un TList.Clear libérait la mémoire, mais ce n'est pas le cas.
Donc, dans la DLL C++, j'ai commencé à écrire une classe héritant de TList et surchargeant la méthode Clear de base.
Via ce code, il est bien plus simple de changer toutes nos déclarations de TList dans la DLL par TListDs<TYPE_CLASSE> et ainsi, nous sommes sûr que tout est bien libéré lorsque nous faisons appel au desctructeur de la classe.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11 template <class T> class TListDs : public TList { public: void __fastcall Clear (void) { for (int i = 0; i < Count; ++i) { delete (T*) Items[i]; } TList::Clear (); } };
Le problème est dû à l'héritage qui ne semble pas fonctionnel entre du Delphi et du C++.
Donc, afin de pallier la chose,
J'ai déclaré dans ma DLL différentes fonctions retournant un pointeur de type TListDs<....>, jusque l'à tout va bien :-)
Ce qui donne ceci.
Au niveau du mapping du côté Delphi, voici ce que j'ai fais.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10 TList * EXPORTCALL NewListPerson (void) { return new TListDs <TPerson>; } TList * EXPORTCALL NewListInteger (void) { return new TListDs <int>; } void EXPORTCALL FreeList (TList *pList) { delete pList; }
J'ai essayé et cela fonctionne nickel, les variables créées à l'aide de NewListInteger et NewListPerson sont bien de type TList ce qui permet de garder l'interface d'une TList et lorsque je libère via FreeList, la DLL utilise bien la classe Template que j'ai écris. Ce qui dont est le but de base.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 function NewListInteger: TList; stdcall; function NewListPerson: TList; stdcall; procedure FreeList (vList : TList); stdcall;
Le problème est que cela ne peut pas aller si on doit modifier toutes les applications rien que pour les TList.
Si j'ai bien compris une instance d'une TList est créée à l'aide de TList.Create
Afin de minimiser les changements dans le code Delphi, il n'est pas intéressant de remplacer les TList.Create par des NewListPerson, etc...
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6 var vList : TList = nil; begin vList := TList.Create; vList.Free; end;
Alors je me suis dis, "essayons de créer une TListDsPerson" qui utiliserait une fonction Create ( et non le constructeur ), afin d'initialiser la TList et de lui retourner un pointeur correspond au bon type de TList; en l'occurence une NewListPerson;
Et maintenant voici le code que j'utilise pour essayer de tester mon système.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 type TListDsPerson = class private Ptr : TList; public function Create : TList; procedure Clear; end; implementation function TListDsPerson.Create : TList; begin WriteLn ('TListDsPerson.Create'); self.Ptr := NewListPerson; Result := self.Ptr; end; procedure TListDsPerson.Clear; begin FreeList (self); WriteLn('TListDsPerson.Clear'); end;
Le problème est que j'arrive à une erreur me disant ceci lors de la compilation.
[Erreur] LoadDLL.dpr(45): Forme d'appel de méthode autorisée seulement pour les méthodes de classes
Donc ma grande question, est-il possible de réaliser ce que j'essaie, c'est à dire retourner quelque chose lors du Create, afin de tromper Delphi, ce qui me permettrait de limiter les changements au sein du code existant.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 var vListPerson : TList = nil; vPerson : Pointer; begin try vListPerson := TListDsPerson.Create; GetList(vListPerson); for Cpt := 0 to vListPerson.Count - 1 do begin vPerson := vListPerson.Items[Cpt]; WriteLn ('Id : ' + IntToStr (Cpt)); WriteLn ('FirstName : ' + GetPersonFirstName (vPerson)); WriteLn ('LastName : ' + GetPersonLastName (vPerson)); end; vListPerson.Clear; except WriteLn ('Une erreur est survenue...'); end; end.
Si oui, comment ;-)
Sinon, :'(
Merci,
Stéphane
Partager