0
votes

On my Windows 7 desktop, I have the Windows Taskbar attached at the LEFT side of the screen (instead of default on the bottom) and a custom desktop toolbar ("True Launch Bar") attached at the TOP of the screen.

In a Delphi XE8 VCL project, I save the main window position values (formMain.Top and formMain.Left) in the FormClose event, and then at program start I restore the main window position with these values in the FormCreate event.

This normally works well. However, when the program is closed while MINIMIZED (formMain.WindowState = wsMinimized) then the form position values are wrong (i.e. REDUCED by the width/height of the toolbars) and so the window is restored at a wrong position at program start.

So how can I solve this problem?

EDIT: I tried the other solution mentioned by David:

var
  WindowPlacement: TWindowPlacement;
  R: TRect;
....
  WindowPlacement.Length := SizeOf(WindowPlacement);
  Win32Check(GetWindowPlacement(formMain.Handle, @WindowPlacement));
  R := WindowPlacement.rcNormalPosition;
  CodeSite.Send('formMainLeft by WinAPI', R.Left);        // normal: 323 minimized: 323
  CodeSite.Send('VCL formMain.Left',      formMain.Left); // normal: 423 minimized: 323

However, this produces the same problem, as it does not take into account the space occupied by the toolbars, as it gets only the WORK AREA values.

Moreover, this is not a duplicate question as mentioned by David, but a SIMILAR question. This problem derives from wrong screen values when in Minimized state, while the other question is about overall restoring state and size.

Please also note: I do NOT want to restore the window state (e.g. Minimized) AND position, but ONLY the window position, so I cannot use SetWindowPlacement as mentioned by David in the other question.

EDIT2: I have now solved the problem with this code:

  if formMain.WindowState = wsMinimized then
  begin
    MinimizedOffsetTop  := Screen.WorkAreaTop;
    MinimizedOffsetLeft := Screen.WorkAreaLeft;
  end
  else if formMain.WindowState = wsNormal then
  begin
    MinimizedOffsetTop  := 0;
    MinimizedOffsetLeft := 0;
  end;
  SettingsIni.WriteInteger('Persistence', 'Top',  formMain.Top  + MinimizedOffsetTop);
  SettingsIni.WriteInteger('Persistence', 'Left', formMain.Left + MinimizedOffsetLeft);

(In the case the window is Maximized, I do not save and restore the window position but do only save and restore the Maximized window state).

1
You can use JediVCL library, where there are TJvFormPlacement and TJvFormStorage components that do auto-save and auto-restoreArioch 'The
Whilst JEDI no doubt has useful classes for this, including JEDI generally forces you to include huge numbers of dependencies. Over the top to reach two Win32 APIs.David Heffernan
I do not want to use JEDI for this purpose, as I want to keep full control over the saving and restoring myself.user1580348
@kobik GetWindowRect gets wrong values when the window is minimized. For example: R.Left then becomes -32000!user1580348
Do not use screen.workareatop/left, your form may not be on a monitor that has the same offset of the work area with the primary monitor. See stackoverflow.com/questions/29747238/…Sertac Akyuz

1 Answers

1
votes

When a window is minimized, it remembers the last normalized bounds and will restore itself there when you restore the window. These bounds are made available to you through GetWindowPlacement. This API returns work area relative coordinates. It does so because that allows for a window to be minimized and restored to the same work area relative location, even if the work area has changed in the intervening time.

Clearly the VCL calls GetWindowPlacement when you ask for Left and Top of a minimized window. How else would it get the coordinates it returns? And of course, it returns work area relative coordinates which is what is confusing you. One might consider it a bug that these properties are sometimes screen relative and other times work area relative.

Your solution is obvious though. Obtain work area relative coordinates by calling GetWindowPlacement. When you need to re-apply these coordinates, do so by calling SetWindowPlacement.

You say that you cannot use SetWindowPlacement because that forces the window to be minimized. But that's not the case. Set the showCmd member to SW_SHOWNORMAL or SW_RESTORE.

We've been using these APIs to store and restore window positions for many many years. They are known to work well.