8

I’m trying to intercept mouse clicks from another program. I’m making a plugin for the program, that overlays a transparent form on the program and displays additional information. When I click on the transparent part of the form I can click on things in the main program. I don’t want this to happen (at least not every time - there are some parts where you are allowed to click and some parts where you aren’t but this isn’t the problem).

The way I’m doing this now is by using WH_MOUSE_LL, this is working fine and I can keep the mouse click from getting to the program by returning a non zero value (http://msdn.microsoft.com/en-gb/library/windows/desktop/ms644988(v=vs.85).aspx).

The problem is, this makes my main program lag, I don’t need to get notifications for all mouse movements, I only want to get a notification if the user actually clicked something. Is there any way I can limit the WH_MOUSE_LL so it only fires on mouse clicks? (The lag isn’t because of calculations in the MouseHookProc method - it’s currently doing nothing except for calling: CallNextHookEx(hHook, nCode, wParam, lParam).)

I’ve tried to fix this by using a global hook (http://www.codeproject.com/Articles/18638/Using-Window-Messages-to-Implement-Global-System-H) that hooks the WM_MOUSEACTIVATE message. The idea was to only hook up the WH_MOUSE_LL when I received a WM_MOUSEACTIVATE notification. Unfortunately WH_MOUSE_LL click notification gets sent before WM_MOUSEACTIVATE so this doesn't work.

EDIT:

@Nanda here’s the proc code:

public int MouseHookProc(int nCode, IntPtr wParam, IntPtr lParam)
{
    return WindowUtility.CallNextHookEx(hHook, nCode, wParam, lParam);
}

As you can see I’m not doing very much with it atm, but it already lags...

@Cody Gray I’ve made a very small test for the Form handling the messages:

public class Form1 : Form
{
    private TrackBar m_Trackbar;

    static void Main()
    {
        Application.EnableVisualStyles();
        Application.SetCompatibleTextRenderingDefault(false);
        Application.Run(new Form1());
    }

    public Form1()
    {
        m_Trackbar = new System.Windows.Forms.TrackBar();
        m_Trackbar.LargeChange = 1;
        m_Trackbar.Location = new System.Drawing.Point(5, 10);
        m_Trackbar.Maximum = 100;
        m_Trackbar.Size = new System.Drawing.Size(280, 40);
        m_Trackbar.Value = 100;
        this.Controls.Add(m_Trackbar);

        m_Trackbar.Scroll += new System.EventHandler(this.m_TrackbarScroll);
    }


    private void m_TrackbarScroll(object sender, System.EventArgs e)
    {
        this.Opacity = ((Convert.ToDouble(m_Trackbar.Value)) / 100);
    }

    protected override void WndProc(ref Message m)
    {
        switch (m.Msg)
        {
            case 0x201: //WM_LBUTTONDOWN
                Console.WriteLine("MouseButton Down!");
                //I could copy the Message over to the MainProgram with this right?
                //SendMessage(MainProgramHwnd, m.Msg, m.WParam, m.LParam);
                //This will also only work on an opacity higher than 0.
                break;
        }
        base.WndProc(ref m);
    }
}

When you said: “return that it's transparent and let it be routed to the window underneath it?” Can I do this by using SendMessage and basically copying the message I receive in my WndProc method?

To make things more complicated I’m also using this form http://www.codeproject.com/Articles/1822/Per-Pixel-Alpha-Blend-in-C. To my understanding this enables me to draw bitmaps on the form who are Anti Aliasing against the background. With this form there seems to be no way to set the opacity, as it’s just transparent all the time. Is there a better way to draw bitmaps on a Form?

P̲̳x͓L̳
  • 3,615
  • 3
  • 29
  • 37
VincentC
  • 245
  • 4
  • 14
  • 1
    May be your hook proc is performing too many operations even before checking if the event type and bailing out on irrelevant event. Bring your hook proc to just a return CallNextHook(...) and add make incremental change. – nanda Apr 02 '13 at 22:55
  • Why can't your overlay form just receive all mouse events that happen to it and filter them appropriately? If it's supposed to process one, process it. If not, return that it's transparent and let it be routed to the window underneath it? Global hooks are almost always the wrong solution (although nanda's suggestion is a good one if you must use one). – Cody Gray - on strike Apr 02 '13 at 23:30
  • Thank you both for your comments, I’ve edited my first question with some code and some additional information. @Nanda I’m not exactly sure what you mean, I’m currently only returning CallNextHookEx but this lags already (I’ve added my proc code to my first post). – VincentC Apr 03 '13 at 20:25
  • @Cody Gray Wouldn’t this only work if my form was at 1% opacity? Because when my form has 0% opacity it can no longer receive any mouse messages. I’ve also added some test code to my first post. – VincentC Apr 03 '13 at 20:26
  • I did not know your HookProc was already what I suggested. I can think of few possible reasons for the lag - as your hook proc is in .NET the interop overhead might be showing up, and the transparent windows (it seems you are using them) could end up causing a nested WM_NCHITTEST messages and accentuating the overhead. – nanda Apr 04 '13 at 05:22

1 Answers1

2

You may want to look into Easyhook (http://easyhook.codeplex.com/) which will allow you to hook Windows API calls from a single process rather than for all processes.

Nick Wilton
  • 113
  • 6