Emmanuel Ichbiah
Emmanuel Ichbiah

Reputation: 309

Wrong side information in WM_SIZING for window with a very small height

  1. I create a captionless window.
  2. I resize it manually (or programmatically) so that its height is 30 pixels or less.
  3. When I then grab the bottom border to resize it vertically, it behaves as if I were dragging the top border. Indeed when debugging the program, the WM_SIZING parameter contains WMSZ_TOP instead of WMSZ_BOTTOM.

My program is written in Delphi, basically the problem is reproducible with a main form with the following FormCreate:

procedure TForm2.FormCreate(Sender: TObject);

  var oldStyle : LongInt;
  var newStyle : LongInt;

begin
  //  Adapt windows style.

  oldStyle := WINDOWS.GetWindowLong (
                          handle,
                          GWL_STYLE);

  newStyle := oldStyle              and
              (not WS_CAPTION)      and
              (not WS_MAXIMIZEBOX);

  WINDOWS.SetWindowLong(
              handle,
              GWL_STYLE,
              newStyle);

  //  SetWindowPos with SWP_FRAMECHANGED needs to be called at that point
  //  in order for the style change to be taken immediately into account.

  WINDOWS.SetWindowPos(
              handle,
              0,
              0,
              0,
              0,
              0,
              SWP_NOZORDER     or
              SWP_NOMOVE       or
              SWP_NOSIZE       or
              SWP_FRAMECHANGED or
              SWP_NOACTIVATE);
end;

Upvotes: 4

Views: 517

Answers (2)

Emmanuel Ichbiah
Emmanuel Ichbiah

Reputation: 309

Well done, thanks. I confirm that it is an OS bug and nothing related to delphi (I was able to reproduce the problem with a simple window created using the WINDOWS API).

I now ended up with:

procedure TForm2.WMNcHitTest(
                     var msg : TWMNCHitTest);
begin
  inherited;

  case msg.result of

      HTTOP:
        begin
          if msg.pos.y > top + height div 2 then
              msg.result := HTBOTTOM;
        end;

      HTTOPRIGHT:
        begin
          if msg.pos.y > top + height div 2 then
              msg.result := HTBOTTOMRIGHT;
        end;

      HTTOPLEFT:
        begin
          if msg.pos.y > top + height div 2 then
              msg.result := HTBOTTOMLEFT;
        end;

  end;
end;

Upvotes: 5

Sertac Akyuz
Sertac Akyuz

Reputation: 54812

Looks like a bug to me with the OS. Under the conditions of your test case, hit test handling is wrong, default window procedure returns HTTOP when it should return HTBOTTOM. You can override hit test handling for a workaround:

procedure TForm1.WMNCHitTest(var Message: TWMNCHitTest);
begin
  inherited;
  if (Message.Result = HTTOP) and
      (Message.Pos.Y > Top + Height - GetSystemMetrics(SM_CYSIZEFRAME)) then
    Message.Result := HTBOTTOM;
end;

Upvotes: 7

Related Questions