Copy window hides on waking drives

Please report only one bug per message!

Moderators: white, Hacker, petermad, Stefan2

foxidrive
Junior Member
Junior Member
Posts: 90
Joined: 2004-02-28, 11:50 UTC

Copy window hides on waking drives

Post by *foxidrive »

TC 8.01 32 bit under Win8

Cosmetic bug.

I have hard drives set to sleep and with zillions of files.

If I use the copy function (in this instance I am copying over the LAN to another PC) then it firstly counts the files and then starts the copy - but the copy dialog is hidden and Alt Tab twice is needed to bring it into view.
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 48088
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

Sorry, I do not understand - how can you copy files when the drive is asleep? You have to switch to the drive before selecting files, but this would awaken it. Can you give me step by step instructions?
Author of Total Commander
https://www.ghisler.com
foxidrive
Junior Member
Junior Member
Posts: 90
Joined: 2004-02-28, 11:50 UTC

Post by *foxidrive »

I should add that there are 4 drives in the spanned array. Maybe the file listings are retrieved from a drive that is awake and then the other spanned drive with the content on has to wake up.

Windows seems to cache certain parts of a drive listing when it is accessed, and then the drive can go to sleep and in TC I can still see the root directory and move up and down the list.

I select a folder to copy and the target in the right pane and hit F5.

It then pauses for a while, when I presume the drive is waking up and then TC counts the filesize and the copy begins - where the copy dialog window is not on the screen until I alt tab to bring it into focus.

I hope I made it a bit clearer.
umbra
Power Member
Power Member
Posts: 871
Joined: 2012-01-14, 20:41 UTC

Post by *umbra »

Windows really caches content of recently visited directories and some of their neighbors. I can traverse a part of the directory tree on my external drive while it's sleeping. And it wakes up only when I try to access files' content or some distant branch of the tree.
But even in such case, the copy dialog is alway on top of TC. So no, I cannot reproduce it.
Windows 7 Pro x64, Windows 10 Pro x64
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

This is probably a problem with Z-order of the main TCMD window:
- user presses F5,
- TCMD creates a copy dialog and brings it to the top (this is a modal dialog, so main TCMD window becomes disabled),
- after showing a dialog, something brings the main (disabled!) TCMD window to the top.

I created a piece of code that reproduces this kind of problem. Form1 has a button with Onclick event = Button1Click. Form2 is an empty form. After clicking a button, disabled(!) Form1 is being moved over active Form2. Pressing Alt+Tab restores the proper Z-order.

To solve the problem described in this bug report, it must be found what brings the main TCMD window to the front after displaying a copy dialog.

Code: Select all

program Project1;

uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1},
  Unit2 in 'Unit2.pas' {Form2};

{$R *.RES}

begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.CreateForm(TForm2, Form2);
  Application.Run;
end.

Code: Select all

unit Unit1;

interface

uses
  Windows, Messages, Classes, Controls, Forms, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    procedure WMUser(var Message : TMessage); message WM_USER;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

uses
  Unit2;

procedure TForm1.Button1Click(Sender: TObject);
begin
  PostMessage(Handle,WM_USER,0,0);
  {ShowModal has inner message loop, so it will execute WM_USER for
   Form1 - so it will bring the disabled(!) Form1 over the active Form2}
  Form2.ShowModal;
end;

procedure TForm1.WMUser(var Message : TMessage);
begin
  BringToFront;
end;

end.

Code: Select all

unit Unit2;

interface

uses
  Windows, Classes, Controls, Forms;

type
  TForm2 = class(TForm)
  end;

var
  Form2: TForm2;

implementation

{$R *.DFM}

end.
Regards
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

Additional note:

such situations, like described above, can be detected automatically:

Code: Select all

    procedure WMWindowPosChanged(var Message : TWMWindowPosChanged); message WM_WINDOWPOSCHANGED;

Code: Select all

procedure TForm1.WMWindowPosChanged(var Message : TWMWindowPosChanged);
begin
  inherited;
  if GetWindowLong(Handle,GWL_STYLE) and WS_DISABLED <> 0 then
  if GetForegroundWindow = Handle then
    raise Exception.Create('Disabled window moved to top');
end;
Exception handler should report the call stack, so the bug report will allow to find a cause of this problem.

This code can be used for example in beta version of Total Commander. Or even a plugin for Total Commander can be created, that hooks messages of main TCMD window and detects such situations. This plugin could be sent to the author of this bug report.
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 48088
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

Hmm, an exception doesn't solve anything. Maybe I could just call SetWindowPos with flag HWND_BOTTOM in this situation?
Author of Total Commander
https://www.ghisler.com
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

Well, this is not a normal situation (when something brings a disabled window to the top programatically), so I suggested raising an exception to find a cause of this situation and fix it.

Calling SetWindowPos with HWND_BOTTOM is not a solution, because the window will be placed below all other windows belonging to the desktop (for example Explorer, internet browser, Microsoft Office...).

The code below may be used as a workaround, it restores the proper window order. Note: This code works with Delphi 5, but not with Delphi 2. Probably FormState property is private in Delphi 2. As I checked with a debugger, fsModal is being set in FormState (inside a TCustomForm.ShowModal method) also in Delphi 2, so moving FormState property to the public or protected section should solve the problem.

Code: Select all

procedure TForm1.WMWindowPosChanged(var Message : TWMWindowPosChanged);
var
  I : Integer;
  DWP : HDWP;
  WndInsertAfter : HWND;
begin
  inherited;
  if GetWindowLong(Handle,GWL_STYLE) and WS_DISABLED <> 0 then
  if GetForegroundWindow = Handle then
  begin
    DWP:=BeginDeferWindowPos(0);
    try
      {There may be more than one modal form at the same time (Form1 fires Form2 as modal,
       Form2 fires Form3 as modal etc.)}
      WndInsertAfter:=HWND_TOP;
      with Screen do
      for I:=0 to FormCount-1 do
      if fsModal in Forms[I].FormState then {FormState is a private property in Delphi 2 ?}
      begin
        DWP:=DeferWindowPos(DWP,Forms[I].Handle,WndInsertAfter,0,0,0,0,SWP_NOSIZE or SWP_NOMOVE);
        WndInsertAfter:=Handle;
      end;
    finally
      EndDeferWindowPos(DWP);
    end;
    if GetForegroundWindow = Handle then {EndDeferWindowPos failed or there is no modal form}
      raise Exception.Create('Disabled window moved to top');
  end;
end;
Regards
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 48088
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

OK, I have added some code now (in OnActivate, not WindowPosChanged), but I cannot reproduce it myself -therefore please test it when the first beta of TC 8.5 comes out.
Author of Total Commander
https://www.ghisler.com
foxidrive
Junior Member
Junior Member
Posts: 90
Joined: 2004-02-28, 11:50 UTC

Post by *foxidrive »

Ok, I shall. Thanks.
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

I'm afraid that OnActivate will not work.

If we use OnActivate of main TCMD window, the event will not be fired when the main TCMD window is disabled.

If we use OnActivate of copy dialog:
1) we have no guarantee that this will work, because main window may be brought to top _after_ handling OnActivate event,
2) it's not an universal solution, because we should add such OnActivate handling also to all other modal dialogs.

So I'm afraid that WM_WINDOWPOSCHANGED is the only reliable solution.

Regards
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 48088
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

In my tests, I did NOT receive WM_WINDOWPOSCHANGED messages with the copy progress dialog, but I did receive OnActivate notifications...
Author of Total Commander
https://www.ghisler.com
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

Mhmm, do you use OnActivate event of copy dialog or OnActivate event of main TCMD window?

WM_WINDOWPOSCHANGED should be used with the main TCMD window.

OnActivate event of copy dialog seems not to be a good solution - please note my previous post.

Regards
foxidrive
Junior Member
Junior Member
Posts: 90
Joined: 2004-02-28, 11:50 UTC

Post by *foxidrive »

Some more info here: I was copying between two local drives and the target was the spanned drive set (Z: drive).

I copied from the right hand to left hand panes - the D: source drive was in the right hand pane.

When I pressed F5 to start the copy it took a while and then the TC main window lost focus and displayed a background window, and I instinctively used Alt Tab (once/twice?) to bring it back into focus where the copy was progressing.

Sorry for the lack of details but when it happens I just use alt tab without thinking - and it's not a show stopper.

Addendum: I have spent some time trying to reproduce the issue but it is not merely a case of the drive being asleep, and haven't been able to reproduce it yet.
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

ghisler(Author) wrote:In my tests, I did NOT receive WM_WINDOWPOSCHANGED messages with the copy progress dialog, but I did receive OnActivate notifications...
Well, I omitted one very important thing.

In my example above, Form1 shows Form2 as modal, but Form1 is not the owner of Form2 [the owner of Form2 is the Application window (class 'TApplication')].

In Total Commander, the main window (class 'TTOTAL_CMD') shows copy dialog (class 'TDLG2FILEACTIONMIN') as modal, and the main window is the owner of copy dialog.

So my code (procedure TForm1.WMWindowPosChanged, called for message WM_WINDOWPOSCHANGED) will NOT work in this case. Moreover, in this case, the main TCMD window can't be placed over the copy dialog and cover it - operating system will not allow this. So I must have misunderstood foxidrive's bug report. And I have no idea what is really the problem.

So the only hope is that foxidrive will be able to reproduce the problem and tell us exactly how to reproduce it. Or maybe also make a small video that shows the problem.

So I apologize, but all modifications of OnActivate or WM_WINDOWPOSCHANGED message are useless in this case.

Regards
Post Reply