[edit - DrO 22/06/2012]
see post #2 for the code required to implement this in your own plug-ins
This post is mostly notes to myself for future reference in-case I forget. I think it would be a good idea for a mod to sticky this if possible until an official documentation is provided. I actually found this system by accident and have slowly worked up a working theory for its use and handling.
Windows normally (and quite unintuitively for end-users) sends all WM_MOUSEWHEEL messages to the currently focused window regardless of where the mouse cursor is pointed. However, for intuitive scroll wheel functionality, Winamp seems to have implemented a rather easy system for redirecting mouse wheel messages to the window procedure for the window that the mouse cursor is actually positioned over regardless of which window control has the active window input focus:
After experimenting with a dummy empty plugin that creates a GenEmbed window with various controls, I have found the following behavior of Winamp's mouse wheel message handling:
If the mouse cursor is over a window that does not have the active input focus but another window does, Winamp Send(Message)s the WINAMP_WM_DIRECT_MOUSE_WHEEL message to that window first before allowing the window with the actual input focus to receive the WM_MOUSEWHEEL message. The wParam and lParam fields from the original WM_MOUSEWHEEL message are directly copied as the fields of the WINAMP_WM_DIRECT_MOUSE_WHEEL message. If the window procedure that receives the sent WINAMP_WM_DIRECT_MOUSE_WHEEL message returns zero (or FALSE) then Winamp will allow the original mouse wheel message to enter the original window's procedure. If however, the result of the message is non-zero (or TRUE) then Winamp will block the original mouse wheel message from reaching the original window's procedure in-lieu of mouse wheel message processing for the new target window (the one that the mouse cursor is actually positioned over.)
If the mouse cursor is over the window that has the active input focus, then Winamp does not block the original WM_MOUSEWHEEL message from reaching it's originally intended target window procedure and does not
generate a WINAMP_WM_DIRECT_MOUSE_WHEEL message (well, at least not anywhere that I could find.)
My recommendations for the handling of this message and the WM_MOUSEWEEL message:
If a window procedure processes the WINAMP_WM_DIRECT_MOUSE_WHEEL message in any way, it should always return non-zero (or TRUE) to prevent more than one window from scrolling at the same time. If processing from within a constructed framework, you should SendMessage (preferably not
PostMessage) the WM_MOUSEWHEEL message to the same window handle as the one that received the WINAMP_WM_DIRECT_MOUSE_WHEEL message if you don't directly process the WINAMP_WM_DIRECT_MOUSE_WHEEL as a WM_MOUSEWHEEL message in your base class(es), copying the wParam and lParam parameters to the new WM_MOUSEWHEEL message. Do not
generate a WINAMP_WM_DIRECT_MOUSE_WHEEL message in your code. Only respond to it appropriately. If processing the parameters of the WM_MOUSEWHEEL and WINAMP_WM_DIRECT_MOUSE_WHEEL messages, you probably do not need to check if the message's x=(short)LOWORD(lParam) and y=(short)HIWORD(lParam) cursor point location is within the control's bounding rectangle as Winamp seems to have already done this for you (except for instances where Winamp received a zero (or FALSE) response to the WINAMP_WM_DIRECT_MOUSE_WHEEL message or you want to be picky about it or you're coding a custom window class with multiple or confined scrolling regions needing special processing.)
My current theory for how this works:
The Winamp main UI thread message pump seems to have special handling for certain messages, including the WM_MOUSEWHEEL messages (among others.) It appears that when Winamp's UI message pump encounters a posted WM_MOUSEWHEEL message, before it reaches DispatchMessage, it checks to see if the cursor is over the window it's posted for and if not, sends the WINAMP_WM_DIRECT_MOUSE_WHEEL message to the window that is. If the window procedure responds non-zero (or TRUE) then Winamp doesn't call DispatchMessage. But if the window procedure responds zero (or FALSE) then Winamp will pass the original WM_MOUSEWHEEL message to DispatchMessage. This theory is based upon my observations to what various window message hooking applications report at which stage and whether or not my window procedures (in testing) actually received the original WM_MOUSEWHEEL message or not.
Wow, that took a while to write and proof-read.