Bladeren bron

Merge branch 'main' into autoreload

Martijn Laan 1 maand geleden
bovenliggende
commit
6f3d187ed6

+ 193 - 0
Components/BitmapButton.pas

@@ -0,0 +1,193 @@
+unit BitmapButton;
+
+{
+  Inno Setup
+  Copyright (C) 1997-2025 Jordan Russell
+  Portions by Martijn Laan
+  For conditions of distribution and use, see LICENSE.TXT.
+
+  A TImage-like component for bitmaps without the TPicture bloat and
+  which is actually a button with a focus rectangle when focused - in
+  other words: an accessible TImage
+  
+  Make sure to set the Caption property, even if it isn't visible
+
+  Also see TBitmapImage which is the TGraphicControl version
+}
+
+interface
+
+uses
+  Windows, Messages, Controls, Graphics, Classes,
+  BitmapImage;
+
+type
+  TBitmapButton = class(TCustomControl)
+  private
+    FFocusBorderWidthHeight: Integer;
+    FImpl: TBitmapImageImplementation;
+    FOnClick: TNotifyEvent;
+    FOnDblClick: TNotifyEvent;
+    procedure SetBackColor(Value: TColor);
+    procedure SetBitmap(Value: TBitmap);
+    procedure SetCenter(Value: Boolean);
+    procedure SetReplaceColor(Value: TColor);
+    procedure SetReplaceWithColor(Value: TColor);
+    procedure SetStretch(Value: Boolean);
+    procedure WMSetFocus(var Message: TWMSetFocus); message WM_SETFOCUS;
+    procedure WMKillFocus(var Message: TWMKillFocus); message WM_KILLFOCUS;
+    procedure CNCommand(var Message: TWMCommand); message CN_COMMAND;
+  protected
+    procedure CreateParams(var Params: TCreateParams); override;
+    function GetPalette: HPALETTE; override;
+    procedure Paint; override;
+    procedure SetAutoSize(Value: Boolean); override;
+  public
+    constructor Create(AOwner: TComponent); override;
+    destructor Destroy; override;
+    function InitializeFromIcon(const Instance: HINST; const Name: PChar; const BkColor: TColor; const AscendingTrySizes: array of Integer): Boolean;
+  published
+    property Align;
+    property Anchors;
+    property AutoSize: Boolean read FImpl.AutoSize write SetAutoSize default False;
+    property BackColor: TColor read FImpl.BackColor write SetBackColor default clNone;
+    property Caption;
+    property Center: Boolean read FImpl.Center write SetCenter default True;
+    property Enabled;
+    property ParentShowHint;
+    property Bitmap: TBitmap read FImpl.Bitmap write SetBitmap;
+    property PopupMenu;
+    property ShowHint;
+    property Stretch: Boolean read FImpl.Stretch write SetStretch default False;
+    property ReplaceColor: TColor read FImpl.ReplaceColor write SetReplaceColor default clNone;
+    property ReplaceWithColor: TColor read FImpl.ReplaceWithColor write SetReplaceWithColor default clNone;
+    property TabOrder;
+    property TabStop default True;
+    property Visible;
+    property OnClick: TNotifyEvent read FOnClick write FOnClick;
+    property OnDblClick: TNotifyEvent read FOnDblClick write FOnDblClick;
+    property OnPaint: TPaintEvent read FImpl.OnPaint write FImpl.OnPaint;
+  end;
+
+procedure Register;
+
+implementation
+
+procedure Register;
+begin
+  RegisterComponents('JR', [TBitmapButton]);
+end;
+
+constructor TBitmapButton.Create(AOwner: TComponent);
+begin
+  inherited;
+  ControlStyle := ControlStyle + [csReplicatable];
+  { Using a fixed focus border width/height to avoid design problems between systems }
+  FFocusBorderWidthHeight := 2;
+  const DoubleFBWH = 2*FFocusBorderWidthHeight;
+  FImpl.Init(Self, DoubleFBWH, DoubleFBWH);
+  Center := True;
+  TabStop := True;
+  Width := 75+DoubleFBWH;
+  Height := 25+DoubleFBWH;
+end;
+
+procedure TBitmapButton.CreateParams(var Params: TCreateParams);
+begin
+  inherited;
+  CreateSubClass(Params, 'BUTTON');
+end;
+
+destructor TBitmapButton.Destroy;
+begin
+  FImpl.DeInit;
+  inherited;
+end;
+
+function TBitmapButton.InitializeFromIcon(const Instance: HINST; const Name: PChar; const BkColor: TColor; const AscendingTrySizes: array of Integer): Boolean;
+begin
+  Result := FImpl.InitializeFromIcon(HInstance, Name, BkColor, AscendingTrySizes);
+end;
+
+procedure TBitmapButton.SetAutoSize(Value: Boolean);
+begin
+  FImpl.SetAutoSize(Self, Value);
+end;
+
+procedure TBitmapButton.SetBackColor(Value: TColor);
+begin
+  FImpl.SetBackColor(Self, Value);
+end;
+
+procedure TBitmapButton.SetBitmap(Value: TBitmap);
+begin
+  FImpl.SetBitmap(Value);
+end;
+
+procedure TBitmapButton.SetCenter(Value: Boolean);
+begin
+  FImpl.SetCenter(Self, Value);
+end;
+
+procedure TBitmapButton.SetReplaceColor(Value: TColor);
+begin
+  FImpl.SetReplaceColor(Self, Value);
+end;
+
+procedure TBitmapButton.SetReplaceWithColor(Value: TColor);
+begin
+  FImpl.SetReplaceWithColor(Self, Value);
+end;
+
+procedure TBitmapButton.SetStretch(Value: Boolean);
+begin
+  FImpl.SetStretch(Self, Value);
+end;
+
+function TBitmapButton.GetPalette: HPALETTE;
+begin
+  Result := FImpl.GetPalette;
+end;
+
+procedure TBitmapButton.Paint;
+begin
+  Canvas.Font := Font;
+  Canvas.Brush.Color := Color;
+
+  var R := ClientRect;
+
+  if Focused and (SendMessage(Handle, WM_QUERYUISTATE, 0, 0) and UISF_HIDEFOCUS = 0) then begin
+    { See TBitBtn.DrawItem in Vcl.Buttons.pas }
+    Canvas.Pen.Color := clWindowFrame;
+    Canvas.Brush.Style := bsSolid;
+    Canvas.Brush.Color := clBtnFace;
+    { This might draw a focus border thinner or thicker than our FFocusBorderWidthHeight but that's okay }
+    Canvas.DrawFocusRect(R);
+  end;
+
+  InflateRect(R, -FFocusBorderWidthHeight, -FFocusBorderWidthHeight);
+
+  FImpl.Paint(Self, Canvas, R);
+end;
+
+procedure TBitmapButton.WMSetFocus(var Message: TWMSetFocus);
+begin
+  inherited;
+  Invalidate;
+end;
+
+procedure TBitmapButton.WMKillFocus(var Message: TWMKillFocus);
+begin
+  inherited;
+  Invalidate;
+end;
+
+procedure TBitmapButton.CNCommand(var Message: TWMCommand);
+begin
+  if (Message.NotifyCode = BN_CLICKED) and Assigned(FOnClick) then
+    FOnClick(Self)
+  else if (Message.NotifyCode = BN_DBLCLK) and Assigned(FOnDblClick) then
+    FOnDblClick(Self);
+end;
+
+end.

+ 240 - 157
Components/BitmapImage.pas

@@ -2,11 +2,13 @@ unit BitmapImage;
 
 {
   Inno Setup
-  Copyright (C) 1997-2019 Jordan Russell
+  Copyright (C) 1997-2025 Jordan Russell
   Portions by Martijn Laan
   For conditions of distribution and use, see LICENSE.TXT.
 
   A TImage-like component for bitmaps without the TPicture bloat
+
+  Also see TBitmapButton which is the TWinControl version
 }
 
 interface
@@ -15,25 +17,48 @@ uses
   Windows, Controls, Graphics, Classes;
 
 type
-  TBitmapImage = class(TGraphicControl)
+  TPaintEvent = procedure(Sender: TObject; Canvas: TCanvas; var ARect: TRect) of object;
+
+  TBitmapImageImplementation = record
   private
-    FAutoSize: Boolean;
-    FBackColor: TColor;
-    FBitmap: TBitmap;
-    FCenter: Boolean;
-    FReplaceColor: TColor;
-    FReplaceWithColor: TColor;
-    FStretch: Boolean;
-    FStretchedBitmap: TBitmap;
-    FStretchedBitmapValid: Boolean;
+    FControl: TControl;
+  public
+    AutoSize: Boolean;
+    AutoSizeExtraWidth, AutoSizeExtraHeight: Integer;
+    BackColor: TColor;
+    Bitmap: TBitmap;
+    Center: Boolean;
+    ReplaceColor: TColor;
+    ReplaceWithColor: TColor;
+    Stretch: Boolean;
+    StretchedBitmap: TBitmap;
+    StretchedBitmapValid: Boolean;
+    OnPaint: TPaintEvent;
+    procedure Init(const AControl: TControl; const AAutoSizeExtraWidth: Integer = 0;
+      const AAutoSizeExtraHeight: Integer = 0);
+    procedure DeInit;
+    function InitializeFromIcon(const Instance: HINST; const Name: PChar; const BkColor: TColor; const AscendingTrySizes: array of Integer): Boolean;
     procedure BitmapChanged(Sender: TObject);
+    procedure SetAutoSize(Sender: TObject; Value: Boolean);
+    procedure SetBackColor(Sender: TObject; Value: TColor);
+    procedure SetBitmap(Value: TBitmap);
+    procedure SetCenter(Sender: TObject; Value: Boolean);
+    procedure SetReplaceColor(Sender: TObject; Value: TColor);
+    procedure SetReplaceWithColor(Sender: TObject; Value: TColor);
+    procedure SetStretch(Sender: TObject; Value: Boolean);
+    function GetPalette: HPALETTE;
+    procedure Paint(const Sender: TObject; const Canvas: TCanvas; var R: TRect);
+  end;
+
+  TBitmapImage = class(TGraphicControl)
+  private
+    FImpl: TBitmapImageImplementation;
     procedure SetBackColor(Value: TColor);
     procedure SetBitmap(Value: TBitmap);
     procedure SetCenter(Value: Boolean);
     procedure SetReplaceColor(Value: TColor);
     procedure SetReplaceWithColor(Value: TColor);
     procedure SetStretch(Value: Boolean);
-    function GetBitmap: TBitmap;
   protected
     function GetPalette: HPALETTE; override;
     procedure Paint; override;
@@ -45,19 +70,19 @@ type
   published
     property Align;
     property Anchors;
-    property AutoSize: Boolean read FAutoSize write SetAutoSize default False;
-    property BackColor: TColor read FBackColor write SetBackColor default clBtnFace;
-    property Center: Boolean read FCenter write SetCenter default False;
+    property AutoSize: Boolean read FImpl.AutoSize write SetAutoSize default False;
+    property BackColor: TColor read FImpl.BackColor write SetBackColor default clBtnFace;
+    property Center: Boolean read FImpl.Center write SetCenter default False;
     property DragCursor;
     property DragMode;
     property Enabled;
     property ParentShowHint;
-    property Bitmap: TBitmap read GetBitmap write SetBitmap;
+    property Bitmap: TBitmap read FImpl.Bitmap write SetBitmap;
     property PopupMenu;
     property ShowHint;
-    property Stretch: Boolean read FStretch write SetStretch default False;
-    property ReplaceColor: TColor read FReplaceColor write SetReplaceColor default clNone;
-    property ReplaceWithColor: TColor read FReplaceWithColor write SetReplaceWithColor default clNone;
+    property Stretch: Boolean read FImpl.Stretch write SetStretch default False;
+    property ReplaceColor: TColor read FImpl.ReplaceColor write SetReplaceColor default clNone;
+    property ReplaceWithColor: TColor read FImpl.ReplaceWithColor write SetReplaceWithColor default clNone;
     property Visible;
     property OnClick;
     property OnDblClick;
@@ -67,6 +92,7 @@ type
     property OnMouseDown;
     property OnMouseMove;
     property OnMouseUp;
+    property OnPaint: TPaintEvent read FImpl.OnPaint write FImpl.OnPaint;
     property OnStartDrag;
   end;
 
@@ -75,51 +101,68 @@ procedure Register;
 implementation
 
 uses
-  Math, Resample;
+  SysUtils, Math, Resample;
 
 procedure Register;
 begin
   RegisterComponents('JR', [TBitmapImage]);
 end;
 
-function TBitmapImage.InitializeFromIcon(const Instance: HINST; const Name: PChar; const BkColor: TColor; const AscendingTrySizes: array of Integer): Boolean;
-var
-  Flags: Cardinal;
-  Handle: THandle;
-  Icon: TIcon;
-  I, Size: Integer;
+{ TBitmapImageImplementation }
+
+procedure TBitmapImageImplementation.Init(const AControl: TControl;
+  const AAutoSizeExtraWidth, AAutoSizeExtraHeight: Integer);
+begin
+  FControl := AControl;
+  AutoSizeExtraWidth := AAutoSizeExtraWidth;
+  AutoSizeExtraHeight := AAutoSizeExtraHeight;
+  Bitmap := TBitmap.Create;
+  Bitmap.OnChange := BitmapChanged;
+  BackColor := clNone;
+  ReplaceColor := clNone;
+  ReplaceWithColor := clNone;
+  StretchedBitmap := TBitmap.Create;
+end;
+
+procedure TBitmapImageImplementation.DeInit;
+begin
+  FreeAndNil(StretchedBitmap);
+  FreeAndNil(Bitmap);
+end;
+
+function TBitmapImageImplementation.InitializeFromIcon(const Instance: HINST; const Name: PChar; const BkColor: TColor; const AscendingTrySizes: array of Integer): Boolean;
 begin
   { Find the largest regular icon size smaller than the scaled image }
-  Size := 0;
-  for I := Length(AscendingTrySizes)-1 downto 0 do begin
-    if (Width >= AscendingTrySizes[I]) and (Height >= AscendingTrySizes[I]) then begin
+  var Size := 0;
+  for var I := Length(AscendingTrySizes)-1 downto 0 do begin
+    if (FControl.Width >= AscendingTrySizes[I]) and (FControl.Height >= AscendingTrySizes[I]) then begin
       Size := AscendingTrySizes[I];
       Break;
     end;
   end;
   if Size = 0 then
-    Size := Min(Width, Height);
+    Size := Min(FControl.Width, FControl.Height);
 
   { Load the desired icon }
-  Flags := LR_DEFAULTCOLOR;
+  var Flags := LR_DEFAULTCOLOR;
   if Instance = 0 then
     Flags := Flags or LR_LOADFROMFILE;
-  Handle := LoadImage(Instance, Name, IMAGE_ICON, Size, Size, Flags);
+  var Handle := LoadImage(Instance, Name, IMAGE_ICON, Size, Size, Flags);
   if Handle = 0 then
     Handle := LoadImage(Instance, Name, IMAGE_ICON, 0, 0, Flags);
   if Handle <> 0 then begin
-    Icon := TIcon.Create;
+    const Icon = TIcon.Create;
     try
       Icon.Handle := Handle;
 
       { Set sizes (overrides any scaling) }
-      Width := Icon.Width;
-      Height := Icon.Height;
+      FControl.Width := Icon.Width;
+      FControl.Height := Icon.Height;
 
       { Draw icon into bitmap }
       Bitmap.Canvas.Brush.Color := BkColor;
-      Bitmap.Width := Width;
-      Bitmap.Height := Height;
+      Bitmap.Width := FControl.Width;
+      Bitmap.Height := FControl.Height;
       Bitmap.Canvas.Draw(0, 0, Icon);
 
       Result := True;
@@ -130,173 +173,213 @@ begin
     Result := False;
 end;
 
+procedure TBitmapImageImplementation.BitmapChanged(Sender: TObject);
+begin
+  StretchedBitmapValid := False;
+  if AutoSize and (Bitmap.Width > 0) and (Bitmap.Height > 0) then
+    FControl.SetBounds(FControl.Left, FControl.Top, Bitmap.Width + AutoSizeExtraWidth,
+      Bitmap.Height + AutoSizeExtraHeight);
+  if (Bitmap.Width >= FControl.Width) and (Bitmap.Height >= FControl.Height) then
+    FControl.ControlStyle := FControl.ControlStyle + [csOpaque] - [csParentBackground]
+  else
+    FControl.ControlStyle := FControl.ControlStyle - [csOpaque] + [csParentBackground];
+  FControl.Invalidate;
+end;
+
+procedure TBitmapImageImplementation.SetAutoSize(Sender: TObject; Value: Boolean);
+begin
+  AutoSize := Value;
+  BitmapChanged(Sender);
+end;
+
+procedure TBitmapImageImplementation.SetBackColor(Sender: TObject; Value: TColor);
+begin
+  if BackColor <> Value then begin
+    BackColor := Value;
+    BitmapChanged(Sender);
+  end;
+end;
+
+procedure TBitmapImageImplementation.SetBitmap(Value: TBitmap);
+begin
+  Bitmap.Assign(Value);
+end;
+
+procedure TBitmapImageImplementation.SetCenter(Sender: TObject; Value: Boolean);
+begin
+  if Center <> Value then begin
+    Center := Value;
+    BitmapChanged(Sender);
+  end;
+end;
+
+procedure TBitmapImageImplementation.SetReplaceColor(Sender: TObject; Value: TColor);
+begin
+  if ReplaceColor <> Value then begin
+    ReplaceColor := Value;
+    BitmapChanged(Sender);
+  end;
+end;
+
+procedure TBitmapImageImplementation.SetReplaceWithColor(Sender: TObject; Value: TColor);
+begin
+  if ReplaceWithColor <> Value then begin
+    ReplaceWithColor := Value;
+    BitmapChanged(Sender);
+  end;
+end;
+
+procedure TBitmapImageImplementation.SetStretch(Sender: TObject; Value: Boolean);
+begin
+  if Stretch <> Value then begin
+    Stretch := Value;
+    StretchedBitmap.Assign(nil);
+    BitmapChanged(Sender);
+  end;
+end;
+
+function TBitmapImageImplementation.GetPalette: HPALETTE;
+begin
+  Result := Bitmap.Palette;
+end;
+
+procedure TBitmapImageImplementation.Paint(const Sender: TObject; const Canvas: TCanvas; var R: TRect);
+begin
+  const Is32bit = (Bitmap.PixelFormat = pf32bit) and
+    (Bitmap.AlphaFormat in [afDefined, afPremultiplied]);
+
+  var W, H: Integer;
+  var Bmp: TBitmap;
+  if Stretch then begin
+    W := R.Width;
+    H := R.Height;
+    Bmp := StretchedBitmap;
+    if not StretchedBitmapValid or (StretchedBitmap.Width <> W) or
+        (StretchedBitmap.Height <> H) then begin
+      StretchedBitmapValid := True;
+      if (Bitmap.Width = W) and (Bitmap.Height = H) then
+        StretchedBitmap.Assign(Bitmap)
+      else begin
+        StretchedBitmap.Assign(nil);
+        if not StretchBmp(Bitmap, StretchedBitmap, W, H, Is32bit) then begin
+          if Is32bit then begin
+            StretchedBitmapValid := False;
+            Bmp := Bitmap;
+          end else begin
+            StretchedBitmap.Palette := CopyPalette(Bitmap.Palette);
+            StretchedBitmap.Width := W;
+            StretchedBitmap.Height := H;
+            StretchedBitmap.Canvas.StretchDraw(Rect(0, 0, W, H), Bitmap);
+          end;
+        end;
+      end;
+    end;
+  end else begin
+    Bmp := Bitmap;
+    W := Bmp.Width;
+    H := Bmp.Height;
+  end;
+
+  if (BackColor <> clNone) and (Is32Bit or (Bmp.Width < FControl.Width) or (Bmp.Height < FControl.Height)) then begin
+    Canvas.Brush.Style := bsSolid;
+    Canvas.Brush.Color := BackColor;
+    Canvas.FillRect(R);
+  end;
+
+  if csDesigning in FControl.ComponentState then begin
+    Canvas.Pen.Style := psDash;
+    Canvas.Brush.Style := bsClear;
+    Canvas.Rectangle(0, 0, FControl.Width, FControl.Height);
+  end;
+
+  var X := R.Left;
+  var Y := R.Top;
+  if Center then begin
+    Inc(X, (R.Width - W) div 2);
+    if X < 0 then
+      X := 0;
+    Inc(Y, (R.Height - H) div 2);
+    if Y < 0 then
+      Y := 0;
+  end;
+
+  if not Is32bit and (ReplaceColor <> clNone) and (ReplaceWithColor <> clNone) then begin
+    Canvas.Brush.Color := ReplaceWithColor;
+    Canvas.BrushCopy(Rect(X, Y, X + W, Y + H), Bmp, Rect(0, 0, Bmp.Width, Bmp.Height), ReplaceColor);
+  end else
+    Canvas.Draw(X, Y, Bmp);
+
+  if Assigned(OnPaint) then
+    OnPaint(Sender, Canvas, R);
+end;
+
+{ TBitmapImage }
+
 constructor TBitmapImage.Create(AOwner: TComponent);
 begin
-  inherited Create(AOwner);
+  inherited;
   ControlStyle := ControlStyle + [csReplicatable];
-  FBackColor := clBtnFace;
-  FBitmap := TBitmap.Create;
-  FBitmap.OnChange := BitmapChanged;
-  FReplaceColor := clNone;
-  FReplaceWithColor := clNone;
-  FStretchedBitmap := TBitmap.Create;
-  Height := 105;
+  FImpl.Init(Self);
+  FImpl.BackColor := clBtnFace;
   Width := 105;
+  Height := 105;
 end;
 
 destructor TBitmapImage.Destroy;
 begin
-  FStretchedBitmap.Free;
-  FBitmap.Free;
-  inherited Destroy;
+  FImpl.DeInit;
+  inherited;
 end;
 
-procedure TBitmapImage.BitmapChanged(Sender: TObject);
+function TBitmapImage.InitializeFromIcon(const Instance: HINST; const Name: PChar; const BkColor: TColor; const AscendingTrySizes: array of Integer): Boolean;
 begin
-  FStretchedBitmapValid := False;
-  if FAutoSize and (FBitmap.Width > 0) and (FBitmap.Height > 0) then
-    SetBounds(Left, Top, FBitmap.Width, FBitmap.Height);
-  if (FBitmap.Width >= Width) and (FBitmap.Height >= Height) then
-    ControlStyle := ControlStyle + [csOpaque]
-  else
-    ControlStyle := ControlStyle - [csOpaque];
-  Invalidate;
+  Result := FImpl.InitializeFromIcon(HInstance, Name, BkColor, AscendingTrySizes);
 end;
 
 procedure TBitmapImage.SetAutoSize(Value: Boolean);
 begin
-  FAutoSize := Value;
-  BitmapChanged(Self);
+  FImpl.SetAutoSize(Self, Value);
 end;
 
 procedure TBitmapImage.SetBackColor(Value: TColor);
 begin
-  if FBackColor <> Value then begin
-    FBackColor := Value;
-    BitmapChanged(Self);
-  end;
+  FImpl.SetBackColor(Self, Value);
 end;
 
 procedure TBitmapImage.SetBitmap(Value: TBitmap);
 begin
-  FBitmap.Assign(Value);
+  FImpl.SetBitmap(Value);
 end;
 
 procedure TBitmapImage.SetCenter(Value: Boolean);
 begin
-  if FCenter <> Value then begin
-    FCenter := Value;
-    BitmapChanged(Self);
-  end;
+  FImpl.SetCenter(Self, Value);
 end;
 
 procedure TBitmapImage.SetReplaceColor(Value: TColor);
 begin
-  if FReplaceColor <> Value then begin
-    FReplaceColor := Value;
-    BitmapChanged(Self);
-  end;
+  FImpl.SetReplaceColor(Self, Value);
 end;
 
 procedure TBitmapImage.SetReplaceWithColor(Value: TColor);
 begin
-  if FReplaceWithColor <> Value then begin
-    FReplaceWithColor := Value;
-    BitmapChanged(Self);
-  end;
+  FImpl.SetReplaceWithColor(Self, Value);
 end;
 
 procedure TBitmapImage.SetStretch(Value: Boolean);
 begin
-  if FStretch <> Value then begin
-    FStretch := Value;
-    FStretchedBitmap.Assign(nil);
-    BitmapChanged(Self);
-  end;
-end;
-
-function TBitmapImage.GetBitmap: TBitmap;
-begin
-  Result := FBitmap;
+  FImpl.SetStretch(Self, Value);
 end;
 
 function TBitmapImage.GetPalette: HPALETTE;
 begin
-  Result := FBitmap.Palette;
+  Result := FImpl.GetPalette;
 end;
 
 procedure TBitmapImage.Paint;
-var
-  R: TRect;
-  Bmp: TBitmap;
-  X, Y, W, H: Integer;
-  Is32bit: Boolean;
 begin
-  with Canvas do begin
-    R := ClientRect;
-    Is32bit := (FBitmap.PixelFormat = pf32bit) and
-      (FBitmap.AlphaFormat in [afDefined, afPremultiplied]);
-
-    if Stretch then begin
-      W := R.Right;
-      H := R.Bottom;
-      Bmp := FStretchedBitmap;
-      if not FStretchedBitmapValid or (FStretchedBitmap.Width <> W) or
-         (FStretchedBitmap.Height <> H) then begin
-        FStretchedBitmapValid := True;
-        if (FBitmap.Width = W) and (FBitmap.Height = H) then
-          FStretchedBitmap.Assign(FBitmap)
-        else begin
-          FStretchedBitmap.Assign(nil);
-          if not StretchBmp(FBitmap, FStretchedBitmap, W, H, Is32bit) then begin
-            if Is32bit then begin
-              FStretchedBitmapValid := False;
-              Bmp := FBitmap;
-            end else begin
-              FStretchedBitmap.Palette := CopyPalette(FBitmap.Palette);
-              FStretchedBitmap.Width := W;
-              FStretchedBitmap.Height := H;
-              FStretchedBitmap.Canvas.StretchDraw(R, FBitmap);
-            end;
-          end;
-        end;
-      end;
-    end else begin
-      Bmp := FBitmap;
-      W := Bmp.Width;
-      H := Bmp.Height;
-    end;
-
-    if (FBackColor <> clNone) and (Is32Bit or (Bmp.Width < Width) or (Bmp.Height < Height)) then begin
-      Brush.Style := bsSolid;
-      Brush.Color := FBackColor;
-      FillRect(R);
-    end;
-
-    if csDesigning in ComponentState then begin
-      Pen.Style := psDash;
-      Brush.Style := bsClear;
-      Rectangle(0, 0, Width, Height);
-    end;
-
-    if Center then begin
-      X := R.Left + ((R.Right - R.Left) - W) div 2;
-      if X < 0 then
-        X := 0;
-      Y := R.Top + ((R.Bottom - R.Top) - H) div 2;
-      if Y < 0 then
-        Y := 0;
-    end else begin
-      X := 0;
-      Y := 0;
-    end;
-
-    if not Is32bit and (FReplaceColor <> clNone) and (FReplaceWithColor <> clNone) then begin
-      Brush.Color := FReplaceWithColor;
-      BrushCopy(Rect(X, Y, X + W, Y + H), Bmp, Rect(0, 0, Bmp.Width, Bmp.Height), FReplaceColor);
-    end else
-      Draw(X, Y, Bmp);
-  end;
+  var R := ClientRect;
+  FImpl.Paint(Self, Canvas, R);
 end;
 
 end.

+ 1 - 0
Components/Components.dpk

@@ -38,6 +38,7 @@ requires
 
 contains
   BidiCtrls in 'BidiCtrls.pas',
+  BitmapButton in 'BitmapButton.pas',
   BitmapImage in 'BitmapImage.pas',
   DropListBox in 'DropListBox.pas',
   FolderTreeView in 'FolderTreeView.pas',

+ 2 - 2
Components/NewProgressBar.pas

@@ -2,13 +2,13 @@ unit NewProgressBar;
 
 {
   Inno Setup
-  Copyright (C) 1997-2024 Jordan Russell
+  Copyright (C) 1997-2025 Jordan Russell
   Portions by Martijn Laan
   For conditions of distribution and use, see LICENSE.TXT.
 
   TNewProgressBar component - a smooth 32 bit TProgressBar
 
-  Note: themed animated progress bars and don't immediately show changes.
+  Note: themed animated progress bars don't immediately show changes.
   This applies both to Position and State. For example if you set State while the
   progress bar is still moving towards a new Position, the new State doesnt show until
   the moving animation has finished.

+ 36 - 14
Examples/CodeClasses.iss

@@ -27,11 +27,6 @@ begin
   MsgBox('You clicked the button!', mbInformation, mb_Ok);
 end;
 
-procedure BitmapImageOnClick(Sender: TObject);
-begin
-  MsgBox('You clicked the image!', mbInformation, mb_Ok);
-end;
-
 procedure FormButtonOnClick(Sender: TObject);
 var
   Form: TSetupForm;
@@ -132,6 +127,7 @@ var
   CheckListBox, CheckListBox2: TNewCheckListBox;
   FolderTreeView: TFolderTreeView;
   BitmapImage, BitmapImage2, BitmapImage3: TBitmapImage;
+  BitmapButton, BitmapButton2: TBitmapButton;
   BitmapFileName: String;
   RichEditViewer: TRichEditViewer;
 begin
@@ -353,32 +349,58 @@ begin
   BitmapImage := TBitmapImage.Create(Page);
   BitmapImage.AutoSize := True;
   BitmapImage.Bitmap.LoadFromFile(BitmapFileName);
-  BitmapImage.Cursor := crHand;
-  BitmapImage.OnClick := @BitmapImageOnClick;
   BitmapImage.Parent := Page.Surface;
 
   BitmapImage2 := TBitmapImage.Create(Page);
-  BitmapImage2.BackColor := $400000;
+  BitmapImage2.BackColor := clNone;
   BitmapImage2.Bitmap := BitmapImage.Bitmap;
   BitmapImage2.Center := True;
   BitmapImage2.Left := BitmapImage.Width + 10;
-  BitmapImage2.Height := 2*BitmapImage.Height;
   BitmapImage2.Width := 2*BitmapImage.Width;
-  BitmapImage2.Cursor := crHand;
-  BitmapImage2.OnClick := @BitmapImageOnClick;
+  BitmapImage2.Height := 2*BitmapImage.Height;
   BitmapImage2.Parent := Page.Surface;
 
   BitmapImage3 := TBitmapImage.Create(Page);
   BitmapImage3.Bitmap := BitmapImage.Bitmap;
   BitmapImage3.Stretch := True;
   BitmapImage3.Left := 3*BitmapImage.Width + 20;
-  BitmapImage3.Height := 4*BitmapImage.Height;
   BitmapImage3.Width := 4*BitmapImage.Width;
+  BitmapImage3.Height := 4*BitmapImage.Height;
   BitmapImage3.Anchors := [akLeft, akTop, akRight, akBottom];
-  BitmapImage3.Cursor := crHand;
-  BitmapImage3.OnClick := @BitmapImageOnClick;
   BitmapImage3.Parent := Page.Surface;
 
+  { TBitmapButton - Always has a 2 pixel margin around the image, used to
+    display a focus rectangle. Other changes compared to TBitmapImage are:
+    • Has a Caption property which should always be set
+    • Center defaults to True
+    • BackColor defaults to clNone }
+
+  Page := CreateCustomPage(Page.ID, 'Custom wizard page controls', 'TBitmapButton (Press Alt to see focus rectangle)');
+  
+  BitmapButton := TBitmapButton.Create(Page);
+  BitmapButton.AutoSize := True;
+  BitmapButton.Bitmap := BitmapImage.Bitmap;
+  BitmapButton.Caption := 'Show Message'; { For accessibility }
+  BitmapButton.Hint := 'TBitmapButton is an accessible version of TBitmapImage';
+  BitmapButton.ShowHint := True;
+  BitmapButton.Width := 2*BitmapButton.Width;
+  BitmapButton.Cursor := crHand;
+  BitmapButton.OnClick := @ButtonOnClick;
+  BitmapButton.Parent := Page.Surface;
+
+  BitmapButton2 := TBitmapButton.Create(Page);
+  BitmapButton2.BackColor := $400000;
+  BitmapButton2.Bitmap := BitmapImage.Bitmap;
+  BitmapButton2.Caption := BitmapButton.Caption;
+  BitmapButton2.Hint := BitmapButton.Hint;
+  BitmapButton2.ShowHint := True;
+  BitmapButton2.Left := BitmapButton.Width + 10;
+  BitmapButton2.Width := 2*BitmapButton.Width;
+  BitmapButton2.Height := 2*BitmapButton.Height;
+  BitmapButton2.Cursor := crHand;
+  BitmapButton2.OnClick := @ButtonOnClick;
+  BitmapButton2.Parent := Page.Surface;
+
   { TRichViewer }
 
   Page := CreateCustomPage(Page.ID, 'Custom wizard page controls', 'TRichViewer');

+ 14 - 0
ISHelp/isxclasses.pas

@@ -667,6 +667,20 @@ TStartMenuFolderTreeView = class(TCustomFolderTreeView)
   property OnRename: TFolderRenameEvent; read write;
 end;
 
+TBitmapButton = class(TCustomControl)
+  property Anchors: TAnchors; read write;
+  property AutoSize: Boolean; read write;
+  property BackColor: TColor; read write;
+  property Caption: Boolean; read write;
+  property Center: Boolean; read write;
+  property Bitmap: TBitmap; read write;
+  property ReplaceColor: TColor; read write;
+  property ReplaceWithColor: TColor; read write;
+  property Stretch: Boolean; read write;
+  property OnClick: TNotifyEvent; read write;
+  property OnDblClick: TNotifyEvent; read write;
+end;
+
 TBitmapImage = class(TGraphicControl)
   property Anchors: TAnchors; read write;
   property AutoSize: Boolean; read write;

+ 23 - 23
ISHelp/isxclasses_wordlists_generated.pas

@@ -16,29 +16,29 @@ var
 
   PascalTypes_Isxclasses: array of AnsiString = [
     'HBITMAP', 'TAlign', 'TAlignment', 'TAlphaFormat', 'TAnchorKind', 'TAnchors', 'TBevel',
-    'TBevelKind', 'TBevelShape', 'TBevelStyle', 'TBevelWidth', 'TBitmap', 'TBitmapImage',
-    'TBorderIcon', 'TBorderIcons', 'TBorderStyle', 'TBorderWidth', 'TBrush', 'TBrushStyle',
-    'TButton', 'TButtonControl', 'TCanvas', 'TCheckBox', 'TCheckBoxState', 'TCheckItemOperation',
-    'TCloseAction', 'TCloseEvent', 'TCloseQueryEvent', 'TColor', 'TComboBox', 'TComboBoxStyle',
-    'TComponent', 'TConstraintSize', 'TControl', 'TCursor', 'TCustomCheckBox', 'TCustomComboBox',
-    'TCustomControl', 'TCustomEdit', 'TCustomFolderTreeView', 'TCustomLabel', 'TCustomLinkLabel',
-    'TCustomListBox', 'TCustomMemo', 'TCustomPanel', 'TDownloadWizardPage', 'TDuplicates',
-    'TEdit', 'TEditCharCase', 'TEShiftState', 'TExtractionWizardPage', 'TFileStream', 'TFolderRenameEvent',
-    'TFolderTreeView', 'TFont', 'TFontStyle', 'TFontStyles', 'TForm', 'TFormBorderStyle',
-    'TFormStyle', 'TGraphic', 'TGraphicControl', 'TGraphicsObject', 'THandleStream', 'TInputDirWizardPage',
-    'TInputFileWizardPage', 'TInputOptionWizardPage', 'TInputQueryWizardPage', 'TKeyEvent',
-    'TKeyPressEvent', 'TLabel', 'TLinkLabel', 'TListBox', 'TListBoxStyle', 'TMemo', 'TNewButton',
-    'TNewCheckBox', 'TNewCheckListBox', 'TNewComboBox', 'TNewEdit', 'TNewLinkLabel', 'TNewListBox',
-    'TNewMemo', 'TNewNotebook', 'TNewNotebookPage', 'TNewProgressBar', 'TNewProgressBarState',
-    'TNewProgressBarStyle', 'TNewRadioButton', 'TNewStaticText', 'TNotifyEvent', 'TObject',
-    'TOutputMarqueeProgressWizardPage', 'TOutputMsgMemoWizardPage', 'TOutputMsgWizardPage',
-    'TOutputProgressWizardPage', 'TPanel', 'TPanelBevel', 'TPasswordEdit', 'TPen', 'TPenMode',
-    'TPenStyle', 'TPersistent', 'TPopupMode', 'TPosition', 'TRadioButton', 'TRichEditViewer',
-    'TScrollingWinControl', 'TScrollStyle', 'TSetupForm', 'TShiftState', 'TSizeConstraints',
-    'TStartMenuFolderTreeView', 'TStream', 'TStringList', 'TStrings', 'TStringStream',
-    'TSysLinkEvent', 'TSysLinkType', 'TUIStateForm', 'TUninstallProgressForm', 'TWinControl',
-    'TWizardForm', 'TWizardPage', 'TWizardPageButtonEvent', 'TWizardPageCancelEvent', 'TWizardPageNotifyEvent',
-    'TWizardPageShouldSkipEvent'
+    'TBevelKind', 'TBevelShape', 'TBevelStyle', 'TBevelWidth', 'TBitmap', 'TBitmapButton',
+    'TBitmapImage', 'TBorderIcon', 'TBorderIcons', 'TBorderStyle', 'TBorderWidth', 'TBrush',
+    'TBrushStyle', 'TButton', 'TButtonControl', 'TCanvas', 'TCheckBox', 'TCheckBoxState',
+    'TCheckItemOperation', 'TCloseAction', 'TCloseEvent', 'TCloseQueryEvent', 'TColor',
+    'TComboBox', 'TComboBoxStyle', 'TComponent', 'TConstraintSize', 'TControl', 'TCursor',
+    'TCustomCheckBox', 'TCustomComboBox', 'TCustomControl', 'TCustomEdit', 'TCustomFolderTreeView',
+    'TCustomLabel', 'TCustomLinkLabel', 'TCustomListBox', 'TCustomMemo', 'TCustomPanel',
+    'TDownloadWizardPage', 'TDuplicates', 'TEdit', 'TEditCharCase', 'TEShiftState', 'TExtractionWizardPage',
+    'TFileStream', 'TFolderRenameEvent', 'TFolderTreeView', 'TFont', 'TFontStyle', 'TFontStyles',
+    'TForm', 'TFormBorderStyle', 'TFormStyle', 'TGraphic', 'TGraphicControl', 'TGraphicsObject',
+    'THandleStream', 'TInputDirWizardPage', 'TInputFileWizardPage', 'TInputOptionWizardPage',
+    'TInputQueryWizardPage', 'TKeyEvent', 'TKeyPressEvent', 'TLabel', 'TLinkLabel', 'TListBox',
+    'TListBoxStyle', 'TMemo', 'TNewButton', 'TNewCheckBox', 'TNewCheckListBox', 'TNewComboBox',
+    'TNewEdit', 'TNewLinkLabel', 'TNewListBox', 'TNewMemo', 'TNewNotebook', 'TNewNotebookPage',
+    'TNewProgressBar', 'TNewProgressBarState', 'TNewProgressBarStyle', 'TNewRadioButton',
+    'TNewStaticText', 'TNotifyEvent', 'TObject', 'TOutputMarqueeProgressWizardPage', 'TOutputMsgMemoWizardPage',
+    'TOutputMsgWizardPage', 'TOutputProgressWizardPage', 'TPanel', 'TPanelBevel', 'TPasswordEdit',
+    'TPen', 'TPenMode', 'TPenStyle', 'TPersistent', 'TPopupMode', 'TPosition', 'TRadioButton',
+    'TRichEditViewer', 'TScrollingWinControl', 'TScrollStyle', 'TSetupForm', 'TShiftState',
+    'TSizeConstraints', 'TStartMenuFolderTreeView', 'TStream', 'TStringList', 'TStrings',
+    'TStringStream', 'TSysLinkEvent', 'TSysLinkType', 'TUIStateForm', 'TUninstallProgressForm',
+    'TWinControl', 'TWizardForm', 'TWizardPage', 'TWizardPageButtonEvent', 'TWizardPageCancelEvent',
+    'TWizardPageNotifyEvent', 'TWizardPageShouldSkipEvent'
   ];
 
   PascalEnumValues_Isxclasses: array of AnsiString = [

+ 7 - 1
ISHelp/isxfunc.xml

@@ -1931,7 +1931,7 @@ end;</pre></example>
         <prototype>procedure MapArchiveExtensions(const DestExt, SourceExt: String);</prototype>
         <description><p>Allows files with a specified destination extension, such as .exe, to be treated as if they have a different source extension, such as .7z, for extraction purposes.</p>
 <p>An exception will be raised if there was an error.</p></description>
-        <remarks><p>Calls to this function are ignored if the <link topic="setup_archiveextraction">ArchiveExtraction</link> [Setup] section directive is set to <tt>basic</tt>.</p></remarks>
+        <remarks><p>Calls to this function are ignored if the <link topic="setup_archiveextraction">ArchiveExtraction</link> [Setup] section directive is set to <tt>basic</tt>. In this case files as always extracted as .7z, regardless of the extension.</p></remarks>
         <seealso><p><link topic="isxfunc_ExtractArchive">ExtractArchive</link><br/>
 <link topic="isxfunc_CreateExtractionPage">CreateExtractionPage</link></p></seealso>
         <example><pre>
@@ -2818,6 +2818,12 @@ end;</pre></example>
         <prototype>function ScaleY(Y: Integer): Integer;</prototype>
         <description><p>Takes a Y coordinate or height and returns it scaled to fit the size of the current dialog font. If the dialog font is 8-point MS Sans Serif and the user is running Windows in 100% DPI (96 dpi), then Y is returned unchanged.</p></description>
       </function>
+      <function>
+        <name>InitializeBitmapButtonFromIcon</name>
+        <prototype>function InitializeBitmapButtonFromIcon(const BitmapButton: TBitmapButton; const IconFilename: String; const BkColor: TColor; const AscendingTrySizes: TArrayOfInteger): Boolean;</prototype>
+        <description><p>Initializes the given bitmap button with an icon from the given icon file using the given background color for transparent parts.</p>
+<p>See <link topic="isxfunc_InitializeBitmapImageFromIcon">InitializeBitmapImageFromIcon</link> for more information.</p></description>
+      </function>
       <function>
         <name>InitializeBitmapImageFromIcon</name>
         <prototype>function InitializeBitmapImageFromIcon(const BitmapImage: TBitmapImage; const IconFilename: String; const BkColor: TColor; const AscendingTrySizes: TArrayOfInteger): Boolean;</prototype>

+ 3 - 0
Projects/Compil32.dpr

@@ -47,6 +47,8 @@ uses
   NewStaticText in '..\Components\NewStaticText.pas',
   BidiUtils in '..\Components\BidiUtils.pas',
   DropListBox in '..\Components\DropListBox.pas',
+  BitmapButton in '..\Components\BitmapButton.pas',
+  BitmapImage in '..\Components\BitmapImage.pas',
   NewCheckListBox in '..\Components\NewCheckListBox.pas',
   NewNotebook in '..\Components\NewNotebook.pas',
   TaskbarProgressFunc in '..\Components\TaskbarProgressFunc.pas',
@@ -73,6 +75,7 @@ uses
   ECDSA in '..\Components\ECDSA.pas',
   ISSigFunc in '..\Components\ISSigFunc.pas',
   StringScanner in '..\Components\StringScanner.pas',
+  Resample in '..\Components\Resample.pas',
   VCL.Styles,
   VCL.Themes;
 

+ 3 - 0
Projects/Compil32.dproj

@@ -127,6 +127,8 @@
         <DCCReference Include="..\Components\NewStaticText.pas"/>
         <DCCReference Include="..\Components\BidiUtils.pas"/>
         <DCCReference Include="..\Components\DropListBox.pas"/>
+        <DCCReference Include="..\Components\BitmapButton.pas"/>
+        <DCCReference Include="..\Components\BitmapImage.pas"/>
         <DCCReference Include="..\Components\NewCheckListBox.pas"/>
         <DCCReference Include="..\Components\NewNotebook.pas"/>
         <DCCReference Include="..\Components\TaskbarProgressFunc.pas"/>
@@ -159,6 +161,7 @@
         <DCCReference Include="..\Components\ECDSA.pas"/>
         <DCCReference Include="..\Components\ISSigFunc.pas"/>
         <DCCReference Include="..\Components\StringScanner.pas"/>
+        <DCCReference Include="..\Components\Resample.pas"/>
         <BuildConfiguration Include="Base">
             <Key>Base</Key>
         </BuildConfiguration>

+ 1 - 0
Projects/Setup.dpr

@@ -75,6 +75,7 @@ uses
   BidiUtils in '..\Components\BidiUtils.pas',
   PathFunc in '..\Components\PathFunc.pas',
   BidiCtrls in '..\Components\BidiCtrls.pas',
+  BitmapButton in '..\Components\BitmapButton.pas',
   BitmapImage in '..\Components\BitmapImage.pas',
   FolderTreeView in '..\Components\FolderTreeView.pas',
   NewCheckListBox in '..\Components\NewCheckListBox.pas',

+ 1 - 0
Projects/Setup.dproj

@@ -148,6 +148,7 @@
         <DCCReference Include="..\Components\BidiUtils.pas"/>
         <DCCReference Include="..\Components\PathFunc.pas"/>
         <DCCReference Include="..\Components\BidiCtrls.pas"/>
+        <DCCReference Include="..\Components\BitmapButton.pas"/>
         <DCCReference Include="..\Components\BitmapImage.pas"/>
         <DCCReference Include="..\Components\FolderTreeView.pas"/>
         <DCCReference Include="..\Components\NewCheckListBox.pas"/>

+ 20 - 1
Projects/Src/Compiler.ScriptClasses.pas

@@ -229,13 +229,31 @@ begin
   end;
 end;
 
-procedure RegisterBitmapImage_C(Cl: TPSPascalCompiler);
+procedure RegisterBitmapButton_C(Cl: TPSPascalCompiler);
 begin
   Cl.AddTypeS('TAlphaFormat', '(afIgnored, afDefined, afPremultiplied)');
   with Cl.FindClass('TBitmap') do
   begin
     RegisterProperty('AlphaFormat', 'TAlphaFormat', iptrw);
   end;
+  with Cl.AddClassN(CL.FindClass('TCustomControl'),'TBitmapButton') do
+  begin
+    RegisterProperty('Anchors', 'TAnchors', iptrw);
+    RegisterProperty('AutoSize', 'Boolean', iptrw);
+    RegisterProperty('BackColor', 'TColor', iptrw);
+    RegisterProperty('Caption', 'String', iptrw);
+    RegisterProperty('Center', 'Boolean', iptrw);
+    RegisterProperty('Bitmap', 'TBitmap', iptrw);
+    RegisterProperty('ReplaceColor', 'TColor', iptrw);
+    RegisterProperty('ReplaceWithColor', 'TColor', iptrw);
+    RegisterProperty('Stretch', 'Boolean', iptrw);
+    RegisterProperty('OnClick', 'TNotifyEvent', iptrw);
+    RegisterProperty('OnDblClick', 'TNotifyEvent', iptrw);
+  end;
+end;
+
+procedure RegisterBitmapImage_C(Cl: TPSPascalCompiler);
+begin
   with Cl.AddClassN(CL.FindClass('TGraphicControl'),'TBitmapImage') do
   begin
     RegisterProperty('Anchors', 'TAnchors', iptrw);
@@ -663,6 +681,7 @@ begin
   RegisterCustomFolderTreeView_C(Cl);
   RegisterFolderTreeView_C(Cl);
   RegisterStartMenuFolderTreeView_C(Cl);
+  RegisterBitmapButton_C(Cl);
   RegisterBitmapImage_C(Cl);
   RegisterBidiCtrls_C(Cl);
 

+ 39 - 28
Projects/Src/Compression.SevenZipDLLDecoder.pas

@@ -75,11 +75,10 @@ type
   TSequentialOutStream = class(TInterfacedObject, ISequentialOutStream)
   private
     FFile: TFile;
-    FOwnsFile: Boolean;
   protected
     function Write(data: Pointer; size: UInt32; processedSize: PUInt32): HRESULT; stdcall;
   public
-    constructor Create(const AFile: TFile; const AOwnsFile: Boolean = True);
+    constructor Create(const AFileToBeDuplicated: TFile);
     destructor Destroy; override;
   end;
 
@@ -210,6 +209,7 @@ type
       const Password: String; const Index: UInt32; const DestF: TFile;
       const OnExtractToHandleProgress: TOnExtractToHandleProgress;
       const OnExtractToHandleProgressParam: Integer64);
+    destructor Destroy; override;
   end;
 
 { Helper functions }
@@ -274,11 +274,11 @@ begin
 end;
 
 function GetProperty(const InArchive: IInArchive; index: UInt32; propID: PROPID;
-  out value: Integer64): Boolean; overload;
+  out value: UInt64): Boolean; overload;
 begin
   var varValue: OleVariant;
   Result := GetProperty(InArchive, index, propID, [varUInt64], varValue);
-  value := Integer64(UInt64(varValue));
+  value := varValue;
 end;
 
 function GetProperty(const InArchive: IInArchive; index: UInt32; propID: PROPID;
@@ -334,9 +334,11 @@ function TInStream.Seek(offset: Int64; seekOrigin: UInt32;
 begin
   try
     case seekOrigin of
-      STREAM_SEEK_SET: FFile.Seek64(Integer64(offset));
-      STREAM_SEEK_CUR: FFile.Seek64(Integer64(Int64(FFile.Position) + offset));
-      STREAM_SEEK_END: FFile.Seek64(Integer64(Int64(FFile.Size) + offset));
+      STREAM_SEEK_SET: FFile.Seek(offset);
+      STREAM_SEEK_CUR: FFile.Seek(FFile.Position + offset);
+      STREAM_SEEK_END: FFile.Seek(FFile.Size + offset);
+    else
+      Exit(E_INVALIDARG);
     end;
     if newPosition <> nil then
       newPosition^ := UInt64(FFile.Position);
@@ -351,17 +353,15 @@ end;
 
 { TSequentialOutStream }
 
-constructor TSequentialOutStream.Create(const AFile: TFile; const AOwnsFile: Boolean);
+constructor TSequentialOutStream.Create(const AFileToBeDuplicated: TFile);
 begin
   inherited Create;
-  FFile := AFile;
-  FOwnsFile := AOwnsFile;
+  FFile := TFile.CreateDuplicate(AFileToBeDuplicated);
 end;
 
 destructor TSequentialOutStream.Destroy;
 begin
-  if FOwnsFile then
-    FFile.Free;
+  FFile.Free;
   inherited;
 end;
 
@@ -756,16 +756,21 @@ begin
            (ExistingFileAttr and FILE_ATTRIBUTE_READONLY <> 0) then
           SetFileAttributesRedir(FDisableFsRedir, NewCurrent.ExpandedPath, ExistingFileAttr and not FILE_ATTRIBUTE_READONLY);
         const DestF = TFileRedir.Create(FDisableFsRedir, NewCurrent.ExpandedPath, fdCreateAlways, faWrite, fsNone);
-        var BytesLeft: Integer64;
-        if GetProperty(FInArchive, index, kpidSize, BytesLeft) then begin
-          { To avoid file system fragmentation, preallocate all of the bytes in the
-            destination file }
-          DestF.Seek64(BytesLeft);
-          DestF.Truncate;
-          DestF.Seek(0);
+        try
+          var BytesLeft: UInt64;
+          if GetProperty(FInArchive, index, kpidSize, BytesLeft) then begin
+            { To avoid file system fragmentation, preallocate all of the bytes in the
+              destination file }
+            DestF.Seek(Int64(BytesLeft));
+            DestF.Truncate;
+            DestF.Seek(0);
+          end;
+          { From IArchive.h: can also set outstream to nil to tell 7zip to skip the file }
+          outstream := TSequentialOutStream.Create(DestF);
+        finally
+          { TSequentialOutStream duplicates the TFile, so DestF is no longer needed }
+          DestF.Free;
         end;
-        { From IArchive.h: can also set outstream to nil to tell 7zip to skip the file }
-        outstream := TSequentialOutStream.Create(DestF);
         NewCurrent.outStream := outStream;
       end;
     end;
@@ -852,11 +857,17 @@ constructor TArchiveExtractToHandleCallback.Create(const InArchive: IInArchive;
 begin
   inherited Create(InArchive, numItems, Password);
   FIndex := Index;
-  FDestF := DestF;
+  FDestF := TFile.CreateDuplicate(DestF);
   FOnExtractToHandleProgress := OnExtractToHandleProgress;
   FOnExtractToHandleProgressParam := OnExtractToHandleProgressParam;
 end;
 
+destructor TArchiveExtractToHandleCallback.Destroy;
+begin
+  FDestF.Free;
+  inherited;
+end;
+
 function TArchiveExtractToHandleCallback.GetIndices: TArchiveExtractBaseCallback.TArrayOfUInt32;
 begin
   SetLength(Result, 1);
@@ -874,15 +885,15 @@ begin
       GetProperty(FInArchive, index, kpidIsDir, IsDir);
       if IsDir then
         OleError(E_INVALIDARG);
-      var BytesLeft: Integer64;
+      var BytesLeft: UInt64;
       if GetProperty(FInArchive, index, kpidSize, BytesLeft) then begin
         { To avoid file system fragmentation, preallocate all of the bytes in the
           destination file }
-        FDestF.Seek64(BytesLeft);
+        FDestF.Seek(Int64(BytesLeft));
         FDestF.Truncate;
         FDestF.Seek(0);
       end;
-      outstream := TSequentialOutStream.Create(FDestF, False);
+      outstream := TSequentialOutStream.Create(FDestF);
     end;
     Result := S_OK;
   except
@@ -1137,10 +1148,10 @@ begin
     FindData.dwFileAttributes := FindData.dwFileAttributes or Attrib;
     GetProperty(InArchive, currentIndex, kpidCTime, FindData.ftCreationTime);
     GetProperty(InArchive, currentIndex, kpidMTime, FindData.ftLastWriteTime);
-    var Size: Integer64;
+    var Size: UInt64;
     GetProperty(InArchive, currentIndex, kpidSize, Size);
-    FindData.nFileSizeHigh := Size.Hi;
-    FindData.nFileSizeLow := Size.Lo;
+    FindData.nFileSizeHigh := Int64Rec(Size).Hi;
+    FindData.nFileSizeLow := Int64Rec(Size).Lo;
   end;
 end;
 

+ 9 - 9
Projects/Src/IDE.InputQueryMemoForm.dfm

@@ -27,15 +27,15 @@ object InputQueryMemoForm: TInputQueryMemoForm
     Caption = '...'
     FocusControl = ValueControl
   end
-  object DocImage: TImage
-    Left = 8
-    Top = 115
-    Width = 16
-    Height = 16
+  object DocBitBtn: TBitmapButton
+    Left = 6
+    Top = 113
+    Width = 20
+    Height = 20
     Cursor = crHandPoint
     Anchors = [akLeft, akBottom]
-    AutoSize = True
-    Transparent = True
+    Caption = 'Help'
+    TabOrder = 1
   end
   object OKButton: TButton
     Left = 421
@@ -46,7 +46,7 @@ object InputQueryMemoForm: TInputQueryMemoForm
     Caption = 'OK'
     Default = True
     ModalResult = 1
-    TabOrder = 1
+    TabOrder = 2
   end
   object CancelButton: TButton
     Left = 501
@@ -57,7 +57,7 @@ object InputQueryMemoForm: TInputQueryMemoForm
     Cancel = True
     Caption = 'Cancel'
     ModalResult = 2
-    TabOrder = 2
+    TabOrder = 3
   end
   object ValueControl: TMemo
     Left = 279

+ 12 - 12
Projects/Src/IDE.InputQueryMemoForm.pas

@@ -2,7 +2,7 @@ unit IDE.InputQueryMemoForm;
 
 {
   Inno Setup
-  Copyright (C) 1997-2020 Jordan Russell
+  Copyright (C) 1997-2025 Jordan Russell
   Portions by Martijn Laan
   For conditions of distribution and use, see LICENSE.TXT.
 
@@ -14,7 +14,7 @@ unit IDE.InputQueryMemoForm;
 interface
 
 uses
-  Classes, Controls, StdCtrls, UIStateForm, Vcl.ExtCtrls;
+  Classes, Controls, StdCtrls, UIStateForm, ExtCtrls, BitmapButton;
 
 type
   TInputQueryMemoForm = class(TUIStateForm)
@@ -22,7 +22,7 @@ type
     CancelButton: TButton;
     PromptLabel: TLabel;
     ValueControl: TMemo;
-    DocImage: TImage;
+    DocBitBtn: TBitmapButton;
     procedure FormCreate(Sender: TObject);
     procedure ValueControlKeyPress(Sender: TObject; var Key: Char);
     procedure ValueControlChange(Sender: TObject);
@@ -36,16 +36,16 @@ type
     procedure SetPrompt(const APrompt: String);
     procedure SetValue(const AValue: String);
     procedure UpdateImages;
-    procedure SetDocImageClick(const Value: TNotifyEvent);
+    procedure SetDocBitBtnClick(const Value: TNotifyEvent);
   public
-    property DocImageClick: TNotifyEvent write SetDocImageClick;
+    property DocBitBtnClick: TNotifyEvent write SetDocBitBtnClick;
     property Prompt: String write SetPrompt;
     property SingleLine: Boolean write FSingleLine;
     property Value: String read GetValue write SetValue;
   end;
 
 function InputQueryMemo(const ACaption, APrompt: String; var AValue: String;
-  const ASingleLine: Boolean = False; const ADocImageClick: TNotifyEvent = nil): Boolean;
+  const ASingleLine: Boolean = False; const ADocBitBtnClick: TNotifyEvent = nil): Boolean;
 
 implementation
 
@@ -56,14 +56,14 @@ uses
 {$R *.DFM}
 
 function InputQueryMemo(const ACaption, APrompt: String; var AValue: String;
-  const ASingleLine: Boolean; const ADocImageClick: TNotifyEvent): Boolean;
+  const ASingleLine: Boolean; const ADocBitBtnClick: TNotifyEvent): Boolean;
 begin
   with TInputQueryMemoForm.Create(Application) do try
     Caption := ACaption;
     Prompt := APrompt;
     Value := AValue;
     SingleLine := ASingleLine;
-    DocImageClick := ADocImageClick;
+    DocBitBtnClick := ADocBitBtnClick;
     if ShowModal = mrOk then begin
       AValue := Value;
       Result := True;
@@ -92,10 +92,10 @@ begin
   Result := ValueControl.Text;
 end;
 
-procedure TInputQueryMemoForm.SetDocImageClick(const Value: TNotifyEvent);
+procedure TInputQueryMemoForm.SetDocBitBtnClick(const Value: TNotifyEvent);
 begin
-  DocImage.OnClick := Value;
-  DocImage.Visible := Assigned(DocImage.OnClick);
+  DocBitBtn.OnClick := Value;
+  DocBitBtn.Visible := Assigned(DocBitBtn.OnClick);
 end;
 
 procedure TInputQueryMemoForm.SetPrompt(const APrompt: String);
@@ -149,7 +149,7 @@ procedure TInputQueryMemoForm.UpdateImages;
 begin
  { After a DPI change the button's Width and Height isn't yet updated, so calculate it ourselves }
   var WH := MulDiv(16, CurrentPPI, 96);
-  DocImage.Picture.Graphic:= GetImage(MainForm.HelpButton, WH);
+  DocBitBtn.Bitmap.Assign(GetImage(MainForm.HelpButton, WH));
 end;
 
 end.

+ 23 - 18
Projects/Src/IDE.MainForm.dfm

@@ -373,33 +373,38 @@ object MainForm: TMainForm
     TabOrder = 1
     Visible = False
     StyleName = 'Windows'
-    object UpdatePanelClosePaintBox: TPaintBox
+    object UpdatePanelCloseBitBtn: TBitmapButton
       AlignWithMargins = True
-      Left = 330
-      Top = 10
-      Width = 21
-      Height = 21
-      Margins.Top = 10
-      Margins.Right = 10
-      Margins.Bottom = 10
+      Left = 328
+      Top = 8
+      Width = 25
+      Height = 25
+      Margins.Top = 8
+      Margins.Right = 8
+      Margins.Bottom = 8
       Align = alRight
-      OnClick = UpdatePanelClosePaintBoxClick
-      OnPaint = UpdatePanelClosePaintBoxPaint
+      Caption = 'Close Banner'
+      TabOrder = 1
+      OnClick = UpdatePanelCloseBitBtnClick
+      OnPaint = UpdatePanelCloseBitBtnPaint
     end
-    object UpdatePanelDonateImage: TImage
+    object UpdatePanelDonateBitBtn: TBitmapButton
       AlignWithMargins = True
-      Left = 303
-      Top = 10
-      Width = 21
-      Height = 21
+      Left = 300
+      Top = 8
+      Width = 25
+      Height = 25
       Cursor = crHandPoint
-      Margins.Top = 10
-      Margins.Bottom = 10
+      Margins.Top = 8
+      Margins.Right = 0
+      Margins.Bottom = 8
       Align = alRight
+      Caption = 'Donate'
       Center = True
       ParentShowHint = False
       ShowHint = True
-      OnClick = UpdatePanelDonateImageClick
+      TabOrder = 2
+      OnClick = UpdatePanelDonateBitBtnClick
     end
     object UpdateLinkLabel: TLinkLabel
       Left = 13

+ 21 - 20
Projects/Src/IDE.MainForm.pas

@@ -26,7 +26,7 @@ uses
   Generics.Collections, UIStateForm, StdCtrls, ExtCtrls, Menus, Buttons, ComCtrls, CommCtrl,
   ScintInt, ScintEdit, IDE.ScintStylerInnoSetup, NewTabSet, ModernColors, IDE.IDEScintEdit,
   Shared.DebugStruct, Shared.CompilerInt.Struct, NewUxTheme, ImageList, ImgList, ToolWin, IDE.HelperFunc,
-  VirtualImageList, BaseImageCollection;
+  VirtualImageList, BaseImageCollection, BitmapButton;
 
 const
   WM_StartCommandLineCompile = WM_USER + $1000;
@@ -263,8 +263,8 @@ type
     EFindRegEx: TMenuItem;
     UpdatePanel: TPanel;
     UpdateLinkLabel: TLinkLabel;
-    UpdatePanelClosePaintBox: TPaintBox;
-    UpdatePanelDonateImage: TImage;
+    UpdatePanelCloseBitBtn: TBitmapButton;
+    UpdatePanelDonateBitBtn: TBitmapButton;
     procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
     procedure FExitClick(Sender: TObject);
     procedure FOpenMainFileClick(Sender: TObject);
@@ -389,9 +389,9 @@ type
     procedure EFindRegExClick(Sender: TObject);
     procedure UpdateLinkLabelLinkClick(Sender: TObject; const Link: string;
       LinkType: TSysLinkType);
-    procedure UpdatePanelClosePaintBoxPaint(Sender: TObject);
-    procedure UpdatePanelClosePaintBoxClick(Sender: TObject);
-    procedure UpdatePanelDonateImageClick(Sender: TObject);
+    procedure UpdatePanelCloseBitBtnPaint(Sender: TObject; Canvas: TCanvas; var ARect: TRect);
+    procedure UpdatePanelCloseBitBtnClick(Sender: TObject);
+    procedure UpdatePanelDonateBitBtnClick(Sender: TObject);
   private
     { Private declarations }
     FMemos: TList<TIDEScintEdit>;                      { FMemos[0] is the main memo and FMemos[1] the preprocessor output memo - also see MemosTabSet comment above }
@@ -1015,7 +1015,7 @@ begin
 
   ToolBarPanel.ParentBackground := False;
   UpdatePanel.ParentBackground := False;
-  UpdatePanelDonateImage.Hint := RemoveAccelChar(HDonate.Caption);
+  UpdatePanelDonateBitBtn.Hint := RemoveAccelChar(HDonate.Caption);
 
   UpdateImages;
 
@@ -1033,6 +1033,7 @@ begin
   FHiddenFiles := TStringList.Create(dupError, True, True);
   FActiveMemo := FMainMemo;
   FActiveMemo.Visible := True;
+  ActiveControl := FActiveMemo;
   FErrorMemo := FMainMemo;
   FStepMemo := FMainMemo;
   UpdateMarginsAndSquigglyAndCaretWidths;
@@ -1326,8 +1327,12 @@ begin
       if ControlToAdd <> nil then
         AddControlToArray(ControlToAdd, Controls, NControls);
     end;
-    if UpdatePanel.Visible and FUpdatePanelMessages[UpdateLinkLabel.Tag].HasLink then
-      AddControlToArray(UpdateLinkLabel, Controls, NControls);
+    if UpdatePanel.Visible then begin
+      if FUpdatePanelMessages[UpdateLinkLabel.Tag].HasLink then
+        AddControlToArray(UpdateLinkLabel, Controls, NControls);
+      AddControlToArray(UpdatePanelDonateBitBtn, Controls, NControls);
+      AddControlToArray(UpdatePanelCloseBitBtn, Controls, NControls);
+    end;
 
     { Now move focus to next }
     if NControls > 1 then begin
@@ -1671,9 +1676,6 @@ begin
     to the form's height decreasing }
   if StatusPanel.Visible then
     UpdateStatusPanelHeight(StatusPanel.Height);
-  { Violently resizing the form leaves UpdatePanelDonateImage and UpdatePanelPaintBox artifacts
-    under and over UpdateLinkLabel. Invalidating it prevents this. }
-  UpdateLinkLabel.Invalidate;
 end;
 
 procedure TMainForm.WndProc(var Message: TMessage);
@@ -4238,7 +4240,7 @@ begin
   var Images := ImagesModule.LightToolBarImageCollection;
 
   var Image := Images.GetSourceImage(Images.GetIndexByName('heart-filled'), WH, WH);
-  UpdatePanelDonateImage.Picture.Graphic:= Image;
+  UpdatePanelDonateBitBtn.Bitmap.Assign(Image);
 end;
 
 procedure TMainForm.UpdateOutputTabSetListsItemHeightAndDebugTimeWidth;
@@ -8090,10 +8092,10 @@ begin
   end else
     Handled := False;
   if Handled then
-    UpdatePanelClosePaintBoxClick(Sender);
+    UpdatePanelCloseBitBtnClick(Sender);
 end;
 
-procedure TMainForm.UpdatePanelClosePaintBoxClick(Sender: TObject);
+procedure TMainForm.UpdatePanelCloseBitBtnClick(Sender: TObject);
 begin
   var MessageToHideIndex := UpdateLinkLabel.Tag;
   var Ini := TConfigIniFile.Create;
@@ -8106,20 +8108,19 @@ begin
   UpdateUpdatePanel;
 end;
 
-procedure TMainForm.UpdatePanelDonateImageClick(Sender: TObject);
+procedure TMainForm.UpdatePanelDonateBitBtnClick(Sender: TObject);
 begin
   HDonate.Click;
 end;
 
-procedure TMainForm.UpdatePanelClosePaintBoxPaint(Sender: TObject);
+procedure TMainForm.UpdatePanelCloseBitBtnPaint(Sender: TObject; Canvas: TCanvas; var ARect: TRect);
 const
   MENU_SYSTEMCLOSE = 17;
   MSYSC_NORMAL = 1;
 begin
-  var Canvas := UpdatePanelClosePaintBox.Canvas;
-  var R := TRect.Create(0, 0, UpdatePanelClosePaintBox.Width, UpdatePanelClosePaintBox.Height);
+  var R := ARect;
   if FMenuThemeData <> 0 then begin
-    var Offset := MulDiv(1, CurrentPPI, 96);
+    var Offset := MulDiv(2, CurrentPPI, 96);
     Inc(R.Left, Offset);
     DrawThemeBackground(FMenuThemeData, Canvas.Handle, MENU_SYSTEMCLOSE, MSYSC_NORMAL, R, nil);
   end else begin

+ 8 - 16
Projects/Src/IDE.RegistryDesignerForm.dfm

@@ -18,15 +18,14 @@ object RegistryDesignerForm: TRegistryDesignerForm
     496
     347)
   TextHeight = 13
-  object AppRegistryMinVerDocImage: TImage
-    Left = 406
-    Top = 170
-    Width = 16
-    Height = 16
+  object AppRegistryMinVerDocBitBtn: TBitmapButton
+    Left = 404
+    Top = 168
+    Width = 20
+    Height = 20
     Anchors = [akTop, akRight]
-    AutoSize = True
-    Transparent = True
-    ExplicitLeft = 414
+    Caption = 'Help'
+    TabOrder = 9
   end
   object Panel1: TPanel
     Left = 0
@@ -35,9 +34,7 @@ object RegistryDesignerForm: TRegistryDesignerForm
     Height = 42
     Align = alBottom
     BevelOuter = bvNone
-    TabOrder = 9
-    ExplicitTop = 320
-    ExplicitWidth = 500
+    TabOrder = 10
     DesignSize = (
       496
       42)
@@ -61,7 +58,6 @@ object RegistryDesignerForm: TRegistryDesignerForm
       ModalResult = 1
       TabOrder = 0
       OnClick = InsertButtonClick
-      ExplicitLeft = 330
     end
     object CancelButton: TButton
       Left = 406
@@ -73,7 +69,6 @@ object RegistryDesignerForm: TRegistryDesignerForm
       Caption = 'Cancel'
       ModalResult = 2
       TabOrder = 1
-      ExplicitLeft = 410
     end
     object PrivilegesRequiredLabel: TNewStaticText
       Left = 8
@@ -101,7 +96,6 @@ object RegistryDesignerForm: TRegistryDesignerForm
     Height = 21
     Anchors = [akLeft, akTop, akRight]
     TabOrder = 1
-    ExplicitWidth = 392
   end
   object AppRegistryFileButton: TButton
     Left = 406
@@ -111,7 +105,6 @@ object RegistryDesignerForm: TRegistryDesignerForm
     Anchors = [akTop, akRight]
     Caption = '&Browse...'
     TabOrder = 2
-    ExplicitLeft = 414
   end
   object AppRegistrySettingsLabel: TNewStaticText
     Left = 8
@@ -165,6 +158,5 @@ object RegistryDesignerForm: TRegistryDesignerForm
     Height = 21
     Anchors = [akLeft, akTop, akRight]
     TabOrder = 8
-    ExplicitWidth = 140
   end
 end

+ 4 - 4
Projects/Src/IDE.RegistryDesignerForm.pas

@@ -2,7 +2,7 @@ unit IDE.RegistryDesignerForm;
 
 {
   Inno Setup
-  Copyright (C) 1997-2024 Jordan Russell
+  Copyright (C) 1997-2025 Jordan Russell
   Portions by Martijn Laan
   For conditions of distribution and use, see LICENSE.TXT.
 
@@ -16,7 +16,7 @@ interface
 uses
   SysUtils, Classes,
   Forms, Controls, StdCtrls, ExtCtrls,
-  IDE.Wizard.WizardFormRegistryHelper, NewStaticText;
+  IDE.Wizard.WizardFormRegistryHelper, NewStaticText, BitmapButton;
 
 type
   TRegistryDesignerForm = class(TForm)
@@ -34,7 +34,7 @@ type
     AppRegistryMinVerCheck: TCheckBox;
     AppRegistryMinVerEdit: TEdit;
     PrivilegesRequiredLabel: TNewStaticText;
-    AppRegistryMinVerDocImage: TImage;
+    AppRegistryMinVerDocBitBtn: TBitmapButton;
     procedure InsertButtonClick(Sender: TObject);
     procedure FormCreate(Sender: TObject);
     procedure FormDestroy(Sender: TObject);
@@ -74,7 +74,7 @@ begin
   FRegistryHelper := TWizardFormRegistryHelper.Create(Self, AppRegistryFileEdit,
     AppRegistryFileButton, AppRegistryUninsDeleteKeyCheck,
     AppRegistryUninsDeleteKeyIfEmptyCheck, AppRegistryUninsDeleteValueCheck,
-    AppRegistryMinVerCheck, AppRegistryMinVerEdit, AppRegistryMinVerDocImage);
+    AppRegistryMinVerCheck, AppRegistryMinVerEdit, AppRegistryMinVerDocBitBtn);
 end;
 
 procedure TRegistryDesignerForm.FormDestroy(Sender: TObject);

+ 3 - 3
Projects/Src/IDE.SignToolsForm.pas

@@ -32,7 +32,7 @@ type
     procedure SignToolsListBoxDblClick(Sender: TObject);
   private
     FSignTools: TStringList;
-    procedure CommandDocImageClick(Sender: TObject);
+    procedure CommandDocBitBtnClick(Sender: TObject);
     procedure UpdateSignTools;
     procedure UpdateSignToolsButtons;
     procedure SetSignTools(SignTools: TStringList);
@@ -91,7 +91,7 @@ begin
   SendMessage(Handle, WM_SETICON, ICON_BIG, 0);
 end;
 
-procedure TSignToolsForm.CommandDocImageClick(Sender: TObject);
+procedure TSignToolsForm.CommandDocBitBtnClick(Sender: TObject);
 begin
   if Assigned(HtmlHelp) then
     HtmlHelp(GetDesktopWindow, PChar(GetHelpFile), HH_DISPLAY_TOPIC, Cardinal(PChar('topic_setup_signtool.htm')));
@@ -128,7 +128,7 @@ begin
       end;
     end;
 
-    if InputQueryMemo(Caption, 'Command of the Sign Tool:', SignToolCommand, True, CommandDocImageClick) then begin
+    if InputQueryMemo(Caption, 'Command of the Sign Tool:', SignToolCommand, True, CommandDocBitBtnClick) then begin
       if SignToolCommand = '' then begin
         AppMessageBox(PChar('Invalid command.'), PChar(Caption), MB_OK or MB_ICONSTOP);
         Exit;

+ 170 - 172
Projects/Src/IDE.StartupForm.dfm

@@ -18,30 +18,28 @@ object StartupForm: TStartupForm
     579
     419)
   TextHeight = 13
-  object DonateImage: TImage
-    Left = 8
-    Top = 383
-    Width = 62
-    Height = 31
+  object DonateBitBtn: TBitmapButton
+    Left = 6
+    Top = 381
+    Width = 66
+    Height = 35
     Cursor = crHandPoint
-    Hint = 'Support Inno Setup - Thank you!'
     Anchors = [akLeft, akBottom]
-    AutoSize = True
+    Caption = 'Donate'
     ParentShowHint = False
-    Picture.Data = {
-      07544269746D6170F60B0000424DF60B00000000000036040000280000003E00
-      00001F0000000100080000000000C0070000C40E0000C40E0000000100000001
-      000000000000663300006F3F0F004D36220070401000794C1D0073482400794D
-      200082582C0081573200835930008C643B00996633009F6F3E008C664000926E
-      4E009F70400095704900967350009E7D5800A5784A00A6794D00AC815500AC83
-      5900A0806000A8896700A2836800B28A6100B38C6600B8936C00A98D7000B195
-      7500B2997F00BE9D7800BAA18300BFA08000B8A08800BCA58F00BDA79400BBBB
-      BB00C4A68300C6A98D00CAAE8E00C4AD9200C5B29F00CCB29900D1B79A00CAB7
-      A400CDBAA100CFBFAF00D2BCA500D7C0A500D6C6AF00D3C4B400D9C5B200DDCA
-      B100D9CCBF00E0D2BE00E3D3BC00DAD5D100E2D9CF00E5D9CC00E9DCC800E9DE
-      CD00E5DCD200E9E1D700ECE5DF00F0E5D300F3EBDB00F6EEDF00E9E9E900F2EC
-      E500F4F1EE00F5F2EF00FCF7EA00F9F5F200FFFFFF0000000000000000000000
-      0000000000000000000000000000000000000000000000000000000000000000
+    Bitmap.Data = {
+      F60B0000424DF60B00000000000036040000280000003E0000001F0000000100
+      080000000000C0070000C40E0000C40E00000001000000010000000000006633
+      00006F3F0F004D36220070401000794C1D0073482400794D200082582C008157
+      3200835930008C643B00996633009F6F3E008C664000926E4E009F7040009570
+      4900967350009E7D5800A5784A00A6794D00AC815500AC835900A0806000A889
+      6700A2836800B28A6100B38C6600B8936C00A98D7000B1957500B2997F00BE9D
+      7800BAA18300BFA08000B8A08800BCA58F00BDA79400BBBBBB00C4A68300C6A9
+      8D00CAAE8E00C4AD9200C5B29F00CCB29900D1B79A00CAB7A400CDBAA100CFBF
+      AF00D2BCA500D7C0A500D6C6AF00D3C4B400D9C5B200DDCAB100D9CCBF00E0D2
+      BE00E3D3BC00DAD5D100E2D9CF00E5D9CC00E9DCC800E9DECD00E5DCD200E9E1
+      D700ECE5DF00F0E5D300F3EBDB00F6EEDF00E9E9E900F2ECE500F4F1EE00F5F2
+      EF00FCF7EA00F9F5F200FFFFFF00000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
@@ -63,99 +61,99 @@ object StartupForm: TStartupForm
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      0000060603030303030303030303030303030303030303030303030303030303
+      0000000000000000000000000000000000000000000000000000060603030303
       0303030303030303030303030303030303030303030303030303030303030303
-      0000094135272727272727272727272727272727272727272727272727272727
-      2727272727272727272727272727272727272727272727272727272727272603
-      00000F4C48464646464646464646464646464646464646464646464646464646
-      4646464646464646464646464646464646464646464646464646464646413506
-      00001A4C4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A
-      4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4C4C06
-      00001A4C4C4C4C4C4C4C4C4C4C4C4C000000004C4C4C0000004C4C004C4C4C00
-      4C4C004C4C4C004C4C4C004C4C4C000000004C4C4C4C4C4C4C4C4C4C4C483B06
-      00001A4C4A4A4A4A4A4A4A4A4A4A4A004A4A4A004A004A4A4A004A004A4A0000
-      4A4A004A4A4A004A4A4A004A4A4A004A4A4A4A4A4A4A4A4A4A4A4A4A4A483B06
-      00001A4C4C4C4C4C4C4C4C4C4C4C4C004C4C4C004C004C4C4C004C004C004C00
-      4C4C00000000004C4C4C004C4C4C0000004C4C4C4C4C4C4C4C4C4C4C4C483B06
-      00001A4C4A4A4A4A4A4A4A4A4A4A4A004A4A4A004A004A4A4A004A00004A4A00
-      4A4A004A4A4A004A4A4A004A4A4A004A4A4A4A4A4A4A4A4A4A4A4A4A4A483B06
-      00001A4C4C4C4C4C4C4C4C4C4C4C4C000000004C4C4C0000004C4C004C4C4C00
-      4C4C4C0000004C4C00000000004C000000004C4C4C4C4C4C4C4C4C4C4C483B06
-      00001A4C4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A
-      4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A483B06
-      00001A4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C
-      4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C483B06
-      00001A4C4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A
-      4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A483B06
-      00001A4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C312025494C4C
-      4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C483B06
-      00001A4C4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A1F0101114A4A
-      4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A483B06
-      00001A4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C070101384C
-      4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C483B06
-      00001A4C4A4A4A4A4A4A4A4A4A4A4A4A4A4A3F34394A4A4A4A4A4A300101054A
-      4A4A4A4A4A4A4A4A4A4A4A4A4A3E3A454A4A4A4A4A4A4A4A4A4A4A4A4A483B06
-      00001A4C4C4C4C4C01010E4C4C4C4C4C4C2C0101010E01010A4C4C3801010120
-      4C4C360C0C2D4C4C4C4C4C4C230C0C0C1C0C0C293D0C0C324C4C4C4C4C483B06
-      00001A4C4A4A4A4A020101444A4A4A4A4A02010108080101013F4A1F01010102
-      3F4A3A0C0C164A4A4A4A4A3E0C0C0C1B140C0C16430C0C1D4A4A4A4A4A483B06
-      00001A4C4C4C4C4C0E0101314C4C4C4C4C070101494C1E0101314C1801010101
-      124C4C0C0C0C4B4C4C4C4C470C0C174C4C170C0C4B100C104C4C4C4C4C483B06
-      00001A4C4A4A4A4A1F0101050B111F394A2201010519130101194A0B01010501
-      01344A1B0C0C161B282E434A1B0C0C162A1B0C0C371D0C0C434A4A4A4A483B06
-      00001A4C4C4C4C4C38010101010101010E49310E01010101010A4C0401043801
-      01074C2D0C0C0C0C0C0C0C294B2D150C0C0C0C0C292D0C0C364C4C4C4C483B06
-      00001A4C4A4A4A4A4A01010119190201010844394A3F340501014401010B4A11
-      01011F3A0C0C0D2A210C0C0C2843434A3A370C0C1B3A0C0C214A4A4A4A483B06
-      00001A4C4C4C4C4C4C0E0101384C490401012001040E070101013801011E4C42
-      040104400C0C0C4C4C3D0C0C0C2D0C171C100C0C1C4C0C0C174C4C4C4C483B06
-      00001A4C4A4A4A4A4A1901011F4A4A0801012B05010101010222340101224A4A
-      1F010111160C0C3E4A450C0C0C3E0C0C0C0C0C143A4A160C0C454A4A4A483B06
-      00001A4C4C4C4C4C4C310101040E0A010101384C4C3C38424C4C4C38384C4C4C
-      4C3C3838290C0C151C150C0C0C4C4C4B3D3D474C4C4C290C0C3D4C4C4C483B06
-      00001A4C4A4A4A4A4A4401010101010101134A4A4A4A4A4A4A4A4A4A4A4A4A4A
-      4A4A4A4A370C0C0C0C0C0C0C334A4A4A4A4A4A4A4A4A370C0C2A3A4A4A483B06
-      00001A4C4C4C4C4C4C4C3120202020253C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C
-      4C4C4C4C4B2D2D2D2D2D36474C4C4C4C4C4C4C4C4C4C4C322D323D4C4C483B06
-      00001A4C4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A
-      4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4C4606
-      0000244C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C
-      4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C06
-      0000244A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A
-      4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A09
-      0000262F26262626262626262626262626262626262626262626262626262626
-      2626262626262626262626262626262626262626262626262626262626241A0F
-      0000}
+      0303030303030303030303030303030303030303030303030000094135272727
+      2727272727272727272727272727272727272727272727272727272727272727
+      27272727272727272727272727272727272727272727260300000F4C48464646
+      4646464646464646464646464646464646464646464646464646464646464646
+      46464646464646464646464646464646464646464641350600001A4C4A4A4A4A
+      4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A
+      4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4C4C0600001A4C4C4C4C4C
+      4C4C4C4C4C4C4C000000004C4C4C0000004C4C004C4C4C004C4C004C4C4C004C
+      4C4C004C4C4C000000004C4C4C4C4C4C4C4C4C4C4C483B0600001A4C4A4A4A4A
+      4A4A4A4A4A4A4A004A4A4A004A004A4A4A004A004A4A00004A4A004A4A4A004A
+      4A4A004A4A4A004A4A4A4A4A4A4A4A4A4A4A4A4A4A483B0600001A4C4C4C4C4C
+      4C4C4C4C4C4C4C004C4C4C004C004C4C4C004C004C004C004C4C00000000004C
+      4C4C004C4C4C0000004C4C4C4C4C4C4C4C4C4C4C4C483B0600001A4C4A4A4A4A
+      4A4A4A4A4A4A4A004A4A4A004A004A4A4A004A00004A4A004A4A004A4A4A004A
+      4A4A004A4A4A004A4A4A4A4A4A4A4A4A4A4A4A4A4A483B0600001A4C4C4C4C4C
+      4C4C4C4C4C4C4C000000004C4C4C0000004C4C004C4C4C004C4C4C0000004C4C
+      00000000004C000000004C4C4C4C4C4C4C4C4C4C4C483B0600001A4C4A4A4A4A
+      4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A
+      4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A483B0600001A4C4C4C4C4C
+      4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C
+      4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C483B0600001A4C4A4A4A4A
+      4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A
+      4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A483B0600001A4C4C4C4C4C
+      4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C312025494C4C4C4C4C4C4C4C4C4C
+      4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C483B0600001A4C4A4A4A4A
+      4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A1F0101114A4A4A4A4A4A4A4A4A4A
+      4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A483B0600001A4C4C4C4C4C
+      4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C070101384C4C4C4C4C4C4C4C4C
+      4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C483B0600001A4C4A4A4A4A
+      4A4A4A4A4A4A4A4A4A4A3F34394A4A4A4A4A4A300101054A4A4A4A4A4A4A4A4A
+      4A4A4A4A4A3E3A454A4A4A4A4A4A4A4A4A4A4A4A4A483B0600001A4C4C4C4C4C
+      01010E4C4C4C4C4C4C2C0101010E01010A4C4C38010101204C4C360C0C2D4C4C
+      4C4C4C4C230C0C0C1C0C0C293D0C0C324C4C4C4C4C483B0600001A4C4A4A4A4A
+      020101444A4A4A4A4A02010108080101013F4A1F010101023F4A3A0C0C164A4A
+      4A4A4A3E0C0C0C1B140C0C16430C0C1D4A4A4A4A4A483B0600001A4C4C4C4C4C
+      0E0101314C4C4C4C4C070101494C1E0101314C1801010101124C4C0C0C0C4B4C
+      4C4C4C470C0C174C4C170C0C4B100C104C4C4C4C4C483B0600001A4C4A4A4A4A
+      1F0101050B111F394A2201010519130101194A0B0101050101344A1B0C0C161B
+      282E434A1B0C0C162A1B0C0C371D0C0C434A4A4A4A483B0600001A4C4C4C4C4C
+      38010101010101010E49310E01010101010A4C040104380101074C2D0C0C0C0C
+      0C0C0C294B2D150C0C0C0C0C292D0C0C364C4C4C4C483B0600001A4C4A4A4A4A
+      4A01010119190201010844394A3F340501014401010B4A1101011F3A0C0C0D2A
+      210C0C0C2843434A3A370C0C1B3A0C0C214A4A4A4A483B0600001A4C4C4C4C4C
+      4C0E0101384C490401012001040E070101013801011E4C42040104400C0C0C4C
+      4C3D0C0C0C2D0C171C100C0C1C4C0C0C174C4C4C4C483B0600001A4C4A4A4A4A
+      4A1901011F4A4A0801012B05010101010222340101224A4A1F010111160C0C3E
+      4A450C0C0C3E0C0C0C0C0C143A4A160C0C454A4A4A483B0600001A4C4C4C4C4C
+      4C310101040E0A010101384C4C3C38424C4C4C38384C4C4C4C3C3838290C0C15
+      1C150C0C0C4C4C4B3D3D474C4C4C290C0C3D4C4C4C483B0600001A4C4A4A4A4A
+      4A4401010101010101134A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A370C0C0C
+      0C0C0C0C334A4A4A4A4A4A4A4A4A370C0C2A3A4A4A483B0600001A4C4C4C4C4C
+      4C4C3120202020253C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4B2D2D2D
+      2D2D36474C4C4C4C4C4C4C4C4C4C4C322D323D4C4C483B0600001A4C4A4A4A4A
+      4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A
+      4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4C46060000244C4C4C4C4C
+      4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C
+      4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C4C060000244A4A4A4A4A
+      4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A
+      4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A4A090000262F26262626
+      2626262626262626262626262626262626262626262626262626262626262626
+      262626262626262626262626262626262626262626241A0F0000}
     ShowHint = True
-    OnClick = DonateImageClick
+    TabOrder = 4
+    OnClick = DonateBitBtnClick
   end
-  object MailingListImage: TImage
-    Left = 78
-    Top = 383
-    Width = 62
-    Height = 31
+  object MailingListBitBtn: TBitmapButton
+    Left = 76
+    Top = 381
+    Width = 66
+    Height = 35
     Cursor = crHandPoint
     Hint = 'Be notified by e-mail of new Inno Setup releases'
     Anchors = [akLeft, akBottom]
-    AutoSize = True
+    Caption = 'Subscribe'
     ParentShowHint = False
-    Picture.Data = {
-      07544269746D6170F60B0000424DF60B00000000000036040000280000003E00
-      00001F0000000100080000000000C0070000C40E0000C40E0000000100000001
-      0000000000005D2E03005F2F0200512C0A00532C0900542D0800602F0100612F
-      0100622F0000632F000063330200643000006432010066320000673300006936
-      03006A3603006E3A0700663B0F006B3A09006D3A08006F3B08006E3C0A006F3D
-      0C00703C0800713D0B00713F0D00723E0C00733F0C004D36220074400D007541
-      0F007A461300734824007F5B37008E5B2A008F5B29008F5D2B008E5E2E008F5E
-      2D00905E2C00915E2C0081573200875D3200805B3600815B3600845C34008C5E
-      300093602E008D633A0091643700926436009364360095653500966534009765
-      34009865330090643800926E4E00B3815000B4815000B7855300B4855400B588
-      5B00BA8B5B00A2836800D19F6E00DBAD7E00DDAD7C00B8A08800BDA79400BBBB
-      BB00E1B58A00E3B68900CAB7A400D3BBA200D4BBA100D7C1AA00DBC3AA00D3C4
-      B400DFCFBB00DAD5D100E0D4C300E6DFCF00E9E0CF00E8E1D100E9E1D100E9E1
-      D700E9E9E900F2F0E300F1F0E400FCF7E500FCF8E200FCF8E400F4F1EE00F5F5
-      ED00F6F6EF00FCF7E900F8F8F200F9F9F200FCFCF600FDFDF600FEFEF900FFFF
-      FA00FFFFFE000000000000000000000000000000000000000000000000000000
+    Bitmap.Data = {
+      F60B0000424DF60B00000000000036040000280000003E0000001F0000000100
+      080000000000C0070000C40E0000C40E00000001000000010000000000005D2E
+      03005F2F0200512C0A00532C0900542D0800602F0100612F0100622F0000632F
+      00006333020064300000643201006632000067330000693603006A3603006E3A
+      0700663B0F006B3A09006D3A08006F3B08006E3C0A006F3D0C00703C0800713D
+      0B00713F0D00723E0C00733F0C004D36220074400D0075410F007A4613007348
+      24007F5B37008E5B2A008F5B29008F5D2B008E5E2E008F5E2D00905E2C00915E
+      2C0081573200875D3200805B3600815B3600845C34008C5E300093602E008D63
+      3A00916437009264360093643600956535009665340097653400986533009064
+      3800926E4E00B3815000B4815000B7855300B4855400B5885B00BA8B5B00A283
+      6800D19F6E00DBAD7E00DDAD7C00B8A08800BDA79400BBBBBB00E1B58A00E3B6
+      8900CAB7A400D3BBA200D4BBA100D7C1AA00DBC3AA00D3C4B400DFCFBB00DAD5
+      D100E0D4C300E6DFCF00E9E0CF00E8E1D100E9E1D100E9E1D700E9E9E900F2F0
+      E300F1F0E400FCF7E500FCF8E200FCF8E400F4F1EE00F5F5ED00F6F6EF00FCF7
+      E900F8F8F200F9F9F200FCFCF600FDFDF600FEFEF900FFFFFA00FFFFFE000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
@@ -174,71 +172,72 @@ object StartupForm: TStartupForm
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
       0000000000000000000000000000000000000000000000000000000000000000
-      000021211D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D
+      000000000000000000000000000000000000000000000000000021211D1D1D1D
       1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D
-      00002A574F474747474747474747474747474747474747474747474747474747
-      474747474747474747474747474747474747474747474747474747474747461D
-      00003A685E585858585858585858585858585858585858585858585858585858
-      5858585858585858585858585858585858585858585858585858585858574F21
-      0000416861616161616161616161616161616161616161616161616161616161
-      6161616161616161616161616161616161616161616161616161616161686821
-      0000416868680000000068686800000068680000000068680000000068686800
-      00006868006868680068000000000068000000006868000000000068685E5121
-      0000416861616161616100610061616100610061616100616161616100610061
-      61610061006161610061616100616161006161610061006161616161615E5121
-      0000416868686800000068680068686800680000000068686800000068680068
-      68686868000000006868686800686868000000006868000000006868685E5121
-      0000416861610061616161610061616100610061616100610061616161610061
-      61610061006161610061616100616161006161610061006161616161615E5121
-      0000416868686800000000680068686800680000000068686800000000686800
-      00006868000000006868000000000068000000006868000000000068685E5121
-      0000416861616161616161616161616161616161616161616161616161616161
-      61616161616161616161616161616161616161616161616161616161615E5121
-      0000416868686868686868686868686868686868686868686868686868686868
-      68686868686868686868686868686868686868686868686868686868685E5121
-      0000416861616161616161616161616161616161616161616161616161616161
-      61616161616161616161616161616161616161616161616161616161615E5121
-      0000416868686868686868686868686868686868686868686867676767676767
-      67676767676767676768686868686868686868686868686868686868685E5121
-      00004168616161616161616161616161616161616161615D1A09090909080809
-      09090909090909091C5C616161616161616161616161616161616161615E5121
-      0000416868686868686868686868686868686868686868121437363331313235
-      3838383838383838181C676868686868686868686868686868686868685E5121
-      0000416861616161616161616161616161616161616161052B67686868686867
-      676767676767676729095C6161616161616161616161616161616161615E5121
-      0000416868686868686868686868686868686868686868042D68686868685F4D
-      424D6068686868672909676868686868686868686868686868686868685E5121
-      000041686161616161616161616161616161616161616105226868686752240B
-      0B0925526768686729095D6161616161616161616161616161616161615E5121
-      0000416868686868686868686868686868686868686868052C68686448130F3D
-      4E3E1014496468672909676868686868686868686868686868686868685E5121
-      0000416861616161616161616161616161616161616161032E68633F0A174B66
-      68664C190E40626727075D6161616161616161616161616161616161615E5121
-      00004168686868686868686868686868686868686868680326532F0723556868
-      68686856240930542907676868686868686868686868686868686868685E5121
-      0000416861616161616161616161616161616161616161011F200C3B5A686868
-      68686868593C0D201F095D6161616161616161616161616161616161615E5121
-      0000416868686868686868686868686868686868686868080B15436568686868
-      68686868686544150909676868686868686868686868686868686868685E5121
-      000041686161616161616161616161616161616161615B081E50666868686868
-      68686868686866501B095D6161616161616161616161616161616161615E5121
-      0000416868686868686868686868686868686868686868072867686868686868
-      68686868686867672909676868686868686868686868686868686868685E5121
-      000041686161616161616161616161616161616161615B161135393932323334
-      3333333436373838111B5D6161616161616161616161616161616161615E5121
-      0000416868686868686868686868686868686868686868671C08060602060606
-      070707070909090B1E67686868686868686868686868686868686868685E5121
-      0000416861616161616161616161616161616161616161615B5B5B5D5D5B5B5B
-      5B5B5B5B5B5B5D5D5D6161616161616161616161616161616161616161685821
-      0000456868686868686868686868686868686868686868686868686868686868
-      6868686868686868686868686868686868686868686868686868686868686821
-      0000456161616161616161616161616161616161616161616161616161616161
-      616161616161616161616161616161616161616161616161616161616161612A
-      0000464A46464646464646464646464646464646464646464646464646464646
-      464646464646464646464646464646464646464646464646464646464645413A
-      0000}
+      1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D1D00002A574F474747
+      4747474747474747474747474747474747474747474747474747474747474747
+      47474747474747474747474747474747474747474747461D00003A685E585858
+      5858585858585858585858585858585858585858585858585858585858585858
+      585858585858585858585858585858585858585858574F210000416861616161
+      6161616161616161616161616161616161616161616161616161616161616161
+      6161616161616161616161616161616161616161616868210000416868680000
+      0000686868000000686800000000686800000000686868000000686800686868
+      0068000000000068000000006868000000000068685E51210000416861616161
+      6161006100616161006100616161006161616161006100616161006100616161
+      0061616100616161006161610061006161616161615E51210000416868686800
+      0000686800686868006800000000686868000000686800686868686800000000
+      6868686800686868000000006868000000006868685E51210000416861610061
+      6161616100616161006100616161006100616161616100616161006100616161
+      0061616100616161006161610061006161616161615E51210000416868686800
+      0000006800686868006800000000686868000000006868000000686800000000
+      6868000000000068000000006868000000000068685E51210000416861616161
+      6161616161616161616161616161616161616161616161616161616161616161
+      6161616161616161616161616161616161616161615E51210000416868686868
+      6868686868686868686868686868686868686868686868686868686868686868
+      6868686868686868686868686868686868686868685E51210000416861616161
+      6161616161616161616161616161616161616161616161616161616161616161
+      6161616161616161616161616161616161616161615E51210000416868686868
+      6868686868686868686868686868686868676767676767676767676767676767
+      6768686868686868686868686868686868686868685E51210000416861616161
+      6161616161616161616161616161615D1A090909090808090909090909090909
+      1C5C616161616161616161616161616161616161615E51210000416868686868
+      6868686868686868686868686868681214373633313132353838383838383838
+      181C676868686868686868686868686868686868685E51210000416861616161
+      616161616161616161616161616161052B676868686868676767676767676767
+      29095C6161616161616161616161616161616161615E51210000416868686868
+      686868686868686868686868686868042D68686868685F4D424D606868686867
+      2909676868686868686868686868686868686868685E51210000416861616161
+      61616161616161616161616161616105226868686752240B0B09255267686867
+      29095D6161616161616161616161616161616161615E51210000416868686868
+      686868686868686868686868686868052C68686448130F3D4E3E101449646867
+      2909676868686868686868686868686868686868685E51210000416861616161
+      616161616161616161616161616161032E68633F0A174B6668664C190E406267
+      27075D6161616161616161616161616161616161615E51210000416868686868
+      6868686868686868686868686868680326532F07235568686868685624093054
+      2907676868686868686868686868686868686868685E51210000416861616161
+      616161616161616161616161616161011F200C3B5A68686868686868593C0D20
+      1F095D6161616161616161616161616161616161615E51210000416868686868
+      686868686868686868686868686868080B154365686868686868686868654415
+      0909676868686868686868686868686868686868685E51210000416861616161
+      61616161616161616161616161615B081E506668686868686868686868686650
+      1B095D6161616161616161616161616161616161615E51210000416868686868
+      6868686868686868686868686868680728676868686868686868686868686767
+      2909676868686868686868686868686868686868685E51210000416861616161
+      61616161616161616161616161615B1611353939323233343333333436373838
+      111B5D6161616161616161616161616161616161615E51210000416868686868
+      686868686868686868686868686868671C08060602060606070707070909090B
+      1E67686868686868686868686868686868686868685E51210000416861616161
+      616161616161616161616161616161615B5B5B5D5D5B5B5B5B5B5B5B5B5B5D5D
+      5D61616161616161616161616161616161616161616858210000456868686868
+      6868686868686868686868686868686868686868686868686868686868686868
+      6868686868686868686868686868686868686868686868210000456161616161
+      6161616161616161616161616161616161616161616161616161616161616161
+      61616161616161616161616161616161616161616161612A0000464A46464646
+      4646464646464646464646464646464646464646464646464646464646464646
+      46464646464646464646464646464646464646464645413A0000}
     ShowHint = True
-    OnClick = MailingListImageClick
+    TabOrder = 5
+    OnClick = MailingListBitBtnClick
   end
   object OKButton: TButton
     Left = 418
@@ -352,9 +351,8 @@ object StartupForm: TStartupForm
     Top = 390
     Width = 260
     Height = 17
-    TabStop = False
     Anchors = [akLeft, akRight, akBottom]
     Caption = '&Don'#39't show this dialog again'
-    TabOrder = 4
+    TabOrder = 6
   end
 end

+ 9 - 9
Projects/Src/IDE.StartupForm.pas

@@ -2,7 +2,7 @@ unit IDE.StartupForm;
 
 {
   Inno Setup
-  Copyright (C) 1997-2024 Jordan Russell
+  Copyright (C) 1997-2025 Jordan Russell
   Portions by Martijn Laan
   For conditions of distribution and use, see LICENSE.TXT.
 
@@ -13,7 +13,7 @@ interface
 
 uses
   Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
-  UIStateForm, StdCtrls, ExtCtrls;
+  UIStateForm, StdCtrls, ExtCtrls, BitmapButton;
 
 type
   TStartupFormResult = (srNone, srEmpty, srWizard, srOpenFile, srOpenDialog,
@@ -31,8 +31,8 @@ type
     StartupCheck: TCheckBox;
     NewImage: TImage;
     OpenImage: TImage;
-    DonateImage: TImage;
-    MailingListImage: TImage;
+    DonateBitBtn: TBitmapButton;
+    MailingListBitBtn: TBitmapButton;
     procedure RadioButtonClick(Sender: TObject);
     procedure FormCreate(Sender: TObject);
     procedure DblClick_(Sender: TObject);
@@ -40,8 +40,8 @@ type
     procedure OKButtonClick(Sender: TObject);
     procedure FormAfterMonitorDpiChanged(Sender: TObject; OldDPI,
       NewDPI: Integer);
-    procedure DonateImageClick(Sender: TObject);
-    procedure MailingListImageClick(Sender: TObject);
+    procedure DonateBitBtnClick(Sender: TObject);
+    procedure MailingListBitBtnClick(Sender: TObject);
   private
     FResult: TStartupFormResult;
     FResultMainFileName: TFileName;
@@ -101,7 +101,7 @@ begin
   InitFormFont(Self);
   InitFormTheme(Self);
 
-  DonateImage.Hint := MainForm.UpdatePanelDonateImage.Hint;
+  DonateBitBtn.Hint := MainForm.UpdatePanelDonateBitBtn.Hint;
 
   UpdateImages;
 
@@ -152,12 +152,12 @@ begin
   OpenRadioButton.Checked := True;
 end;
 
-procedure TStartupForm.DonateImageClick(Sender: TObject);
+procedure TStartupForm.DonateBitBtnClick(Sender: TObject);
 begin
   OpenDonateSite;
 end;
 
-procedure TStartupForm.MailingListImageClick(Sender: TObject);
+procedure TStartupForm.MailingListBitBtnClick(Sender: TObject);
 begin
   OpenMailingListSite;
 end;

+ 7 - 7
Projects/Src/IDE.Wizard.WizardForm.dfm

@@ -1054,14 +1054,14 @@ object WizardForm: TWizardForm
           DesignSize = (
             485
             245)
-          object AppRegistryMinVerDocImage: TImage
-            Left = 360
-            Top = 161
-            Width = 16
-            Height = 16
+          object AppRegistryMinVerDocBitBtn: TBitmapButton
+            Left = 358
+            Top = 159
+            Width = 20
+            Height = 20
             Anchors = [akTop, akRight]
-            AutoSize = True
-            Transparent = True
+            Caption = 'Help'
+            TabOrder = 9
           end
           object AppRegistryFileLabel: TNewStaticText
             Left = 36

+ 3 - 3
Projects/Src/IDE.Wizard.WizardForm.pas

@@ -14,7 +14,7 @@ interface
 uses
   Windows, Forms, Classes, Graphics, StdCtrls, ExtCtrls, Controls, Dialogs, pngimage,
   UIStateForm, NewStaticText, DropListBox, NewCheckListBox, NewNotebook,
-  IDE.Wizard.WizardFormFilesHelper, IDE.Wizard.WizardFormRegistryHelper;
+  IDE.Wizard.WizardFormFilesHelper, IDE.Wizard.WizardFormRegistryHelper, BitmapButton;
 
 type
   TWizardPage = (wpWelcome, wpAppInfo, wpAppDir, wpAppFiles, wpAppAssoc, wpAppIcons,
@@ -139,7 +139,7 @@ type
     AppRegistryUninsDeleteValueCheck: TCheckBox;
     AppRegistryMinVerCheck: TCheckBox;
     AppRegistryMinVerEdit: TEdit;
-    AppRegistryMinVerDocImage: TImage;
+    AppRegistryMinVerDocBitBtn: TBitmapButton;
     WelcomeImageDark: TImage;
     InnerImageDark: TImage;
     procedure FormCreate(Sender: TObject);
@@ -289,7 +289,7 @@ begin
   FRegistryHelper := TWizardFormRegistryHelper.Create(Self, AppRegistryFileEdit,
     AppRegistryFileButton, AppRegistryUninsDeleteKeyCheck,
     AppRegistryUninsDeleteKeyIfEmptyCheck, AppRegistryUninsDeleteValueCheck,
-    AppRegistryMinVerCheck, AppRegistryMinVerEdit, AppRegistryMinVerDocImage);
+    AppRegistryMinVerCheck, AppRegistryMinVerEdit, AppRegistryMinVerDocBitBtn);
 
   FLanguages := TStringList.Create;
   FLanguages.Sorted := True;

+ 12 - 12
Projects/Src/IDE.Wizard.WizardFormRegistryHelper.pas

@@ -2,7 +2,7 @@ unit IDE.Wizard.WizardFormRegistryHelper;
 
 {
   Inno Setup
-  Copyright (C) 1997-2024 Jordan Russell
+  Copyright (C) 1997-2025 Jordan Russell
   Portions by Martijn Laan
   For conditions of distribution and use, see LICENSE.TXT.
 
@@ -12,7 +12,7 @@ unit IDE.Wizard.WizardFormRegistryHelper;
 interface
 
 uses
-  Forms, StdCtrls, ExtCtrls;
+  Forms, StdCtrls, ExtCtrls, BitmapButton;
 
 type
   TPrivilegesRequired = (prAdmin, prLowest, prDynamic);
@@ -24,7 +24,7 @@ type
       FUninsDeleteKeyCheck, FUninsDeleteKeyIfEmptyCheck,
       FUninsDeleteValueCheck, FMinVerCheck: TCheckBox;
       FMinVerEdit: TEdit;
-      FMinVerDocImage: TImage;
+      FMinVerDocBitBtn: TBitmapButton;
       FPrivilegesRequired: TPrivilegesRequired;
       procedure SetPrivilegesRequired(const Value: TPrivilegesRequired);
       procedure UpdateImages;
@@ -32,12 +32,12 @@ type
       procedure FileButtonClick(Sender: TObject);
       procedure UninsDeleteKeyIfEmptyCheckClick(Sender: TObject);
       procedure MinVerCheckClick(Sender: TObject);
-      procedure MinVerDocImageClick(Sender: TObject);
+      procedure MinVerDocBitBtnClick(Sender: TObject);
     public
       constructor Create(const Form: TForm; const FileEdit: TEdit;
         const FileButton: TButton; const UninsDeleteKeyCheck,
         UninsDeleteKeyIfEmptyCheck, UninsDeleteValueCheck, MinVerCheck: TCheckBox;
-        const MinVerEdit: TEdit; const MinVerDocImage: TImage);
+        const MinVerEdit: TEdit; const MinVerDocBitBtn: TBitmapButton);
       procedure AddScript(var Registry: String; const AllowException: Boolean);
       property PrivilegesRequired: TPrivilegesRequired write SetPrivilegesRequired;
     end;
@@ -67,13 +67,13 @@ procedure TWizardFormRegistryHelper.UpdateImages;
 begin
  { After a DPI change the button's Width and Height isn't yet updated, so calculate it ourselves }
   var WH := MulDiv(16, FForm.CurrentPPI, 96);
-  FMinVerDocImage.Picture.Graphic:= GetImage(MainForm.HelpButton, WH);
+  FMinVerDocBitBtn.Bitmap.Assign(GetImage(MainForm.HelpButton, WH));
 end;
 
 constructor TWizardFormRegistryHelper.Create(const Form: TForm;
   const FileEdit: TEdit; const FileButton: TButton; const UninsDeleteKeyCheck,
   UninsDeleteKeyIfEmptyCheck, UninsDeleteValueCheck, MinVerCheck: TCheckBox;
-  const MinVerEdit: TEdit; const MinVerDocImage: TImage);
+  const MinVerEdit: TEdit; const MinVerDocBitBtn: TBitmapButton);
 begin
   FForm := Form;
   FFileEdit := FileEdit;
@@ -82,14 +82,14 @@ begin
   FUninsDeleteValueCheck := UninsDeleteValueCheck;
   FMinVerCheck := MinVerCheck;
   FMinVerEdit := MinVerEdit;
-  FMinVerDocImage := MinVerDocImage;
+  FMinVerDocBitBtn := MinVerDocBitBtn;
 
   FileButton.OnClick := FileButtonClick;
   UninsDeleteKeyIfEmptyCheck.OnClick := UninsDeleteKeyIfEmptyCheckClick;
   MinVerCheck.OnClick := MinVerCheckClick;
   MinVerCheck.OnClick(nil);
-  MinVerDocImage.OnClick := MinVerDocImageClick;
-  MinVerDocImage.Cursor := crHandPoint;
+  MinVerDocBitBtn.OnClick := MinVerDocBitBtnClick;
+  MinVerDocBitBtn.Cursor := crHandPoint;
 
   TryEnableAutoCompleteFileSystem(FileEdit.Handle);
 
@@ -119,12 +119,12 @@ end;
 procedure TWizardFormRegistryHelper.MinVerCheckClick(Sender: TObject);
 begin
   FMinVerEdit.Enabled := FMinVerCheck.Checked;
-  FMinVerDocImage.Visible := FMinVerCheck.Checked;
+  FMinVerDocBitBtn.Visible := FMinVerCheck.Checked;
   if FMinVerEdit.Enabled then
     FForm.ActiveControl := FMinVerEdit;
 end;
 
-procedure TWizardFormRegistryHelper.MinVerDocImageClick(Sender: TObject);
+procedure TWizardFormRegistryHelper.MinVerDocBitBtnClick(Sender: TObject);
 begin
   if Assigned(HtmlHelp) then
     HtmlHelp(GetDesktopWindow, PChar(GetHelpFile), HH_DISPLAY_TOPIC, Cardinal(PChar('topic_winvernotes.htm')));

+ 8 - 2
Projects/Src/Setup.ScriptClasses.pas

@@ -25,7 +25,7 @@ uses
   uPSR_stdctrls, uPSR_extctrls, uPSR_comobj,
   NewStaticText, NewCheckListBox, NewProgressBar, RichEditViewer,
   ExtCtrls, UIStateForm, Setup.SetupForm, Setup.MainForm, Setup.WizardForm, Shared.SetupTypes, PasswordEdit,
-  FolderTreeView, BitmapImage, NewNotebook, Setup.ScriptDlg, BidiCtrls,
+  FolderTreeView, BitmapButton, BitmapImage, NewNotebook, Setup.ScriptDlg, BidiCtrls,
   Setup.UninstallProgressForm;
 
 type
@@ -138,12 +138,17 @@ end;
 procedure TBitmapAlphaFormat_W(Self: TBitmap; const T: TAlphaFormat); begin Self.AlphaFormat := T; end;
 procedure TBitmapAlphaFormat_R(Self: TBitmap; var T: TAlphaFormat); begin T := Self.AlphaFormat; end;
 
-procedure RegisterBitmapImage_R(Cl: TPSRuntimeClassImporter);
+procedure RegisterBitmapButton_R(Cl: TPSRuntimeClassImporter);
 begin
   with Cl.FindClass('TBitmap') do
   begin
     RegisterPropertyHelper(@TBitmapAlphaFormat_R, @TBitmapAlphaFormat_W, 'AlphaFormat');
   end;
+  Cl.Add(TBitmapButton);
+end;
+
+procedure RegisterBitmapImage_R(Cl: TPSRuntimeClassImporter);
+begin
   Cl.Add(TBitmapImage);
 end;
 
@@ -431,6 +436,7 @@ begin
     RegisterCustomFolderTreeView_R(Cl);
     RegisterFolderTreeView_R(Cl);
     RegisterStartMenuFolderTreeView_R(Cl);
+    RegisterBitmapButton_R(Cl);
     RegisterBitmapImage_R(Cl);
     RegisterBidiCtrls_R(Cl);
 

+ 6 - 1
Projects/Src/Setup.ScriptFunc.pas

@@ -21,7 +21,7 @@ implementation
 uses
   Windows,
   Forms, SysUtils, Classes, Graphics, ActiveX, Generics.Collections,
-  uPSUtils, PathFunc, ISSigFunc, ECDSA, BrowseFunc, MD5, SHA1, SHA256, BitmapImage, PSStackHelper,
+  uPSUtils, PathFunc, ISSigFunc, ECDSA, BrowseFunc, MD5, SHA1, SHA256, BitmapButton, BitmapImage, PSStackHelper,
   Shared.Struct, Setup.ScriptDlg, Setup.MainFunc, Shared.CommonFunc.Vcl,
   Shared.CommonFunc, Shared.FileClass, SetupLdrAndSetup.RedirFunc,
   Setup.Install, SetupLdrAndSetup.InstFunc, Setup.InstFunc, Setup.InstFunc.Ole,
@@ -1814,6 +1814,11 @@ var
       if ErrorCode <> 0 then
         raise Exception.Create(Win32ErrorString(ErrorCode));
     end);
+    RegisterScriptFunc('INITIALIZEBITMAPBUTTONFROMICON', procedure(const Caller: TPSExec; const OrgName: AnsiString; const Stack: TPSStack; const PStart: Cardinal)
+    begin
+      var AscendingTrySizes := Stack.GetIntArray(PStart-4);
+      Stack.SetBool(PStart, TBitmapButton(Stack.GetClass(PStart-1)).InitializeFromIcon(0, PChar(Stack.GetString(PStart-2)), Stack.GetInt(PStart-3), AscendingTrySizes));
+    end);
     RegisterScriptFunc('INITIALIZEBITMAPIMAGEFROMICON', procedure(const Caller: TPSExec; const OrgName: AnsiString; const Stack: TPSStack; const PStart: Cardinal)
     begin
       var AscendingTrySizes := Stack.GetIntArray(PStart-4);

+ 12 - 0
Projects/Src/Shared.FileClass.pas

@@ -58,6 +58,7 @@ type
     constructor Create(const AFilename: String;
       ACreateDisposition: TFileCreateDisposition; AAccess: TFileAccess;
       ASharing: TFileSharing);
+    constructor CreateDuplicate(const ASourceFile: TFile);
     constructor CreateWithExistingHandle(const AHandle: THandle);
     destructor Destroy; override;
     function Read(var Buffer; Count: Cardinal): Cardinal; override;
@@ -217,6 +218,17 @@ begin
   FHandleCreated := True;
 end;
 
+constructor TFile.CreateDuplicate(const ASourceFile: TFile);
+begin
+  inherited Create;
+  var LHandle: THandle;
+  if not DuplicateHandle(GetCurrentProcess, ASourceFile.Handle,
+     GetCurrentProcess, @LHandle, 0, False, DUPLICATE_SAME_ACCESS) then
+    RaiseLastError;
+  FHandle := LHandle;  { assign only on success }
+  FHandleCreated := True;
+end;
+
 constructor TFile.CreateWithExistingHandle(const AHandle: THandle);
 begin
   inherited Create;

+ 1 - 0
Projects/Src/Shared.ScriptFunc.pas

@@ -539,6 +539,7 @@ initialization
     'function CreateCallback(Method: AnyMethod): Longword;',
     'function IsDotNetInstalled(const MinVersion: TDotNetVersion; const MinServicePack: Cardinal): Boolean;',
     'function IsMsiProductInstalled(const UpgradeCode: String; const PackedMinVersion: Int64): Boolean;',
+    'function InitializeBitmapButtonFromIcon(const BitmapButton: TBitmapButton; const IconFilename: String; const BkColor: TColor; const AscendingTrySizes: TArrayOfInteger): Boolean;',
     'function InitializeBitmapImageFromIcon(const BitmapImage: TBitmapImage; const IconFilename: String; const BkColor: TColor; const AscendingTrySizes: TArrayOfInteger): Boolean;',
     'procedure Extract7ZipArchive(const ArchiveFileName, DestDir: String; const FullPaths: Boolean; const OnExtractionProgress: TOnExtractionProgress);',
     'procedure ExtractArchive(const ArchiveFilename, DestDir, Password: String; const FullPaths: Boolean; const OnExtractionProgress: TOnExtractionProgress);',

+ 6 - 4
README.md

@@ -84,6 +84,7 @@ the following component units, which can be found in the [Components]
 directory.
 
 - BidiCtrls
+- BitmapButton
 - BitmapImage
 - FolderTreeView
 - NewCheckListBox
@@ -158,18 +159,19 @@ How do the projects link together?
 Source code tips
 ----------------
 
-- When building the projects in Debug mode it outputs to [Projects\Bin] and when
-  debugging it will run from within this directory. To prepare this directory
+- When building the projects in Debug mode, it outputs to [Projects\Bin] and when
+  debugging, it will run from within this directory. To prepare this directory
   with some extra files you must run **Projects\Bin\synch-isfiles.bat**. Running
   the aforementioned **build.bat** or **build-ce.bat** first is not necessary.
 
-- When debugging the Setup project you should first build all projects in Debug
+- When debugging the Setup project, you should first build all projects in Debug
   mode, then run the Compil32 project and compile the Debug.iss script which
   should open automatically, and finally open and run the Setup project.
   This way you can simulate an actual installation while running under the
   Delphi debugger.
   
-- When building the projects in Release mode it outputs to [Files].
+- When building the projects in Release mode, it outputs to [Files]. Before
+  running Compil32, ensure that all .issig files are up to date.
   
 - All of the forms in the Setup project have Scaled set to False. This is
   because they dynamically scale themselves at run-time by calling a function

+ 29 - 25
isdonateandmail.iss

@@ -7,18 +7,20 @@ Source: "ismail.bmp"; Flags: dontcopy noencryption
 
 [CustomMessages]
 ; No need to localize: The IS website is in English only
+IsDonateAndMailDonateCaption=Donate
 IsDonateAndMailDonateHint=Support Inno Setup - Thank you!
+IsDonateAndMailMailCaption=Subscribe
 IsDonateAndMailMailHint=Be notified by e-mail of new Inno Setup releases
 
 [Code]
-procedure DonateImageOnClick(Sender: TObject);
+procedure DonateBitmapButtonOnClick(Sender: TObject);
 var
   ErrorCode: Integer;
 begin
   ShellExecAsOriginalUser('open', 'https://jrsoftware.org/isdonate.php', '', '', SW_SHOWNORMAL, ewNoWait, ErrorCode);
 end;
 
-procedure MailImageOnClick(Sender: TObject);
+procedure MailBitmapButtonOnClick(Sender: TObject);
 var
   ErrorCode: Integer;
 begin
@@ -29,7 +31,7 @@ end;
 procedure IsDonateAndMailInitializeWizard;
 var
   ImageFileName: String;
-  DonateImage, MailImage: TBitmapImage;
+  DonateBitmapButton, MailBitmapButton: TBitmapButton;
   BevelTop: Integer;
 begin
   if WizardSilent then
@@ -38,31 +40,33 @@ begin
   ImageFileName := ExpandConstant('{tmp}\isdonate.bmp');
   ExtractTemporaryFile(ExtractFileName(ImageFileName));
 
-  DonateImage := TBitmapImage.Create(WizardForm);
-  DonateImage.AutoSize := True;
-  DonateImage.Bitmap.LoadFromFile(ImageFileName);
-  DonateImage.Hint := CustomMessage('IsDonateAndMailDonateHint');
-  DonateImage.ShowHint := True;
-  DonateImage.Anchors := [akLeft, akBottom];
+  DonateBitmapButton := TBitmapButton.Create(WizardForm);
+  DonateBitmapButton.AutoSize := True;
+  DonateBitmapButton.Bitmap.LoadFromFile(ImageFileName);
+  DonateBitmapButton.Caption := CustomMessage('IsDonateAndMailDonateCaption');
+  DonateBitmapButton.Hint := CustomMessage('IsDonateAndMailDonateHint');
+  DonateBitmapButton.ShowHint := True;
+  DonateBitmapButton.Anchors := [akLeft, akBottom];
   BevelTop := WizardForm.Bevel.Top;
-  DonateImage.Top := BevelTop + (WizardForm.ClientHeight - BevelTop - DonateImage.Bitmap.Height) div 2;
-  DonateImage.Left := DonateImage.Top - BevelTop;
-  DonateImage.Cursor := crHand;
-  DonateImage.OnClick := @DonateImageOnClick;
-  DonateImage.Parent := WizardForm;
+  DonateBitmapButton.Top := BevelTop + (WizardForm.ClientHeight - BevelTop - DonateBitmapButton.Bitmap.Height) div 2;
+  DonateBitmapButton.Left := DonateBitmapButton.Top - BevelTop;
+  DonateBitmapButton.Cursor := crHand;
+  DonateBitmapButton.OnClick := @DonateBitmapButtonOnClick;
+  DonateBitmapButton.Parent := WizardForm;
 
   ImageFileName := ExpandConstant('{tmp}\ismail.bmp');
   ExtractTemporaryFile(ExtractFileName(ImageFileName));
 
-  MailImage := TBitmapImage.Create(WizardForm);
-  MailImage.AutoSize := True;
-  MailImage.Bitmap.LoadFromFile(ImageFileName);
-  MailImage.Hint := CustomMessage('IsDonateAndMailMailHint');
-  MailImage.ShowHint := True;
-  MailImage.Anchors := [akLeft, akBottom];
-  MailImage.Top := DonateImage.Top
-  MailImage.Left := DonateImage.Left + DonateImage.Width + ScaleX(8);
-  MailImage.Cursor := crHand;
-  MailImage.OnClick := @MailImageOnClick;
-  MailImage.Parent := WizardForm;
+  MailBitmapButton := TBitmapButton.Create(WizardForm);
+  MailBitmapButton.AutoSize := True;
+  MailBitmapButton.Bitmap.LoadFromFile(ImageFileName);
+  MailBitmapButton.Caption := CustomMessage('IsDonateAndMailMailCaption');
+  MailBitmapButton.Hint := CustomMessage('IsDonateAndMailMailHint');
+  MailBitmapButton.ShowHint := True;
+  MailBitmapButton.Anchors := [akLeft, akBottom];
+  MailBitmapButton.Top := DonateBitmapButton.Top
+  MailBitmapButton.Left := DonateBitmapButton.Left + DonateBitmapButton.Width + ScaleX(4);
+  MailBitmapButton.Cursor := crHand;
+  MailBitmapButton.OnClick := @MailBitmapButtonOnClick;
+  MailBitmapButton.Parent := WizardForm;
 end;

+ 3 - 1
whatsnew.htm

@@ -212,6 +212,7 @@ issigtool --key-file="MyKey.ispublickey" verify "MyProg.dll"</code></pre>
           The <i>Highlight occurrences of current selection</i> option (which is enabled by default) still does.</li>
       <li>Dark mode is now supported throughout.</li>
       <li>Improved support for high-contrast themes.</li>
+      <li>Improved support for screen readers.</li>
     </ul>
   </li>
   <li><tt>[Files]</tt> section parameter <tt>Excludes</tt> can now be combined with the <tt>external</tt> flag.</li>
@@ -227,8 +228,9 @@ issigtool --key-file="MyKey.ispublickey" verify "MyProg.dll"</code></pre>
   </li>
   <li>Pascal Scripting changes:
     <ul>
+      <li>Added new <tt>TBitmapButton</tt> support class which works just like <tt>TBitmapImage</tt>, but is accessible by keyboard and compatible with screen readers. Make sure to set the <tt>Caption</tt> property, even if it isn't visible. See updated example script <i>CodeClasses.iss</i> for an example.</li>
+      <li>Added new <tt>InitializeBitmapButtonFromIcon</tt> and <tt>GetSHA256OfStream</tt> support functions.</li>
       <li>Added new <tt>LastBaseNameOrUrl</tt> property to support class <tt>TDownloadWizardPage</tt>. See updated example script <i>CodeDownloadFiles.iss</i> for an example.</li>
-      <li>Added new <tt>GetSHA256OfStream</tt> support function.</li>
       <li><i>Fix:</i> Event function <tt>CurPageChanged</tt> is now always only triggered when the current page actually changes. Before it was called twice in a row for <tt>wpPreparing</tt> when the script had a <tt>PrepareToInstall</tt> event function which returned a non empty string to instruct Setup to stop.</li>
     </ul>
   </li>