Autor |
Beitrag |
Alice
      
Beiträge: 120
|
Verfasst: Di 28.08.07 17:58
hi all,
ich weiss zu dem thema gibt es einen haufen threats hier, aber keiner passt so richtig ich habe sie mir angesehen.
das ganze mit shellexec. + createproc. ist soweit klar denke ich.
jedoch folg. problem:
das programm was gestarten werden soll, braucht immer einen moment bis es soweit fertig mit dem laden von seinen eigenen *.sys und *.vxd treibern ist, mal länger mal kürzer.
im taskmanager ist sofort nach dem aufruf da, aber noch lange nicht *betriebsbereit.
wie kann ich nun feststellen ob das programm quasi einsatzbereit geladen ist? und dann erst mit meinem eingenen programm weiter fortfahren.
klar ich könnte nach dem aufrufen aus meinem programm einfach 1min warten und dann erst fortfahren... dann ist es auf jeden fall geladen, ist jedoch nicht das gelbe vom ei und ich will auch nicht jedesmal eine minute warten  ...
gibt es da einen kniff?
cu
alice
Moderiert von Tino: Überflüssige Zeilenumbrüche entfernt.
|
|
fuba
      
Beiträge: 125
Win7
D7 Ent.
|
Verfasst: Mo 03.09.07 21:31
Soweit ich das hier verstanden habe, startet du ein prog, dass dann minimiert oder im tray aktiv ist oder?
wenn dies der flal ist, ists klar dass dir Programm starten / warten nicht hilft, weil das programm warscheinlich immer aktiv sein wird oder?
Weil, wenn ja, wartet dein programm, bis das ausgeführte programm wieder beendet wird, erst dann wird die nächste aktion ausgeführt.
Aber wenn dir bekannst ist, welche dll, sys oder was auch immer geladen wird, könntest du, FALLS diese nur kurz von dem programm aufgerufen werden mit dieser procedure prüfen, ob die dll, sys,... files InUse (also benutzt werden) sind.
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14:
| function IsFileInUse(Path: string): boolean; var hFile: THandle;
begin Result := False; if not FileExists(Path) then Exit;
hFile := CreateFile(pchar(Path), GENERIC_READ or GENERIC_WRITE or GENERIC_EXECUTE, 0, nil, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, 0); Result := hFile = INVALID_HANDLE_VALUE; if not Result then CloseHandle(hFile);
end; |
sollte aber das programm, das du startest, nur kurz erscheinen und wieder geschlossen werden, kannst du dies verwenden:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33:
| procedure RunProcessAndWait(aFilename, aParameters, aDirectory: String; aShowCmd: Integer = SW_SHOWNORMAL); Var StartupInfo : TStartupInfo; ProcessInfo : TProcessInformation; Result: Boolean; Begin FillChar (StartupInfo, SizeOf (TStartupInfo), 0); StartupInfo.cb := Sizeof (TStartupInfo);
StartupInfo.dwFlags := STARTF_USESHOWWINDOW OR STARTF_USEPOSITION OR STARTF_USESIZE ; StartupInfo.wShowWindow := aShowCmd;
aParameters := Format('"%s" %s', [aFilename, TrimRight(aParameters)]);
Result := CreateProcess ( nil, pChar (aParameters), nil, nil, false, NORMAL_PRIORITY_CLASS, nil, pChar(aDirectory), StartupInfo, ProcessInfo );
If Result then WaitForSingleObject (ProcessInfo.hProcess, INFINITE);
if ProcessInfo.hProcess <> 0 then CloseHandle (ProcessInfo.hProcess); end; |
sollte beides nicht helfen, weis ich auch nicht was man da machen könnte
Aber ich hoffe ich konnte dir helfen oder dich auf ne neue idee bringen 
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Di 04.09.07 14:42
Du kannst über GetWindowProcessID, EnumWindows u.ä. die zum gestarteten Prozess gehörigen Fenster ermitteln. Anschließend brauchst Du nur an ein beliebiges dieser Fenster eine WM_NULL-Nachricht mit SendMessageTimeout schicken (Timeout relativ klein), und schauen, ab wann der Timeout 5 mal hintereinander nicht mehr überschritten wird.
Sobald dies der Fall ist, kannst Du davon ausgehen, dass das andere Programm geladen ist.
ACHTUNG: Funktioniert nicht für Konsolen-Programme 
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
Alice 
      
Beiträge: 120
|
Verfasst: Do 06.09.07 20:14
BenBE hat folgendes geschrieben: | Du kannst über GetWindowProcessID, EnumWindows u.ä. die zum gestarteten Prozess gehörigen Fenster ermitteln. Anschließend brauchst Du nur an ein beliebiges dieser Fenster eine WM_NULL-Nachricht mit SendMessageTimeout schicken (Timeout relativ klein), und schauen, ab wann der Timeout 5 mal hintereinander nicht mehr überschritten wird.
Sobald dies der Fall ist, kannst Du davon ausgehen, dass das andere Programm geladen ist.
|
hi,
hört sich gut an. habe es auch mal probiert, bin aber gescheitert.
gibt es dazu einen beispiel quelltext!?
cu
alice
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Do 06.09.07 20:19
Hi,
Nope, hab dazu leider keinen ... Vielleicht können wir aber aus deinem Versuch eine Lauffähige Version basteln
MfG,
BenBE.
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
Alice 
      
Beiträge: 120
|
Verfasst: Do 06.09.07 20:36
BenBE hat folgendes geschrieben: | Hi,
Nope, hab dazu leider keinen ... Vielleicht können wir aber aus deinem Versuch eine Lauffähige Version basteln
|
ok, werde mein bestes geben...
und hoffe das ich (wir) hier etwas daraus basteln können.... !
// edit: 1 versuch folgt ...
cu
alice
Moderiert von Gausi: Quote-Tags repariert.
|
|
Alice 
      
Beiträge: 120
|
Verfasst: Fr 07.09.07 10:07
hi,
so, gleich mal meinen democode ausgepackt  :
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52:
| procedure TForm1.Appisactive(fname:string); var Res: DWORD; H : HWND; begin
H := FindWindow(nil, Pchar(fname));
if H = 0 then Label1.Caption := 'prog. n.vorhanden' else if SendMessageTimeout(H, WM_NULL, 0, 0, SMTO_NORMAL, 100, Res) <> 0 then Label1.Caption := 'reagiert';
end;
procedure TForm1.ExecNewProcess(ProgramName : String); var StartInfo : TStartupInfo; ProcInfo : TProcessInformation; CreateOK : Boolean; begin
FillChar(StartInfo,SizeOf(TStartupInfo),#0); FillChar(ProcInfo,SizeOf(TProcessInformation),#0); StartInfo.cb := SizeOf(TStartupInfo); CreateProcess(PChar(ProgramName),nil, nil, nil,False, CREATE_NEW_PROCESS_GROUP+NORMAL_PRIORITY_CLASS, nil, nil, StartInfo, ProcInfo);
end;
procedure TForm1.startClick(Sender: TObject); begin
ExecNewProcess('c:\demo.exe');
end;
procedure TForm1.stopClick(Sender: TObject); begin
WHILE FindWindow(nil,'demo') <> 0 DO begin PostMessage(FindWindow(NIL, 'demo'), wm_close, 0, 0); end;
end;
procedure TForm1.Timer1Timer(Sender: TObject); begin
Appisactive('demo');
end; |
das ganze funkt. auch soweit ganz gut, nur...
ich nutze einen timer, alle 50ms = nicht elegant...
mir ist es nicht gelungen das alles in eine funktion zu packen. d.h.:
eine einzelne funktion die über variablen path+exename, exe startverz. einen boolean zurückliefert
wenn das zu startende prog. *fertig geladen ist.
intressant wäre noch, eine art max. wartedauer wenn die überschritten wird, abbruch: result = false
so weit bin ich gekommen und hoffe nun auf weitere hilfestellungen
// edit:
wie sicher ist das ganze? also kann ich davon ausgehen wenn SendMessageTimeout <>0 liefert
das prog. auch wirklich voll da ist?
was sagen mir die beiden variablen : SMTO_NORMAL und 100 (SendMessageTimeout)
cu and thx
alice
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Fr 07.09.07 13:46
Ich schau's durch. Dauert ggf. etwas.
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
Alice 
      
Beiträge: 120
|
Verfasst: Fr 07.09.07 17:05
BenBE hat folgendes geschrieben: | Ich schau's durch. Dauert ggf. etwas. |
hi,
schonmal danke im vorraus, wenn es so klappen sollte,
dann ist DAS die lösung beim aufrufen von externen prog.!!
cu
alice
|
|
BenBE
      
Beiträge: 8721
Erhaltene Danke: 191
Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
|
Verfasst: Fr 07.09.07 18:40
Ok, hab ne Version fertig, die bei mir soweit läuft:
1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113:
| Function CreateProcessWaitReady(ProgramFile: String; Commandline: String = ''; CurrDir: String = '.'): Boolean; Var StartInfo: TStartupInfo; ProcInfo: TProcessInformation;
WFSO: DWORD; SMT_Count: Integer; SMT_Done: Boolean; Type TEWPInfo = Packed Record PI: PProcessInformation; SMTD: PBoolean; End; PEWPInfo = ^TEWPInfo; Var EWPI: TEWPInfo;
Function ETWProc(wnd: HWND; Param: PEWPInfo): Boolean; Stdcall; Var Res: DWORD; Begin If SendMessageTimeoutA( wnd, WM_NULL, 0, 0, SMTO_ABORTIFHUNG, 50, Res) <> 0 Then Begin Param.SMTD^ := True; Sleep(10); End; Result := Not Param.SMTD^; End;
Begin FillChar(StartInfo, SizeOf(TStartupInfo), #0); FillChar(ProcInfo, SizeOf(TProcessInformation), #0); StartInfo.cb := SizeOf(TStartupInfo); StartInfo.dwFlags := STARTF_USESHOWWINDOW Or STARTF_USEPOSITION Or STARTF_USESIZE; StartInfo.wShowWindow := SW_SHOW;
Commandline := Format('"%s" %s', [ProgramFile, Trim(Commandline)]);
Result := CreateProcess( Nil, pChar(Commandline), Nil, Nil, false, NORMAL_PRIORITY_CLASS, Nil, pChar(CurrDir), StartInfo, ProcInfo );
If Result Then Begin SMT_Count := 0; EWPI.PI := @ProcInfo; EWPI.SMTD := @SMT_Done; Repeat
WFSO := WaitForSingleObject(ProcInfo.hProcess, 100);
SMT_Done := False; EnumThreadWindows(ProcInfo.dwThreadId, @ETWProc, Integer(@EWPI)); If SMT_Done Then Inc(SMT_Count) Else SMT_Count := 0; Until (WAIT_OBJECT_0 = WFSO) Or (SMT_Count >= 10);
Result := SMT_Count >= 10; End;
If ProcInfo.hProcess <> 0 Then CloseHandle(ProcInfo.hProcess); End;
Procedure TForm1.Button1Click(Sender: TObject); Begin Panel1.Caption := 'Starting ...'; Panel1.Color := clYellow; Update; Try If CreateProcessWaitReady(Edit1.Text) Then Begin Panel1.Caption := 'Started !!!'; Panel1.Color := clLime; Update; End Else Begin Panel1.Caption := 'Failed !!!'; Panel1.Color := clRed; Update; Raise EOSError.Create(SysErrorMessage(GetLastError)); End; Finally Sleep(500); Panel1.Caption := 'Bereit'; Panel1.Color := clBtnFace; Update; End; End; |
Edit1 ist der auszuführende Befehl, Panel1 zeigt den Status an, Button1 ist zum Starten der Anwendung.
Hinweise zur Funktionsweise:
Diese Routine prüft, ob mindestens ein Fenster des Hauptthreads der Anwendung innerhalb von 50ms auf eine WM_NULL-Nachricht reagiert. Ist dies der Fall, wird ein interner Zähler erhöht und erneut eine solche Prüfung durchgeführt, solang, bis 10 mal erfolgreich eine WM_NULL-Nachricht verarbeitet wurde. Wird zwischendurch eine Nachricht verschluckt, so wird der Zähler wieder zurückgesetzt.
Man könnte hir noch etwas Feintunen, aber grob vom Prinzip her funktioniert das so jetzt.
Hab's mit PHPEdit von Waterproof getestet, dort bekomm ich grünes Licht, sobald er wirklich alle Arbeiten abgeschlossen hat (Auf Grund des Zählers etwas verzögert) und man wirklich mit dem Programm arbeiten kann. Während der SplashScreen noch am laden ist, der zahlreiche Stellen mit ApplicationProcessMessages hat, zeigt er mir den Status Starting an; also wie zu erwarten.
HTH.
P.S.: Verwendung der Routine unter Angabe meines Copyrights gestattet (Siehe Source).
_________________ Anyone who is capable of being elected president should on no account be allowed to do the job.
Ich code EdgeMonkey - In dubio pro Setting.
|
|
Alice 
      
Beiträge: 120
|
Verfasst: Mo 10.09.07 14:54
BenBE hat folgendes geschrieben: |
Hab's mit PHPEdit von Waterproof getestet, dort bekomm ich grünes Licht, sobald er wirklich alle Arbeiten abgeschlossen hat (Auf Grund des Zählers etwas verzögert) und man wirklich mit dem Programm arbeiten kann. Während der SplashScreen noch am laden ist, der zahlreiche Stellen mit ApplicationProcessMessages hat, zeigt er mir den Status Starting an; also wie zu erwarten. |
hi,
habe es eben mal getestet und es läuft sehr gut!
thx!!
cu
alice
|
|
|