Copy window hides on waking drives
Moderators: Hacker, petermad, Stefan2, white
Copy window hides on waking drives
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.
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.
- ghisler(Author)
- Site Admin
- Posts: 50386
- Joined: 2003-02-04, 09:46 UTC
- Location: Switzerland
- Contact:
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
https://www.ghisler.com
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.
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.
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.
But even in such case, the copy dialog is alway on top of TC. So no, I cannot reproduce it.
Windows 10 Pro x64, Windows 11 Pro x64
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.
Regards
- 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.
Additional note:
such situations, like described above, can be detected automatically:
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.
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;
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.
- ghisler(Author)
- Site Admin
- Posts: 50386
- Joined: 2003-02-04, 09:46 UTC
- Location: Switzerland
- Contact:
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
https://www.ghisler.com
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.
Regards
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;
- ghisler(Author)
- Site Admin
- Posts: 50386
- Joined: 2003-02-04, 09:46 UTC
- Location: Switzerland
- Contact:
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
https://www.ghisler.com
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
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
- ghisler(Author)
- Site Admin
- Posts: 50386
- Joined: 2003-02-04, 09:46 UTC
- Location: Switzerland
- Contact:
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
https://www.ghisler.com
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.
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.
Well, I omitted one very important thing.ghisler(Author) wrote:In my tests, I did NOT receive WM_WINDOWPOSCHANGED messages with the copy progress dialog, but I did receive OnActivate notifications...
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