Autor Beitrag
Alice
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 120



BeitragVerfasst: 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 user profile iconTino: Überflüssige Zeilenumbrüche entfernt.
fuba
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 125

Win7
D7 Ent.
BeitragVerfasst: 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.

ausblenden 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,
                      0nil, 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:

ausblenden volle Höhe Delphi-Quelltext
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 :D
Aber ich hoffe ich konnte dir helfen oder dich auf ne neue idee bringen ;)
BenBE
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 120



BeitragVerfasst: Do 06.09.07 20:14 
user profile iconBenBE 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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 120



BeitragVerfasst: Do 06.09.07 20:36 
user profile iconBenBE 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 ... :shock:

cu

alice

Moderiert von user profile iconGausi: Quote-Tags repariert.
Alice Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 120



BeitragVerfasst: Fr 07.09.07 10:07 
hi,

so, gleich mal meinen democode ausgepackt :-) :

ausblenden volle Höhe Delphi-Quelltext
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, 00, 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),nilnilnil,False, CREATE_NEW_PROCESS_GROUP+NORMAL_PRIORITY_CLASS, nilnil, 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, 00);
  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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: 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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 120



BeitragVerfasst: Fr 07.09.07 17:05 
user profile iconBenBE 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
ontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic starofftopic star
Beiträge: 8721
Erhaltene Danke: 191

Win95, Win98SE, Win2K, WinXP
D1S, D3S, D4S, D5E, D6E, D7E, D9PE, D10E, D12P, DXEP, L0.9\FPC2.0
BeitragVerfasst: Fr 07.09.07 18:40 
Ok, hab ne Version fertig, die bei mir soweit läuft:

ausblenden volle Höhe Delphi-Quelltext
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:
//Wait for a process to be fully started and responding.
// (C) 2007 by Benny Baumann (BenBE).
// User in freeware or with written permission granted as long copyright and licence remained intact.
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

            //At first check if the process is still running (and lower CPU load) ...
            WFSO := WaitForSingleObject(ProcInfo.hProcess, 100);

            //Now check for at least one window that
            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 Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starhalf ontopic star
Beiträge: 120



BeitragVerfasst: Mo 10.09.07 14:54 
user profile iconBenBE 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