jnmchl
Messages postés63Date d'inscriptiondimanche 16 octobre 2005StatutMembreDernière intervention13 novembre 2009
-
17 févr. 2007 à 12:04
jnmchl
Messages postés63Date d'inscriptiondimanche 16 octobre 2005StatutMembreDernière intervention13 novembre 2009
-
18 févr. 2007 à 13:22
Bonjour,
J'ai lu tous (sauf oubli) les topics sur ce sujet...
Malheureusement, je ne trouve pas la solution à mon problème.
Voilà j'ai donc une appli qui me fait le "RunTime Error 216" à un moment précis :
lorsque je quitte l'application. C'est frustrant car tout fonctionne bien, et dès qu'on quitte :
hop ce message d'erreur, laissant penser que le programmeur a laissé un bug, c'est pas propre !
Mes observations :
- une fois j'ai retiré le fichier d'aide et ça ne le faisait plus
- une fois j'ai rendu visible un Memo caché et ça ne le faisait plus
- il me semble qu'une fois ça marchait puis plus alors que je n'étais pas intervenu sur le code !!!
Maintenant, je n'ai plus ce mémo car inutile et je ai enlevé le fichier d'aide ... et j'ai l'erreur !
Note : mon application use de "tout ce qui est à risque" dans la génération des RunTime Error 216 :
- utilisation d'objets perso crées en dynamique
- utilisation d'un PChar (pour des messageBox) ...
mais bon ... à l'exécution ça marche très bien !
Faut-il libérer des trucs à la fermeture ? Est-ce un pb de mémoire ?
Merci de m'aider. Je commence à tourner en bourrique !
Jean-Michel
f0xi
Messages postés4205Date d'inscriptionsamedi 16 octobre 2004StatutModérateurDernière intervention12 mars 202237 18 févr. 2007 à 03:03
essaye plutot comme ça :
procedure TFPrinc.PnlTblClick(Sender: TObject);
begin
if not BtAjoute.Enabled then
Application.MessageBox(PChar(MessageValid),'Saisie incomplète',0);
end;
jnmchl
Messages postés63Date d'inscriptiondimanche 16 octobre 2005StatutMembreDernière intervention13 novembre 20091 18 févr. 2007 à 13:07
Bonjour,
J'ai découvert d'où venait mon bug ...
Je défini un type :
TGRP = record // caractéristiques des groupements
ID,Lib : string;
Nz : integer;
TbZ : array [0..12] of String;
end;
et puis après ...
var MonGRP : TGRP;
...
MonGRP[i]:=StGRP;
avec i = 20 !!!
Curieusement lors de la compilation j'aurais dû avoir l'erreur "indice hors limite" ?
A ceux qui tiennent une base de données sur le RunTime Error 216 !
J'ai rectifié avec un tableau dynamique, et là impecable !
Je prends en compte toutefois toutes les autres recomandations, MERCI à tous.
WhiteHippo
Messages postés1154Date d'inscriptionsamedi 14 août 2004StatutMembreDernière intervention 5 avril 20123 17 févr. 2007 à 13:28
Bonjour,
Le plus simple pour découvrir d'où vient le problème c'est de créer un fichier log pour avoir un suivi de tout ce que fait ton application. Des logiciels comme Memory Sleuth, MemCheck(http://v.mahon.free.fr/pro/freeware/memcheck/) permmettent également le débuggage des problèmes de mémoire.
Cordialement.
<hr />"L'imagination est plus importante que le savoir." Albert Einstein
jnmchl
Messages postés63Date d'inscriptiondimanche 16 octobre 2005StatutMembreDernière intervention13 novembre 20091 17 févr. 2007 à 14:07
je l'ai fait : tout fonctionne nickel, jusqu'au bout ...
dès que je quitte l'application ... j'ai le message d'erreur : l'application est bien fermée !
J'ai l'impression qu'il fait peut-être appel à quelque chose qui est déjà détruit.
Pour info : je ne libère rien : on m'a dit que de toutes façons le CLOSE libère tout !
... je commence à douter.
Jean-Michel
Vous n’avez pas trouvé la réponse que vous recherchez ?
WhiteHippo
Messages postés1154Date d'inscriptionsamedi 14 août 2004StatutMembreDernière intervention 5 avril 20123 17 févr. 2007 à 15:03
Pour ma part, si je crée un objet, un pointeur, etc... alors je me charge de le détruire... Ainsi je maitrise entièrement ce qui se passe dans l'application, et je n'ai pas de mauvaises surprises. Delphi ne dispose pas d'un véritable ramasse miettes, alors il me semble plus que risqué de lui laisser gérer TOUTES les libérations...
P.S. Je ne parlais pas de la gestion avec des interfaces
Cordialement.
<hr />"L'imagination est plus importante que le savoir." Albert Einstein
jnmchl
Messages postés63Date d'inscriptiondimanche 16 octobre 2005StatutMembreDernière intervention13 novembre 20091 17 févr. 2007 à 16:12
Oui, mais de toutes façons :
1) j'ai besoin des objets créés jusqu'à la fin ... à quel moment les détruire ?
sur un évènement OnForm ? Close, CloseQuery, Destroy, Desactivate ?
2) j'ai fais un test j'ai mis entre {} toutes les parties de code des objets créés, donc avec zéro objet créé : même résultat !
Merci
Jean-Michel
var TSeg:TSegment;
...
// Affichage des segments
for i0:=0 to CompteurSeg-1 do begin
TSeg := TSegment.Create(FPrinc);
TSeg.X1:= ListSeg[i0].x1;
TSeg.Y1:= ListSeg[i0].y1;
TSeg.X2:= ListSeg[i0].x2;
TSeg.Y2:= ListSeg[i0].y2;
end;
Comment détruire ?
TSeg.free;
il y en a une centaine ...
for i := Componentcount-1 downto 0 do
if (Components[i] is TSegment) then Components[i].free;
WhiteHippo
Messages postés1154Date d'inscriptionsamedi 14 août 2004StatutMembreDernière intervention 5 avril 20123 17 févr. 2007 à 17:55
Alors voyons, comment j'envisagerais l'affaire :
1 - Création d'une TList pour maintenir la liste de chacun des segments.
2 - La destruction de ceux ci se résumerait alors à parcourir les éléments de la liste et les détruire 1 à 1, avant de détruire la liste elle-même dans le destroy de la fiche.
3 - Si le problème continue sans les objets crées, il faut vérifier si l'erreur ne vient pas d'un composant perso ou non posé sur la fiche.
N.B. Moi je préfère un bon vieux FreeAndNil à la méthode Free
Cordialement.
<hr />"L'imagination est plus importante que le savoir." Albert Einstein
f0xi
Messages postés4205Date d'inscriptionsamedi 16 octobre 2004StatutModérateurDernière intervention12 mars 202237 17 févr. 2007 à 19:35
Runtime Error 216 : general protection fault
ce qu'en dis microsoft :
erreur qui se produit quand l'ordinateur est infecté par le cheval de troie SubSeven
bon je pense qu'en tant qu'utilisateur avertis, tu as un anti-virus a jours et que tu scan regulierement ton pc avec un anti-malware.
liberer les objets ne suffit pas!
il y a une convention de liberation a respecter
exemple :
objet1 := {classe}.create({parent});
plus tard :
objet2 := {classe}.create({parent});
a la fermeture :
Incorrect :
objet1.Free;
objet2.Free;
Correct :
objet2.Free;
objet1.Free;
ceci :
var TSeg:TSegment;
...
for i0:=0 to CompteurSeg-1 do begin
TSeg := TSegment.Create(FPrinc);
TSeg.X1:= ListSeg[i0].x1;
TSeg.Y1:= ListSeg[i0].y1;
TSeg.X2:= ListSeg[i0].x2;
TSeg.Y2:= ListSeg[i0].y2;
end;
n'est pas bien ! car a chaque Create seul FPrinc garde les references de TSeg et encore ce n'est pas sur.
il faut utiliser soit : un tableau dynamique de TSeg, soit mieux, un TObjectList qu'on derive pour utiliser avec TSeg.
on peu egalement utiliser les TCollectionItem et TCollection qui ont un fonctionnement a peu prés similaire au TObjectList.
constructor TSegmentList.Create(AOwnsObjects: Boolean);
begin
inherited Create;
FOwnsObjects := AOwnsObjects;
end;
function TSegmentList.Add(Segment: TSegment): Integer;
begin
Result := inherited Add(Segment);
end;
function TSegmentList.Extract(Item: TSegment): TSegment;
begin
Result := TSegment(inherited Extract(Item));
end;
function TSegmentList.First: TSegment;
begin
Result := TSegment(inherited First);
end;
function TSegmentList.Last : TSegment;
begin
Result := TSegment(inherited Last);
end;
function TSegmentList.GetItem(Index: Integer): TSegment;
begin
Result := inherited Items[Index];
end;
function TSegmentList.IndexOf(Segment: TSegment): Integer;
begin
Result := inherited IndexOf(Segment);
end;
procedure TSegmentList.Insert(Index: Integer; Segment: TSegment);
begin
inherited Insert(Index, Segment);
end;
function TSegmentList.FindInstanceOf(AClass: TClass; AExact: Boolean;
AStartAt: Integer): Integer;
var
I: Integer;
begin
Result := -1;
for I := AStartAt to Count - 1 do
if (AExact and (Items[I].ClassType = AClass)) or
(not AExact and Items[I].InheritsFrom(AClass)) then
begin
Result := I;
break;
end;
end;
procedure TSegmentList.Notify(Ptr: Pointer; Action: TListNotification);
begin
if OwnsObjects then
if Action = lnDeleted then
TSegment(Ptr).Free;
inherited Notify(Ptr, Action);
end;
function TSegmentList.Remove(Segment: TSegment): Integer;
begin
Result := inherited Remove(Segment);
end;
procedure TForm1.FormCreate(Sender: TObject);
var N : integer;
begin
TSL := TSegmentList.Create(true);
for N := 0 to 9 do
TSL.Add(TSegment.Create(Self));
end;
procedure TForm1.FormDestroy(Sender: TObject);
var N : integer;
begin
for N := TSL.Count-1 to 0 do
TSL.Remove(TSL.Items[N]);
TSL.Free;
end;
jnmchl
Messages postés63Date d'inscriptiondimanche 16 octobre 2005StatutMembreDernière intervention13 novembre 20091 17 févr. 2007 à 22:12
Bonsoir,
Oui, j'ai bien lu l'histoire du cheval de Troie : je ne suis pas infecté.
Je pensais bien que le code suivant n'est pas pur ...
var TSeg:TSegment;
...
for i0:=0 to CompteurSeg-1 do begin
TSeg := TSegment.Create(FPrinc);
TSeg.X1:= ListSeg[i0].x1;
TSeg.Y1:= ListSeg[i0].y1;
TSeg.X2:= ListSeg[i0].x2;
TSeg.Y2:= ListSeg[i0].y2;
end;
pourtant l'erreur a subsisté même après avoir mis la création des objets hors service.
Je vais essayer tes préconisations, merci.
Sinon l'autre partie sensible du code pourrait être
var MessageValid : string;
...
// Aide à la validation
procedure TFPrinc.PnlTblClick(Sender: TObject);
var p:PansiChar;
begin
if not BtAjoute.Enabled then begin
GetMem(P,Length(MessageValid)+1);
StrCopy(P,PChar(MessageValid));
Application.MessageBox(P,'Saisie incomplète',0);
FreeMem(P);
end;
end;
MessageValid étant un string donc le contenu dépend deu traitement.