Besoin d'aide pour mon script de simulation de clics

Résolu
grandMOJ Messages postés 10 Date d'inscription jeudi 23 février 2012 Statut Membre Dernière intervention 13 mai 2012 - 26 févr. 2012 à 14:38
grandMOJ Messages postés 10 Date d'inscription jeudi 23 février 2012 Statut Membre Dernière intervention 13 mai 2012 - 7 mars 2012 à 23:06
Bonjour à toutes et à tous !

Je viens tout juste de découvrir le C# et, pour me familiariser avec ses rudiments, j'élabore un mini-programme qui, mine de rien, peut s'avérer très utile. Il consiste à générer l'effet d'un clic sur une fenêtre sans passer par l'intermédiaire du curseur. Autrement dit, il ne devra y avoir aucune perte de contrôle de la souris par l'utilisateur, et les clics se doivent de fonctionner même quand l'application est minimisée !

Il se lance via la ligne de commande suivante :
simulation_clic.exe 'handle' 'x_absolu' 'y_absolu'

... Et voici mon code source :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Runtime.InteropServices;
using System.Drawing;
using System.Windows.Forms;

namespace ConsoleApplication2
{
    class source
    {  
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
        static extern bool ScreenToClient(IntPtr hWnd, ref Point lpPoint);


        // Le programme se lance avec la ligne de commande suivante :
        // simulation_clic.exe 'handle' 'X_absolu' 'Y_absolu'
        static void Main(string[] args)
        {              
            // Récupération des paramètres et modification des types de variables
            IntPtr handle = Marshal.StringToHGlobalUni(args[0]);
            int X_absolu = int.Parse(args[1]);
            int Y_absolu = int.Parse(args[2]);

            // Conversion des deux 'int' en un 'Point'
            Point coord_fenetre = new Point(X_absolu, Y_absolu);

            // Transformation des coordonnées absolues en coordonnées relatives à la fenêtre
            ScreenToClient(handle, ref coord_fenetre);

            Console.WriteLine(coord_fenetre);
            // ScreenToClient n'a eu aucun effet, les coordonnées sont restées les mêmes !!!
            


            // Il me faudrait maintenant utiliser les API Win32 pour simuler un clic dans le référentiel de mon handle
            //   ...
        }
    }
}


Voilà, je n'ai donc pas réussi à convertir mes coordonnées relatives en coordonnées absolues, et je n'ai pas trouvé une façon juste, comprise par le Studio, de simuler le clic.

Pouvez-vous m'aider à finir mon script ?

Merci d'avance !

7 réponses

Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
29 févr. 2012 à 11:50
Je suis pris sur un autre projet.. mais pour répondre rapidement :

- Ajoute la lib RawInput.NET.dll à ton projet.
- Ajoute le namespace Windows.RawInput dans ton fichier source.

et le code

Input[ ] inputs = new Input[ 3 ];
inputs[ 0 ].SetInput( x, y, 0, MouseInput.MouseMove );
inputs[ 1 ].SetInput( 0, 0, 0, MouseInput.LeftButtonDown );
inputs[ 2 ].SetInput( 0, 0, 0, MouseInput.LeftButtonUp );
Input.SendInput( inputs );
3
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
27 févr. 2012 à 08:21
Salut, ce n'est pas évident de corriger ton code car à peu près tout est faux ^^

Un handle de fenêtre (HWND) est un objet particulier qu'on récupère grâce aux fonctions Win32, le framework .NET n'a pas été pensé pour gérer ce genre de handle et c'est un peu compliqué pour un débutant d'utiliser ces fonctions Win32.

La fonction Marshal.StringToHGlobalUni n'a absolument rien à faire dans ton code, elle permet d'allouer une chaine managée dans la mémoire non managée.

Pour simuler un click on utilise la fonction SendInput, elle aussi une fonction Win32 qui n'appartient pas au framework .NET.
0
grandMOJ Messages postés 10 Date d'inscription jeudi 23 février 2012 Statut Membre Dernière intervention 13 mai 2012
27 févr. 2012 à 19:20
Salut !

Tout d'abord merci pour cette réponse très explicative ! J'ai depuis corrigé et amélioré mon code, dans le sens où j'ai compris que le handle d'une fenêtre stocké dans une variable ne l'était pas sous la forme '000xFFF'. De même, j'ai réussi à trouver comment utiliser, certes de façon très approximative, les API Windows dans le but de simuler un "clic indépendant du pointeur".

La ligne de commande de mon programme est dorénavant la suivante : simulation_clic.exe 'titre de la fenêtre' 'x_absolu' 'y_absolu'
La source quant à elle la voici :

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using System.Runtime.InteropServices;
using System.Drawing;
using System.Windows.Forms;

namespace ConsoleApplication2
{
    class source
    {
        private const uint WM_LBUTTONDOWN = 0x0201;
        private const uint WM_LBUTTONUP = 0x0202;

        private static readonly IntPtr MK_LBUTTON = new IntPtr(0x0001);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        private static extern int SendMessage(IntPtr hWnd, int wMsg, IntPtr wParam, IntPtr lParam);

        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true, ExactSpelling = true)]
        static extern bool ScreenToClient(IntPtr hWnd, ref Point lpPoint);

        private class NativeMethods
        {
            [DllImport("user32.dll", SetLastError = false)]
            internal static extern bool PostMessage(IntPtr hWnd, uint Msg, IntPtr wParam, IntPtr lParam);
        }

        [DllImport("user32.dll", EntryPoint = "FindWindow")]
        private static extern int FindWindow(string sClass, string sWindow);



           /* Le programme se lance avec la ligne de commande suivante :
           simulation_clic.exe "titre de la fenêtre" X_absolu Y_absolu */

        static void Main(string[] args)
        {              
            // Récupération des paramètres et modification des types de variables
            string titre_fenetre = args[0];
            int X_absolu = int.Parse(args[1]);
            int Y_absolu = int.Parse(args[2]);
            
            // Détermination du handle de la fenêtre en fonction de son titre
            int handle_int = FindWindow(null, titre_fenetre);
            IntPtr handle = new IntPtr(handle_int);

            // Conversion des deux 'int' en un 'Point'
            Point coord_fenetre = new Point(X_absolu, Y_absolu);

            // Transformation des coordonnées absolues en coordonnées relatives à la fenêtre
            ScreenToClient(handle, ref coord_fenetre);


            // ... Jusque là c'est ok !


            // Mise au point du lParam
            IntPtr lParam = new IntPtr(coord_fenetre.X | (coord_fenetre.Y << 16));

            // Simulation du clic
            NativeMethods.PostMessage(handle, WM_LBUTTONDOWN, MK_LBUTTON, lParam);
            NativeMethods.PostMessage(handle, WM_LBUTTONUP, IntPtr.Zero, lParam);

            // Le clic ne s'exécute pas...
        }
    }
}


La syntaxe semble correcte, je suis approuvé par le débogueur et je pense avoir respecté consciencieusement les standards de Microsoft.
De plus, ma fenêtre est bel est bien reconnue, et mes coordonnées absolues sont véritablement converties en coordonnées relatives à celle-ci.

Et pourtant, le clic ne s'exécute toujours pas !!

Pouvez-vous m'indiquer ce qui cloche ?

PS : Je tourne sous Windows 7 64bits si jamais ça changeait quelque chose (on parle d'API Win32 alors voilà...)
0
Lutinore Messages postés 3246 Date d'inscription lundi 25 avril 2005 Statut Membre Dernière intervention 27 octobre 2012 41
28 févr. 2012 à 11:08
Sûrement une limitation de PostMessage, la fonction n'est peut être pas autorisée à accéder a une fenêtre d'un autre processus, ou du moins pour ces messages en particulier.. J'ai pas le courage de me replonger dans la documentation de PostMessage.

Essaye avec SendMessage, tu peux t'inspirer de ma fonction WriteToNotepad :

http://www.csharpfr.com/forum/sujet-CSHARP-OUVRIR-NOTEPAD-ECRIRE-DEDANS_1233180.aspx

Et dans ma lib RawInput, tu trouveras un classe "Input" qui permet de simuler la souris :

http://www.csharpfr.com/codes/LIBRAIRIE-RAWINPUT-NET_43573.aspx
0

Vous n’avez pas trouvé la réponse que vous recherchez ?

Posez votre question
grandMOJ Messages postés 10 Date d'inscription jeudi 23 février 2012 Statut Membre Dernière intervention 13 mai 2012
28 févr. 2012 à 13:45
OK merci ! J'y jetterai un œil. Mais avant, tu pourrais m'assurer que via ces fonctions-là le clic sera simulé de façon indépendante à la souris ? J'ai peur de me faire de faux espoirs...
0
grandMOJ Messages postés 10 Date d'inscription jeudi 23 février 2012 Statut Membre Dernière intervention 13 mai 2012
28 févr. 2012 à 23:13
Re ! J'ai essayé de m'inspirer SendMessage, mais malheureusement cela ne marche toujours pas . Je vais donc m'orienter vers ta librairie, mais le fait est que je suis novice, et par extension je ne sais trop comment l'intégrer dans un projet console par défaut ^^

Pourrais-tu s'il te plaît me montrer un code exemple, complet sur les débuts, faisant usage de celle-ci ? (avec les "using", les importations de dll, etc. un truc lançable quoi ! )

Merci d'avance !
0
grandMOJ Messages postés 10 Date d'inscription jeudi 23 février 2012 Statut Membre Dernière intervention 13 mai 2012
7 mars 2012 à 23:06
J'ai finalement trouvé, mais merci quand même !
0
Rejoignez-nous