GTA-Place - Fr 15.08.08 16:16
Titel: ShellExecute beeinflusst Prozeduren / Timer?
Hallo,
mir ist was merkwürdiges aufgefallen. Hat man einen Timer, beispielsweise auf 50ms, prüft darin mittels
GetKeyState ob die linke Maustaste gedrückt ist und ruft dann mit
ShellExecute eine URL auf, dann geht die nicht nur einmal, sondern 20x auf. Das folgende
Sleep oder ähnliche Delays werden vollkommen ignoriert. Ich halte bewusst die Maustaste eine kurze Zeit lang gedrückt. Beispiel:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7:
| if GetKeyState(VK_LBUTTON) AND 128 = 128 then begin MainForm.Memo1.Lines.Add('Test 1'); ShellExecute(MainForm.Handle, 'open', 'http://www.heiliger-damm.de', nil, nil, SW_SHOW); Sleep(1000); MainForm.Memo1.Lines.Add('Test 2'); end; |
Logischerweiße müsste er
ShellExecute ausführen, dann
Sleep(1000); und erst danach die Prozedur erneut aufrufen. Das würde ja im Memo wie folgt aussehen (und das tut es auch, wenn ich
ShellExecute weglasse (
!)):
Zitat: |
Test 1
Test 2
Test 1
Test 2
Test 1
Test 2 |
Was passiert aber in Wirklichkeit?
Zitat: |
Test 1
Test 1
Test 1
Test 2
Test 2
Test 2 |
Die Prozedur wird drei Mal aufgerufen ohne den Rest zu beachten.
Sleep zieht erst danach. Wie oben erwähnt, habe ich dieses Verhalten nicht, wenn
ShellExecute weggelassen wird.
Kann sich einer erklären, in wie fern
ShellExecute den Programmablauf beeinflusst? Wieso wird es plötzlich möglich, dass die Prozedur mehrmals gleichzeitig aufgerufen wird? Eine Notlösung ist die, dass ich am Anfang eine Boolean-Variable auf False setze und die Prozedur sofort verlasse, falls diese False ist. Dann wird das ganze auch nur einmal aufgerufen.
Bei Bedarf kann ich auch mal ein Testprojekt anhängen.
Grüße
GTA-Place
Xentar - Fr 15.08.08 17:29
Vermutung:
ShellExecute kehrt erst zurück, wenn das Programm vollständig geöffnet / geladen wurde. In der Zwischenzeit werden aber bereits weitere Messages des Programms abgearbeitet, und somit auch neue Timer Ereignisse.
Deswegen verwend ich in solchen Situationen:
Delphi-Quelltext
1: 2: 3: 4: 5: 6:
| TTimer(Sender).Enabled := false; try ... finally TTimer(Sender).Enabled := true; end; |
Tilman - Fr 15.08.08 17:45
Es scheint zu funktionieren wenn man den Timer abstellt:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9:
| timer1.Enabled := false; if GetKeyState(VK_LBUTTON) AND 128 = 128 then begin Memo1.Lines.Add('Test 1'); ShellExecute(Handle, 'open', 'http://www.heiliger-damm.de', nil, nil, SW_SHOW); Sleep(3000); Memo1.Lines.Add('Test 2'); end; timer1.Enabled := true; |
Es bleibt aber das Problem, dass wenn der Browser aufgeht der Timer immer weiterläuft (das Programm weiß ja nicht ob die Seite schon geöffnet ist. Wenn man im Browser linksklickt, dann geht ein weiterer Tab auf usw.). Es wäre daher vermutlich einfacher mit einer Komponente (z.B. einer leeren tPaintBox) und deren OnClick-Event zu realisieren.
// edit: irgendwie bin ich heute immer zu langsam ^^
GTA-Place - Sa 16.08.08 20:34
Das hier hat den selben Effekt:
Delphi-Quelltext
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15:
| procedure TForm1.Timer1Timer(Sender: TObject); var X: Integer; begin if not (CheckBox1.Checked) then Exit;
X := 10; Memo1.Lines.Add('ABC');
while X = 10 do Application.ProcessMessages;
Memo1.Lines.Add('DEF'); end; |
Das
Application.ProcessMessages; führt dazu, dass der Timer auch ausgeführt wird, obwohl die Prozedur noch gar nicht zu Ende ist. Da könnte man jetzt Spielereien aller Art durchführen ^_^