| Autor |
Beitrag |
Seifriz
Hält's aus hier
Beiträge: 8
Win 7 - 64 Bit
Delphi 6 Prof., Delphi 2007 Win32
|
Verfasst: Di 04.09.07 22:05
Hallo,
ich versuche mich gearde zum ersten Mal an dem Einsatz von Threads.
Mein Ziel:
Ich möchte remote bei 20 PC's eine Console öffnen (mit sysinternals psexec.exe) und den Output der Console (Func. habe ich im WWW gefunden) auswerten!
Funktioniert alles prima wenn ich jeden PC hintereinander abfrage und auf den Output warte... das dauert mir aber zu lange, deshalb möchte ich den Aufruf der Console und den Output in einem Thread unterbringen...
Macht das Sinn?
Hier mein bisheriges Ergebnis:
Der Output der Console (Output bzw. Error) wird zum Test hier in zwei TMemo's angezeigt.
Leider ist das Ergebnis nicht wirklich gut. In dem Beispiel (... dir c:\ ...) werden oft nur die ersten paar Zeilen des Outputs angezeigt und nicht der komplette Inhalt von C:\. Liegt vermute ich an der Synchronisierung?!
Hat jemand einen guten Tip?
Danke!
ThreadObject VCL:
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:
| unit MyThreadObj;
interface
uses Classes, Windows;
type TCMD = class(TThread) private procedure DoCMD; function GetConsoleOutput(const Command: String; Output, Errors: TStringList): Boolean; procedure UpdateMainForm; protected procedure Execute; override; public Nummer: Integer; PCName: String; Benutzer: String; Passwort: String; Output: TStringList; Errors: TStringList; end;
implementation
uses Unit1;
procedure TCMD.Execute; begin Output:=TStringList.Create; Errors:=TStringList.Create; DoCMD; Output.free; Errors.free; end;
procedure TCMD.DoCMD; begin if GetConsoleOutput('cmd /c psexec -u ' + PCName + '\' + Benutzer + ' -p ' + Passwort + ' -n 25 \\' + PCName + ' cmd /c "dir c:\"', Output, Errors) then begin Synchronize(UpdateMainForm); end else begin Output.Add('Error - GetConsoleOutput'); Synchronize(UpdateMainForm); end; end;
procedure TCMD.UpdateMainForm; begin Form1.UpdateInMainForm(Output, Errors, Nummer, PCName, Benutzer, Passwort); end;
function TCMD.GetConsoleOutput(const Command: String; Output, Errors: TStringList): Boolean; begin ... end; |
und hier die Form1:
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:
| unit Unit1;
interface
uses Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms, Dialogs, StdCtrls, MyThreadObj;
type TForm1 = class(TForm) btnStart: TButton; btnStopp: TButton; Memo1: TMemo; Memo2: TMemo; procedure btnStartClick(Sender: TObject); procedure btnStoppClick(Sender: TObject); procedure FormCreate(Sender: TObject); private CMDoutput: Array[1..20] of TCMD; public procedure UpdateInMainForm(Output, Errors: TStringList; Nr: Integer; ComputerName, B, P: String); end;
var Form1: TForm1; PC, B, P: Array[1..20] of String;
implementation
{$R *.dfm}
procedure TForm1.UpdateInMainForm(Output, Errors: TStringList; Nr: Integer; ComputerName, B, P: String); begin Memo1.Lines.AddStrings(Output);
Memo2.Lines.AddStrings(Errors); end;
procedure TForm1.btnStartClick(Sender: TObject); var i:Integer; begin Memo1.Clear; Memo1.Lines.Add('Threads gestartet!');
for i:=1 to 20 do begin CMDoutput[i]:=TCMD.Create(True); CMDoutput[i].Nummer:=i; CMDoutput[i].PCName:=PC[i]; CMDoutput[i].Benutzer:=B[i]; CMDoutput[i].Passwort:=P[i]; CMDoutput[i].Output:=nil; CMDoutput[i].Errors:=nil; CMDoutput[i].Priority:=tpIdle; CMDoutput[i].FreeOnTerminate:=True; CMDoutput[i].Resume; end; end;
procedure TForm1.btnStoppClick(Sender: TObject); var i: Integer; begin for i:=1 to 20 do begin CMDoutput[i].Terminate; end;
Memo1.Lines.Add('Threads beendet!'); end;
procedure TForm1.FormCreate(Sender: TObject); begin PC[1]:='192.168.xxx.xx'; B[1]:='Benutzer'; P[1]:='Passwort'; ... end;
end. |
|
|
Narses
      

Beiträge: 10185
Erhaltene Danke: 1261
W11x64
TP3 .. D7pro .. D10.2CE
|
Verfasst: Di 04.09.07 22:15
Moin und  im Forum!
Zunächst mal gibt´s hier eine optimierte Version der Consolen-Funktion.
Ich habe mir deinen Quelltext nicht soo genau angesehen, aber mir ist direkt aufgefallen, dass du alle Ausgaben in die selben Memos schreibst...  das kann ja nicht gut gehen!
Ansatz: Mach ein Array of String jeweils für die Ausgabe und die Fehler und gibt die Strings geweils erst auf Anforderung ins Memo aus - oder mach mehr Memos auf die Form.
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
Seifriz 
Hält's aus hier
Beiträge: 8
Win 7 - 64 Bit
Delphi 6 Prof., Delphi 2007 Win32
|
Verfasst: Di 04.09.07 22:34
Hallo Narses,
danke für die schnelle Antwort.
Das mit dem einzigen Memo ist noch ein Relikt aus der "Nacheinander"-Version, da habe ich den Output wie in ein Log-File geschreiben.
Mehr Memos führen leider genau zum gleichen Ergebnis
Werde mir Dein optimierten Consolen-Output ansehen und eine Nacht darüber schlafen.
Danke
F.S.
|
|
alzaimar
      
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: Mi 05.09.07 07:21
_________________ Na denn, dann. Bis dann, denn.
|
|
Narses
      

Beiträge: 10185
Erhaltene Danke: 1261
W11x64
TP3 .. D7pro .. D10.2CE
|
Verfasst: Mi 05.09.07 08:40
Moin!
alzaimar hat folgendes geschrieben: | | Ein Memo für die Ausgaben mehrerer Threads zu verwenden, funktioniert tadellos, |
Bitte beachten: "geht nicht gut" <> "funktioniert nicht"!
Da er die Ausgaben "kommentarlos" in ein Memo klatscht, kann man sie nicht auseinanderhalten!
cu
Narses
_________________ There are 10 types of people - those who understand binary and those who don´t.
|
|
alzaimar
      
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: Mi 05.09.07 08:45
|
|
Seifriz 
Hält's aus hier
Beiträge: 8
Win 7 - 64 Bit
Delphi 6 Prof., Delphi 2007 Win32
|
Verfasst: Mi 05.09.07 10:02
Danke alzaimar, danke Narses,
Ihr hängt Euch wirklich rein...
1. Narses: der optimierte Consolen-Output funktioniert und ist schneller - zumindest scheint mir das so.
2. Die Ausgabe in das Memo soll mir nur zeigen was ich zurück bekomme. Für die Auswertung müssen die Outputs natürlich getrennt und jeder für sich betrachtet werden...
3. Das mit der 'Critical Section' versteh ich nicht wirklich. Ich dachte ich hätte in jedem Thread je ein TSringList für den Output und die Errors  und damit auch einen klaren Bezug (s.Code).
Delphi-Quelltext 1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17:
| type TCMD = class(TThread) private procedure DoCMD; function ExecConsole(const Command: String; var Output, Errors: String): Boolean; procedure UpdateMainForm; protected procedure Execute; override; public Nummer: Integer; PCName: String; Benutzer: String; Passwort: String; Output: TStringList; Errors: TStringList; end; |
Ich habe aber immer noch das komische Phänomen, dass der Output von cmd /c dir c:\ nach 2 oder 3 Zeilen aufhört. Kann das nicht damit zusammenhänegn, dass Synchronize arbeitet, bevor der Output-String fertig aufgebaut ist
Grüße
F.S.
|
|
alzaimar
      
Beiträge: 2889
Erhaltene Danke: 13
W2000, XP
D6E, BDS2006A, DevExpress
|
Verfasst: Mi 05.09.07 12:19
Ach so:
Seifriz hat folgendes geschrieben: |
3. Das mit der 'Critical Section' versteh ich nicht wirklich. Ich dachte ich hätte in jedem Thread je ein TSringList für den Output und die Errors und damit auch einen klaren Bezug (s.Code). |
Oho, hab ich übersehen. Dann brauchst Du das natürlich nicht. Critical sections verwendest Du dann, wenn Du eine Resource vor gleichzeitigem Zugriff unterschiedlicher Threads schützen must. Das ist ja hier nicht der Fall.
_________________ Na denn, dann. Bis dann, denn.
|
|
Seifriz 
Hält's aus hier
Beiträge: 8
Win 7 - 64 Bit
Delphi 6 Prof., Delphi 2007 Win32
|
Verfasst: Mi 05.09.07 12:35
Hi,
danke an alle für Eure Hilfe. Hab' wieder einiges über Threads dazugelernt...
Habe das 'Problem' im Griff. Das mit den Threads und den TStringList funktionierte (ob es guter Code ist  ).
Die Ursache lag an den doppelten Anführungszeichen um den dir-Befehl in der Consolen-Kommandozeile :
Delphi-Quelltext 1: 2: 3:
| ... if GetConsoleOutput('cmd /c psexec -u ' + PCName + '\' + Benutzer + ' -p ' + Passwort + ' -n 25 \\' + PCName + ' cmd /c "dir c:\"', Output, Errors) then ... |
so klappt es
Delphi-Quelltext 1: 2: 3:
| ... if GetConsoleOutput('cmd /c psexec -u ' + PCName + '\' + Benutzer + ' -p ' + Passwort + ' -n 25 \\' + PCName + ' cmd /c dir c:\', Output, Errors) then ... |
Grüße
F.S.
|
|
|