API FindWindow non fonctionnelle sur Windows 7 64 Bits
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 :
Code:
1 2
| lServiceHandle := FindWindow('TApplication', '<Nom de mon service>');
lTrayAppHandle := FindWindow('TApplication', '<Nom de l'application Tray Icon>'); |
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.
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 :
Code:
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; |
Ca fait deux jours que je sèche sur ce problème totalement incompréhensible.
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.