2

running the form below and continuously scrolling the treeview up and down will freeze the form on (my) Windows 10. The scrollbar, the form title bar and its buttons all become unresponsive, but will still update on timer events. Clicking on treeview still works normally. On (my) Windows 7, the freezing does not happen.

On (my) Windows 10 When you click or Alt-tab away from the application and back, form becomes responsive again. Which means that whenever I switched away to Delphi IDE to pause and see what was going on, problem was gone. On one occasion I did manage to get form so stuck that switching away from it to debugger did not unfreeze it, and the Call Stack was deep inside UxTheme.dll.

As you can see in the code I have a sort of a workaround but it is not very satisfying. Can anybody explain what is going on here ?

I did my best to make the code sample below easy to run from scratch, that's why I included the .dpr The problem originates from a much more complex form updated from a background thread.

Update: just tried same sort of thing with TListView and I get no freezing.

Update: as nolaspeaker suggested, compiling without "enable runtime themes" fixes the problem.

Update: my original complex form was not fixed by compiling without "enable runtime themes" - as the app uses a custom manifest. However using DisableThemesApp from here How to switch an Application between Themed and not Themed at run-time? helped. In fact skipping STAP_ALLOW_NONCLIENT was enough. The only downside being, on Windows 10 the app now looks like something from Deliverance - i.e. inbred :). So I will continue using my GetLastInputInfo bodge until someone suggests something better.

unit Win10Freezing;

interface

uses
  Winapi.Windows, Winapi.Messages, System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
  Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ExtCtrls, Vcl.ComCtrls;

type
  TWin10FreezingForm = class(TForm)
  private
    FTreeView: TTreeView;
    procedure TimerTimer(Sender: TObject);
    function HasASecondPassedSinceLastInput: boolean;
  public
    constructor Create(AOwner: TComponent);override;
  end;

var
  Win10FreezingForm: TWin10FreezingForm;

implementation

{$R *.dfm}

constructor TWin10FreezingForm.Create(AOwner: TComponent);
begin
  inherited;
  Width := 355;
  Height := 355;
  FTreeView := TTreeView.Create(self);
  with FTreeView do begin
    Parent := self;
    Align := alClient
  end;
  with TTimer.Create(self) do begin
    OnTimer := TimerTimer;
    Interval := 2000;
    Enabled := TRUE
  end;
  TimerTimer(self)
end;

procedure TWin10FreezingForm.TimerTimer(Sender: TObject);
var
  i: Integer;
begin
  //once the TreeView has been populated
  //continuously scroling the listView up and down will freeze the form
  //uncomment the following line as a not very good workaround
  //if HasASecondPassedSinceLastInput then
  with FTreeView.Items do begin
    BeginUpdate;
    try
      Clear;
      for i := 0 to 30 + Random(10) do
        AddChild(nil, IntToStr(Random(100)))
    finally
      EndUpdate
    end
  end
end;

function TWin10FreezingForm.HasASecondPassedSinceLastInput: boolean;
var lii: TLastInputInfo;
begin
  lii.cbSize := SizeOf(TLastInputInfo);
  result := GetLastInputInfo(lii) and (GetTickCount - lii.dwTime > 1000)
end;

end.

program Win10Freeze;

uses
  Vcl.Forms,
  Win10Freezing in 'Win10Freezing.pas' {Win10FreezingForm};

{$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Application.CreateForm(TWin10FreezingForm, Win10FreezingForm);
  Application.Run;
end.
Peter
  • 123
  • 1
  • 8
  • 1
    What happens if you compile the application without "enable runtime themes" enabled? – Freddie Bell Aug 22 '18 at 10:46
  • @nolaspeaker I tried that on my original problem - it did not help, will try with the sample now .. – Peter Aug 22 '18 at 10:47
  • @nolaspeaker - it works, putting false in .dproj fixes the problem ! Do you want to write an answer ? – Peter Aug 22 '18 at 10:52
  • 2
    So the problem is probably located in the W10 common runtime. Maybe it's better to avoid updating the treeview if the user is scrolling it? – whosrdaddy Aug 22 '18 at 10:56
  • @whosrdaddy - that's what I attempted to do using GetLastInputInfo - is there a better way ? – Peter Aug 22 '18 at 11:00
  • Funny problem, I was only able to reproduce it once, now it always works... – whosrdaddy Aug 22 '18 at 11:22
  • @Peter It was a guess (not from experience). My clue was when you said it was 'deep inside UxTheme.dll.' Enjoy – Freddie Bell Aug 22 '18 at 11:39
  • Did you try disabling the timer before populating the control and then enabling it again afterwards? – Sertac Akyuz Aug 22 '18 at 16:26
  • @Sertac Akyuz - yes, the only reason I did not include that was to have more compact code. Plus I got the same problem when updating the code from background thread using PostMessage. – Peter Aug 22 '18 at 16:27
  • Ok. That shouldn't help anyway, timer messages does not accumulate or not re-entrant. Unless you aren't processing queue messages in the timer handler, which you aren't. Wanted to ask anyway as there's apparently a difference on OS part... – Sertac Akyuz Aug 22 '18 at 16:32

0 Answers0