Bonjour à tous.
J'aurai besoin de votre aide sur un sujet qui me dépasse complètement.
J'ai une application composée de 2 process séparés : un moteur et une interface graphique (HMI). Tout le travail est fait par le process moteur, mais toutes les interactions utilisateur sont prises en charge par le process HMI. La HMI affiche ce que fait le moteur et lui envoie des commandes lorsque l'utilisateur clique quelque part.
Le moteur et sa HMI sont 2 objets COM. Chacun connait et exploite l'interface COM de l'autre pour communiquer.
Actuellement, l'exécution dans le moteur est synchrone avec l'affichage dans la HMI.
Je souhaite désynchroniser l'affichage dans la HMI d'avec l'exécution dans le moteur.
J'ai donc mis en place un pipe de communication entre les 2 process. Le pipe est créé par la HMI, laquelle attends ensuite la connexion du moteur puis lorsque la connexion est établie, la HMI crée un thread qui se chargera de lire les données reçues du moteur et de mettre à jour l'interface graphique.
La HMI accuse un léger retard par rapport au moteur, mais ca permet au moteur de tourner plus vite. Bref, ça fonctionne bien.
Jusqu'à ce que l'utilisateur fasse un clic quelque part : la HMI envoie la demande au moteur à travers son interface COM. Et là, il arrive de façon aléatoire que la HMI se fige complètement. TOTALEMENT.
Je ne comprends pas ce qu'il se passe, je n'ai aucune piste. Je croyais avoir bien fait les choses, autant dans la gestion du pipe que dans celle des objets COM.
Voici le code du moteur :
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 {$REGION 'Moteur'} {$REGION 'Connexion au pipe'} repeat kernel.CursorPipeHandle := CreateFile(pwidechar(format('\\.\pipe\%0:s',[_IN_sCurseurPipeName])), GENERIC_WRITE, 0, nil, OPEN_EXISTING, FILE_FLAG_WRITE_THROUGH, 0); until kernel.CursorPipeHandle <> INVALID_HANDLE_VALUE ; {$ENDREGION} {$REGION 'Ecriture dans le pipe'} procedure EcireDansPipe(); const g_PipeBufferSizeCursors = 100 ; var l_iWrittenInDefectPipe : Cardinal ; l_acBufferCursorPipe: array [0 .. g_PipeBufferSizeCursors - 1] of char; l_sStrCursorPipe: pchar; begin l_sStrCursorPipe := PWideChar(format('blabla',[])); fillchar(l_acBufferCursorPipe, g_PipeBufferSizeCursors, #0); move(l_sStrCursorPipe[0], l_acBufferCursorPipe[0], Length(l_sStrCursorPipe) * Sizeof(char)); WriteFile(kernel.CursorPipeHandle, l_acBufferCursorPipe[0], Length(l_sStrCursorPipe) * Sizeof(char), l_iWrittenInDefectPipe, nil); if(l_iWrittenInDefectPipe <> (Length(l_sStrCursorPipe) * Sizeof(char)))then begin exit ; end; end; {$ENDREGION} {$ENDREGION}
Et voici le code de la HMI :
Quelqu'un a une idée ?
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 {$REGION 'HMI'} const g_PipeBufferSize = 32768 ; {$REGION 'Création du pipe et attente de connexion'} procedure TCursorPipeReaderManager.Execute; var l_iHandleNewPipe : THandle; begin l_iHandleNewPipe := CreateNamedPipe(PWidechar(format('\\.\pipe\%0:s',[self.mPr_sPipeName])), PIPE_ACCESS_DUPLEX, PIPE_TYPE_MESSAGE or PIPE_READMODE_MESSAGE or PIPE_WAIT, PIPE_UNLIMITED_INSTANCES, g_PipeBufferSize, g_PipeBufferSize, 0, nil); ConnectNamedPipe(l_iHandleNewPipe, nil); mPr_PipeReader := TPipeReaderCursors.Create(l_iHandleNewPipe, true); mPr_PipeReader.FreeOnTerminate := true ; mPr_PipeReader.sName := self.mPr_sPipeName ; mPr_PipeReader.InfoNotification := self.mPr_InfoNotification ; mPr_PipeReader.Start ; end; {$ENDREGION} {$REGION 'Thread de lecture du pipe'} procedure TPipeReaderCursors.Execute; // thread var l_iRead: cardinal; l_dOccupationEnPourcentage : double ; l_sMsg : string ; l_acBuffer: array[0..g_PipeBufferSize - 1] of char; l_bSuccess : boolean ; procedure Traiter(const _IN_sReçu : string); begin l_dOccupationEnPourcentage := (mPr_iRemplissage/g_PipeBufferSize) * 100 ; if(assigned(mPr_InfoNotification))then begin Synchronize(procedure begin // Mise à jour de la HMI. mPr_InfoNotification(self.sName, l_dOccupationEnPourcentage, _IN_sReçu); end); end; end; procedure LocalFinalize(); begin DisconnectNamedPipe(mPr_iHandlePipe); CoUninitialize(); end; begin CoInitialize(nil); try while not self.terminated do begin l_sMsg := ''; FillChar(l_acBuffer, g_PipeBufferSize, #0); l_bSuccess := ReadFile(mPr_iHandlePipe, l_acBuffer[0], g_PipeBufferSize, l_iRead, nil); if Terminated then begin LocalFinalize(); exit ; end; if((l_bSuccess = false) or (l_iRead = 0))then begin LocalFinalize(); exit ; end else begin l_sMsg := l_sMsg + Copy(l_acBuffer, 0, l_iRead); mPr_iRemplissage := GetFileSize(mPr_iHandlePipe,nil) ; Traiter(l_sMsg); end; end; Except on E : exception do begin LocalFinalize(); exit; end; end; LocalFinalize(); end; {$ENDREGION} {$REGION 'Méthode évènementielle sur HMI'} procedure onBtnClick(Sender : TObject); begin // Appel d'une méthode chez le Moteur via son interface COM. // L'exécution de cette ligne provoque de façon aléatoire le figeage total de la HMI. Hmi.m_fKernel.HtkEvent_BtnOnClick(...); end; {$ENDREGION} {$ENDREGION}
Partager