Search code examples
delphiwinapiwindows-8dialogposition

Dialog shifted to the left and upward in Windows 8


This dialog shows exactly under button, but in Windows 8 dialog is shifted to the left and upward. How to get the same results in all Windows versions?

procedure TForm1.Button3Click(Sender: TObject);
var p: TPoint;
begin
  p := Button3.ClientToScreen(Point(0, Button3.Height));
  MessageDlgPos('', mtInformation, [mbOK], 0, p.X, p.Y);
end;

Shifted dialog in Win 8

update: In case we open Form instead of Dialog, and if that Form has BorderStyle bsSizeable or bsSizeToolWin, then everything is OK. Otherwise (bsDialog, bsSingle, bsToolWindow), Form opens shifted as Dialog from the example above.


Solution

  • Running the exact code you have shown on Windows 7, I am not able to reproduce the same dialog positioning you have shown in your Windows 7 screnshot. The MessageDlgPos window is offset up and to the left in the same manner as your Windows 8 screenshot:

    screenshot

    That being said, I notice you are positioning your MessageDlg window relative to the button's client area:

    screenshot

    If you want the dialog positioned relative to its actual bottom edge, you need to call ClientToScreen() on the button's Parent rather than on the button itself:

    p := Button3.Parent.ClientToScreen(Point(Button3.Left, Button3.Top+Button3.Height));
    

    screenshot

    The end result is about the same, though:

    screenshot

    Now, why is the overlap occurring in the first place? Because the window is being positioned such that the top-left corner of its non-client area falls at the specified coordinates:

    screenshot

    You can adjust the window coordinates to account for that:

    p := Button3.Parent.ClientToScreen(Point(Button3.Left, Button3.Top + Button3.Height));
    Inc(p.X, GetSystemMetrics(SM_CXFIXEDFRAME) + GetSystemMetrics(SM_CXBORDER));
    Inc(p.Y, GetSystemMetrics(SM_CYFIXEDFRAME) + GetSystemMetrics(SM_CYBORDER));
    

    Which gets you much closer to the desired position:

    screenshot

    Note that Aero "tweaks" system metrics a bit, so you might need to use things like DwmGetWindowAttribute(DWMWA_EXTENDED_FRAME_BOUNDS) and/or GetThemeSysSize() to get more accurate metrics.