10
votes

Comment puis-je obtenir des fonctionnalités similaires à Spy ++ dans mon application C #?

Je suis intéressé à travailler sur un plugin pour Keepass , le gestionnaire de mots de passe open-source. En ce moment, Keepass détecte actuellement quel mot de passe pour copier / coller pour vous basé sur le titre de la fenêtre. Cela empêche de détecter le mot de passe actuel dont vous avez besoin pour les applications qui ne mettent pas activement à jour leur titre de fenêtre en fonction du site actuel (chrome par exemple).

Comment puis-je parcourir un autre processus d'éléments de fenêtre (boutons, étiquettes, zone de texte) similaire à la façon dont Spy ++ fonctionne? Lorsque vous exécutez SPY ++, vous pouvez survoler d'autres programmes Windows et obtenir toutes sortes d'informations sur diverses propriétés concernant diverses commandes (étiquettes, boîtes de texte, etc.). Idéalement, j'aimerais que mon plugin Keepass améliore la détection de la fenêtre actuelle en parcourant les éléments de la fenêtre active dans un effort pour trouver un compte correspondant à copier / coller le mot de passe.

Comment puis-je marcher sur d'autres processus de fenêtre et pouvoir récupérer des valeurs d'étiquettes et de textes à l'aide de C #?


1 commentaires

Intéressant Questin, je ne serais pas surpris, mais si elle s'est avérée que vous devriez avoir à pincer à Winapi pour y parvenir.


5 Réponses :


3
votes

Vous pouvez utiliser Enumwindows pour trouver Toute fenêtre chromée de niveau supérieur, puis appelez EnumChildWindows récursivement (Voir Jeroen Wiert Pluimers 'Commenter) Pour obtenir chaque enfant de la fenêtre principale. Alternativement, une fois que vous avez la fenêtre principale chromée, vous pouvez utiliser GetWindow naviguer manuellement dans l'arbre depuis que vous savez probablement ce que vous recherchez (collection d'enfants de la 3ème enfant ou quelque chose de similaire).

Une fois que vous avez trouvé votre fenêtre, vous pouvez utiliser SendMessage avec un paramètre wm_gettext pour lire l'étiquette de la fenêtre.


7 commentaires

@Blindy, merci pour l'info! Je cherche à le faire à n'importe quelle fenêtre active, pas seulement chrome. Une fois que j'ai les poignées aux fenêtres / fenêtres enfants, comment naviguer dans ces éléments Windows?


Ce sont tous des appels d'API Windows natifs et non géré les appels .NET Framework afin qu'ils nécessitent p / invoke auprès de CLR.


@Drjokepu, aye. Je pensais que je devais faire de la magie p / invoquer.


@Blindy, une fois que j'ai une référence à une fenêtre, comment puis-je itération à travers tous ses boutons, étiquettes, texte, etc.?


Les navigateurs utilisent généralement des commandes sans fenêtre, en raison de la limite de poignée de 10K sous Windows. Vous devrez peut-être écrire des crochets spécifiques pour chaque navigateur.


Eh bien, si vous pouvez le voir dans Spy ++, vous pouvez le voir aussi avec cela. Pour naviguer sur les fenêtres, vous utilisez getwindow avec gw_hwndnext / gw_hwndprev pour les frères et sœurs et gw_child pour les enfants.


Ne recursez pas EnumChildWindows comme cela recute déjà. Voir L'ancienne nouvelle chose sur EnumchildWindows



1
votes

pour la fonctionnalité de pointe vers une fenêtre. Vous devez SETCCAPTURE () afin que vous obteniez des messages de souris qui sont en dehors de votre fenêtre. Ensuite, utilisez windowfrompoint () pour convertir une position de souris en une fenêtre. Vous devrez convertir la position de la moust des coordonnées des clients en coordonnées de fenêtre en premier.

Si vous essayez un appel SetCapture () n'importe où, mais sur un message de souris, vous serez probablement ignoré. C'est la raison pour laquelle Spy ++ vous fait cliquer sur une icône et glisser-la déposer sur la fenêtre que vous souhaitez pointer vers.


5 commentaires

Ce que je tente de faire, c'est simplement itérer à travers un élément Windows sans l'interaction de la souris. Une fois que j'appelle Enumchildwindows, comment puis-je obtenir le texte des éléments appartenant à cette fenêtre enfant?


Envoyez les messages de la fenêtre. WM_GetText, etc. Si cela n'est pas assez bon, vous devez définir ce que vous entendez par «éléments»?


@John Knoeller, toutes les étiquettes de texte, Textboxes et boutons.


EnumChildWindows de vos fenêtres enfants. Répétez la répétition de manière récursive jusqu'à ce que vous manquiez de générations.


@SimuCal, où vous pouvez énumérer tous les éléments de la fenêtre enfant et obtenir les valeurs correspondantes? Si oui, s'il vous plaît partager



3
votes

regarder cet article ici contient des informations sur le géré. Espion et pourquoi l'auteur a écrit l'outil.


1 commentaires

N'oubliez pas que l'application que vous appelez uniquement des œuvres pour les applications gérées , pas non gérées comme la plupart des navigateurs.



25
votes

J'ai répondu à des questions similaires comme celle-ci ici: Comment puis-je détecter si un thread contient des poignées de Windows? . Comme il l'indique, l'idée principale est d'énumérer via des fenêtres de processus et de leurs fenêtres enfants à l'aide de Enumwindows et EnumchildWindows Appels API Pour obtenir des poignées de fenêtre, puis appelez GetWindowtext ou SendDlgitemMessage avec WM_GETTEXT pour obtenir le texte de la fenêtre. J'ai modifié le code pour faire un exemple qui devrait faire ce dont vous avez besoin (désolé c'est un peu long :). Il iTère à travers des processus et de leurs fenêtres et décharge du texte de fenêtre dans la console.

static void Main(string[] args)
{
    foreach (Process procesInfo in Process.GetProcesses())
    {
        Console.WriteLine("process {0} {1:x}", procesInfo.ProcessName, procesInfo.Id);
        foreach (ProcessThread threadInfo in procesInfo.Threads)
        {
            // uncomment to dump thread handles
            //Console.WriteLine("\tthread {0:x}", threadInfo.Id);
            IntPtr[] windows = GetWindowHandlesForThread(threadInfo.Id);
            if (windows != null && windows.Length > 0)
                foreach (IntPtr hWnd in windows)
                    Console.WriteLine("\twindow {0:x} text:{1} caption:{2}",
                        hWnd.ToInt32(), GetText(hWnd), GetEditText(hWnd));
        }
    }
    Console.ReadLine();
}

private static IntPtr[] GetWindowHandlesForThread(int threadHandle)
{
    _results.Clear();
    EnumWindows(WindowEnum, threadHandle);
    return _results.ToArray();
}

// enum windows

private delegate int EnumWindowsProc(IntPtr hwnd, int lParam);

[DllImport("user32.Dll")]
private static extern int EnumWindows(EnumWindowsProc x, int y);
[DllImport("user32")]
private static extern bool EnumChildWindows(IntPtr window, EnumWindowsProc callback, int lParam);
[DllImport("user32.dll")]
public static extern int GetWindowThreadProcessId(IntPtr handle, out int processId);

private static List<IntPtr> _results = new List<IntPtr>();

private static int WindowEnum(IntPtr hWnd, int lParam)
{
    int processID = 0;
    int threadID = GetWindowThreadProcessId(hWnd, out processID);
    if (threadID == lParam)
    {
        _results.Add(hWnd);
        EnumChildWindows(hWnd, WindowEnum, threadID);
    }
    return 1;
}

// get window text

[DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
static extern int GetWindowText(IntPtr hWnd, StringBuilder lpString, int nMaxCount);
[DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)]
static extern int GetWindowTextLength(IntPtr hWnd);

private static string GetText(IntPtr hWnd)
{
    int length = GetWindowTextLength(hWnd);
    StringBuilder sb = new StringBuilder(length + 1);
    GetWindowText(hWnd, sb, sb.Capacity);
    return sb.ToString();
}

// get richedit text 

public const int GWL_ID = -12;
public const int WM_GETTEXT = 0x000D;

[DllImport("User32.dll")]
public static extern int GetWindowLong(IntPtr hWnd, int index);
[DllImport("User32.dll")]
public static extern IntPtr SendDlgItemMessage(IntPtr hWnd, int IDDlgItem, int uMsg, int nMaxCount, StringBuilder lpString);
[DllImport("User32.dll")]
public static extern IntPtr GetParent(IntPtr hWnd);

private static StringBuilder GetEditText(IntPtr hWnd)
{
    Int32 dwID = GetWindowLong(hWnd, GWL_ID);
    IntPtr hWndParent = GetParent(hWnd);
    StringBuilder title = new StringBuilder(128);
    SendDlgItemMessage(hWndParent, dwID, WM_GETTEXT, 128, title);
    return title;
}


3 commentaires

J'ai remarqué que sur quelques réponses, les gens disent appeler à l'enumchildwindows récursivement. Ne fais pas ça. Lisez la DOC MSDN pour cela - il est déjà récursif, aurait dû être plus volontiers nommé Enumdescendants.


EnumChildWindows déjà receverise, alors vous faites double récupération ici; Voir L'ancienne nouvelle chose sur EnumchildWindows


Comment pourrions-nous éviter une boucle infinie ici qui arrive sur ma machine. Il devrait logiquement tomber après avoir percé via des fenêtres enfants.



2
votes

Vous pouvez utiliser hwndspy. Le code source est ici .

 Entrez la description de l'image ici


0 commentaires