Entwickler-Ecke
Grafische Benutzeroberflächen (VCL & FireMonkey) - AV unter Windows Vista nach schließen von TOpen/SaveDialog
hui1991 - Mi 25.03.09 23:43
Titel: AV unter Windows Vista nach schließen von TOpen/SaveDialog
Hi,
wenn ich den TOpenDialog oder den TSaveDialog schließe kommt bei mir sofort diese Meldung:
Quelltext
1: 2: 3: 4: 5: 6: 7:
| --------------------------- Benachrichtigung über Debugger-Exception --------------------------- Im Projekt Project1.exe ist eine Exception der Klasse EAccessViolation mit der Meldung 'Access violation at address 769564A1 in module 'comdlg32.dll'. Read of address 6FEC73AC' aufgetreten. --------------------------- Anhalten Fortsetzen Hilfe --------------------------- |
Dieser Fehler kommt, aber nur, wenn ich kein Kompatibilitätsmodus aktiv habe.
Wenn ich Kompatibilitätsmodus auf WinXPSp2 stelle, dann funktioniert Einwandfrei.
Wie kann ich den Fehler beheben?
Muss ich eine andere Komponente nehmen?
Würde gerne die Standard Komponenten verwenden.
Es gibt ein TFileOpenDialog bei D2007, diesen gibt es aber nicht bei D2006 (Turbo Delphi).
Moderiert von
Narses: Topic aus Sonstiges (Delphi) verschoben am Mi 25.03.2009 um 23:28
jaenicke - Mi 25.03.09 23:47
Dann musst du aber noch etwas anderes machen, denn bei mir funktionieren die Dialoge problemlos. :nixweiss:
Xentar - Do 26.03.09 00:00
1. Quellcode?
2. Tritt das auch schon auf, wenn du eine neues Projekt anlegst, und NUR diesen Dialog verwendest?
hui1991 - Do 26.03.09 14:30
So weit ich weiß, kommt der Fehler bei komplett Leeren nicht :(
Nur wenn ich schon Code drin hab.
Hab das Komplett nur auf Vista Rechnern und in allen meinen Projekten die über 400 Zeilen sind.
QuellCode kann ich was zeigen, blos ich denke nicht das dieser weiterhilft.
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| procedure TForm2.Speichernunter1Click(Sender: TObject); begin if SaveDialog1.Execute then begin SaveIniFIle(SaveDialog1.FileName); end; end; |
der fehler kommt vor SaveIniFile
Moderiert von
Narses: Code- durch Delphi-Tags ersetzt
Nersgatt - Do 26.03.09 14:34
Versuch mal alles aus Deinem Projekt rauszulöschen, bis der Fehler nicht mehr kommt. Wenn Du zum Schluss nur noch den Dialog übrig hast, dann poste mal das Projekt.
jaenicke - Do 26.03.09 14:37
Bist du dabei vielleicht in Verzeichnissen, in denen man Adminrechte braucht?
Hast du vielleicht die UAC deaktiviert? Das kann solche Fehler verursachen.
hui1991 - Do 26.03.09 14:55
Ich hab oben geschrieben, dass ich nur das Programm mit Kompatibilitätsmodus auf WinXPSp2 starten muss und dann kommt kein Problem. Denke nicht, dass UAC was auf meinem USB-Stick blocken würde.
Ich kann leider das Projekt nicht soweit löschen bis kein Fehler mehr auftritt, weil ich gerade nicht daheim bin und hier kein Vista Rechner da ist.
jaenicke - Do 26.03.09 14:59
hui1991 hat folgendes geschrieben : |
Denke nicht, dass UAC was auf meinem USB-Stick blocken würde. |
Darum geht es auch nicht, aber leider hat die Deaktivierung der UAC neben dem hohen Sicherheitsrisiko auf einigen Rechnern auch ein paar unangenehme Nebeneffekte wie solche Schutzverletzungen.
hui1991 hat folgendes geschrieben : |
Ich kann leider das Projekt nicht soweit löschen bis kein Fehler mehr auftritt, weil ich gerade nicht daheim bin und hier kein Vista Rechner da ist. |
Dann mach das mal zu Hause, anders wirst du den Fehler kaum finden.
hui1991 - Do 26.03.09 23:15
Ich versteh das nicht.
Ich hab doch keine dynamischen Listen und auch keine Dynamisches Arrays drin.
Warum kommen dann AVs. -.-
Hab gedacht ich nehm ein ähnliches Programm und lade das hoch, blos da kommt das problem nicht.
Laden funktioniert atm, aber bei speichern macht der probleme.
Sogar wenn ich auf Abbrechen klicke in dem Dialog.
jaenicke - Do 26.03.09 23:22
Setz mal ReportMemoryLeaksOnShutdown in der Projektdatei direkt nach dem begin auf True. Wenn dann Speicherlecks erkannt werden, dann sagt Delphi dir das beim Schließen des Projekts. (Das geht erst ab Delphi 2006 / Turbo Delphi.)
Genauer kannst du das mit FastMM z.B. prüfen.
Wie gesagt: Lösch nach und nach in einer kompletten Kopie des Projekts alles raus bis der Fehler nicht mehr auftritt. Wenn allerdings Speicher überschrieben wird, dann nutzt das evtl. nix, weil der Fehler ganz woanders liegen kann.
hui1991 - Fr 27.03.09 15:08
So ich hab etz alle Warnungen weg gemacht, blos da war nur nicht initialisiert und Destroy ausgeblendet.
Und paar sachen das Variablen nicht verwendet wurden.
Ich hab die Warnungen behoben und etz ist 0 Fehler und 0 Warnungen.
Bei ausführen von ReportMemoryLeaksOnShutdown := true; ist TurboDelphi2006 abgestürzt.
Und nach beenden meines Programms kam so eine schöne Fehlermeldung:
Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19:
| --------------------------- Unexpected Memory Leak --------------------------- An unexpected memory leak has occurred. The unexpected small block leaks are:
37 - 44 bytes: TDiagramm x 1
53 - 60 bytes: TBitmap x 1, TStringList x 6
109 - 116 bytes: TBitmapImage x 1
253 - 268 bytes: Unknown x 53
--------------------------- OK --------------------------- |
Hm.. so ganz genau finde ich die Stelle nicht wo der Fehler ist.
jaenicke - Fr 27.03.09 15:27
Unknown ist sehr schlecht, das ist ein fast eindeutiges Zeichen, dass da Speicher überschrieben wird, so dass es nicht mehr möglich ist, die entsprechenden Klassen zu identifizieren.
Allgemein kann ich da aber nichts zu sagen. Zumindest die TStringList-Objekte usw. solltest du doch finden wo du sie erzeugst und nicht wieder freigibst.
Aber für das Überschreiben von Speicher gibt es so viele Möglichkeiten... Pointer, usw.
Du kannst die Bereichsüberprüfung in den Compileroptionen aktivieren, aber da du wie du sagtest keine dynamischen Arrays verwendest, wird das wohl nichts ergeben.
Sonst kannst du nur genau den Quelltext anschauen, der beim Start ausgeführt wird, und schauen, ob da wirklich nichts verdächtiges steht.
Problematisch wird es, wenn du eine Zusatzkomponente verwendest, die einen Fehler hat...
Du solltest einmal FastMM ausprobieren. Vielleicht ist das Log aufschlussreicher. In der Konfigurationsdatei kannst du auch auf ausführlich und aktiv auch außerhalb der Delphi-IDE schalten.
hui1991 - Fr 27.03.09 15:48
So ich hab jetzt alles mögliche was in der Liste war gesucht paar Sachen gefunden, die mit free nicht freigeben wurde.
Und die Unknown sind jetzt auch weg.
Okay anscheinend hat das nicht freigeben die Probleme gemacht.
Ob es das wirklich war, kann ich erst heut Abend sagen, wenn ich wieder am Vista-Rechner bin.
Komisch das ich aber paar Frees vergesehen hab, obwohl ich Member-Variablen im OnCreate erstelle und im OnDestroy wieder freigebe. Und locale Variablen das selbe.
Der Fehler war wahrscheinlich das Image1.Picture.Bitmap := TBitmap.Create;
StringListen benutze ich schon, für die Darstellung des Diagramms.
Die war aber im TDiagramm drin.
Da das Programm erst Abends alle Funktionen durchläuft werde ich noch sehen wie viele Fehler noch kommen werden.
JayEff - Fr 27.03.09 16:25
hui1991 hat folgendes geschrieben : |
Der Fehler war wahrscheinlich das Image1.Picture.Bitmap := TBitmap.Create;
|
:gruebel: Ich dachte, das Parent ist für das Freigeben von Komponentenspeicher verantwortlich, und im TImage code steht auch
Delphi-Quelltext
1: 2: 3: 4: 5:
| destructor TImage.Destroy; begin FPicture.Free; inherited Destroy; end; |
:nixweiss:
Daher denke ich, eigentlich sollte es das nicht gewesen sein.
jaenicke - Fr 27.03.09 17:19
Doch, denn der Setter gibt an der Stelle das alte Bild frei und packt den Inhalt der zugewiesenen Bitmap in eine neue Bitmap (in diesem Fall eben nix). Mehr nicht, das übergebene neu Objekt hängt danach im Speicher herum und wird nie mehr freigegeben.
JayEff - Fr 27.03.09 17:32
jaenicke hat folgendes geschrieben : |
Doch, denn der Setter gibt an der Stelle das alte Bild frei und packt den Inhalt der zugewiesenen Bitmap in eine neue Bitmap (in diesem Fall eben nix). Mehr nicht, das übergebene neu Objekt hängt danach im Speicher herum und wird nie mehr freigegeben. |
:autsch: Dabei hatte ich mir den Setter sogar angeguckt
Delphi-Quelltext
1: 2: 3: 4:
| procedure TImage.SetPicture(Value: TPicture); begin FPicture.Assign(Value); end; |
... Dann macht die Erstellung der Bitmap überhaupt keinen Sinn, schließlich steht im Create des Images schon
FPicture := TPicture.Create; und im Setter von TPicture.Bitmap steht
NewGraphic := TGraphicClass(Value.ClassType).Create; damit wird der Speicher automatisch reserviert, wenn eine Zuweisung auf Picture.Bitmap stattfindet und es wird nur ein Assign durchgeführt; Wär ja auch blöd, da sonst bei
Delphi-Quelltext
1: 2: 3: 4:
| var b: Bitmap; begin
Image1.Picture.Bitmap := b; |
am Ende der Gültigkeit von b auch das Image leer wäre bzw AVs würden geworfen werden.
Wenn ich das richtig verstehe, nutze ich
Delphi-Quelltext
1: 2: 3: 4: 5:
| var b : Bitmap; begin b := TBitmap.Create; Image...Bitmap := b; b.Free; |
nur, wenn ich eine weiße Fläche brauche. Auf die Art müsste auch das Speicherleck weg sein, seh ich das richtig?
jaenicke - Fr 27.03.09 17:39
JayEff hat folgendes geschrieben : |
:autsch: Dabei hatte ich mir den Setter sogar angeguckt Delphi-Quelltext 1: 2: 3: 4:
| procedure TImage.SetPicture(Value: TPicture); begin FPicture.Assign(Value); end; | |
Das ist beim vorliegenden Quelltext der falsche Setter. ;-)
Du musst in den der Eigenschaft Bitmap von TPicture schauen. Da wird genau genommen eine temporäre neue Instanz der übergebenen Klasse erzeugt, der Inhalt hineinkopiert und diese neue Instanz dann in die private Eigenschaft gelegt, wobei ein vorhandenes Objekt vorher freigegeben wird. Wenn nil übergeben wird, dann wird nur das alte Bild freigegeben.
JayEff hat folgendes geschrieben : |
Wenn ich das richtig verstehe, nutze ich
Delphi-Quelltext 1: 2: 3: 4: 5:
| var b : Bitmap; begin b := TBitmap.Create; Image...Bitmap := b; b.Free; | nur, wenn ich eine weiße Fläche brauche. Auf die Art müsste auch das Speicherleck weg sein, seh ich das richtig? |
Das Speicherleck ist so weg, aber was bringt das für einen Vorteil gegenüber der Manipulation der vorhandenen Bitmap? Ich sehe keinen, nur Nachteile, mal abgesehen davon, dass es unübersichtlicher ist.
hui1991 - Fr 27.03.09 18:15
Also ich hab die EXE die ich in der Arbeit erstellt hab compiliert und die hier daheim gestartet.
Kam kein Fehler.
Jetzt hab ich zum test das hier nochmal compiliert und die AV kommt wieder.
Ist jetzt wohl ein Fehler in meiner Delphi Version?
Kann doch nicht sein das in Turbo Delphi alles glatt läuft und in Delphi 2007 die Fehler kommen.
JayEff - Fr 27.03.09 18:21
SetBitmap ruft SetPicture auf
Delphi-Quelltext
1: 2: 3: 4:
| procedure TPicture.SetBitmap(Value: TBitmap); begin SetGraphic(Value); end; |
:nixweiss:
jaenicke hat folgendes geschrieben : |
Da wird genau genommen eine temporäre neue Instanz der übergebenen Klasse erzeugt[...] |
Yup:
JayEff hat folgendes geschrieben : |
[...]im Setter von TPicture.Bitmap steht NewGraphic := TGraphicClass(Value.ClassType).Create; damit wird der Speicher automatisch reserviert, wenn eine Zuweisung auf Picture.Bitmap stattfindet und es wird nur ein Assign durchgeführt; |
;)
Mein Post hatte eine etwas wilde Reihenfolge, aber ich hab schon verstanden was du meinst :)
Meine letzte Frage bezog sich vielmehr darauf: Muss ich in irgendeiner Situation dafür sorgen, dass Picture.Bitmap existiert, oder sind
alle Fälle abgedeckt? Ich tippe ja auf letzteres, von daher ist der Code den ich geschrieben hab im Prinzip nur unübersichtlich-isch für
Brush.Color := clWhite; Fillrect(...) :mrgreen:
Aber das war jetzt Off Topic :(
jaenicke kennt sich doch mit TD bestens aus, wenn ich mich nicht irre, der weiß das sicher besser als ich :oops:
jaenicke - Fr 27.03.09 18:41
:oops: Stimmt, das hab ich überlesen.
Ja, du kannst im Grunde fast alles machen, du kannst auch nil zuweisen. Wenn danach auf das Object zugegriffen wird (z.B. Grpahic oder Bitmap), dann wird es automatisch vorher erstellt, wenn nil drin ist. Es wird also nie nil zurückgegeben, und deshalb muss man sich da nicht weiter drum kümmern.
Genau genommen wird vorher das folgende ForceType aufgerufen um dafür zu sorgen, dass in Graphic nicht nur ein Objekt sondern auch der gewünschte Typ drin ist. Will man auf Bitmap zugreifen und in Graphic ist was anderes, dann wird vorher eine neue Bitmap erzeugt.
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12:
| procedure TPicture.ForceType(GraphicType: TGraphicClass); begin if not (Graphic is GraphicType) then begin FGraphic.Free; FGraphic := nil; FGraphic := GraphicType.Create; FGraphic.OnChange := Changed; FGraphic.OnProgress := Progress; Changed(Self); end; end; |
Der Zugriff auf Bitmap wird ja auch nur auf Graphic gemappt.
Entwickler-Ecke.de based on phpBB
Copyright 2002 - 2011 by Tino Teuber, Copyright 2011 - 2025 by Christian Stelzmann Alle Rechte vorbehalten.
Alle Beiträge stammen von dritten Personen und dürfen geltendes Recht nicht verletzen.
Entwickler-Ecke und die zugehörigen Webseiten distanzieren sich ausdrücklich von Fremdinhalten jeglicher Art!