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

Langage Delphi Discussion :

[D2010] Hook clavier souris


Sujet :

Langage Delphi

  1. #1
    Expert éminent
    Avatar de Lung
    Profil pro
    Analyste-programmeur
    Inscrit en
    Mai 2002
    Messages
    2 664
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Analyste-programmeur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2002
    Messages : 2 664
    Points : 6 967
    Points
    6 967
    Par défaut [D2010] Hook clavier souris
    Je suis en train d'essayer de faire un hook (clavier et souris) avec Delphi 2010, mais j'obtiens une violation d'accès (j'ai déjà fait des hook clavier, sans problème avec Delphi 6).
    Voici ma DLL :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    library DLLHook;
     
    uses Windows, UnitFonctions in 'UnitFonctions.pas';
     
    {$R *.res}
     
    begin
       _nFInstance := HInstance;
       _nMemPartagee := CreateFileMapping($FFFFFFFF, nil, PAGE_READWRITE, 0, SizeOf(TDonnees), 'Hooks clavier souris');
       _VueDonnees := MapViewOfFile(_nMemPartagee, FILE_MAP_WRITE, 0, 0, 0);
    end.
    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
    unit UnitFonctions;
     
    interface
     
    uses Windows, Messages;
     
    const
       WM_CLAVIER = WM_APP + 1;
       WM_SOURIS = WM_APP + 2;
     
    type
       TDonnees = record
          KeyboarddHookHandle: HHOOK;      // Handle du hook du clavier.
          MouseHookHandle: HHOOK;      // Handle du hook de la souris.
          InfoSouris: MOUSEHOOKSTRUCT;
          hDestWindow: HWND;  
       end;
       PDonnees = ^TDonnees;
     
       procedure InitHook(hDest : HWND);   export;   stdcall;
       function KeyboardProc(nCode, wParam, lParam: Integer): Integer;   stdcall;
       function MouseProc(nCode, wParam, lParam: Integer): Integer;   stdcall;
       procedure EndHook;   export;   stdcall;
       procedure UnloadLibrary;   export;   stdcall;
     
    var
       _nFInstance: Cardinal;      // Handle d'instance de la DLL.
       _nMemPartagee: Cardinal;      // Handle de la zone de mémoire partagée.
       _VueDonnees: PDonnees;      // Pointeur vers la zone de mémoire.
     
    implementation
     
    procedure InitHook(hDest: HWND);
    begin
       _VueDonnees^.KeyboarddHookHandle := SetWindowsHookEx(WH_KEYBOARD, @KeyboardProc, _nFInstance, 0);
       _VueDonnees^.MouseHookHandle := SetWindowsHookEx(WH_MOUSE, @MouseProc, _nFInstance, 0);
     
       _VueDonnees^.hDestWindow := hDest;
    end;
     
    function KeyboardProc(nCode, wParam, lParam: Integer): Integer;
    begin
       if nCode >= 0 then
       begin
          PostMessage(_VueDonnees^.hDestWindow, WM_CLAVIER, wParam, lParam);
       end;
     
       Result := CallNextHookEx(_VueDonnees^.KeyboarddHookHandle, nCode, wParam, lParam);
    end;
     
    function MouseProc(nCode, wParam, lParam: Integer): Integer;
    begin
       if nCode >= 0 then
       begin
          // Si clic-gauche.
          if(wParam = WM_LBUTTONDOWN) then
          begin
             _VueDonnees.InfoSouris := PMouseHookStruct(lParam)^;      // Récupère les infos.
             PostMessage(_VueDonnees^.hDestWindow, WM_SOURIS, wParam, LongInt(@_VueDonnees.InfoSouris));
          end;
       end;
     
       Result := CallNextHookEx(_VueDonnees^.MouseHookHandle, nCode, wParam, lParam);
    end;
     
    procedure EndHook;
    begin
       // Supression des hooks.
       UnhookWindowsHookEx(_VueDonnees^.KeyboarddHookHandle);
       UnhookWindowsHookEx(_VueDonnees^.MouseHookHandle);
    end;
     
    procedure UnloadLibrary;
    begin
       UnmapViewOfFile(_VueDonnees);
       CloseHandle(_nMemPartagee);
    end;
     
    end.
    Et voici l'application appelante :
    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
      private
          _nHInstDLL: Cardinal;
          _bHook: Boolean;
          _InitHooks: procedure(hDest: HWND);   stdcall;
          _EndHooks: procedure;   stdcall;
          _UnloadLibrary: procedure;   stdcall;
     
          procedure EvenementClavier(var P: TWMKey);   message WM_CLAVIER;
          procedure EvenementSouris(var P: TWMMouse);   message WM_SOURIS;
     
      public
        { Déclarations publiques }
      end;
     
    var
      Form1: TForm1;
     
    implementation
     
    {$R *.dfm}
     
    procedure TForm1.FormCreate(Sender: TObject);
    begin
       _bHook := False;
       _nHInstDLL := LoadLibrary(PChar(ExtractFilePath(Application.ExeName) + 'DLLHook.dll'));
       if _nHInstDLL = 0 then
          Application.MessageBox(PChar('Erreur :  le chargement de la DLL (DLLHook.dll) a échoué !' + #13#10 + SysErrorMessage(GetLastError)), PChar(Caption + ' - erreur'), MB_ICONERROR + MB_OK)
       else
       begin
          _InitHooks := GetProcAddress(_nHInstDLL, 'InitHook');
          _EndHooks := GetProcAddress(_nHInstDLL, 'EndHook');
          _UnloadLibrary := GetProcAddress(_nHInstDLL, 'UnloadLibrary');
          _bHook := True;
     
          if _nHInstDLL <> 0 then
             _InitHooks(Form1.Handle);
       end;
    end;
     
    procedure TForm1.EvenementClavier(var P: TWMKey);
    begin
       Memo.Lines.Add('Clavier :');
    end;
     
    procedure TForm1.EvenementSouris(var P: TWMMouse);
    begin
       Memo.Lines.Add('Souris :');
    end;
     
    procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
    begin
       if _bHook then
          _EndHooks;
     
       if _nHInstDLL <> 0 then
       begin
          _UnloadLibrary;
          FreeLibrary(_nHInstDLL);
       end;
    end;
    J'obtiens une violation d'accès au moment de l'appel InitHooks.
    Par contre SetWindowsHookEx et MapViewOfFile ont été exécuté sans erreur.
    Qu'est ce que j'ai mal fait ?
    L'urgent est fait, l'impossible est en cours, pour les miracles prévoir un délai. ___ Écrivez dans un français correct !!

    C++Builder 5 - Delphi 6#2 Entreprise - Delphi 2007 Entreprise - Delphi 2010 Architecte - Delphi XE Entreprise - Delphi XE7 Entreprise - Delphi 10 Entreprise - Delphi 10.3.2 Entreprise - Delphi 10.4.2 Entreprise - Delphi 11.1 Entreprise
    OpenGL 2.1 - Oracle 10g - Paradox - Interbase (XE) - PostgreSQL (15.4)

  2. #2
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 694
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 694
    Points : 13 130
    Points
    13 130
    Par défaut
    Modifie déjà ce Form1.Handle. Form1 n'est valide dans l'événement OnCreate que si la fiche est créée en utilisant Application.CreateForm, pas par TForm1.Create.

    Sinon, rien ne me saute aux yeux dans InitHook elle-même.

    Par contre l'utilisation du fichier mappé n'est pas bonne. CreateFileMapping et MapViewOfFile doivent être appelés par tous les processus lors de l'injection (DLL_PROCESS_ATTACH) et non simplement au chargement de la DLL. Telles quelles, _nFInstance, _nMemPartagee et _VueDonnees ne sont valides que pour le processus "installateur" ; VA assurée dans les autres processus (_VueDonnees = nil)...

    L'utilisation du fichier mappé est tout de même discutable ici. Le premier paramètre de CallNextHookEx est ignoré depuis au moins Windows 2000, "0" fait parfaitement l'affaire et FindWindow est suffisant dans la plupart des cas pour retrouver une fenêtre

  3. #3
    Expert éminent
    Avatar de Lung
    Profil pro
    Analyste-programmeur
    Inscrit en
    Mai 2002
    Messages
    2 664
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Analyste-programmeur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2002
    Messages : 2 664
    Points : 6 967
    Points
    6 967
    Par défaut
    Citation Envoyé par Andnotor Voir le message
    Modifie déjà ce Form1.Handle. Form1 n'est valide dans l'événement OnCreate que si la fiche est créée en utilisant Application.CreateForm, pas par TForm1.Create.

    C'est fait.

    Citation Envoyé par Andnotor Voir le message
    Par contre l'utilisation du fichier mappé n'est pas bonne. CreateFileMapping et MapViewOfFile doivent être appelés par tous les processus lors de l'injection (DLL_PROCESS_ATTACH) et non simplement au chargement de la DLL.
    J'ai tout déplacé au début de la procédure InitHook.

    Citation Envoyé par Andnotor Voir le message
    L'utilisation du fichier mappé est tout de même discutable ici.
    C'est à dire ?
    Le code que j'utilise, je l'ai trouvé (à peu prêt) tel quel. Je devine le fonctionnement des différentes fonctions dans les grandes lignes, mais pas plus.

    Citation Envoyé par Andnotor Voir le message
    FindWindow est suffisant dans la plupart des cas pour retrouver une fenêtre
    Je ne comprend pas de quoi tu parles ...
    Tu peux expliquer ?

    Sinon, j'ai toujours ma violation d'accès.
    L'urgent est fait, l'impossible est en cours, pour les miracles prévoir un délai. ___ Écrivez dans un français correct !!

    C++Builder 5 - Delphi 6#2 Entreprise - Delphi 2007 Entreprise - Delphi 2010 Architecte - Delphi XE Entreprise - Delphi XE7 Entreprise - Delphi 10 Entreprise - Delphi 10.3.2 Entreprise - Delphi 10.4.2 Entreprise - Delphi 11.1 Entreprise
    OpenGL 2.1 - Oracle 10g - Paradox - Interbase (XE) - PostgreSQL (15.4)

  4. #4
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 694
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 694
    Points : 13 130
    Points
    13 130
    Par défaut
    Citation Envoyé par Lung Voir le message
    J'ai tout déplacé au début de la procédure InitHook.
    Et bien c'est faux ! L'installation des hooks ne se fait qu'une fois mais la création du fichier mappé et de la vue doit se faire plusieurs fois : une fois par processus dans lesquels la DLL sera injecté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
    procedure DllEntryPoint(dwReason :dword);
    begin
      case dwReason of
        Dll_Process_Attach : begin
                               _nMemPartagee := CreateFileMapping(...);
                               _VueDonnees   := MapViewOfFile(...);
                             end;
     
        Dll_Process_Detach : begin
                               UnmapViewOfFile(_VueDonnees);
                               CloseHandle(_nMemPartagee);
                             end;
      end;
    end;
     
    begin
      DLLProc := @DllEntryPoint;
      DLLEntryPoint(Dll_Process_Attach);
    end.
    Maintenant VA sur InitHook, je ne vois pas trop. StdCall dans l'interface mais pas dans l'implémentation ? De toute façon, je l'écrirais plutôt ainsi :

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    implementation
     
    procedure InitHook(hDest: HWND); stdcall;
    begin
      ...
    end;
     
    exports
      InitHook;
    Sinon, ça peut aussi être une VA dans MouseHook (si la souris a déjà été déplacée) puisque telle quelle _VueDonnees vaut nil dans les processus distants
    Quel est le titre de la fenêtre d'erreur ? Ton application ou une autre ?

    Citation Envoyé par Lung Voir le message
    Je ne comprend pas de quoi tu parles ...
    Tu utilises le fichier mappé pour :
    1. stocker les handles des hooks. Inutile puisque CallNextHookEx n'en a pas (plus) besoin ;
    2. stocker le handle de la fenêtre de destination des messages. Me semble inutile dès lors que tu peux la retrouver par FindWindow.
    3. stocker une copie de MouseStruct. Mais la validité du contenu au traitement du PostMessage par ton application est plus qu'incertaine... A la place, regarde ce tuto qui conviendra parfaitement à cet usage

    Et ce que tu n'as pas encore prévu : la synchronisation (mutex) et bien sûr... les droits d'accès ! Une application d'intégrité inférieure aura un bel Access denied et pas besoin d'UAC pour ça, IE en mode protégé suffit ! A l'arrivée, DeadLock de IE assuré !

  5. #5
    Expert éminent
    Avatar de Lung
    Profil pro
    Analyste-programmeur
    Inscrit en
    Mai 2002
    Messages
    2 664
    Détails du profil
    Informations personnelles :
    Âge : 43
    Localisation : France, Haute Savoie (Rhône Alpes)

    Informations professionnelles :
    Activité : Analyste-programmeur
    Secteur : High Tech - Éditeur de logiciels

    Informations forums :
    Inscription : Mai 2002
    Messages : 2 664
    Points : 6 967
    Points
    6 967
    Par défaut
    Citation Envoyé par Andnotor Voir le message
    Sinon, ça peut aussi être une VA dans MouseHook (si la souris a déjà été déplacée) puisque telle quelle _VueDonnees vaut nil dans les processus distants
    Comment peut-elle valoir nil ?
    Ma fonction MouseProc ne peut se déclancher qu'à partir du moment où l'instruction SetWindowsHookEx(WH_MOUSE, @MouseProc, _nFInstance, 0); a été appelée, non ?

    Citation Envoyé par Andnotor Voir le message
    Quel est le titre de la fenêtre d'erreur ? Ton application ou une autre ?
    L'application appelante de la DLL.

    Citation Envoyé par Andnotor Voir le message
    stocker le handle de la fenêtre de destination des messages. Me semble inutile dès lors que tu peux la retrouver par FindWindow.
    Pourquoi rechercher avec un FindWindow le handle de l'application que j'ai déjà (et qui ne risque pas de changer) ?

    Citation Envoyé par Andnotor Voir le message
    stocker une copie de MouseStruct. Mais la validité du contenu au traitement du PostMessage par ton application est plus qu'incertaine...
    Pourquoi incertaine ?
    Qui d'autre que ma fonction peut remplir MouseStruct ?

    Citation Envoyé par Andnotor Voir le message
    Et ce que tu n'as pas encore prévu : la synchronisation (mutex)
    La synchronisation de quoi ?
    Utiliser PostMessage au lieu de SendMessage, c'est pas justement pour ne pas bloquer la DLL ?
    L'urgent est fait, l'impossible est en cours, pour les miracles prévoir un délai. ___ Écrivez dans un français correct !!

    C++Builder 5 - Delphi 6#2 Entreprise - Delphi 2007 Entreprise - Delphi 2010 Architecte - Delphi XE Entreprise - Delphi XE7 Entreprise - Delphi 10 Entreprise - Delphi 10.3.2 Entreprise - Delphi 10.4.2 Entreprise - Delphi 11.1 Entreprise
    OpenGL 2.1 - Oracle 10g - Paradox - Interbase (XE) - PostgreSQL (15.4)

  6. #6
    Rédacteur/Modérateur
    Avatar de Andnotor
    Inscrit en
    Septembre 2008
    Messages
    5 694
    Détails du profil
    Informations personnelles :
    Localisation : Autre

    Informations forums :
    Inscription : Septembre 2008
    Messages : 5 694
    Points : 13 130
    Points
    13 130
    Par défaut
    Citation Envoyé par Lung Voir le message
    Comment peut-elle valoir nil ?
    Si tu veux utiliser un fichier mappé, c'est bien pour partager des données entre processus, non ?
    VueDonnees n'est pas partagée, c'est juste une variable globale définie dans la DLL et son allocation est propre au processus. Ce que tu n'as pas compris est que l'injection de la DLL dans un autre processus va réallouer une autre variable VueDonnees.

    Tu auras une variable distinct VueDonnees par processus.

    Citation Envoyé par Lung Voir le message
    Ma fonction MouseProc ne peut se déclancher qu'à partir du moment où l'instruction SetWindowsHookEx(WH_MOUSE, @MouseProc, _nFInstance, 0); a été appelée, non ?
    Bien sûr mais à la fin tu appelles CallNextHookEx sur une variable à nil (VueDonnees), conséquence VA !

    Citation Envoyé par Lung Voir le message
    L'application appelante de la DLL.
    Donc ton application et là aucun problème ne me saute aux yeux (à part cette histoire d'export/stdcall précisée précédemment) !

    Citation Envoyé par Lung Voir le message
    Pourquoi rechercher avec un FindWindow le handle de l'application que j'ai déjà (et qui ne risque pas de changer) ?
    Que tu auras lorsque le fichier mappé sera utilisé correctement
    C'était juste histoire de dire que pour ce Handle, le fichier mappé n'avait pas un caractère obligatoire.

    Citation Envoyé par Lung Voir le message
    Pourquoi incertaine ? Qui d'autre que ma fonction peut remplir MouseStruct ?
    Dès lors que la notification passe par PostMessage (asynchrone), plusieurs cliques peuvent survenir avant que ton application ait la main pour s'en occuper. Résultat : elle traitera N fois le dernier !

    Citation Envoyé par Lung Voir le message
    La synchronisation de quoi ?
    Utiliser PostMessage au lieu de SendMessage, c'est pas justement pour ne pas bloquer la DLL ?
    Rien à voir. Lorsque ton app lit la donnée, qui te dit qu'un hook (un autre processus) n'est pas en train de la rafraîchir ?

Discussions similaires

  1. [Débutant] Hook Clavier Souris sous DirectX C#
    Par landsraad59 dans le forum C#
    Réponses: 8
    Dernier message: 24/03/2015, 10h48
  2. [À télécharger] Mise en oeuvre des Hooks clavier / souris
    Par pottiez dans le forum Téléchargez
    Réponses: 0
    Dernier message: 09/11/2010, 17h36
  3. Réponses: 1
    Dernier message: 09/04/2009, 09h45
  4. [WIN32] Hook clavier / souris
    Par olive_le_malin dans le forum MFC
    Réponses: 6
    Dernier message: 07/06/2006, 15h21
  5. Clavier / Souris Sans Fil problème installation
    Par Harbaingan dans le forum Matériel
    Réponses: 3
    Dernier message: 17/05/2004, 17h11

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