File move and unsynchronized dialog windows

The behaviour described in the bug report is either by design, or would be far too complex/time-consuming to be changed

Moderators: Hacker, petermad, Stefan2, white

Post Reply
browny
Senior Member
Senior Member
Posts: 362
Joined: 2007-09-10, 13:19 UTC

File move and unsynchronized dialog windows

Post by *browny »

OS Windows 8.1 64-bit, TC 9.0 rc2 64-bit.

A file was to be moved with overwrite from one disk to another using F6 key function (different partitions of the same drive in this case, though this should not be important).

What should happen.
1) Dialog to select destination is displayed. Just press Enter.
2) Standard Rename/Move dialog with Pause/Cancel/Background buttons appears.
3) Now overwrite dialog with lots of options is displayed; and Overwrite button is selected by default.
3) Press spacebar, and the process completes.

What happened.
Dialog #3 usually appears very quickly, so pressing spacebar shortly after the dialog #2 would be fine as the key goes to dialog #3.
But this time the system had some disk activity and there was substantial delay before dialog #3.

Spacebar was pressed after the dialog #2 appeared but well before dialog #3.
However, overwrite dialog was displayed.
Overwrite button was pressed.
File was successfully moved.
But in the end there was "User abort" messagebox.
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

It sounds like a problem with not flushed message queue.

Calling the code below at the moment of showing any new window (or dialog window), for example in WM_INITDIALOG handler, should help:

Code: Select all

procedure FlushInputMessages;
var
  TempMsg : TMsg;
begin
  while PeekMessage(TempMsg,0,$200{WM_MOUSEFIRST},$20E{WM_MOUSELAST},PM_REMOVE) do;

  while PeekMessage(TempMsg,0,$100{WM_KEYFIRST},$109{WM_KEYLAST},PM_REMOVE) do;

  while PeekMessage(TempMsg,0,$FF{WM_INPUT},$FF{WM_INPUT},PM_REMOVE) do;

  while PeekMessage(TempMsg,0,WM_HOTKEY,WM_HOTKEY,PM_REMOVE) do;
end;
Note: WM_MOUSELAST and WM_KEYLAST values have been taken from the last available windows.h.
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 50550
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

This would actually kill the messages which the user wants to get sent to the newly created window, although he pressed it too early...
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 »

MarcinW wrote:Calling the code below at the moment of showing any new window (or dialog window), for example in WM_INITDIALOG handler, should help
This was a bit unfortunate statement. Normally, there is no need to flush message queue when creating a window, because the window is being created and displayed immediately.

The problem is only when there is a huge pause in message handling (either during window creation or during its normal work) - in particular when there is some long-lasting operation in the window's initialization code (most probably in WM_CREATE or WM_INITDIALOG handler). The operating system collects all unhandled messages - including input messages - for all existing windows and delivers them when the thread becomes responsive.

And this is exactly what should be prevented in our case - the user presses some keys, but several seconds later a window (already created, but still not painted on the screen) appears and the keystrokes are delivered to this window, forcing some unintentional actions.

ghisler(Author) wrote:This would actually kill the messages which the user wants to get sent to the newly created window, although he pressed it too early...
More precisely, this will kill all input messages, for all windows - but it's just what we want to do: we want to ensure that no keystrokes or mouseclicks will be collected and delivered after TC becomes responsive again. We want to flush stale messages for all windows - just because we want to prevent ALL windows from performing unintentional actions.

Since normally there are no unhandled messages, this code does nothing in most cases. Unhandled messages may appear only during TC unresponsiveness - and this is the case when we want to remove them.

You may easily perform some tests - place Sleep(4000) in the WM_INITDIALOG handler and place - or not - a FlushInputMessages call below.
User avatar
MarcinW
Power Member
Power Member
Posts: 852
Joined: 2012-01-23, 15:58 UTC
Location: Poland

Post by *MarcinW »

Additional note:

If you perform some potentially blocking and long-lasting operations during the dialog initialization, you may try to call FlushInputMessages at the end of each initialization handler. In our example, TC probably tried to access the filesystem, but antivirus software blocked the access for a while; since (most probably) many TC dialogs must use filesystem during the initialization, you DO perform potentially blocking operations during the initialization process.

For example, if you perform these potentially blocking operations in a WM_INITDIALOG handler, you may consider adding a FlushInputMessages call at the end of each WM_INITDIALOG handler. You certainly use your own, subclassed dialog template, so this should be easy to add such a call to FlushInputMessages globally. And this would solve the problem globally, in all TC dialogs.
User avatar
ghisler(Author)
Site Admin
Site Admin
Posts: 50550
Joined: 2003-02-04, 09:46 UTC
Location: Switzerland
Contact:

Post by *ghisler(Author) »

But some people WANT to keep these hotkeys they press in advance! For example read this thread:
http://ghisler.ch/board/viewtopic.php?t=45684
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, it's a choice between convenience and safety...

In my personal opinion, it's rather rare case, when TC becomes unresponsive - so I'd prefer to choose safety.
User avatar
Hacker
Moderator
Moderator
Posts: 13142
Joined: 2003-02-06, 14:56 UTC
Location: Bratislava, Slovakia

Post by *Hacker »

I prefer convenience. :D

Roman
Mal angenommen, du drückst Strg+F, wählst die FTP-Verbindung (mit gespeichertem Passwort), klickst aber nicht auf Verbinden, sondern fällst tot um.
browny
Senior Member
Senior Member
Posts: 362
Joined: 2007-09-10, 13:19 UTC

Post by *browny »

ghisler(Author) wrote:But some people WANT to keep these hotkeys they press in advance!
No objections to buffered input.
Could it be that (in my example) if operation completed then all buffered input would be ignored in Pause/Cance/Backgound dialog procefure?
No belated 'User abort' dialogs should be seen.
If operation was in progress (big file), then input would be processed as usual.
Post Reply