Autor Beitrag
Blamaster
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 164



BeitragVerfasst: Di 04.09.07 15:50 
Hi,

mein Programm hängt sich während es entpackt erstmal total auf, nach dem entpacken läuft es wieder ohne Probleme. Wie kann ich das umgehen ?

Code:

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:
procedure TForm1.Button2Click(Sender: TObject);

function ExecConsole(var Output, Errors: String): Boolean;
  var
    StartupInfo: TStartupInfo;
    ProcessInfo: TProcessInformation;
    SecurityAttr: TSecurityAttributes;
    PipeOutputRead, PipeOutputWrite,
    PipeErrorsRead, PipeErrorsWrite: THandle;

  // Pipe in einen String auslesen (speicherschonend)
  function ReadPipeToString(const hPipe: THandle): String;
    const
      MEM_CHUNK_SIZE = 8192// Blockgröße, mit der Speicher angefordert wird
    var
      NumberOfBytesRead,
      NumberOfBytesTotal: Cardinal;
  begin
    Result := ''// Standard-Ergebnis
    NumberOfBytesTotal := 0// noch nichts gelesen
    repeat
      SetLength(Result,Length(Result) +MEM_CHUNK_SIZE); // mehr Platz machen
      // versuchen, aus der Pipe zu lesen
      if ReadFile(hPipe,(@Result[1+NumberOfBytesTotal])^,MEM_CHUNK_SIZE,
                  NumberOfBytesRead,NILthen // hat geklappt
        Inc(NumberOfBytesTotal,NumberOfBytesRead); // Gesamtanzahl aktualisieren
      SetLength(Result,NumberOfBytesTotal); // überzählige Bytes abschneiden
    until (NumberOfBytesRead = 0); // bis die Pipe leer ist
  end;

begin
  // Win-API-Strukturen initialisieren/füllen
  FillChar(ProcessInfo,SizeOf(TProcessInformation),0);
  FillChar(SecurityAttr,SizeOf(TSecurityAttributes),0);
  SecurityAttr.nLength := SizeOf(SecurityAttr);
  SecurityAttr.bInheritHandle := TRUE;
  SecurityAttr.lpSecurityDescriptor := NIL;
  CreatePipe(PipeOutputRead,PipeOutputWrite,@SecurityAttr,0);
  CreatePipe(PipeErrorsRead,PipeErrorsWrite,@SecurityAttr,0);
  FillChar(StartupInfo,SizeOf(TStartupInfo),0);
  StartupInfo.cb := SizeOf(StartupInfo);
  StartupInfo.hStdInput := 0;
  StartupInfo.hStdOutput := PipeOutputWrite;
  StartupInfo.hStdError := PipeErrorsWrite;
  StartupInfo.wShowWindow := SW_HIDE;
  StartupInfo.dwFlags := STARTF_USESHOWWINDOW or STARTF_USESTDHANDLES;
  // Befehl ausführen (Prozess starten)
  Result := CreateProcess(NIL,PChar(winrar+'rar.exe e -p'+(Pwid)+ ' ' +(Archivid)+ ' ' +(Archiv2)),NIL,NIL,TRUE,
                          CREATE_DEFAULT_ERROR_MODE
                          or CREATE_NEW_CONSOLE
                          or NORMAL_PRIORITY_CLASS,
                          NIL,NIL,StartupInfo,ProcessInfo);

  // Write-Pipes schließen
  CloseHandle(PipeOutputWrite);
  CloseHandle(PipeErrorsWrite);
  if (Result) then begin // konnte der Befehl ausgeführt werden?
    Output := ReadPipeToString(PipeOutputRead); // Ausgabe-Read-Pipe auslesen
    Errors := ReadPipeToString(PipeErrorsRead); // Fehler-Read-Pipe auslesen
    WaitForSingleObject(ProcessInfo.hProcess,INFINITE); // auf Prozessende warten
    CloseHandle(ProcessInfo.hProcess); // und Handle freigeben
  end;
  // Read-Pipes schließen
  CloseHandle(PipeOutputRead);
  CloseHandle(PipeErrorsRead);
end;

begin
try
ini:=TIniFile.create(ExtractFilePath(ParamStr(0))+'einstellungen.ini');
Pwcheck:= ini.ReadInteger('Optionen','Id',-1);
finally
ini.free;
end;
try
if ExecConsole(Output,Errors) then begin
if (Errors <> ''then begin
Pwid:=(Listbox1.Items[Pwcheck + 1]);
Archivid:=(Listbox2.Items[0]);

Filename:=ExtractFileName(Archivid);
Filename2:=ExtractFileExt(Filename);
Fund:=Pos(Filename2,Filename);
if Fund <> -1 then
begin
FileNameNew:=Copy(Filename,0,Fund-1);
end;
if Archiv = False then
Archiv2:='' else
Archiv2:=(Archivpfad)+(Filenamenew) +'\';
try
ini:=TIniFile.create(ExtractFilePath(ParamStr(0))+'einstellungen.ini');
ini.WriteInteger('Optionen','Id',Pwcheck + 1);
finally
ini.free;
end;
end;
Button2.Click;
end

else

finally

end;
end;
noidic
ontopic starontopic starontopic starontopic starontopic starontopic starofftopic starofftopic star
Beiträge: 851

Win 2000 Win XP Vista
D7 Ent, SharpDevelop 2.2
BeitragVerfasst: Di 04.09.07 15:54 
Das WaitforSingleObject blockiert das Programm, pack das entpacken in nen eigenen Thread.

_________________
Bravery calls my name in the sound of the wind in the night...
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 16:10 
Kannst Du den Zeilen 68ff bitte mal etwas Layout verpassen?

Ferner: Ein leerer Finally-Teil hat wenig Sinn.

Genauso ein leere Else-Zweig.

Ansonsten: Anstatt bei WaitForSignleObject als Timeout Infinite anzugeben, nimmste nen Wert von ~200ms und prüfst in ner While-Schleife, ob das Timeout erreicht wurde, oder er ne Rückmeldung bekommen hat. Als Schleifen-Köprper kommt dann ein Application.ProcessMessages;.

_________________
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.
Blamaster Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 164



BeitragVerfasst: Di 04.09.07 16:54 
Kannst du das nochmal genauer erklären versteh ich irgendwie nicht so ganz :oops:
Blamaster Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 164



BeitragVerfasst: Di 04.09.07 20:29 
Bzw diesen Teil kann ich mir nicht ganz vorstellen:

"Prüfe in ner While-Schleife, ob das Timeout erreicht wurde, oder er ne Rückmeldung bekommen hat. Als Schleifen-Köprper kommt dann ein Application.ProcessMessages;."

Wie genau prüfe ich ob das Timeout erreicht wurde ?
Und was passiert mit Application.ProcessMessages ?
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 21:20 
Für Zeile 60 siehe Suche im MSDN WAITFORSINGLEOBJECT und ändere diese Zeile entsprechend. Manchmal sind Rückgabewerte dazu da, um diese abzufragen Aber auch nur manchmal...

Und das ganze dann in eine While Condition_For_WaitForSingleObject Do Application.ProcessMessages; zu packen, solltest Du selber hinbekommen.

_________________
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.
Blamaster Threadstarter
ontopic starontopic starontopic starontopic starontopic starontopic starontopic starontopic star
Beiträge: 164



BeitragVerfasst: Di 04.09.07 22:48 
Habe das Problem jetzt dank BenBE gelöst:

While WaitForSingleObject(ProcessInfo.hProcess,50) = WAIT_TIMEOUT do Application.ProcessMessages;

mfg Bla