Announcement

Collapse
No announcement yet.

Problem beim Starten eines Installers von Delphi aus

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • Problem beim Starten eines Installers von Delphi aus

    Hallo,

    ich habe folgendes Problem: Von einem Delphi-Programm aus (erstellt mit Delphi 5) starte ich einen Installer mit Hilfe einer Funktion namens WinExecAndWait32. Die Funktion habe ich irgendwo mal runtergeladen. Wie der Name schon sagt startet diese Funktion den Install-Prozess und kehrt erst zurück, wenn dieser beendet wurde. So weit so gut.

    Das Problem ist nur, dass der Prozess, der da gestartet wird nicht das eigentliche Installationsprogramm ist, sondern nur mal eine Entpackroutine, die bevor sie beendet wird den eigentlichen Install-Prozess startet. Nun passiert es sehr häufig, dass ungeduldige Benutzer auf meine Oberfläche klicken und dadurch der Installer nun hinter meinem Programm aufgeht und der Benutzer den Installer gar nicht bemerkt.

    Um dieses Problem zu umgehen mache ich mein Programm für 15 sec. invisible. Aber je nach Rechner-Geschwindigkeit wird meine Applikation genau dann wieder sichtbar, wenn der Installer auch gerade startet. Manchmal ist dann meine Applikation auch wieder im Vordergrund.

    Primitive Lösung: Zeit verlängern. Möchte ich eigentlich nicht. Wenn mit dem Installer was nicht in Ordnung ist, dann dauert es ewig bis mein Programm wieder da ist.

    Deshalb meine Frage: Wie bekomme ich die vollständige Kontrolle über den Installer und lasse meine Programm erst dann weitermachen, wenn der vollständige Install-Prozess beendet wurde.

    Alternativ würde es mir schon reichen, wenn ich es schaffen würde, dass wenn ich meine Applikation wieder sichtbar mache, dass diese nicht das aktive Programm im Vordergrund wäre.

    Hier der Code der Funktion, falls es der Lösung dienen kann:

    function WinExecAndWait32(FileName: string; Visibility: integer): integer;

    var

    zAppName: array[0..512] of char;

    zCurDir: array[0..255] of char;

    WorkDir: string;

    ResulA: Cardinal;

    StartupInfo: TStartupInfo;

    ProcessInfo: TProcessInformation;

    begin

    StrPCopy(zAppName, FileName);

    GetDir(0, WorkDir);

    StrPCopy(zCurDir, WorkDir);

    FillChar(StartupInfo, Sizeof(StartupInfo), #0);

    StartupInfo.cb := Sizeof(StartupInfo);

    StartupInfo.dwFlags := STARTF_USESHOWWINDOW;

    StartupInfo.wShowWindow := Visibility;

    if not CreateProcess(nil,

    zAppName, { pointer to command line string }

    nil, { pointer to process security attributes }

    nil, { pointer to thread security attributes }

    false, { handle inheritance flag }

    CREATE_NEW_CONSOLE or { creation flags }

    NORMAL_PRIORITY_CLASS,

    nil, { pointer to new environment block }

    nil, { pointer to current directory name }

    StartupInfo, { pointer to STARTUPINFO }

    ProcessInfo) then

    Result := -1 { pointer to PROCESS_INF }

    else begin

    while WaitForSingleObject(ProcessInfo.hProcess, 100) = WAIT_TIMEOUT do

    Application.ProcessMessages;

    GetExitCodeProcess(ProcessInfo.hProcess, ResulA);

    Result := ResulA;

    end;

    end;

    Bin für eure Hilfe dankbar.

    Gruß

    Wolfgang

  • #2
    Hallo!

    Vielleicht so?!?

    function GetProcID(sProcName: String): Integer;
    var
    hProcSnap: THandle;
    pe32: TProcessEntry32;
    begin
    result := -1;
    hProcSnap := CreateToolHelp32SnapShot(TH32CS_SNAPPROCESS, 0);
    if hProcSnap = INVALID_HANDLE_VALUE then exit;

    pe32.dwSize := SizeOf(ProcessEntry32);
    sProcName := uppercase ( sProcName );
    { wenn es geklappt hat }
    if Process32First(hProcSnap, pe32) = true then
    { und los geht's: Prozess suchen}
    while Process32Next(hProcSnap, pe32) = true do
    begin
    if pos(sProcName, uppercase(pe32.szExeFile)) <> 0 then
    result := pe32.th32ProcessID;
    end;
    end;

    Anwendung:
    if GetProcID ( 'setup.exe' ) > -1 then begin
    //Setup.exe läuft noch
    end;

    das zusammen mit einem Timer, der alle paar Sekunden nachsieht, ob die Setup.exe noch läuft.
    Geht natürlich schief, wenn eine andere setup.exe gerade läuft...

    BYE BERN

    Comment


    • #3
      Hi,
      vielleicht reicht es ja auch schon vor dem Starten des Setup deine Form auf Enabled:=False zu setzen...
      Ich hatte das so gemacht:

      procedure TfrmMain.ImgdeveClick(Sender: TObject);
      const
      Command = '.\gb\FLDM\Deviceinstaller\setup.exe';
      var
      ExitCode: DWORD;
      begin
      Screen.Cursor:=crHourGlass;
      frmMain.Enabled:=False;
      Application.ProcessMessages;
      if ConsoleExec(Command, ExitCode)=False then
      ShowMessage('An error has occured, please try again.');
      Self.WindowState:=wsNormal;
      Application.BringToFront;
      frmMain.Enabled:=True;
      Screen.Cursor:=crDefault;
      end;

      Dazu hatte ich diese Funktion gefunden:

      function TfrmMain.ConsoleExec(const Command: string; out ExitCode: DWORD): Boolean;
      var
      CommandLine: string;
      StartupInfo: TStartupInfo;
      ProcessInfo: TProcessInformation;
      begin
      Result := False;
      CommandLine := GetEnvironmentVariable('ComSpec') + ' /C ' + Command;
      FillChar(StartupInfo, SizeOf(StartupInfo), 0);
      StartupInfo.cb := SizeOf(TStartupInfo);
      StartupInfo.dwFlags := STARTF_USESHOWWINDOW;
      StartupInfo.wShowWindow := SW_SHOWMINIMIZED;
      if CreateProcess(nil, PChar(CommandLine), nil, nil, False,
      CREATE_NEW_CONSOLE or CREATE_NEW_PROCESS_GROUP, nil, nil,
      StartupInfo, ProcessInfo) then
      try
      WaitForSingleObject(ProcessInfo.hProcess, INFINITE);
      Result := GetExitCodeProcess(ProcessInfo.hProcess, ExitCode);
      finally
      CloseHandle(ProcessInfo.hThread);
      CloseHandle(ProcessInfo.hProcess);
      end;
      end;

      Gruß
      Jen

      Comment


      • #4
        Hi Wolfgang.

        Ich habe das so gelöst!

        Dabei habe ich die Jedi VCL Componenten installiert.
        http://www.delphi-jedi.org/

        Daraus benutze ich die Komponente JVCreateProcess

        Hier mein Code:
        Also mit InstallShiled InstallScript SingleExecutable Setups ist das kein Problem und funktioniert. Dies muss aber auch mit allen anderen Installern gehen.

        if (FileExists(szPath + szFilename)) then
        begin
        JvCreateProcess1.CommandLine := szPath + szFilename;
        JvCreateProcess1.Run;

        while (bWait=false) do
        begin
        Application.ProcessMessages;
        end;
        end;

        procedure TfrmInstallExecute.JvCreateProcess1Terminate(Sende r: TObject;
        ExitCode: Cardinal);
        begin
        bWait := TRUE;
        end

        Comment


        • #5
          Hallo,

          Danke für eure Antworten. Mir scheint Bernds Methode die aussichtsreichste zu sein. Wenn ich es richtig sehe, geht's bei den anderen Methoden auch wieder nur darum einen Prozess zu starten und zu überwachen. Der Installer besteht aber nicht nur aus dem einen Prozess, sondern startet widerum einen anderen Prozess und terminiert dann. Dadurch läuft dann mein Delphi-Programm weiter obwohl die Installation noch nicht abgeschlossen ist.

          Meine Windows-API-Kenntnisse reichen aber nicht aus sagen zu können, dass eure (Jens und Thorsten) Prozess-Überwachung die den vom 1. Installer-Prozess gestarteten 2. Prozess nicht noch mit einschließt und die Kontrolle nicht doch erst dann an das Delphi-Programm zurückgegeben wird, wenn auch dieser 2. Prozess terminiert. Bitte korrigiert mich, wenn ich falsch liege.

          Gruß

          Wolfgan

          Comment

          Working...
          X