views:

739

answers:

2

I have a hook setup for getting mouse events in a plugin I develop. I need to get the WM_LBUTTONDBLCLK, and I expect the message flow to be:

WM_LBUTTONDOWN, WM_LBUTTONUP, WM_LBUTTONDBLCLK

If the I call the next hook when dealing with the first WM_LBUTTONDOWN, then the flow is as expected. However, if I return my own result, then the expected double click comes as a mouse down message. Any idea why this is happening? I need the message to stop after I handle it, and not have it passed to the next hook.

A: 

Are you calling CallNextHookEx() before returning your own result - according to MSDN's documentation MouseProc it is highly recommended that you call it since when you return your own result you prevent other hooks from being called.

Have you considered using a low level mouse hook? It doesn't require your DLL to be injected into the process being hooked and I find it to be a more consistent and powerful hook (albeit more resource intensive if not coded appropriately) - especially when listening for clicks in some legacy applications (there was one that was coded in ancient delphi) and clicks in applications served via terminal servers (citrix). The only issue with low level mouse hooks is that they don't receive double clicks per se - which means you have to query the registry for the 'DoubleClickSpeed' and then check for two mouse down events within that interval before triggering a double click.

Faisal Vali
I think he *wants* to prevent other hooks from receiving the messages by failing to call `CallNextHookEx()` (the merits/ethics of which I won't touch on). The problem, though (if I'm reading this right), is that when he does, his program receives a `WM_LBUTTONDOWN` message in lieu of `WM_LBUTTONDBLCLK`, behaviour I don't have an answer for.
GRB
Exactly. Thanks GRB.
macfarley5
Faisal, my plugin builds on top of the UI of the software I'm plugging into. So when I get a click on something in my UI, I don't want the main program to get the click because that could modify things and I lose the original state of the program.
macfarley5
+2  A: 

After having done a little reading over at the MSDN, I think the explanation of this behaviour lies in this remark on the WM_LBUTTONDBLCLK page:

Only windows that have the CS_DBLCLKS style can receive WM_LBUTTONDBLCLK messages, which the system generates whenever the user presses, releases, and again presses the left mouse button within the system's double-click time limit.

If your program is returning a nonzero value when it handles WM_LBUTTONDOWN or WM_LBUTTONUP, then those messages aren't sent to the target window -- as expected. However, my inference, based on the above quote, is that since no window with the CS_DBLCLKS style is therefore receiving the messages (since the hook prevents any window from receiving the messages), the system therefore doesn't feel like it needs to generate a WM_LBUTTONDBLCLK.

To put it another way, the system only generates a WM_LBUTTONDBLCLK if and only if (a) a window receives the previous WM_LBUTTONDOWN/WM_LBUTTONUP messages and (b) that window has the CS_DBLCLKS style. Since your hook prevents condition (a) from being satisfied, WM_LBUTTONDBLCLK is never generated and so a WM_LBUTTONDOWN message is sent instead.

As to a workaround, I doubt there's a perfect solution. I assume the reason why you want to receive the WM_LBUTTONDBLCLK message is so your hook knows whether or not a regular WM_LBUTTONDOWN message represents the second click of a double-click, right? In that case, what you could do is read the double-click time from the registry as Faisal suggests and have your hook measure the time between WM_LBUTTONDOWN messages, however there's a large chance that you will get inaccurate results (due to the lag time between the messages being sent). Alternatively if there's some way you could instead redirect the WM_LBUTTONDOWN/WM_LBUTTONUP messages to maybe a hidden window that your hook owns (which has the CS_DBLCLKS style), the system may end up generating a WM_LBUTTONDBLCLK message and sending it to your hidden window, which you can then process in that window's WndProc (though I don't have a lot of experience with hooking so I don't know if this is possible).

GRB
GRB, thanks for the input. It makes a lot of sense. I ended up using the first workaround you mentioned and it seems to work well (at least on my machine). We'll see how well the users like it.
macfarley5