Entwickler-Ecke

Delphi Language (Object-Pascal) / CLX - Application.ProcessMessages löscht Variablen?


Seven of Nine - So 19.08.12 06:24
Titel: Application.ProcessMessages löscht Variablen?
Mir ist heute folgendes aufgefallen:

- Um einen internen Handler auf eine Queue von abzuarbeitenden Tasks zu schreiben, habe ich einige Variablen definiert.
Die Variablen werden dann "vorbelegt" und wenn komplettiert einem "Queue Handler" zum Abarbeiten übergeben

blos mal so als Bsp.


Delphi-Quelltext
1:
2:
3:
4:
5:
6:
7:
8:
9:
10:
11:
12:
13:
14:
15:
16:
17:
18:
type
  TADub = record
    trackID: String;
    title: String;
    SongIndex: LongInt;
    Status: Integer;
  end;

var
  ADub : Array of TADub;

//....
  SetLength(ADub, CountSelectedTitles); // set length of dynamic array
//....
  ADub[I].Status     := 0;
  ADub[I].TrackID    := Song[SongIndex].trackID;
  ADub[I].SongIndex  := SongIndex;
  ADub[I].title      := aTitle;



mein Problem: jeder Aufruf von "Application.ProcessMessages" löscht (bzw initilialisert wieder) genau die Inhalte dieser Variablen ?!?
wie ist das möglich? Was kann ich dagegen tun?


lG Martin


bummi - So 19.08.12 06:31

An welcher Stelle im Code hast Du denn die Initialisierung eingebaut?


Seven of Nine - So 19.08.12 06:51

Du meinst die Definition des Records sowie die anschließende Definiton des records als DynArray ?
eigentlich so wie ich das immer mache, unterhalb

Delphi-Quelltext
1:
2:
3:
4:
5:
  private
    { Private-Deklarationen }
  public
    { Public-Deklarationen }
  end;


(das komische ist, andere Variablen werden mir ja auch nicht überschrieben, diese aber schon)
Falsch: auch andere Varaiablen haben das gleiche problem
Es ist echt zum Haare raufen.

lG M


bummi - So 19.08.12 07:56

nein ich meine in welchem Ereignis/Prozedur ... der Code ab Zeile 13 ausgeführt wird.


jaenicke - So 19.08.12 09:23

Falls es in einem Timer sein sollte, wird in Application.ProcessMessages die nächste WM_TIMER Botschaft abgearbeitet, dein Code also erneut ausgeführt.
Das Problem hättest du aber gar nicht, wenn du keine globalen Variablen / Felder verwenden würdest...


Seven of Nine - So 19.08.12 12:17

Der Code (ab Zeile 13) wird innerhalb einer while schleife einer normalen Procedur (procedure TForm1.HandleConversions_Songs;
) ausgeführt, also nicht innerhalb einem Timer.

Mir ist's immer noch rätselhaft was da passiert :(

lG M


bummi - So 19.08.12 12:46

Ein Callback einer asynchronen Komponente ...


jaenicke - So 19.08.12 13:39

Ok, so kommen wir nicht weiter...

Wie du das selbst herausfinden kannst ist ganz einfach:
Setze in der Routine, die einen Song behandelt drei Haltepunkte, einen in das begin, einen in die folgende Zeile, einen auf das end. Den bei begin setzt du in den Haltepunkteigenschaften (rechte Maustaste auf den Haltepunkt) in Gruppe 1. Den direkt nach dem begin setzt du dort auf Aktiviere Gruppe 1, den bei end auf Deaktiviere Gruppe 1, bei beiden nimm das Häkchen bei Anhalten raus. Dann setzt du noch einen Haltepunkt außen in der Funktion, die die while-Schleife beinhaltet, vor die Schleife und setzt dort ebenfalls auf nicht anhalten und deaktiviere Gruppe 1.

Wenn du jetzt das Programm ausführst und am zweiten Haltepunkt angehalten ankommst, bist du an einer Stelle, an der du gerade innerhalb deiner Funktion bist. Aber dennoch wird dort die Behandlung erneut aufgerufen. Nun musst du nur noch im Stacktrace schauen wo du da herkommst. ;-)


Seven of Nine - Mo 20.08.12 05:04

Hi Sebastian

Puuhh, irgendwie glaube ich nicht das ich der Sache damit auf die Spur komme und vor allem nicht das ich sie damit wirklich lösen kann.
Fact ist, das einen Schritt "vor" Application.processMessages noch alles i.O. ist
und "direkt nach" Application.processMessages die Variablen initilisiert wurden

Ich glaube ich verzichte an dieser Stelle besser einfach auf Application.processMessages

lG M


DonManfred - Mo 20.08.12 05:55

Alternativ könntest Du auch am Anfang der Procedur timer1.enabled := false und am Ende der Procedur wieder timer1.Enabled := true setzen um zu verhindern das während der laufzeit der Procedure ein weiteres Timer-Event auftritt.


jaenicke - Mo 20.08.12 06:28

Also wirklich bei Application.ProcessMessages? Bist du dann vielleicht in OnIdle oder so?
Auf jeden Fall musst du aus irgendeiner Botschaftsbehandlung kommen. Woher genau kannst nur du wissen... und dementsprechend auch was man dagegen tun könnte. (Ansonsten: need more source code ;-))

Wenn du alle globalen Variablen eliminierst, wäre das vollkommen egal, ob die Methode erneut aufgerufen wird.

Jedenfalls kannst du dir ansonsten ein Flag setzen, dass du schon in der Methode drin bist, und am Anfang dies prüfen. So verhinderst du den mehrfachen Aufruf auch.


Seven of Nine - Mo 27.08.12 18:17

Nach kompletter Code-Umstellung tritt das Problem nicht mehr auf.
Ich vermute das die Ursache "sich gegenseitig aufrufende Routinen" bzw. "in einem Timer" die Ursache war
wie acuh immer, vielleicht ist es interessant zu wissen das so etwas vorkommt.

lG M