The Delphi Bug List

Entry No.
612
VCL - General - Controls - TWinControl
VCL bug when handling WM_MOUSEWHEEL messages
1.02 2.01 3.0 3.01 3.02 4.0 4.01 4.02 4.03 5.0 5.01 6.0 6.01 6.02 Kylix 1.0
N/AUnknownUnknownUnknownUnknownExistsExistsExistsExistsExistsExistsFixedFixedFixedN/A
Description
Reported by Mike Lischke
Mouse wheel handlers are often not properly triggered due to the assumption of the VCL, that mouse messages always come with their coordinates being relative to the window they are sent to. This is true with one exception: WM_MOUSEWHEEL. coordinates are screen coordinates.

This is a problem because TWinControl tries to forward each mouse message to an eventual child control. For this task the method IsControlMouseMsg is called passing the message record as TWMMouse record. The IsControlMouseMsg method then tries to find a control to forward the message to by comparing the bounding rectangles of all child controls (which do not need to be windowed controls like TPaintBox) with the passed mouse coordinates. This is obviously wrong when WM_MOUSEWHEEL messages are handled because the coordinates are wrongly interpreted.

Interestingly enough, this error does not appear on Win9x systems because they do not have native mousewheel support. This causes the VCL to take another path in the message handling (see TWinControl.WndProc, 'else' branch of the 'case' command). This path does not involve the search for a child control but instead the mouse wheel message is directly handled.

To reproduce:
Create a new form and place a TShape on it. Make it covering much of the form or set it to alClient alignment. Now include a handler for the OnMouseWheel event of the form, e.g. using Beep; as signal. Compile and run the project. When the form has the focus then mouse wheel messages are sent to it and you can hear the beeps (roll the wheel to make that work). Now move the form far to the left of the screen and try again. Vary also the position of the mouse. The mouse wheel messages will suddenly disappear when the program assumes that the shape control is under the mouse and this can happen somewhere, depending on the position of the form on the screen (and the true mouse position, of course).

Solution / workaround
Change IsControlMouseMsg in Controls.pas to:
function TWinControl.IsControlMouseMsg(var Message: TWMMouse): Boolean;
var
  Control: TControl;
  P: TPoint;
  ClientPos: TPoint;

begin
  // 10-MAR-2000 ml: bug in the VCL!, wheel messages come with screen 
  // coordinates (not client coordinates as other mouse messages)
  ClientPos := SmallPointToPoint(Message.Pos);
  if Message.Msg = WM_MOUSEWHEEL then ClientPos := ScreenToClient(ClientPos);
  
  if GetCapture = Handle then
  begin
    Control := nil;
    if (CaptureControl <> nil) and (CaptureControl.Parent = Self) then
      Control := CaptureControl;
  end else
    Control := ControlAtPos(ClientPos, False);
  Result := False;
  if Control <> nil then
  begin
    P.X := ClientPos.X - Control.Left;
    P.Y := ClientPos.Y - Control.Top;
    Message.Result := Control.Perform(Message.Msg, Message.Keys, 
      Longint(PointToSmallPoint(P)));
    Result := True;
  end;
end;
User-contributed comments
Ben Ark
19 Feb 2002  02:45 PM GMT
The problem cannot be reproduced using the D6.01 trial which leads me to believe that it has been corrected in this version (source code is unavailable with the trial).
Peter Arrenbrecht
03 Apr 2006  01:38 PM GMT
I can confirm this bug for Delphi 7.0 (Build 8.1)
Latest update of this entry: 2002-04-07

Post a comment on this bug


Index page
Delphi Bug List home page
The Delphi Bug Lists are presently maintained by Jordan Russell, who has taken over this task from Reinier Sterkenburg since August 2000.
All feedback is appreciated. See also the feedback section of the Delphi Bug List home page.