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

Lazarus Pascal Discussion :

Piloter une application par un logiciel : utiliser l'assembleur et les interruptions [Lazarus]


Sujet :

Lazarus Pascal

  1. #1
    Candidat au Club
    Homme Profil pro
    ouvrier
    Inscrit en
    Mai 2014
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Saône et Loire (Bourgogne)

    Informations professionnelles :
    Activité : ouvrier
    Secteur : Bâtiment

    Informations forums :
    Inscription : Mai 2014
    Messages : 3
    Points : 3
    Points
    3
    Par défaut Piloter une application par un logiciel : utiliser l'assembleur et les interruptions
    Bonjour.

    Je voudrais pouvoir piloter une application par un logiciel écrit sous Lazarus.

    Pour simuler les frappes touches, j' ai essayé d'utiliser la fonction keybd_event, cela fonctionne en test avec NotePad mais pas avec mon autre application.

    Je n'ai même pas réussi à faire fonctionner SendInput ( qui avait l'air intéressant ).

    Et maintenant, j'essaie d'envoyer directement le code touche dans le buffer clavier.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    procedure TForm1.Button2Click(Sender: TObject);
    begin
      asm
      mov  ah, 05h
      mov  ch, 18
      mov  cl, 69
      int  16h
      not  al
    end;
    end;
    Et à l’exécution, j'obtiens un message d'erreur:
    Le projet Projet1 a levé une exception de class 'External: SIGSEGV'
    In file 'unit1.pas' at line 62: int 16h
    Je ne suis pas un as, il semblerait que le problème vienne du fait que Windows tourne en mode protégé et ne tolère pas que l'on lance une interruption.

    Si vous avez des moyens de faire tourner ce petit bout de programme, ou bien si vous connaissez d'autres fonctions pour l'envoi de touche, je suis preneur.

    Merci.

  2. #2
    Membre chevronné

    Homme Profil pro
    au repos
    Inscrit en
    Février 2014
    Messages
    429
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : au repos

    Informations forums :
    Inscription : Février 2014
    Messages : 429
    Points : 1 884
    Points
    1 884
    Par défaut
    Bonjour,

    Si tu utilises la fonction keybd_event, Windows envoie en retour un ou plusieurs messages (WM_CHAR, WM_KEYDOWN...).
    Alors, pourquoi n'adresses-tu pas directement un message windows à l'application pilotée ?
    Pour cela, il faut connaitre le handle de celle-ci.

    Avec ce petit bout de code, j'ouvre par exemple dans le tableur Open Office la fenêtre de correction d'orthographe (raccourci : F7)

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
     
    var
      H : Hwnd;
    begin
        H:= FindWindow(nil, PChar('Sans nom 1 - OpenOffice Calc'));
        if H <> 0 then   // le handle est trouvé
        begin
            SetforeGroundWindow(H); // on ramène OpenOffice à l'avant-plan
            SendMessage(H, WM_KEYDOWN, VK_F7, 0); // envoi du message touche F7 down
        end;
    end;
    Thierry

  3. #3
    Expert confirmé
    Avatar de Ph. B.
    Homme Profil pro
    Freelance
    Inscrit en
    Avril 2002
    Messages
    1 784
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : France, Haute Garonne (Midi Pyrénées)

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

    Informations forums :
    Inscription : Avril 2002
    Messages : 1 784
    Points : 5 915
    Points
    5 915
    Par défaut
    Bonjour,
    Citation Envoyé par thierry prg Voir le message
    Il semblerait que le problème vienne du fait que Windows tourne en mode protégé et ne tolère pas que l'on lance une interruption.
    En effet, ce mode de fonctionnement était valable du temps du DOS, mais ne l'est plus avec Windows...
    Citation Envoyé par thierry prg Voir le message
    Si vous avez des moyens de faire tourner ce petit bout de programme, ou bien si vous connaissez d'autres fonctions pour l'envoi de touche, je suis preneur.
    ThWilliam vous a donné le principe : envoyer des messages.
    On peut simuler beaucoup de choses dont :

    Pour ce faire, il faut connaitre non pas le Handle de l'application, mais ceux des contrôles fenêtrés qui la composent. Il faut parcourir cette liste de contrôles en utilisant une fonction windows dédiée EnumChildWindows(HandleAppWindow, @EnumChildWindows, 0);, EnumChildWindows étant une fonction callback dans lequel le traitement sera fait ou appelé...

    Bref, le pilotage d'une application tiers, ça peut devenir complexe par ce biais et cela nécessite de connaitre les API Windows.
    Philippe.

  4. #4
    Candidat au Club
    Homme Profil pro
    ouvrier
    Inscrit en
    Mai 2014
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Saône et Loire (Bourgogne)

    Informations professionnelles :
    Activité : ouvrier
    Secteur : Bâtiment

    Informations forums :
    Inscription : Mai 2014
    Messages : 3
    Points : 3
    Points
    3
    Par défaut
    Merci Thierry et Philippe pour vos messages.

    J'ai fait un test de la fonction SendMessage et Notepad.

    Pour connaitre les différents handles, je me sers d'une petite application écrite en Delphi qui donne les renseignements de la fenêtre présente sous la souris ( handle de la fenêtre, nom de classe, Id du processus, nom du module ).

    Pour mon essai, je me retrouve avec deux handles, celui de la fenêtre principale ( nom de classe: Notepad ) et celui de la fenêtre d’édition ( nom de classe: Edit ).

    Et je n'ai pas réussi à envoyer une lettre à Notepad. Notepad prend le focus mais rien ne s'affiche.

    J'ai essayé les combinaisons possibles avec mes deux handles mais rien n'y fait.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    procedure TForm1.Button1Click(Sender: TObject); 
    begin
    SetForegroundWindow(17630192);                     // sélectionne l'application
    SendMessage(17630192, WM_KEYDOWN, 69, 0);  // Pression de la touche 'E'
    sleep (200);                                                   // petit délai
    SendMessage(17630192, WM_KEYUP, 69, 0);       // Lâcher de la touche
    end;
    Je tourne sous Seven avec la version 1.0.10 de Lazarus.

    Le problème doit être sous mes yeux mais à force de chercher, je passe à coté.

  5. #5
    Expert éminent sénior
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    10 700
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 700
    Points : 15 043
    Points
    15 043
    Par défaut
    Yep !
    Citation Envoyé par thierry prg Voir le message
    (...) Pour connaitre les différents handles, je me sers d'une petite application écrite en Delphi qui donne les renseignements de la fenêtre présente sous la souris ( handle de la fenêtre, nom de classe, Id du processus, nom du module ).
    C'est WindowsSpy ton outil ? Vu ta description, je vote à 99% pour oui
    Et si je m'immisce dans la conversation, c'est parce que je trouve la valeur du handle que tu utilises un peu bizarre (ou alors c'est lié à Seven ?)

    Citation Envoyé par thierry prg Voir le message
    (...)
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    SetForegroundWindow(17630192);                     // sélectionne l'application
    Si je fais tourner l'outil dans un XP virtualisé (j'ai pas plus haut), il me renvoie le handle de l'appli sur 6 chiffres, et pareil pour le handle du contrôle éditeur.

    Autre chose : je te recopie-colle une note que j'avais prise à l'époque où j'ai joué moi aussi avec SendKeys :
    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
    {oct 2004 : testé ok si SetForegroundWindow(ParentHwnd); en rem}
     
    procedure SendKeys(WinHandle:Hwnd;Buffer:String);
    var
      I: Integer;
      W: Word;
      D: DWORD;
      P: ^DWORD;
    begin
      P:=@D;
      SystemParametersInfo(SPI_GETFOREGROUNDLOCKTIMEOUT,0,P,0);
      if IsIconic(WinHandle) then
        ShowWindow(WinHandle,SW_RESTORE);
      SetForegroundWindow(WinHandle);
      For I := 1 to Length(Buffer) do
      begin
        W := VkKeyScan(Buffer[i]);
        keybd_event(w,0,0,0);
        keybd_event(w,0,KEYEVENTF_KEYUP,0);
      end;
      SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,0,nil,0);
      //SetForegroundWindow(ParentHwnd);
      SystemParametersInfo(SPI_SETFOREGROUNDLOCKTIMEOUT,D,nil,0);
    end;
     
    procedure TForm1.Button1Click(Sender: TObject);
    begin
      WinExec('notepad.exe', SW_NORMAL);
      SendKeys(FindWindowEx(FindWindow('Notepad', 'Untitled - Notepad'), 0, 'Edit', ''), 'Your Text Here');
    end;
    Faudra adapter les strings de la ligne 29.
    Il a à vivre sa vie comme ça et il est mûr sur ce mur se creusant la tête : peutêtre qu'il peut être sûr, etc.
    Oui, je milite pour l'orthographe et le respect du trait d'union à l'impératif.
    Après avoir posté, relisez-vous ! Et en cas d'erreur ou d'oubli, il existe un bouton « Modifier », à utiliser sans modération
    On a des lois pour protéger les remboursements aux faiseurs d’argent. On n’en a pas pour empêcher un être humain de mourir de misère.
    Mes 2 cts,
    --
    jp

  6. #6
    Expert confirmé
    Avatar de Ph. B.
    Homme Profil pro
    Freelance
    Inscrit en
    Avril 2002
    Messages
    1 784
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : France, Haute Garonne (Midi Pyrénées)

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

    Informations forums :
    Inscription : Avril 2002
    Messages : 1 784
    Points : 5 915
    Points
    5 915
    Par défaut
    Bonjour,
    Citation Envoyé par thierry prg Voir le message
    Pour mon essai, je me retrouve avec deux handles, celui de la fenêtre principale ( nom de classe: Notepad ) et celui de la fenêtre d’édition ( nom de classe: Edit ).
    C'est le second qui nous intéresse...
    Citation Envoyé par thierry prg Voir le message
    Et je n'ai pas réussi à envoyer une lettre à Notepad. Notepad prend le focus mais rien ne s'affiche.
    Il faut plutôt envoyer un message WM_CHAR, cad : SendMessage(Hdle, WM_CHAR, 69, 0);.

    Ensuite, la commande Sleep(200); est inutile car SendMessage est une instruction bloquante qui ne rend la main qu'une fois le message envoyé (contrairement à son homologue PostMessage) ; le message est mis dans la file de traitement du destinataire.

    Pour envoyer du texte à Notepad, je passerais par le message WM_SETTEXT

    Voici un bout de code à adapter à vos besoins (testé sous Lazarus 1.2.2 et XP 32 bits français ) :
    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
    var
      Texte: String;
     
    { ============================================================================ }
    { Cette fonction sera appelée pour chaque contrôle enfant de la fenêtre ciblée }
    { ============================================================================ }
    function EnumChildWindowsCallback(CtrlHdle: HWND; lParam: LPARAM): BOOL; stdcall;
    var
      Classe : PAnsiChar;
    begin
      try
        // Récupération du nom de la classe
        Classe := StrAlloc(16);
        GetClassName(CtrlHdle, Classe, 16);
        //
        if StrPas(Classe) = 'Edit' then   // Le nom du contrôle de Notepad où se fait la saisie
        begin
          // Vider la zone de saisie
          SendMessage(CtrlHdle, WM_CLEAR, 0, 0);
          // Copier le texte dans la zone de saisie
          SendMessage(CtrlHdle, WM_SETTEXT, 0, Integer(PAnsiChar(Texte)));
     
          // Envoyer le caractère A là où se trouve le curseur
          // SendMessage(CtrlHdle, WM_CHAR, 65, 0);
        end;
      finally
        StrDispose(Classe);
      end;
      // Pour que l'énumération continue tant qu'il existe des contrôles enfants
      Result := True;
    end;
     
    procedure SendText(Txt: String);
    var
      WinHandle: THandle;
    begin
      Texte := Txt;
      // Recherche de la fenêtre
      // Personnellement, je préfère aussi indiquer la classe pour éviter toute ambiguïté
      WinHandle := FindWindow(nil, 'Sans titre - Bloc-notes');
      if WinHandle > 0 then
      begin
        if IsWindowVisible(WinHandle) then
        begin
          // Focaliser la fenêtre
          SetForegroundWindow(WinHandle);
          // Enumérer les contrôles enfants et alimenter celui qui nous intéresse
          EnumChildWindows(WinHandle, @EnumChildWindowsCallBack, 0);
        end;
      end;
    end;
    Ne pas oublier préalablement de démarrer Notepad...
    Philippe.

  7. #7
    Membre chevronné

    Homme Profil pro
    au repos
    Inscrit en
    Février 2014
    Messages
    429
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : Belgique

    Informations professionnelles :
    Activité : au repos

    Informations forums :
    Inscription : Février 2014
    Messages : 429
    Points : 1 884
    Points
    1 884
    Par défaut
    Bonjour.

    Après tests faits avec lazarus 1.2.0 (32 bits) sous windows 7 64 bits :

    - WM_KEYDOWN et WM_KEYUP ne marchent pas avec NotePad
    - WM_CHAR : ok
    - tests des codes de Jipété et Philippe : impeccable (venant de leur part, le contraire serait étonnant). La seule différence est que l'emploi de WM_SETTEXT remplace tout le texte (même en enlevant le message WM_CLEAR).

    Mais, avec notepad, je n'obtiens pas le Handle avec :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    FindWindow(nil, 'Sans titre - Bloc-notes')
    ni
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    FindWindow('Notepad', 'Sans titre - Bloc-notes')
    Je dois faire :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    FindWindow('Notepad', nil)
    Je crois que le problème vient du fait que Notepad est en 64 bits, et que la fonction FindWindow fait partie de User32.dll
    Vu sur beaucoup de forums : beaucoup de problèmes avec FindWindow sous 64 bits.
    Mais par quoi la remplacer pour trouver le handle d'une application ?

    Thierry

  8. #8
    Candidat au Club
    Homme Profil pro
    ouvrier
    Inscrit en
    Mai 2014
    Messages
    3
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Saône et Loire (Bourgogne)

    Informations professionnelles :
    Activité : ouvrier
    Secteur : Bâtiment

    Informations forums :
    Inscription : Mai 2014
    Messages : 3
    Points : 3
    Points
    3
    Par défaut
    Merci pour vos contributions.

    Jipété ,tu as raison pour WindowsSpy.

    J'ai essayé vos sources et je suis tombé sur le même problème avec la fonction de FindWindow ( ma version de Seven est en 32 bits ).

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    WinHandle := FindWindow(nil, 'Sans titre - Bloc-notes');
    L'envoi de touche marche très bien.

    Encore merci pour votre aide.

  9. #9
    Expert confirmé
    Avatar de Ph. B.
    Homme Profil pro
    Freelance
    Inscrit en
    Avril 2002
    Messages
    1 784
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : France, Haute Garonne (Midi Pyrénées)

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

    Informations forums :
    Inscription : Avril 2002
    Messages : 1 784
    Points : 5 915
    Points
    5 915
    Par défaut
    Bonjour,
    Citation Envoyé par ThWilliam Voir le message
    La seule différence est que l'emploi de WM_SETTEXT remplace tout le texte (même en enlevant le message WM_CLEAR).
    Au temps pour moi, j'ai oublié de préciser que WM_CLEAR ne s'applique qu'à la partie de texte sélectionné et que WM_SETTEXT remplace l'intégralité... et corriger le code fourni.

    Citation Envoyé par ThWilliam Voir le message
    Mais, avec notepad, je n'obtiens pas le Handle avec :
    FindWindow(nil, 'Sans titre - Bloc-notes')
    ni
    FindWindow('Notepad', 'Sans titre - Bloc-notes')

    Je dois faire :
    FindWindow('Notepad', nil)

    Je crois que le problème vient du fait que Notepad est en 64 bits, et que la fonction FindWindow fait partie de User32.dll
    Vu sur beaucoup de forums : beaucoup de problèmes avec FindWindow sous 64 bits.
    Sur Windows 8.1 64 bits français, j'ai constate aussi ce défaut avec NotePad (avec Lazarus 32 bits ou D7, mais aussi avec XE2 32 ou 64 bits) mais pas avec d'autres applications.
    En effet, toujours avec Notepad, je constate le phénomène suivant ; j'ai rajouté le bout de code suivant :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
        try
          // Récupération du nom de la fenêtre
          WinName := StrAlloc(32);
          GetWindowTextA(WinHandle, WinName, 32);
          ShowMessage(StrPas(WinName));
        finally
          StrDispose(WinName);
        end;
    J'obtiens : 'Sans titre?- Bloc-notes'. Cette scorie ne devrait pas être, même avec un passage Ansi vers UTF8 omis. AMHA, il y a une concaténation de chaines incorrecte (Nom du fichier et titre de la fenêtre) côté Notepad...
    D'autant plus que si je réalise le test avec internet explorer, cela fonctionne parfaitement :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    WinHandle := FindWindow('IEFrame', 'D:\download\test.htm - Internet Explorer');
    Citation Envoyé par ThWilliam Voir le message
    Mais par quoi la remplacer pour trouver le handle d'une application ?
    On peut utiliser EnumWindows associée à une fonction callback, mais cela ne change rien au problème du nom de la fenêtre pour Notepad...
    Philippe.

  10. #10
    Expert éminent sénior
    Avatar de Jipété
    Profil pro
    Inscrit en
    Juillet 2006
    Messages
    10 700
    Détails du profil
    Informations personnelles :
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations forums :
    Inscription : Juillet 2006
    Messages : 10 700
    Points : 15 043
    Points
    15 043
    Par défaut
    Yop !
    Citation Envoyé par Ph. B. Voir le message
    (...) J'obtiens : 'Sans titre?- Bloc-notes'. Cette scorie ne devrait pas être, même avec un passage Ansi vers UTF8 omis. AMHA, il y a une concaténation de chaines incorrecte (Nom du fichier et titre de la fenêtre) côté Notepad...
    D'autant plus que si je réalise le test avec internet explorer, cela fonctionne parfaitement (...)
    Bien vu !

    Un dernier test que tu devrais tenter, c'est d'ouvrir (Fichier / Ouvrir...) un fichier texte existant ("test.txt" c'est bien, non ?) pour voir ce que retourne ton bout de code de récupération de la barre de titre.
    Just curious.
    Moi je ne peux pas, désolé : y a pas de Notepad.exe sous Linux , et je n'ai pas de VM 64 bits.
    Il a à vivre sa vie comme ça et il est mûr sur ce mur se creusant la tête : peutêtre qu'il peut être sûr, etc.
    Oui, je milite pour l'orthographe et le respect du trait d'union à l'impératif.
    Après avoir posté, relisez-vous ! Et en cas d'erreur ou d'oubli, il existe un bouton « Modifier », à utiliser sans modération
    On a des lois pour protéger les remboursements aux faiseurs d’argent. On n’en a pas pour empêcher un être humain de mourir de misère.
    Mes 2 cts,
    --
    jp

  11. #11
    Expert confirmé
    Avatar de Ph. B.
    Homme Profil pro
    Freelance
    Inscrit en
    Avril 2002
    Messages
    1 784
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 57
    Localisation : France, Haute Garonne (Midi Pyrénées)

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

    Informations forums :
    Inscription : Avril 2002
    Messages : 1 784
    Points : 5 915
    Points
    5 915
    Par défaut
    Citation Envoyé par Jipété Voir le message
    Un dernier test que tu devrais tenter, c'est d'ouvrir (Fichier / Ouvrir...) un fichier texte existant ("test.txt" c'est bien, non ?) pour voir ce que retourne ton bout de code de récupération de la barre de titre.
    Just curious.
    Je suis curieux moi aussi, et j'avais réalisé ce test. La scorie apparait également dans ce cas...
    Citation Envoyé par Jipété Voir le message
    Moi je ne peux pas, désolé : y a pas de Notepad.exe sous Linux , et je n'ai pas de VM 64 bits.
    Nobody is perfect
    Philippe.

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

Discussions similaires

  1. Réponses: 5
    Dernier message: 07/09/2011, 12h31
  2. Réponses: 3
    Dernier message: 18/09/2006, 17h42
  3. Réponses: 3
    Dernier message: 09/01/2006, 17h35
  4. Sécuriser l'intallation d'une application par numéro de séri
    Par dadamovic dans le forum Installation, Déploiement et Sécurité
    Réponses: 4
    Dernier message: 05/11/2005, 22h59
  5. Réponses: 2
    Dernier message: 05/12/2003, 12h37

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