Bjr à vous,
Je désire lancer un programme externe qui génère de très longues sorties. Le programme externe est lancé du démarrage de mon application. Il envoie à intervalles irréguliers (en fait, il récupère des données d'un instrument de mesure) des lignes de données texte.
Comme le programme externe travaille en arrière plan, j'ai mis un TAsyncProcess dans un thread.
Je cherche à:
1. Récupérer la sortie standard du programme dans un TListbox ou équivalent
2. Dès qu'une ligne de données arrive, je la récupère pour traitement.
Je bute sur beacoup de choses:
- Le programme externe se lance dans une fenêtre en mode bloquant
- AV à la fermeture
Quelques tuyaux ?
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 procedure TdlgTestAsyncProcess.btnStartProcessClick(Sender: TObject); begin AfficherMessage('Démarrage du thread'); FAsyncProcessThread.Executable := 'Triangulateur.exe'; // Le programme console qui envoie les données AfficherMessage('--> 001'); FAsyncProcessThread.OnReadData := self.AsyncProcessOnReadData; // Le callback censé récupérer les données AfficherMessage('--> 002'); FAsyncProcessThread.OnTerminate := self.AsyncProcessOnTerminate; // Le callback de terminaison du process FAsyncProcessThread.Options := [poUsePipes]; AfficherMessage('--> 003'); FOutputStream := TMemoryStream.Create; AfficherMessage('--> 004'); FOutputStream := TMemoryStream(FAsyncProcessThread.Output); AfficherMessage('--> 005'); FAsyncProcessThread.Execute; end;
L'unité unitTAsyncProcessThread:
La form d'utilisation:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147 unit unitTAsyncProcessThread; {$mode delphi}{$H+} interface uses Classes, SysUtils, process, AsyncProcess, Pipes; type { TAsyncProcessThread } TAsyncProcessThread = class(TThread) private FProcess: TAsyncProcess; FMessage: string; function getExecutable(): TProcessString; function getOptions: TProcessOptions; function getOutput(): TInputPipeStream; procedure setExecutable(const P: TProcessString); function getProcOnReadData(): TNotifyEvent; function getProcOnTerminate(): TNotifyEvent; procedure setOptions(const AValue: TProcessOptions); procedure setProcOnReadData(const E: TNotifyEvent); procedure setProcOnTerminate(const E: TNotifyEvent); protected procedure DoMessage; public constructor Create(AOwner: TComponent); destructor Destroy; override; property Output: TInputPipeStream read getOutput; property Options: TProcessOptions read getOptions write setOptions; property Executable: TProcessString read getExecutable write SetExecutable; procedure AddParameter(const P: TProcessString); property OnReadData: TNotifyEvent read getProcOnReadData write setProcOnReadData; property OnTerminate: TNotifyEvent read getProcOnTerminate write setProcOnTerminate; procedure Execute; override; //procedure ReadData(Sender: TObject); procedure OnProcTerminate(Sender: TObject); procedure SendMessage(AString: string); end; implementation uses Common; procedure TAsyncProcessThread.Execute; begin FreeOnTerminate:= True; try FProcess.Execute; if not FProcess.WaitOnExit then raise Exception.Create('Error: Process exited with status: ' + FProcess.ExitStatus.ToString); finally //FProcess.Free; end; end; procedure TAsyncProcessThread.SendMessage(AString: string); begin FMessage:= AString; Synchronize(DoMessage); end; function TAsyncProcessThread.getExecutable(): TProcessString; begin Result := FProcess.Executable; end; function TAsyncProcessThread.getOptions: TProcessOptions; begin Result := FProcess.Options; end; function TAsyncProcessThread.getOutput: TInputPipeStream; begin Result := FProcess.Output; end; procedure TAsyncProcessThread.setExecutable(const P: TProcessString); begin FProcess.Executable := P; end; function TAsyncProcessThread.getProcOnReadData(): TNotifyEvent; begin Result := FProcess.OnReadData; end; function TAsyncProcessThread.getProcOnTerminate(): TNotifyEvent; begin Result := FProcess.OnTerminate; end; procedure TAsyncProcessThread.setOptions(const AValue: TProcessOptions); begin FProcess.Options := AValue; end; procedure TAsyncProcessThread.setProcOnReadData(const E: TNotifyEvent); begin FProcess.OnReadData := E; end; procedure TAsyncProcessThread.setProcOnTerminate(const E: TNotifyEvent); begin FProcess.OnTerminate := E; end; procedure TAsyncProcessThread.AddParameter(const P: TProcessString); begin FProcess.Parameters.Add(P); end; procedure TAsyncProcessThread.DoMessage; begin //frmMain.OnProcessRead(Self, FMessage); end; constructor TAsyncProcessThread.Create(AOwner: TComponent); begin FProcess := TAsyncProcess.Create(AOwner); end; procedure TAsyncProcessThread.OnProcTerminate(Sender: TObject); begin //SendMessage('Process Terminated'); end; destructor TAsyncProcessThread.Destroy; begin FreeAndNil(FProcess); //SendMessage('<Thread is destroyed!>'); inherited Destroy; end; end.
Exemple de sortie de programme externe que je veux récupérer:
Code : Sélectionner tout - Visualiser dans une fenêtre à part
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
114
115
116
117
118
119
120
121
122
123
124
125
126 unit frmMainTAsyncProcess; // Pilote pour TAsyncProcessThread {$mode delphi}{$H+} interface uses Classes, SysUtils, Forms, Controls, Graphics, Dialogs, StdCtrls, process, unitTAsyncProcessThread; type TdlgTestAsyncProcess = class(TForm) btnStartProcess: TButton; btnStopProcess: TButton; lsbMessages: TListBox; lsbOutput: TListBox; procedure btnStartProcessClick(Sender: TObject); procedure btnStopProcessClick(Sender: TObject); procedure FormCreate(Sender: TObject); private FOutputStream: TMemoryStream; FAsyncProcessThread: TAsyncProcessThread; procedure FormDestroy(Sender: TObject); procedure AfficherMessage(const Msg: string); procedure AsyncProcessOnReadData(Sender: TObject); procedure AsyncProcessOnTerminate(Sender: TObject); public end; var dlgTestAsyncProcess: TdlgTestAsyncProcess; implementation {$R *.lfm} { TdlgTestAsyncProcess } procedure TdlgTestAsyncProcess.AsyncProcessOnReadData(Sender: TObject); var BytesAvailable: DWord; s: string; sa: SysUtils.TStringArray; begin if Assigned(FAsyncProcessThread) then try // Check how much data is waiting BytesAvailable:= FAsyncProcessThread.Output.NumBytesAvailable; setlength(s, BytesAvailable); // Read data and store in string s FAsyncProcessThread.Output.Read(s[1], BytesAvailable); // Split output by cr/lf into separate strings sa:= s.split(#13#10); for s in sa do begin lsbOutput.Items.Add(s); end; except On E : Exception do raise Exception.Create('Exception in procedure ReadData! - ' +E.Message); else raise Exception.Create('No process assigned!'); end; end; procedure TdlgTestAsyncProcess.AsyncProcessOnTerminate(Sender: TObject); begin AfficherMessage('Fin du thread'); AfficherMessage('--> 001'); ShowMessage('Processus nuisible terminé'); end; procedure TdlgTestAsyncProcess.btnStartProcessClick(Sender: TObject); begin AfficherMessage('Démarrage du thread'); //try //try FAsyncProcessThread.Executable := 'Triangulateur.exe'; // Le programme console qui envoie les données AfficherMessage('--> 001'); FAsyncProcessThread.OnReadData := self.AsyncProcessOnReadData; // Le callback censé récupérer les données AfficherMessage('--> 002'); FAsyncProcessThread.OnTerminate := self.AsyncProcessOnTerminate; // Le callback de terminaison du process FAsyncProcessThread.Options := [poUsePipes]; AfficherMessage('--> 003'); FOutputStream := TMemoryStream.Create; AfficherMessage('--> 004'); FOutputStream := TMemoryStream(FAsyncProcessThread.Output); AfficherMessage('--> 005'); FAsyncProcessThread.Execute; //except //end; //finally //end; end; procedure TdlgTestAsyncProcess.btnStopProcessClick(Sender: TObject); begin AfficherMessage('Finalisation du thread et récupération des messages'); FOutputStream.LoadFromStream(FAsyncProcessThread.Output); AfficherMessage('--> 001'); lsbOutput.Items.LoadFromStream(FOutputStream); AfficherMessage('--> 002'); FAsyncProcessThread.Terminate; FreeandNil(FOutputStream); end; procedure TdlgTestAsyncProcess.FormCreate(Sender: TObject); begin FAsyncProcessThread := TAsyncProcessThread.Create(self); end; procedure TdlgTestAsyncProcess.FormDestroy(Sender: TObject); begin FreeAndNil(FAsyncProcessThread); end; procedure TdlgTestAsyncProcess.AfficherMessage(const Msg: string); begin lsbMessages.Items.Add(Msg); lsbMessages.ItemIndex := lsbMessages.Items.Count -1; end; end.
triangle [-prq__a__uAcDjevngBPNEIOXzo_YS__iFlsCQVh] input_file
-p Triangulates a Planar Straight Line Graph (.poly file).
-r Refines a previously generated mesh.
-q Quality mesh generation. A minimum angle may be specified.
-a Applies a maximum triangle area constraint.
-u Applies a user-defined triangle constraint.
-A Applies attributes to identify triangles in certain regions.
-c Encloses the convex hull with segments.
-D Conforming Delaunay: all triangles are truly Delaunay.
-j Jettison unused vertices from output .node file.
-e Generates an edge list.
-v Generates a Voronoi diagram.
-n Generates a list of triangle neighbors.
-g Generates an .off file for Geomview.
-B Suppresses output of boundary information.
-P Suppresses output of .poly file.
-N Suppresses output of .node file.
-E Suppresses output of .ele file.
-I Suppresses mesh iteration numbers.
-O Ignores holes in .poly file.
-X Suppresses use of exact arithmetic.
-z Numbers all items starting from zero (rather than one).
-o2 Generates second-order subparametric elements.
-Y Suppresses boundary segment splitting.
-S Specifies maximum number of added Steiner points.
-i Uses incremental method, rather than divide-and-conquer.
-F Uses Fortune's sweepline algorithm, rather than d-and-c.
-l Uses vertical cuts only, rather than alternating cuts.
-s Force segments into mesh by splitting (instead of using CDT).
-C Check consistency of final mesh.
-Q Quiet: No terminal output except errors.
-V Verbose: Detailed information on what I'm doing.
-h Help: Detailed instructions for Triangle.
Partager