IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

API, COM et SDKs Delphi Discussion :

API FindWindow non fonctionnelle sur Windows 7 64 Bits


Sujet :

API, COM et SDKs Delphi

  1. #1
    Futur Membre du Club
    Inscrit en
    Mars 2006
    Messages
    6
    Détails du profil
    Informations forums :
    Inscription : Mars 2006
    Messages : 6
    Points : 9
    Points
    9
    Par défaut 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 : 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>');
    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 : 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;
    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.

  2. #2
    Futur Membre du Club
    Inscrit en
    Mars 2006
    Messages
    6
    Détails du profil
    Informations forums :
    Inscription : Mars 2006
    Messages : 6
    Points : 9
    Points
    9
    Par défaut Mon problème... Suite !
    J'ai repris le code dans une application et non un service Window et là, tout fonctionne parfaitement.

    Auriez vous une idée ?

  3. #3
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 586
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 586
    Points : 25 254
    Points
    25 254
    Par défaut
    On peut penser que tu n'as accès vec Delphi 2007 qu'aux handles des applis Win32 tourant sur WOW64 !

    Les Autres appli 64Bits doit être dans un autre "sous-système" dont les appli 32 n'a pas accès !

    Même clivage qu'avec la Registry ?

    Tu as un Service et un Exe de Notification, un grand classique !
    Tous les deux en Win32
    WM_COPYDATA est effectivement une méthode pratique !
    Tu pourrais remplacer le FindWindow par une petite mémoire partagé (CreateFileMapping) ou tu stockes les Handles des fenêtres (chaque process ayant une zone mémoire dans la Map pour mettre ses 4 octets de handle)
    Sinon, un vrai fichier (même un ini)

    Sinon même sous Window XP selon la méthode de lancement du Service tu n'as pas accès au Bureau !
    Est-ce que WOW64 supporte qu'un service accède au bureau ???

    Pour mes services, je me fais toujours un petit programme de configuration (plus ou moins inclus avec un Notify selon l'occasion)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    begin
      ShellExecute(0, 'open', 'ServiceTarzan', '/install', nil, SW_NORMAL); //  /silent
      Sleep(1000);
     
      ShellExecute(0, 'open', 'sc.exe', PChar(Format('config "ServiceTarzan" obj= %s password= %s', [edAccountName.Text, edAccountPW.Text])), PChar(ExtractFileDir(Application.ExeName)), SW_NORMAL);
    end;
    Et il faut que l'utilisateur (celui spécifié pour le service) aie des droits suffisants pour accéder au bureau

  4. #4
    Membre expérimenté Avatar de guillemouze
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    876
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Novembre 2004
    Messages : 876
    Points : 1 448
    Points
    1 448
    Par défaut
    regarde de ce cote, ca te sera d'une grande aide je pense. Les messages ne passent pas par un handle, mais par une file de massage nommée, donc il faut juste connaitre le nom de la file que tu as créé dans un process pour pouvoir lui envoyer des messages.

  5. #5
    Futur Membre du Club
    Inscrit en
    Mars 2006
    Messages
    6
    Détails du profil
    Informations forums :
    Inscription : Mars 2006
    Messages : 6
    Points : 9
    Points
    9
    Par défaut Remerciement
    Merci à vous pour vos réponses très constructives.

    Celà m'a permis de régler le problème en utilisant la solution proposée par ShaiLeTroll.

    La réponse de guillemouze, bien que fort intéressante demandais un investissement temps que je n'ai pas actuellement.

    Je reviendrais sur ces dernières car elles semblent très intéressantes.

    Mon expérience Window 7 ne fait que commencer mais je rencontre bon nombre de problèmes liés à la nouvelle gestion de la sécurité. Celle-ci semble plus être faite pour pénaliser les développeurs plutôt que d'améliorer leurs productivités.

    Je crois que nous n'avons de toute façon pas le choix que de faire avec ces aléas.

    Encore merci pour vos réponses !!

  6. #6
    Expert éminent sénior
    Avatar de ShaiLeTroll
    Homme Profil pro
    Développeur C++\Delphi
    Inscrit en
    Juillet 2006
    Messages
    13 586
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 43
    Localisation : France, Seine Saint Denis (Île de France)

    Informations professionnelles :
    Activité : Développeur C++\Delphi
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Juillet 2006
    Messages : 13 586
    Points : 25 254
    Points
    25 254
    Par défaut
    Toujours MadShi, il a décidément une très bonne lib, ce qui est dommage, c'est que l'on a pas le vrai code utilisé !
    Et que c'est payant !

    fort possible que cela soit une bonne encaspulation de CreateNamedPipe


    Citation Envoyé par tarzan68 Voir le message
    Celà m'a permis de régler le problème en utilisant la solution proposée par ShaiLeTroll.
    Laquelle ?
    C'est intéressant, si d'autres personnes, il pourront trouver la réponse

    sc.exe ?
    Fichier Ini ?
    Fichier Mapping

    et un petit

  7. #7
    Futur Membre du Club
    Inscrit en
    Mars 2006
    Messages
    6
    Détails du profil
    Informations forums :
    Inscription : Mars 2006
    Messages : 6
    Points : 9
    Points
    9
    Par défaut
    Je suis passé par un fichier ini car je n'avais pas le temps pour faire mieux et plus propre.

    A souligner que mon problème vient probablement du fait que les services interractifs semblent être par défaut interdits sous Seven car j'obtenais le message suivant : ''Le service XXX est marqué comme étant interactif. Cependant, le système est configuré pour ne pas autoriser les services interactifs. Ce service peut ne pas fonctionner correctement.''

    Je n'ai cependant pas trouvé comment, à l'aide d'une procédure d'installation, supprimer ce verrouillage. J'ai donc désactivé le mode interractif lorsque le service est installé sous Vista ou OS ultérieur.

    Salutations,

  8. #8
    Invité
    Invité(e)
    Par défaut
    Je suis confronté au même problème, à savoir, impossible de faire communiquer un service interactif avec le bureau et une application par le biais de messages ( Windows.PostMessage ) sous Windows Seven seulement.

    Pour mettre en évidence le problème, mon service appelle le code suivant énumérant toutes les fenêtres :

    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
     
     function enumServiceWindows_callback(hWnd: THandle; Param: LPARAM): BOOL; stdcall;
      var
        className: String;
        logger : TAbstractLogger;
      begin
        logger := TAbstractLogger(Param);
        className := JvJCLUtils.WindowClassName(hWnd);
        logger.debug(Format('hWnd: %d, className: %s ', [hWnd, className ]));
      end;
     
      procedure enumServiceWindows;
      begin
        Windows.EnumWindows(@enumServiceWindows_callback, LPARAM(logger));
      end;
    Sous Windows XP, j'ai accès à toutes les fenêtres du système ( plus de 100 ).
    Sous Windows Seven, j'ai seulement accès aux fenêtres de mon service ( moins de 10 ).

    Citation Envoyé par tarzan68 Voir le message
    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 : 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>');
    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.
    Dernière modification par Invité ; 07/07/2011 à 08h12.

  9. #9
    Invité
    Invité(e)
    Par défaut
    Après avoir lu ce document de Microsoft intitulé Impact of Session 0 Isolation on Services and Drivers (http://msdn.microsoft.com/en-us/wind.../gg463353.aspx), je me rends compte qu'il faut revoir l'architechture de mon application, à savoir la communication par messages entre le service et l'application graphique.

    Voici un extrait du document :

    Potential Issues
    Any functionality in a service or a service-hosted driver that assumes the user is running in Session 0 does not work correctly in Windows Vista, Windows Server 2008, and later versions. Some examples of places where this assumption might occur are:

    ...

    A service tries to use window message functions such as SendMessage and PostMessage to communicate with an application. This does not work because the application is running in a different session and therefore has a different message queue. The messages never arrive at their destination. The same is true for applications that try to communicate with services through window messages.

  10. #10
    Membre expérimenté Avatar de guillemouze
    Profil pro
    Inscrit en
    Novembre 2004
    Messages
    876
    Détails du profil
    Informations personnelles :
    Âge : 41
    Localisation : France, Loire Atlantique (Pays de la Loire)

    Informations forums :
    Inscription : Novembre 2004
    Messages : 876
    Points : 1 448
    Points
    1 448
    Par défaut
    Citation Envoyé par stbland Voir le message
    Après avoir lu ce document de Microsoft intitulé Impact of Session 0 Isolation on Services and Drivers (http://msdn.microsoft.com/en-us/wind.../gg463353.aspx), je me rends compte qu'il faut revoir l'architechture de mon application, à savoir la communication par messages entre le service et l'application graphique.
    As tu lu mon message ?

+ Répondre à la discussion
Cette discussion est résolue.

Discussions similaires

  1. Réponses: 2
    Dernier message: 29/11/2012, 17h39
  2. .war non fonctionnelle sur Tomcat
    Par sarsar88 dans le forum Tomcat et TomEE
    Réponses: 3
    Dernier message: 08/04/2012, 20h17
  3. Page non chargée sur Windows/Qt 4.8/MingW
    Par divide dans le forum Réseau
    Réponses: 1
    Dernier message: 31/03/2012, 20h09
  4. Réponses: 8
    Dernier message: 13/09/2011, 17h06
  5. KeyPress non-fonctionnel sur textbox
    Par gwharl dans le forum C#
    Réponses: 3
    Dernier message: 08/03/2011, 21h54

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo