Setting up mouse hook without removing currently running application?

629 Views Asked by At

I have a program that opens a GUI when run. I would then like to set up a mousehook using dllimports, but in order for it to work, I must call a new Application.Run() in this same class. Unfortunately though, this removes the original GUI. Is there any way I can run the mousehook on the original messageloop? I'm a bit lost here.

Here are a few key portions of the code:

//main

public static GUI GUIref;

static void Main()
{
     Application.EnableVisualStyles();
     Application.SetCompatibleTextRenderingDefault(false);
     Application.Run(GUIref = new GUI());
}

.

//Initializing constructor    

    public partial class GUI : Form
    {
        public GUI()
        {
            InitializeComponent();
            keyReceive kR = new keyReceive();
            mouseReceive mR = new mouseReceive();
        }
    }

.

//mousehook class:

    public class mouseReceive : Form
    {
        private static LowLevelMouseProc _proc = HookCallback;
        private static IntPtr _hookID = IntPtr.Zero;
        public mouseReceive()
        {
            _hookID = SetHook(_proc);
            //***This is where I have been putting Application.Run() to make the mousehook work***
            UnhookWindowsHookEx(_hookID);
        }

        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)
        {

            if (nCode >= 0 &&
                MouseMessages.WM_LBUTTONDOWN == (MouseMessages)wParam)
            {
                MessageBox.Show("");

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

        private const int WH_MOUSE_LL = 14;

        private enum MouseMessages
        {
            WM_LBUTTONDOWN = 0x0201
        }


        [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);
    }
1

There are 1 best solutions below

0
On

In the mouseReceive constructor, you are setting the hook and then immediately unhooking it. If you insert the Application.Run() where your comment is, that blocks the thread until the new window closes, thus the hook is not unhooked and works. The real fix would be to remove UnhookWindowsHookEx(_hookID) from the constructor and put it into a IDisposable pattern.

Side note: You also might have problems if you try to instantiate more than one instance of your mouseReceive class as it has static members for _proc and _hookID.