Global Mouse Hook to find Windows Handles in C#

Hi,
I am incorperating a feature similar to that used in the Spy++ application.
I would like to click on a window (not my app) ie notepad, and be able to record the handle information.
I'm pretty sure i need a global mouse hook. If anyone knows how to do this with some pseudo code / tutorial or example
I would be very grateful
Thanks
Jonesey007Asked:
Who is Participating?

[Product update] Infrastructure Analysis Tool is now available with Business Accounts.Learn More

x
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

Mike TomlinsonHigh School Computer Science, Computer Applications, and Mathematics TeachersCommented:
In Spy++ you initiate the selection by dragging cross-hairs from Spy++ and dropping it on the target window.  Since the drag starts from within your app you do not need a global hook.  As long as the mouse is held down you will continue to get MouseMove() events in your app.  To get the target window you simply pass the current cursor position to WindowFromPoint() and then pass that handle to GetWindowRect() to obtain the dimensions.
Jonesey007Author Commented:
Thanks very much for the information, do you think this is going to be alot of work to do using a type of Global hook?
I am currently reading "Processing Global Mouse and Keyboard Hooks in C#" on code project but it does not seem like a trivial task.
When the user presses a button on another application i need to record the window name and the button name when the mouse button is clicked so i can repeat the process later.
I think i need to study the CodeProject example listed above unless you have anyother idea's of a simpler way to achieve this?

Thanks
Mike TomlinsonHigh School Computer Science, Computer Applications, and Mathematics TeachersCommented:
I'll almost done with an example...standby.
Exploring ASP.NET Core: Fundamentals

Learn to build web apps and services, IoT apps, and mobile backends by covering the fundamentals of ASP.NET Core and  exploring the core foundations for app libraries.

_valkyrie_Commented:
Detect mouse click using the library from:
http://www.codeproject.com/KB/cs/globalhook.aspx

Then this code will pull the application name of the window the mouse is over:
       [DllImport("user32.dll")]
        static extern IntPtr WindowFromPoint(POINT Point);
        [DllImport("user32.dll")]
        static extern bool GetCursorPos(out POINT lpPoint);
        [DllImport("user32.dll", ExactSpelling = true, CharSet = CharSet.Auto)]
        static extern IntPtr GetParent(IntPtr hWnd);
        [DllImport("user32.dll", CharSet = CharSet.Auto, SetLastError = true)]
        static extern int GetWindowThreadProcessId(IntPtr handle, out uint processId);

        [StructLayout(LayoutKind.Sequential)]
        public struct POINT
        {
            public int X;
            public int Y;

            public POINT(int x, int y)
            {
                this.X = x;
                this.Y = y;
            }

            public static implicit operator Point(POINT p)
            {
                return new Point(p.X, p.Y);
            }

            public static implicit operator POINT(Point p)
            {
                return new POINT(p.X, p.Y);
            }
        }

        

        public static string GetApplicationMouseIsOver()
        {
            IntPtr windowHandle = GetHandleOfWindowMouseIsOver();
            return GetApplicationName(windowHandle);
        }

        public static IntPtr GetHandleOfWindowMouseIsOver()
        {
            POINT location;
            GetCursorPos(out location);

            IntPtr window = WindowFromPoint(location);
            IntPtr windowParent = IntPtr.Zero;

            while (window != IntPtr.Zero)
            {
                windowParent = window;
                window = GetParent(window);
            }

            return windowParent;
        }

        private static string GetApplicationName(IntPtr windowHandle)
        {
            uint processID = 0;
            MouseMonitor.GetWindowThreadProcessId(windowHandle, out processID);
            Process process = Process.GetProcessById((int)processID);

            string executableName = Path.GetFileName(process.MainModule.FileName);
            return executableName;
        }

Open in new window


Then you can use:
GetApplicationMouseIsOver()
or
GetHandleOfWindowMouseIsOver()

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
Mike TomlinsonHigh School Computer Science, Computer Applications, and Mathematics TeachersCommented:
Here's a pretty good start on a Spy++ type tool.

The form has pictureBox1 and label1 thru label4.  Just drag the PictureBox around the screen and see what happens:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {

        [StructLayout(LayoutKind.Sequential)]
        public struct RECT
        {
            public int Left;
            public int Top;
            public int Right;
            public int Bottom;
        }

        public const int WM_GETTEXT = 0xD;
        public const int WM_GETTEXTLENGTH = 0x000E;

        [DllImport("user32.dll")]
        public static extern IntPtr WindowFromPoint(Point point);

        [DllImport("user32.dll", CharSet = CharSet.Auto)]
        public static extern int GetClassName(IntPtr handle, StringBuilder ClassName, int MaxCount);

        [DllImport("user32.dll")]
        public static extern int SendMessage(IntPtr handle, int msg, int Param1, int Param2);

        [DllImport("user32.dll")]
        public static extern int SendMessage(IntPtr handle, int msg, int Param, System.Text.StringBuilder text);

        [DllImport("user32.dll")]
        [return: MarshalAs(UnmanagedType.Bool)]
        public static extern bool GetWindowRect(IntPtr handle, out RECT Rect);

        public class WindowInfo
        {
            public IntPtr Handle;
            public string ClassName;
            public string Text;
            public Rectangle Rect;

            public WindowInfo(IntPtr Handle)
            {
                this.Handle = Handle;
                this.ClassName = GetWindowClassName(Handle);
                this.Text = GetWindowText(Handle);
                this.Rect = GetWindowRectangle(Handle);
            }
        }

        WindowInfo LastWindow = null;
        WindowInfo CurWindow;

        public Form1()
        {
            InitializeComponent();
        }

        private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                Point pt = Cursor.Position;
                this.Text = "Mouse Position: " + pt.ToString();
                this.CurWindow = new WindowInfo(WindowFromPoint(pt));

                label1.Text = "Handle: " + this.CurWindow.Handle.ToString("X");
                label2.Text = "Class: " + this.CurWindow.ClassName;
                label3.Text = "Text: " + this.CurWindow.Text;
                label4.Text = "Rectangle: " + this.CurWindow.Rect.ToString();

                if (this.LastWindow == null)
                {
                    ControlPaint.DrawReversibleFrame(this.CurWindow.Rect, Color.Black, FrameStyle.Thick);
                }
                else if (!this.CurWindow.Handle.Equals(this.LastWindow.Handle))
                {
                    ControlPaint.DrawReversibleFrame(this.LastWindow.Rect, Color.Black, FrameStyle.Thick);
                    ControlPaint.DrawReversibleFrame(this.CurWindow.Rect, Color.Black, FrameStyle.Thick);                   
                }

                this.LastWindow = this.CurWindow;
            }
        }

        private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                if (this.LastWindow != null)
                {
                    ControlPaint.DrawReversibleFrame(this.LastWindow.Rect, Color.Black, FrameStyle.Thick);

                    // ... do something with "this.LastWindow" ...

                }
            }
        }

        public static string GetWindowClassName(IntPtr handle)
        {
            StringBuilder buffer = new StringBuilder(128);
            GetClassName(handle, buffer, buffer.Capacity);
            return buffer.ToString();
        }

        public static string GetWindowText(IntPtr handle)
        {
            StringBuilder buffer = new StringBuilder(SendMessage(handle, WM_GETTEXTLENGTH,0,0) + 1);
            SendMessage(handle, WM_GETTEXT, buffer.Capacity, buffer);
            return buffer.ToString();
        }

        public static Rectangle GetWindowRectangle(IntPtr handle)
        {
            RECT rect = new RECT();
            GetWindowRect(handle, out rect);
            return new Rectangle(rect.Left, rect.Top, (rect.Right - rect.Left) + 1, (rect.Bottom - rect.Top) + 1);
        }

    }
}

Open in new window

Jonesey007Author Commented:
Hi Idle_Mind
Thank you so much for taking the time to write the example, sorry if this is a stupid question but is there a property i need to set to make the picturebox dragable?

Thanks
Pete
Mike TomlinsonHigh School Computer Science, Computer Applications, and Mathematics TeachersCommented:
I didn't put in any visual cue for the PictureBox being dragged.  A really simply approach is to set the crosshairs cursor in the MouseDown() event:

        private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
        {
            if (e.Button == System.Windows.Forms.MouseButtons.Left)
            {
                pictureBox1.Cursor = Cursors.Cross;
            }
        }

Then set it back to Cursors.Default in the MouseUp() event.

You can make it more sophisticated by using a custom cursor if you want.  It's even possible to build a dynamic custom cursor from the image in the picturebox.
Jonesey007Author Commented:
Thanks for the help guys
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
.NET Programming

From novice to tech pro — start learning today.