Bonjour,
J'établie une communication IPC entre un service windows et une application qui affiche un TrayIcon dans la barre de tâche. Ces applications sont écrites en Delphi 2007.
Le communication IPC passe par des messages WM_COPYDATA et l'API SendMessage. Jusque là rien de bien compliqué.
Pour transmettre un message WM_COPYDATA, il faux transmettre à l'API SendMessage le handle de la fenêtre cible et le handle de l'application source.
J'utilise donc l'API FindWindow comme suit :
Ce code fonctionne parfaitement sous Windows XP mais la communication n'est en aucun cas établie sous Windows 7 : la variable lTrayAppHandle reste déseperément à 0.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 lServiceHandle := FindWindow('TApplication', '<Nom de mon service>'); lTrayAppHandle := FindWindow('TApplication', '<Nom de l'application Tray Icon>');
A souligner que le service fonctionne dans le profil local alors que l'application tourne dans le profil utilisateur.
Tests réalisés :
- Fonctionnement du service avec le compte de l'utilisateur : Non Fonctionnel
- FindWindow sur le nom de la classe de la fenêtre cachée (TTrayForm) : Non Fonctionnel
- Lecture de l'ID de processus de mon TrayIcon et recherche du handle à partir de l'ID de processus : Non Fonctionnel
Bizarrerie :
La recherche du handle de fenêtre à partir de l'ID de processus utilise l'API EnumWindows avec une fonction CallBack. Lorsque je place un point d'arrêt sur la fonction callback, je me rend compte que l'enumération n'est pas réalisée sur la totalitée des fenêtres existantes. Je ne rentre donc jamais dans la condition de la fonction callback puisque l'énumération se termine avant la lecture de toutes les fenêtres.
Pour exemple, voici le code utilisé pour la lecture du handle de fenêtre à partir de son ID de processus :
Ca fait deux jours que je sèche sur ce problème totalement incompréhensible.
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 // Lit l'ID du processus de l'application de notification // NotifyApplication est une constante contenant le nom de l'application Function GetNotifyProcessID : Integer; var ContinueLoop: BOOL; FSnapshotHandle: THandle; FProcessEntry32: TProcessEntry32; Begin Result := 0; FSnapshotHandle := CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0); FProcessEntry32.dwSize := Sizeof(FProcessEntry32); ContinueLoop := Process32First(FSnapshotHandle, FProcessEntry32); while integer(ContinueLoop) <> 0 do begin if (StrIComp(PChar(ExtractFileName(FProcessEntry32.szExeFile)), PChar(NotifyApplication)) = 0) or (StrIComp(FProcessEntry32.szExeFile, PChar(NotifyApplication)) = 0) then begin Result:= FProcessEntry32.th32ProcessID; break; end; ContinueLoop := Process32Next(FSnapshotHandle, FProcessEntry32); end; CloseHandle(FSnapshotHandle); End; // Fonction CallBack utilisé dans l'API EnumWindows appelée dans la fonction GetNotifyHandleFromProcessId function EnumNotifyWinProc(Wnd: THandle; Param: PTopLevelWnd): BOOL; stdcall; var PID: DWORD; C: array [0..Length(ClassNameOfTApplication) + 1] of Char; LengthClassName : Integer; StrClassName : String; Buffer : Array[0..99] of Char; StrWindowTitle : String; begin Try GetWindowThreadProcessId(Wnd, @PID); LengthClassName := GetClassName(Wnd, C, Length(C)); // Pour les besoins de débuggage StrClassName := StrPas(C); GetWindowText(Wnd, Buffer, 100); StrWindowTitle := StrPas(Buffer); // if (PID = Param^.ProcessID) and (LengthClassName > 0) and (C = ClassNameOfTApplication) then begin Result := False; Param^.Wnd := Wnd; end else Result := True; Except Result := True; End; end; // Lit Le handle de fenêtre à partir de l'id de processus // L'ID de processus est passé en parmètre après l'appel de la fonction GetNotifyProcessID Function GetNotifyHandleFromProcessId(AProcessID : Integer) : THandle; var TopLevelWnd: TTopLevelWnd; lRes : Boolean; lErrCode : DWord; Begin TopLevelWnd.ProcessID := AProcessID; TopLevelWnd.Wnd := 0; lRes := EnumWindows(@EnumNotifyWinProc, LPARAM(@TopLevelWnd)); if lRes then Result := TopLevelWnd.Wnd Else Begin lErrCode := GetLastError(); Result := 0; End; End;
Je m'en remet donc aux experts que vous êtes pour entrevoir une solution à ce problème totalement fou.
Par avance merci de vos retours.
Partager