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 :
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}
Quelqu'un a une idée ?