فهرست منبع

Ensure all TSetupForms have a taskbar button when main form hasn't been created or is invisible.

Jordan Russell 8 ماه پیش
والد
کامیت
0b99e785a1
3فایلهای تغییر یافته به همراه34 افزوده شده و 19 حذف شده
  1. 1 12
      Projects/Src/Setup.NewDiskForm.pas
  2. 18 3
      Projects/Src/Setup.SetupForm.pas
  3. 15 4
      Projects/Src/Shared.CommonFunc.Vcl.pas

+ 1 - 12
Projects/Src/Setup.NewDiskForm.pas

@@ -2,7 +2,7 @@ unit Setup.NewDiskForm;
 
 
 {
 {
   Inno Setup
   Inno Setup
-  Copyright (C) 1997-2024 Jordan Russell
+  Copyright (C) 1997-2025 Jordan Russell
   Portions by Martijn Laan
   Portions by Martijn Laan
   For conditions of distribution and use, see LICENSE.TXT.
   For conditions of distribution and use, see LICENSE.TXT.
 
 
@@ -31,8 +31,6 @@ type
     Filename: string;
     Filename: string;
     function GetSanitizedPath: String;
     function GetSanitizedPath: String;
     procedure CMShowingChanged(var Message: TMessage); message CM_SHOWINGCHANGED;
     procedure CMShowingChanged(var Message: TMessage); message CM_SHOWINGCHANGED;
-  protected
-    procedure CreateParams(var Params: TCreateParams); override;
   public
   public
     { Public declarations }
     { Public declarations }
     constructor Create(AOwner: TComponent); override;
     constructor Create(AOwner: TComponent); override;
@@ -91,15 +89,6 @@ begin
   FlipSizeAndCenterIfNeeded(Assigned(WizardForm), WizardForm, False);
   FlipSizeAndCenterIfNeeded(Assigned(WizardForm), WizardForm, False);
 end;
 end;
 
 
-procedure TNewDiskForm.CreateParams(var Params: TCreateParams);
-begin
-  inherited;
-  { Make sure the form gets a taskbar button if WizardForm doesn't exist yet
-    or if it isn't visible because it's a very silent install }
-  if (WizardForm = nil) or not WizardForm.Visible then
-    Params.WndParent := 0;
-end;
-
 procedure TNewDiskForm.CMShowingChanged(var Message: TMessage);
 procedure TNewDiskForm.CMShowingChanged(var Message: TMessage);
 begin
 begin
   inherited;
   inherited;

+ 18 - 3
Projects/Src/Setup.SetupForm.pas

@@ -2,7 +2,7 @@ unit Setup.SetupForm;
 
 
 {
 {
   Inno Setup
   Inno Setup
-  Copyright (C) 1997-2024 Jordan Russell
+  Copyright (C) 1997-2025 Jordan Russell
   Portions by Martijn Laan
   Portions by Martijn Laan
   For conditions of distribution and use, see LICENSE.TXT.
   For conditions of distribution and use, see LICENSE.TXT.
 
 
@@ -13,7 +13,7 @@ interface
 
 
 uses
 uses
   Windows, SysUtils, Messages, Classes, Graphics, Controls, Forms, Dialogs,
   Windows, SysUtils, Messages, Classes, Graphics, Controls, Forms, Dialogs,
-  UIStateForm, Shared.SetupMessageIDs;
+  UIStateForm;
 
 
 type
 type
   TSetupForm = class(TUIStateForm)
   TSetupForm = class(TUIStateForm)
@@ -74,7 +74,7 @@ implementation
 
 
 uses
 uses
   Generics.Collections, UITypes,
   Generics.Collections, UITypes,
-  Shared.CommonFunc, Setup.MainFunc, SetupLdrAndSetup.Messages, BidiUtils;
+  Shared.CommonFunc, Shared.CommonFunc.Vcl, Setup.MainFunc, BidiUtils;
 
 
 var
 var
   WM_QueryCancelAutoPlay: UINT;
   WM_QueryCancelAutoPlay: UINT;
@@ -379,6 +379,21 @@ end;
 procedure TSetupForm.CreateParams(var Params: TCreateParams);
 procedure TSetupForm.CreateParams(var Params: TCreateParams);
 begin
 begin
   inherited;
   inherited;
+  { With Application.MainFormOnTaskBar=True, by default, a form won't get a
+    taskbar button if the main form hasn't been created yet (due to the owner
+    being an invisible Application.Handle), or if the main form exists but
+    isn't visible (e.g., because it's a silent install). Force it to have a
+    taskbar button in those cases by specifying no owner for the window.
+    (Another method is to set WS_EX_APPWINDOW and leave WndParent set to
+    Application.Handle, but it doesn't quite work correctly: if the form
+    displays a message box, and you activate another app's window, clicking on
+    the form's taskbar button activates the message box again, but the taskbar
+    button doesn't change to a "selected" state.) }
+  if (Params.WndParent <> 0) and
+     (Application.MainFormOnTaskBar or (Params.WndParent <> Application.Handle)) and
+     not IsWindowOnTaskbar(Params.WndParent) then
+    Params.WndParent := 0;
+
   if FRightToLeft then
   if FRightToLeft then
     Params.ExStyle := Params.ExStyle or (WS_EX_RTLREADING or WS_EX_LEFTSCROLLBAR or WS_EX_RIGHT);
     Params.ExStyle := Params.ExStyle or (WS_EX_RTLREADING or WS_EX_LEFTSCROLLBAR or WS_EX_RIGHT);
 end;
 end;

+ 15 - 4
Projects/Src/Shared.CommonFunc.Vcl.pas

@@ -56,6 +56,7 @@ function GetMessageBoxRightToLeft: Boolean;
 procedure SetMessageBoxCallbackFunc(const AFunc: TMsgBoxCallbackFunc; const AParam: LongInt);
 procedure SetMessageBoxCallbackFunc(const AFunc: TMsgBoxCallbackFunc; const AParam: LongInt);
 procedure TriggerMessageBoxCallbackFunc(const Flags: LongInt; const After: Boolean);
 procedure TriggerMessageBoxCallbackFunc(const Flags: LongInt; const After: Boolean);
 function GetOwnerWndForMessageBox: HWND;
 function GetOwnerWndForMessageBox: HWND;
+function IsWindowOnTaskbar(const Wnd: HWND): Boolean;
 
 
 implementation
 implementation
 
 
@@ -241,21 +242,31 @@ begin
   if (Result = Application.Handle) and IsIconic(Result) then
   if (Result = Application.Handle) and IsIconic(Result) then
     Exit(0);
     Exit(0);
 
 
+  if not IsWindowOnTaskbar(Result) then
+    Result := 0;
+end;
+
+function IsWindowOnTaskbar(const Wnd: HWND): Boolean;
+begin
   { Find the "root owner" window, which is what appears in the taskbar.
   { Find the "root owner" window, which is what appears in the taskbar.
     We avoid GetAncestor(..., GA_ROOTOWNER) because it's broken in the same
     We avoid GetAncestor(..., GA_ROOTOWNER) because it's broken in the same
     way as GetParent(): it stops if it reaches a top-level window that doesn't
     way as GetParent(): it stops if it reaches a top-level window that doesn't
     have the WS_POPUP style (i.e., a WS_OVERLAPPED window). }
     have the WS_POPUP style (i.e., a WS_OVERLAPPED window). }
-  var RootWnd := Result;
+  var RootWnd := Wnd;
   while True do begin
   while True do begin
+    { Visible WS_EX_APPWINDOW windows have their own taskbar button regardless
+      of their root owner's visibility }
+    if (GetWindowLong(RootWnd, GWL_EXSTYLE) and WS_EX_APPWINDOW <> 0) and
+       (GetWindowLong(RootWnd, GWL_STYLE) and WS_VISIBLE <> 0) then
+      Exit(True);
     var ParentWnd := HWND(GetWindowLongPtr(RootWnd, GWLP_HWNDPARENT));
     var ParentWnd := HWND(GetWindowLongPtr(RootWnd, GWLP_HWNDPARENT));
     if ParentWnd = 0 then
     if ParentWnd = 0 then
       Break;
       Break;
     RootWnd := ParentWnd;
     RootWnd := ParentWnd;
   end;
   end;
 
 
-  if (GetWindowLong(RootWnd, GWL_STYLE) and WS_VISIBLE = 0) or
-     (GetWindowLong(RootWnd, GWL_EXSTYLE) and WS_EX_TOOLWINDOW <> 0) then
-    Result := 0;
+  Result := (GetWindowLong(RootWnd, GWL_STYLE) and WS_VISIBLE <> 0) and
+    (GetWindowLong(RootWnd, GWL_EXSTYLE) and WS_EX_TOOLWINDOW = 0);
 end;
 end;
 
 
 function AppMessageBox(const Text, Caption: PChar; Flags: Longint): Integer;
 function AppMessageBox(const Text, Caption: PChar; Flags: Longint): Integer;