![]() |
Too stupid to execute and wait
Hallo,
ich bin zu doof einen Prozess zu aus der Anwendung zu startetn und zu warten bis er beendet ist. Ich nutze eine modifizierte Version aus der Code lib von EexecAndWait um den Prozess auf zu rufen...aber es ging auch vor den Modifizierungen nicht habe die eingebaut um herauszufinden was da passiert...bzw. um das Ergebniss zu verbessern...erfolglos! Das verhalten ist wie folgt... der Prozessstartet und hängt dann! Er wird von WaitforSingleObject scheinbar blockiert. Weiter als bis zum Splahscreen kommt er nicht. Erst wenn ich den startenden prozess beende läuft der gestartetet Prozess durch. Das ist nicht das Verhalten was ich mir wünsche. Hier der Code zum starten und warten. Das Programm heißt SFX.exe
Delphi-Quellcode:
Der Funktionsaufruf
function ExecAndWait(Filename, Params: string; WindowState: word = SW_SHOWNORMAL): boolean;
var ShExecInfo: SHELLEXECUTEINFO; r : Cardinal; const SEE_MASK_NOASYNC= $100; begin Result := false; if Filename = '' then exit; if not FileExists(FileName) then Begin ShowMessage('Datei nicht existent!'); Exit; End; ZeroMemory(@ShExecInfo, SizeOf(ShExecInfo)); ShExecInfo.Wnd := application.MainFormHandle; //GetForegroundWindow; ShExecInfo.cbSize := sizeof(SHELLEXECUTEINFOA); ShExecInfo.fMask := SEE_MASK_NOCLOSEPROCESS or SEE_MASK_NOASYNC; ShExecInfo.lpVerb := 'open'; ShExecInfo.lpFile := PChar(Filename); ShExecInfo.lpParameters := PChar(Params); ShExecInfo.lpDirectory := PChar(ExtractFileDir(Filename)); ShExecInfo.nShow := WindowState; Result := ShellExecuteEx(@ShExecInfo); try if Result then r := WaitForSingleObject(ShExecInfo.hProcess, INFINITE) else Showmessage('Fehler beim Starten der Anwendung:' + Filename + #13#10'System Fehler: ' + SysErrorMessage(GetLastError)); finally CloseHandle(ShExecInfo.hProcess); end; end;
Delphi-Quellcode:
ExecAndWait(inspath+'\SETUP.EXE','');
Das aufgerufene Programm ist ein Setup.exe ^^ sieht so aus.
Delphi-Quellcode:
program Setup;
uses dialogs, SysUtils, Forms, fmainf; {$R *.RES} begin SplashForm := TSplashForm.Create(Application); SplashForm.Show; SplashForm.Update; Application.ProcessMessages; Application.Title := 'Setup'; Application.HelpFile := 'SETUP.chm';//A.R.DB //Hier würde ein Showmessage noch angezeigt Application.CreateForm(TFmainf, Fmainf); // Er kommt nur bis hierhin....dann wartet er auf das ende der sfx.exe....total dämlich //Hier würde ein Showmessage nicht mehr angezeigt SplashForm.Hide; SplashForm.Free; Application.Run; end. |
AW: Too stupid to execute and wait
Der Code ist ja grausam. Willst du uns irgendwie quälen? Der Ressourcenschutzblock sitzt an der falschen Stelle, bei der Fehlerbehandlung hast du mehrfach doppelten Code und mit einem case wäre das ganze wesentlich übersichtlicher.
|
AW: Too stupid to execute and wait
Ich habe die ExecuteAndWait einfach übernommen und dann so lange vergewaltigt bis sie mir sagt warums sie nicht funktioniert....das ist nicht als bleibender Code gedacht....
try finaly kann nicht wo anders hin so weit ich das sehe. könntest du dennoch was zum thema sagen? |
AW: Too stupid to execute and wait
Hallo QAD,
ich denke mal du nutzt Delphi > 2007. Wenn das der Fall ist dann solltest du darauf achten, dass du WideString und AnsiString nicht vermischst :-) Gruß, Chris [Edit]siehe
Delphi-Quellcode:
[/Edit]
ShExecInfoA.lpVerb := 'open';
[Edit2] und das ist auch komisch:
Delphi-Quellcode:
Ein WideString z.b FileName wird zu nem AnsiString gecastet und dann wird doch wieder nen PChar draus gemacht und einer Struktur übergeben die Ansi als Index trägt :gruebel:
ShExecInfoA.lpFile := PChar(AnsiString(Filename));
ShExecInfoA.lpParameters := PChar(AnsiString(Params)); ShExecInfoA.lpDirectory := PChar(AnsiString(ExtractFileDir(Filename))); [/Edit2] |
AW: Too stupid to execute and wait
Zitat:
Zitat:
Also, es sieht so aus, als ob alles so geschieht, wie es vom Autor gedacht war. Nur die Frage ist jetzt: Was willst du? |
AW: Too stupid to execute and wait
Zitat:
![]() ![]() PS: Bei einem dir unbekannten Fehler oder bei neuen Fehler in neueren Windowsen, wird bei dir niemals ein Fehler angezeigt. :shock: Abgesehn davon ist es bei solchen "Funktionen" nicht schöön, wenn Fehler mit ShowMessage und Co. angezeigt werden, denn was wäre, wenn ich in meinem Programm solche Fehler über abfangen möchte, ohne daß etwas angezeigt wird? (z.B. ein externes Try-Except, was bei ShowMessage aber nicht geht) Zitat:
Oder man lagert das aktuelle ExecAndWait in einen Thread aus, da bleibt dann nur der Thread "hängen" und der GUI-Thread kann problemlos weiterarbeiten. |
AW: Too stupid to execute and wait
@Luckie:
Als Goody extra für dich Case of reingebaut... Ist tatsächlich augenfreundlicher...funktioniert aber auch nicht besser. :( |
AW: Too stupid to execute and wait
Zitat:
du hast also auch keine Idee warum es nicht geht ja? |
AW: Too stupid to execute and wait
Auch mit SysErrorMessage und Co. kann man debuggen. :roll:
Und siehe mein Edit im letzen Post. wie schon jemand sagte: - bei ShExecInfoA, SHELLEXECUTEINFOA und ShellExecuteExA das A weg - WideString zu String - die AnsiString-Casts raus Wer sagt, daß das ForegroundWindow zu deinem Prozess gehört? ... Keiner, also kannst du da doch nicht einfach was dranhängen. |
AW: Too stupid to execute and wait
Zitat:
Zitat:
Scheint das problem aber nicht zu beheben kann das sein? Zitat:
|
AW: Too stupid to execute and wait
Zitat:
Ich bin in sachen Windows API relativ unbeleckt! Und hoffte eigentlich was fertiges zu finden was einfach einen Prozess startet und wartet bis er fertig ist! Der code hat mit Kommandlinetools auch super hingehauen. (gsecexe, Isql.exe) |
AW: Too stupid to execute and wait
Zitat:
Zitat:
Ich will das NUR sfx.exe im Waitforsingleobject hängt aber nicht setup.exe im splashscreen. |
AW: Too stupid to execute and wait
Änderungen eingebaut...wie zu erwarten selbes problem...
änderungen im startpost veröffentlicht. WaitForSingleObject wartet bis das Prozesshandle ungültig wird oder? Wieso hängt der überwachte Prozess wenn er überwacht wird? |
AW: Too stupid to execute and wait
Funktioniert wunderbar:
Delphi-Quellcode:
uses
ShellAPI; procedure ExecAndWait(Filename, Params: Widestring; WindowState: word = SW_SHOWNORMAL); var ShExecInfo: SHELLEXECUTEINFOW; const SEE_MASK_NOASYNC= $100; begin ZeroMemory(@ShExecInfo, SizeOf(ShExecInfo)); ShExecInfo.Wnd := GetForegroundWindow; ShExecInfo.cbSize := sizeof(SHELLEXECUTEINFOW); ShExecInfo.fMask := SEE_MASK_NOCLOSEPROCESS or SEE_MASK_NOASYNC; ShExecInfo.lpVerb := 'open'; ShExecInfo.lpFile := PWideChar(Filename); ShExecInfo.lpParameters := PWideChar(Params); ShExecInfo.lpDirectory := PWideChar(WideString(ExtractFileDir(Filename))); ShExecInfo.nShow := WindowState; if ShellExecuteExW(@ShExecInfo) then begin WaitForSingleObject(ShExecInfo.hProcess, INFINITE); CloseHandle(ShExecInfo.hProcess); end else RaiseLastOSError; end; procedure TForm1.Button1Click(Sender: TObject); begin try ExecAndWait('C:\Windows\Notepad.exe', ''); except on E: Exception do ShowMessage(E.Message); end; ShowMessage('Fertig'); end; |
AW: Too stupid to execute and wait
Zitat:
Zitat:
Zitat:
Delphi-Quellcode:
. Diesen WideString würdest du an eine Struktur übergeben die für AnsiString gedacht ist. Das wäre ein potenzieller Fehler.
'open'
Warum dein aufgerufenes Programm trotzdem hängt weiß ich nicht. Das ist komisch. Funktioniert der Code mit notepad - bzw. einem Programm dass du nicht selber geschrieben hast? (siehe Luckie) Gruß, Chris |
AW: Too stupid to execute and wait
Zitat:
mit isql.exe geht es und mit gsec.exe geht es auch Aber mit meiner setup.exe ist nach dem Splashscreen Schluss. Warum? |
AW: Too stupid to execute and wait
Zitat:
Zitat:
hat jemand ne idee warum er bei setup.exe nur bis zum splashscreen kommt?? |
AW: Too stupid to execute and wait
Zitat:
Delphi-Quellcode:
Ich würde es so versuchen (Deine Sourcen angepasst):
ShExecInfo.lpVerb := 'open';
Delphi-Quellcode:
uses
ShellAPI; procedure ExecAndWait(Filename, Params: string; AHWnd: HWND; WindowState: word = SW_SHOWNORMAL); var ShExecInfo: SHELLEXECUTEINFO; const SEE_MASK_NOASYNC= $100; begin ZeroMemory(@ShExecInfo, SizeOf(ShExecInfo)); ShExecInfo.Wnd := AHWnd; ShExecInfo.cbSize := sizeof(SHELLEXECUTEINFO); ShExecInfo.fMask := SEE_MASK_NOCLOSEPROCESS or SEE_MASK_NOASYNC; ShExecInfo.lpVerb := 'open'; ShExecInfo.lpFile := PChar(Filename); ShExecInfo.lpParameters := PChar(Params); ShExecInfo.lpDirectory := PChar(ExtractFileDir(Filename)); ShExecInfo.nShow := WindowState; if ShellExecuteExW(@ShExecInfo) then begin WaitForSingleObject(ShExecInfo.hProcess, INFINITE); CloseHandle(ShExecInfo.hProcess); end else RaiseLastOSError; end; procedure TForm1.Button1Click(Sender: TObject); begin try ExecAndWait('C:\Windows\Notepad.exe', '', Self.Handle); except on E: Exception do ShowMessage(E.Message); end; ShowMessage('Fertig'); end; Zitat:
Gruß, Chris |
AW: Too stupid to execute and wait
Wo mische ich? Ich habe nur Delphi 7 hier, deshalb habe ich ausdrücklich WideStrings benutzt.
|
AW: Too stupid to execute and wait
Zitat:
über all das selbe Verhalten nur das es bei Windows 7 erst mit Adminrechten überhaupt in den Splashscreen kommt. Ich testete dioe letzen paar minuten hier auf einer Windows 2000 virtuellen maschiene... |
AW: Too stupid to execute and wait
Zitat:
also mit delphi 2007 wäre es ok nur String zu benutzen? weil das schon Widechar ist? mir wird ungut... |
AW: Too stupid to execute and wait
Zitat:
Nicht ganz. Stringkonstanten haben erstmal keinen Typ. Übergibt man sie nun an einen AnsiString- oder PAnsiChar-Parameter, wird dafür eine AnsiString-Konstante eingebunden. Würde man diesen an WideString-, UnicodeString- oder PWideChar-Parameter oder eben eine Variable übergeben, dann wird dafür eine Unicode-Konstante eingebunden. Werden beide Parameter/Variablen verwendet, werden zwei Konstanten eingebunden (Ansi und Unicode). Zitat:
Bis D2007 waren String, Char und PChar auf AnsiString, AnsiChar und PAnsiChar gemapt wurden, wärend dieses seit D2009 auf UnicodeString (nicht WideString), WideChar und PWideChar zeigt. |
AW: Too stupid to execute and wait
kann es ein problem sein das GDI+ in der Setup.exe genutzt wird?
msdn sagt: ![]() A thread that uses a wait function with no time-out interval may cause the system to become deadlocked. For example, the Dynamic Data Exchange (DDE) protocol and the COM function CoInitialize both indirectly create windows that can cause a deadlock. Therefore, if you have a thread that creates windows, use MsgWaitForMultipleObjects or MsgWaitForMultipleObjectsEx, rather than WaitForSingleObject. [/QUOTE] ist das nicht ein bisschen...extrem krass... |
AW: Too stupid to execute and wait
Zitat:
Zitat:
Aber meine Codeanpassung hatte auch nicht eine Fehler :-) Ich habe ShellExecuteExW aufgerufen anstatt ShellExecuteEx. Ich denke nur, dass man auf explizite WideString bzw. AnsiString-Verwendung verzichten sollte wo es geht. Dann funktioniert der Quelltext unter 2007 und >=2009 :-) Gruß, Chris |
AW: Too stupid to execute and wait
ja...schön...
der code funktionierte ja .... in jedem der bisherigen zustände... nur produziert er eben nen deadlock in einem fall |
AW: Too stupid to execute and wait
Zitat:
Zitat:
|
AW: Too stupid to execute and wait
PROBLEM GELÖST
Delphi-Quellcode:
WaitForSingleObject produziert scheinbar wie vorgesehen einen deadlock wenn der aufgerufen prozess ein neues Fenster erzeugt.
function ExecAndWait(Filename, Params: string; WindowState: word = SW_SHOWNORMAL): boolean;
var ShExecInfo: SHELLEXECUTEINFO; r : Cardinal; const SEE_MASK_NOASYNC= $100; begin Result := false; if Filename = '' then exit; if not FileExists(FileName) then Begin ShowMessage('Datei nicht existent!'); Exit; End; ZeroMemory(@ShExecInfo, SizeOf(ShExecInfo)); ShExecInfo.Wnd := application.MainFormHandle; //GetForegroundWindow; ShExecInfo.cbSize := sizeof(SHELLEXECUTEINFOA); ShExecInfo.fMask := SEE_MASK_NOCLOSEPROCESS or SEE_MASK_NOASYNC; ShExecInfo.lpVerb := 'open'; ShExecInfo.lpFile := PChar(Filename); ShExecInfo.lpParameters := PChar(Params); ShExecInfo.lpDirectory := PChar(ExtractFileDir(Filename)); ShExecInfo.nShow := WindowState; Result := ShellExecuteEx(@ShExecInfo); try if Result then begin repeat R := MsgWaitForMultipleObjects(1, ShExecInfo.hProcess, False, INFINITE,QS_ALLINPUT); if r <> WAIT_OBJECT_0 then Application.ProcessMessages; until r = WAIT_OBJECT_0; end else Showmessage('Fehler beim Starten der Anwendung:' + Filename + #13#10'System Fehler: ' + SysErrorMessage(GetLastError)); finally CloseHandle(ShExecInfo.hProcess); end; end; Und die msdn hatte recht...(seltsam) mit MsgWaitForMultipleObjects geht es dann trotzdem.
Delphi-Quellcode:
repeat
R := MsgWaitForMultipleObjects(1, ShExecInfo.hProcess, False, INFINITE,QS_ALLINPUT); if r <> WAIT_OBJECT_0 then Application.ProcessMessages; until r = WAIT_OBJECT_0; Und danke für die Code Verschönerungstips, sieht jetzt auch viel übersichtlicher aus! |
AW: Too stupid to execute and wait
Zitat:
|
AW: Too stupid to execute and wait
Zitat:
die von dir empfohlene SysErrorMessage funktion benutzt. sehr praktisch, danke. Ich packe Handle Freigaben usw. immer in ein Finally. warum magst du das nicht? wie würdest du es denn machen? |
AW: Too stupid to execute and wait
Delphi-Quellcode:
uses
ShellAPI; procedure ExecAndWait(Filename, Params: string; WindowState: word = SW_SHOWNORMAL); var ShExecInfo: SHELLEXECUTEINFO; RetValue: DWORD; const SEE_MASK_NOASYNC= $100; begin ZeroMemory(@ShExecInfo, SizeOf(ShExecInfo)); ShExecInfo.Wnd := Application.Handle ; //GetForegroundWindow; ShExecInfo.cbSize := sizeof(SHELLEXECUTEINFO); ShExecInfo.fMask := SEE_MASK_NOCLOSEPROCESS or SEE_MASK_NOASYNC; ShExecInfo.lpVerb := 'open'; ShExecInfo.lpFile := PChar(Filename); ShExecInfo.lpParameters := PChar(Params); ShExecInfo.lpDirectory := PChar(ExtractFileDir(Filename)); ShExecInfo.nShow := WindowState; if ShellExecuteEx(@ShExecInfo) then begin repeat RetValue := MsgWaitForMultipleObjects(1, ShExecInfo.hProcess, False, INFINITE, QS_ALLINPUT); if RetValue <> WAIT_OBJECT_0 then Application.ProcessMessages; until RetValue = WAIT_OBJECT_0; CloseHandle(ShExecInfo.hProcess); end else RaiseLastOSError; end; procedure TForm1.Button1Click(Sender: TObject); begin try ExecAndWait('C:\Windows\Notepad.exe', ''); ShowMessage('Fertig'); except on E: Exception do ShowMessage(E.Message); end; end; |
AW: Too stupid to execute and wait
Für INFINITE könnte man noch einen ausreichend langen Timeout setzen, damit eventuelle Deadlocks gleich mit abgefangen werden.
|
AW: Too stupid to execute and wait
Ich würde vielleicht noch einmal überdenken, ob die verwendeten Flags wirklich zielführend sind. Vielleicht sollte man ja die folgende Kombination verwenden:
SEE_MASK_NOCLOSEPROCESS or SEE_MASK_WAITFORINPUTIDLE or SEE_MASK_NOZONECHECKS Dann kann man sich vermutlich auch all dieses Application.ProcessMessages-gefrickel sparen. |
AW: Too stupid to execute and wait
Hallo,
da seh ich gerade noch:
Delphi-Quellcode:
Hier sollte das A hinten noch weg.
ShExecInfo.cbSize := sizeof(SHELLEXECUTEINFOA);
Und dann noch eine Frage zu dem WaitFor: Sollte man hier nicht auch auf Application.Terminated prüfen? Ist vielleicht eine Glaubensfrage für den Anwendungsfall aber ich würde es machen. Also etwa so:
Delphi-Quellcode:
Gruß, Chris
repeat
RetValue := MsgWaitForMultipleObjects(1, ShExecInfo.hProcess, False, INFINITE, QS_ALLINPUT); if RetValue <> WAIT_OBJECT_0 then Application.ProcessMessages; until (RetValue = WAIT_OBJECT_0) or Application.Terminated; |
AW: Too stupid to execute and wait
Das ProcessMessages sorgt dafür, das der Thread (Hauptthread) nicht "einschläft"
WAITFORINPUTIDLE wartet "nur" bis das gestartete programm "aufnahmebereit" ist, wärend das MsgWaitFor (ohne MsgWaitFor) auf die komplette Beendigung des Programms wartet. |
AW: Too stupid to execute and wait
Zitat:
oder hat das damit nichts zu tun? |
AW: Too stupid to execute and wait
Zitat:
Aber wieso erspart mir diese flag kombination das ProcessMessages? |
AW: Too stupid to execute and wait
Zitat:
|
AW: Too stupid to execute and wait
Noch ne frage
wo wir gerade am tunen sind...
Delphi-Quellcode:
Oder
ShExecInfo.Wnd := application.MainFormHandle;
Delphi-Quellcode:
Oder
ShExecInfo.Wnd := application.Handle;
Delphi-Quellcode:
ShExecInfo.Wnd := GetForegroundWindow;
|
AW: Too stupid to execute and wait
Zitat:
|
AW: Too stupid to execute and wait
MainFormHandle kannte mein D7 nicht, deswegen nur Handle. Und GetForeGroundWindow ist gefährlich, da dein Programmfenster beim ausführen des Codes nicht das oberste Fenster sein muss.
|
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:32 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024-2025 by Thomas Breitkreuz