получение имени активного окна на основе щелчков мышью в c # - PullRequest
2 голосов
/ 13 марта 2012

Я пытаюсь заставить приложение получить местоположение щелчка мышью и названия (имена) окон, в которых нажимает пользователь.В настоящее время я использовал LowLevelMouseProc, который дает хорошие результаты, но он вызывает сбой приложения при каждом нажатии на Google Chrome.Вот код:

 using System;
 using System.Collections.Generic;
 using System.Linq;
 using System.Text;
 using System.Runtime.InteropServices;
  using System.Windows.Forms;
 using System.Diagnostics;

        //An attempt to print the screen name of the active window and mouse coordinates at every mouse click
namespace Project1
 {
class InterceptMouse
{

    private static LowLevelMouseProc _proc = HookCallback;
    private static IntPtr _hookID = IntPtr.Zero;

    public static void Main()
    {
        _hookID = SetHook(_proc);
        Application.Run();
        UnhookWindowsHookEx(_hookID);
        Application.Exit();
    }

    private static IntPtr SetHook(LowLevelMouseProc proc)
    {
        using (Process curProcess = Process.GetCurrentProcess())
        using (ProcessModule curModule = curProcess.MainModule)
        {
            return SetWindowsHookEx(WH_MOUSE_LL, proc,
                GetModuleHandle(curModule.ModuleName), 0);
        }
    }

    private delegate IntPtr LowLevelMouseProc(int nCode, IntPtr wParam, IntPtr lParam);

    private static IntPtr HookCallback(
        int nCode, IntPtr wParam, IntPtr lParam)
    {
        int nodeCount;
        LinkedListNode<StringBuilder> nodefirst = new LinkedListNode<StringBuilder>(null);
        LinkedListNode<StringBuilder> nodeprev = new LinkedListNode<StringBuilder>(null);
        LinkedList<StringBuilder> windowlist = new LinkedList<StringBuilder>();


        if (nCode >= 0 &&
            MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
        {
            MSLLHOOKSTRUCT hookStruct = (MSLLHOOKSTRUCT)Marshal.PtrToStructure(lParam, typeof(MSLLHOOKSTRUCT));
            Console.WriteLine(hookStruct.pt.x + ", " + hookStruct.pt.y);
           IntPtr hwnd = GetForegroundWindow();
           StringBuilder windowtitle = new StringBuilder();
           if(GetWindowText(hwnd, windowtitle, 2000)>0)
           Console.WriteLine(windowtitle);
           //Console.WriteLine(nodeCount);

           if (nodeCount == 0)
           {
               nodefirst = windowlist.AddFirst(windowtitle);
               nodeCount++;
           }
           else
           {
               if (nodeCount == 1)
               {
                   nodeprev = windowlist.AddAfter(nodefirst, windowtitle);
                   nodeCount++;
               }
               if (nodeCount > 1)
               {
                   nodeprev = windowlist.AddAfter(nodeprev, windowtitle);
                   nodeCount++;
               }

           }

        }

        return CallNextHookEx(_hookID, nCode, wParam, lParam);

    }

    private const int WH_MOUSE_LL = 14;

    private enum MouseMessages
    {
        WM_LBUTTONDOWN = 0x0201,
        WM_LBUTTONUP = 0x0202,
        WM_MOUSEMOVE = 0x0200,
        WM_MOUSEWHEEL = 0x020A,
        WM_RBUTTONDOWN = 0x0204,
        WM_RBUTTONUP = 0x0205
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct POINT
    {
        public int x;
        public int y;
    }

    [StructLayout(LayoutKind.Sequential)]
    private struct MSLLHOOKSTRUCT
    {
        public POINT pt;
        public uint mouseData;
        public uint flags;
        public uint time;
        public IntPtr dwExtraInfo;
        IntPtr hwnd;

    }

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr SetWindowsHookEx(int idHook,
        LowLevelMouseProc lpfn, IntPtr hMod, uint dwThreadId);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool UnhookWindowsHookEx(IntPtr hhk);

    [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr CallNextHookEx(IntPtr hhk, int nCode,
        IntPtr wParam, IntPtr lParam);

    [DllImport("kernel32.dll", CharSet = CharSet.Auto, SetLastError = true)]
    private static extern IntPtr GetModuleHandle(string lpModuleName);

    [DllImport("user32.dll", CharSet = CharSet.Auto, ExactSpelling = true)]
    public static extern IntPtr GetForegroundWindow();

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

Хотя, когда я не использую низкоуровневый хук, а просто использую Thread.sleep (5000) и продолжаю получать имена активных окон каждые 5 секунд, он не падает.Пожалуйста, помогите мне выяснить, почему?,Пожалуйста, помогите мне.

Ответы [ 3 ]

2 голосов
/ 14 марта 2012

Вам необходимо указать емкость для StringBuilder. Чтобы быть более тщательным, вы можете использовать GetWindowTextLength , как описано здесь .

StringBuilder windowtitle = new StringBuilder(256);
if (GetWindowText(hwnd, windowtitle, windowtitle.Capacity) > 0)
    Console.WriteLine(windowtitle);
1 голос
/ 24 сентября 2014

Этот ответ является копией моего ответа, опубликованного здесь: Как получить имя активного окна на основе мыши [...]
Этот код не входит в тему мониторинга мыши. Это о том, какое окно получило фокус. Также обратите внимание: это как раз то, о чем вы просили - имя окна / заголовок -.


Ссылка: Как получить дескриптор активного окна и заголовок

Namespaces:

using System;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading;

Методы:

[DllImport("user32.dll")]
private static extern IntPtr GetForegroundWindow();

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

Звонок:

// get handle
IntPtr handle = GetForegroundWindow();

// get title
const int count = 512;
var text = new StringBuilder(count);

if (GetWindowText(handle, text, count) > 0)
{
    MessageBox.Show(text.ToString());
}

Я использовал этот код несколько раз. Действительно прост в использовании. Вы можете настроить таймер, который срабатывает каждые 10 мс. Сохраните 2 переменные. Один с активным окном и один с последним окном, которое было сфокусировано. В псевдокоде сказано: Если newWindow! = OldWindow -> listView.Add (Window).


Наконец-то это может выглядеть так:

public partial class Form1 : Form
    {
        // DECLARE GLOBALS //
        [DllImport("user32.dll")]
        private static extern IntPtr GetForegroundWindow();

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

        public static string oldWindow = "";
        public static string currentWindow = "";

        // TIMER EVENT //
        private void timerCheckFocus_Tick(object sender, EventArgs e)
        {
            // get handle
            IntPtr handle = GetForegroundWindow();

            // get title
            const int count = 512;
            var currentWindow = new StringBuilder(count);

            // if the current title is NOT the old title - so if its a new window //
            if (currentWindow.ToString() != oldWindow)
            {
                // add your window to a listView //
                listView1.Add(currentWindow.ToString());
                // save your currentWindow as oldWindow cuz it got handled //
                oldWindow = currentWindow.ToString();
            }
        }
0 голосов
/ 14 марта 2012

Это очень странно, по возможности следует избегать зацепок. Почему бы просто не использовать GetForeGroundWindow . Когда пользователь щелкает окно, оно становится окном переднего плана, верно? Так почему нужно зацепить мышь?

Что касается сбоя вашего приложения в Chrome, вы должны установить GetLastError в значение true в вызовах API, а затем печатать коды ошибок при каждом вызове API, чтобы мы могли попытаться выяснить, какой метод API потерпел неудачу и почему. Также вы точно не указали, где вы вызываете свой Thread.Sleep, который не работает.

Во-вторых, вы можете взглянуть на два действительно подробных проекта на CodeProject, которые делают то, что вы делаете, и даже больше: .NET Object Spy и WinForm Spy .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...