Avis aux experts Delphi, Mapping DLL C++ et surcharge TList.
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.
Code:
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 ();
}
}; |
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.
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.
Code:
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;
} |
Au niveau du mapping du côté Delphi, voici ce que j'ai fais.
Code:
1 2 3 4 5
|
function NewListInteger: TList; stdcall;
function NewListPerson: TList; stdcall;
procedure FreeList (vList : TList); stdcall; |
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.
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
Code:
1 2 3 4 5 6
|
var vList : TList = nil;
begin
vList := TList.Create;
vList.Free;
end; |
Afin de minimiser les changements dans le code Delphi, il n'est pas intéressant de remplacer les TList.Create par des NewListPerson, etc...
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;
Code:
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; |
Et maintenant voici le code que j'utilise pour essayer de tester mon système.
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
Code:
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. |
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.
Si oui, comment ;-)
Sinon, :'(
Merci,
Stéphane