瀏覽代碼

Merge branch 'main' into autoreload

Martijn Laan 1 月之前
父節點
當前提交
340c9c500e

+ 43 - 0
.github/workflows/build2.yml

@@ -0,0 +1,43 @@
+name: build2
+
+on:
+  push:
+  workflow_dispatch:
+
+env:
+  HOME: "${{github.workspace}}\\home"
+
+jobs:
+  build2:
+    # Only set the topic `has-issrc-build2-env` if the secrets are available
+    if: contains(github.event.repository.topics, 'has-issrc-build2-env')
+    runs-on: windows-latest
+    steps:
+      - uses: actions/checkout@v3
+        with:
+          submodules: true
+      - name: Initialize build environment
+        env:
+          ISSRC_BUILD2_ENV_ZIP_PASSWORD: ${{ secrets.ISSRC_BUILD2_ENV_ZIP_PASSWORD }}
+          ISSRC_BUILD2_ENV_ZIP_URL: ${{ secrets.ISSRC_BUILD2_ENV_ZIP_URL }}
+        run: |
+          (New-Object Net.WebClient).DownloadFile($env:ISSRC_BUILD2_ENV_ZIP_URL, "issrc-build-env.zip")
+          & "C:\\Program Files\\7-Zip\\7z.exe" x -oissrc-build-env -p"$env:ISSRC_BUILD2_ENV_ZIP_PASSWORD" issrc-build-env.zip
+          if (!(Test-Path issrc-build-env\bin\dcc32.exe)) {
+            Write-Host "Failed to extract dcc32.exe"
+            Exit 1
+          }
+          Remove-Item issrc-build-env.zip
+          $DELPHIXEROOT = (Get-Item .\issrc-build-env).FullName
+          "DELPHIXEROOT=$DELPHIXEROOT" | Out-File -NoNewLine -Encoding ascii -Append "$env:GITHUB_ENV"
+      - name: Build issrc
+        run: |
+          "set DELPHIXEROOT=$env:DELPHIXEROOT" | Out-File -Encoding ascii compilesettings.bat
+          "set ISSIGTOOL_KEY_FILE=${{github.workspace}}\mykey.isprivatekey" | Out-File -NoNewline -Encoding ascii -Append compilesettings.bat
+          "set DELPHIXEROOT=$env:DELPHIXEROOT" | Out-File -NoNewline -Encoding ascii ISHelp\ISHelpGen\compilesettings.bat
+          "set HHCEXE=%ProgramFiles(x86)%\HTML Help Workshop\hhc.exe" | Out-File -NoNewline -Encoding ascii ISHelp\compilesettings.bat
+          .\build.bat
+      - name: Clean up temporary files
+        if: always()
+        shell: bash
+        run: rm -rf mykey.isprivatekey

+ 8 - 9
Components/BitmapButton.pas

@@ -26,8 +26,6 @@ type
   private
     FFocusBorderWidthHeight: Integer;
     FImpl: TBitmapImageImplementation;
-    FOnClick: TNotifyEvent;
-    FOnDblClick: TNotifyEvent;
     procedure SetBackColor(Value: TColor);
     procedure SetBitmap(Value: TBitmap);
     procedure SetCenter(Value: Boolean);
@@ -64,8 +62,8 @@ type
     property TabOrder;
     property TabStop default True;
     property Visible;
-    property OnClick: TNotifyEvent read FOnClick write FOnClick;
-    property OnDblClick: TNotifyEvent read FOnDblClick write FOnDblClick;
+    property OnClick;
+    property OnDblClick;
     property OnPaint: TPaintEvent read FImpl.OnPaint write FImpl.OnPaint;
   end;
 
@@ -81,7 +79,7 @@ end;
 constructor TBitmapButton.Create(AOwner: TComponent);
 begin
   inherited;
-  ControlStyle := ControlStyle + [csReplicatable];
+  ControlStyle := ControlStyle + [csReplicatable] - [csClickEvents];
   { Using a fixed focus border width/height to avoid design problems between systems }
   FFocusBorderWidthHeight := 2;
   const DoubleFBWH = 2*FFocusBorderWidthHeight;
@@ -96,6 +94,7 @@ procedure TBitmapButton.CreateParams(var Params: TCreateParams);
 begin
   inherited;
   CreateSubClass(Params, 'BUTTON');
+  Params.Style := Params.Style or BS_NOTIFY; { For BN_DBLCLK }
 end;
 
 destructor TBitmapButton.Destroy;
@@ -184,10 +183,10 @@ 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);
+  if (Message.NotifyCode = BN_CLICKED) then
+    Click
+  else if (Message.NotifyCode = BN_DBLCLK) then
+    DblClick;
 end;
 
 end.

+ 1 - 1
Components/ISSigFunc.pas

@@ -102,7 +102,7 @@ function CalcHashToSign(const AIncludeFileNameAndTag: Boolean; const AFileName:
   procedure SHA256UpdateWithString(var Context: TSHA256Context; const S: String);
   begin
     const U = UTF8String(S);
-    const N: Int32 = Length(U);
+    const N = UInt32(Length(U));
     SHA256Update(Context, N, SizeOf(N));
     if N > 0 then
       SHA256Update(Context, Pointer(U)^, N*SizeOf(U[1]));

+ 10 - 5
Projects/Src/Compression.SevenZipDLLDecoder.pas

@@ -214,16 +214,19 @@ type
 
 { Helper functions }
 
-procedure SevenZipWin32Error(const FunctionName: String; ErrorCode: DWORD = 0); overload;
+procedure SevenZipWin32Error(const FunctionName: String; const ErrorCode: DWORD); overload;
 begin
-  if ErrorCode = 0 then
-    ErrorCode := GetLastError;
   const ExceptMessage = FmtSetupMessage(msgErrorFunctionFailedWithMessage,
     [FunctionName, IntToStr(ErrorCode), Win32ErrorString(ErrorCode)]);
   const LogMessage = Format('Function %s returned error code %d', [FunctionName, ErrorCode]);
   SevenZipError(ExceptMessage, LogMessage);
 end;
 
+procedure SevenZipWin32Error(const FunctionName: String); overload;
+begin
+  SevenZipWin32Error(FunctionName, GetLastError);
+end;
+
 function GetHandler(const Filename, NotFoundErrorMsg: String): TGUID; forward;
 
 const
@@ -600,8 +603,9 @@ begin
         case WaitForSingleObject(ThreadHandle, 50) of
           WAIT_OBJECT_0: Break;
           WAIT_TIMEOUT: HandleProgress; { This calls the user's OnExtractionProgress handler! }
+          WAIT_FAILED: SevenZipWin32Error('WaitForSingleObject');
         else
-          SevenZipWin32Error('WaitForSingleObject');
+          SevenZipError('WaitForSingleObject returned unknown value');
         end;
       end;
     except
@@ -1008,7 +1012,8 @@ begin
   try
     F := TFileRedir.Create(DisableFsRedir, ArchiveFilename, fdOpenExisting, faRead, fsRead);
   except
-    SevenZipWin32Error('CreateFile');
+    on E: EFileError do
+      SevenZipWin32Error('CreateFile', E.ErrorCode);
   end;
   const InStream: IInStream = TInStream.Create(F);
   var ScanSize := DefaultScanSize;

+ 32 - 38
Projects/Src/Setup.MainFunc.pas

@@ -2622,8 +2622,7 @@ var
     Abort;
   end;
 
-  procedure ReadFileIntoStream(const Stream: TStream;
-    const R: TCompressedBlockReader);
+  procedure ReadFileIntoStream(const Reader: TCompressedBlockReader; const Stream: TStream);
   type
     PBuffer = ^TBuffer;
     TBuffer = array[0..8191] of Byte;
@@ -2633,11 +2632,11 @@ var
   begin
     New(Buf);
     try
-      R.Read(BytesLeft, SizeOf(BytesLeft));
+      Reader.Read(BytesLeft, SizeOf(BytesLeft));
       while BytesLeft > 0 do begin
         Bytes := BytesLeft;
         if Bytes > SizeOf(Buf^) then Bytes := SizeOf(Buf^);
-        R.Read(Buf^, Bytes);
+        Reader.Read(Buf^, Bytes);
         Stream.WriteBuffer(Buf^, Bytes);
         Dec(BytesLeft, Bytes);
       end;
@@ -2646,13 +2645,11 @@ var
     end;
   end;
 
-  function ReadWizardImage(const R: TCompressedBlockReader): TBitmap;
-  var
-    MemStream: TMemoryStream;
+  function ReadWizardImage(const Reader: TCompressedBlockReader): TBitmap;
   begin
-    MemStream := TMemoryStream.Create;
+    const MemStream = TMemoryStream.Create;
     try
-      ReadFileIntoStream(MemStream, R);
+      ReadFileIntoStream(Reader, MemStream);
       MemStream.Seek(0, soFromBeginning);
       Result := TBitmap.Create;
       Result.AlphaFormat := TAlphaFormat(SetupHeader.WizardImageAlphaFormat);
@@ -2701,11 +2698,8 @@ var
     end;
   end;
 
-var
-  Reader: TCompressedBlockReader;
-
-  procedure ReadEntriesWithoutVersion(const EntryType: TEntryType;
-    const Count: Integer; const Size: Integer);
+  procedure ReadEntriesWithoutVersion(const Reader: TCompressedBlockReader;
+    const EntryType: TEntryType; const Count: Integer; const Size: Integer);
   var
     I: Integer;
     P: Pointer;
@@ -2719,8 +2713,8 @@ var
     end;
   end;
 
-  procedure ReadEntries(const EntryType: TEntryType; const Count: Integer;
-    const Size: Integer; const MinVersionOfs, OnlyBelowVersionOfs: Integer);
+  procedure ReadEntries(Reader: TCompressedBlockReader; const EntryType: TEntryType;
+    const Count: Integer; const Size: Integer; const MinVersionOfs, OnlyBelowVersionOfs: Integer);
   var
     I: Integer;
     P: Pointer;
@@ -3111,22 +3105,22 @@ begin
     if TestID <> SetupID then
       AbortInit(msgSetupFileCorruptOrWrongVer);
     try
-      Reader := TCompressedBlockReader.Create(SetupFile, TLZMA1Decompressor);
+      var Reader := TCompressedBlockReader.Create(SetupFile, TLZMA1Decompressor);
       try
         { Header }
         SECompressedBlockRead(Reader, SetupHeader, SizeOf(SetupHeader),
           SetupHeaderStrings, SetupHeaderAnsiStrings);
         { Language entries }
-        ReadEntriesWithoutVersion(seLanguage, SetupHeader.NumLanguageEntries,
+        ReadEntriesWithoutVersion(Reader, seLanguage, SetupHeader.NumLanguageEntries,
           SizeOf(TSetupLanguageEntry));
         { CustomMessage entries }
-        ReadEntriesWithoutVersion(seCustomMessage, SetupHeader.NumCustomMessageEntries,
+        ReadEntriesWithoutVersion(Reader, seCustomMessage, SetupHeader.NumCustomMessageEntries,
           SizeOf(TSetupCustomMessageEntry));
         { Permission entries }
-        ReadEntriesWithoutVersion(sePermission, SetupHeader.NumPermissionEntries,
+        ReadEntriesWithoutVersion(Reader, sePermission, SetupHeader.NumPermissionEntries,
           SizeOf(TSetupPermissionEntry));
         { Type entries }
-        ReadEntries(seType, SetupHeader.NumTypeEntries, SizeOf(TSetupTypeEntry),
+        ReadEntries(Reader, seType, SetupHeader.NumTypeEntries, SizeOf(TSetupTypeEntry),
           Integer(@PSetupTypeEntry(nil).MinVersion),
           Integer(@PSetupTypeEntry(nil).OnlyBelowVersion));
 
@@ -3198,47 +3192,47 @@ begin
         NeedsRestart := shAlwaysRestart in SetupHeader.Options;
 
         { Component entries }
-        ReadEntries(seComponent, SetupHeader.NumComponentEntries, SizeOf(TSetupComponentEntry),
+        ReadEntries(Reader, seComponent, SetupHeader.NumComponentEntries, SizeOf(TSetupComponentEntry),
           -1, -1);
         { Task entries }
-        ReadEntries(seTask, SetupHeader.NumTaskEntries, SizeOf(TSetupTaskEntry),
+        ReadEntries(Reader, seTask, SetupHeader.NumTaskEntries, SizeOf(TSetupTaskEntry),
           -1, -1);
         { Dir entries }
-        ReadEntries(seDir, SetupHeader.NumDirEntries, SizeOf(TSetupDirEntry),
+        ReadEntries(Reader, seDir, SetupHeader.NumDirEntries, SizeOf(TSetupDirEntry),
           Integer(@PSetupDirEntry(nil).MinVersion),
           Integer(@PSetupDirEntry(nil).OnlyBelowVersion));
         { ISSigKey entries }
-        ReadEntriesWithoutVersion(seISSigKey, SetupHeader.NumISSigKeyEntries, SizeOf(TSetupISSigKeyEntry));
+        ReadEntriesWithoutVersion(Reader, seISSigKey, SetupHeader.NumISSigKeyEntries, SizeOf(TSetupISSigKeyEntry));
         { File entries }
-        ReadEntries(seFile, SetupHeader.NumFileEntries, SizeOf(TSetupFileEntry),
+        ReadEntries(Reader, seFile, SetupHeader.NumFileEntries, SizeOf(TSetupFileEntry),
           Integer(@PSetupFileEntry(nil).MinVersion),
           Integer(@PSetupFileEntry(nil).OnlyBelowVersion));
         { Icon entries }
-        ReadEntries(seIcon, SetupHeader.NumIconEntries, SizeOf(TSetupIconEntry),
+        ReadEntries(Reader, seIcon, SetupHeader.NumIconEntries, SizeOf(TSetupIconEntry),
           Integer(@PSetupIconEntry(nil).MinVersion),
           Integer(@PSetupIconEntry(nil).OnlyBelowVersion));
         { INI entries }
-        ReadEntries(seIni, SetupHeader.NumIniEntries, SizeOf(TSetupIniEntry),
+        ReadEntries(Reader, seIni, SetupHeader.NumIniEntries, SizeOf(TSetupIniEntry),
           Integer(@PSetupIniEntry(nil).MinVersion),
           Integer(@PSetupIniEntry(nil).OnlyBelowVersion));
         { Registry entries }
-        ReadEntries(seRegistry, SetupHeader.NumRegistryEntries, SizeOf(TSetupRegistryEntry),
+        ReadEntries(Reader, seRegistry, SetupHeader.NumRegistryEntries, SizeOf(TSetupRegistryEntry),
           Integer(@PSetupRegistryEntry(nil).MinVersion),
           Integer(@PSetupRegistryEntry(nil).OnlyBelowVersion));
         { InstallDelete entries }
-        ReadEntries(seInstallDelete, SetupHeader.NumInstallDeleteEntries, SizeOf(TSetupDeleteEntry),
+        ReadEntries(Reader, seInstallDelete, SetupHeader.NumInstallDeleteEntries, SizeOf(TSetupDeleteEntry),
           Integer(@PSetupDeleteEntry(nil).MinVersion),
           Integer(@PSetupDeleteEntry(nil).OnlyBelowVersion));
         { UninstallDelete entries }
-        ReadEntries(seUninstallDelete, SetupHeader.NumUninstallDeleteEntries, SizeOf(TSetupDeleteEntry),
+        ReadEntries(Reader, seUninstallDelete, SetupHeader.NumUninstallDeleteEntries, SizeOf(TSetupDeleteEntry),
           Integer(@PSetupDeleteEntry(nil).MinVersion),
           Integer(@PSetupDeleteEntry(nil).OnlyBelowVersion));
         { Run entries }
-        ReadEntries(seRun, SetupHeader.NumRunEntries, SizeOf(TSetupRunEntry),
+        ReadEntries(Reader, seRun, SetupHeader.NumRunEntries, SizeOf(TSetupRunEntry),
           Integer(@PSetupRunEntry(nil).MinVersion),
           Integer(@PSetupRunEntry(nil).OnlyBelowVersion));
         { UninstallRun entries }
-        ReadEntries(seUninstallRun, SetupHeader.NumUninstallRunEntries, SizeOf(TSetupRunEntry),
+        ReadEntries(Reader, seUninstallRun, SetupHeader.NumUninstallRunEntries, SizeOf(TSetupRunEntry),
           Integer(@PSetupRunEntry(nil).MinVersion),
           Integer(@PSetupRunEntry(nil).OnlyBelowVersion));
         { Wizard images }
@@ -3252,13 +3246,13 @@ begin
         DecompressorDLL := nil;
         if SetupHeader.CompressMethod in [cmZip, cmBzip] then begin
           DecompressorDLL := TMemoryStream.Create;
-          ReadFileIntoStream(DecompressorDLL, Reader);
+          ReadFileIntoStream(Reader, DecompressorDLL);
         end;
         { SevenZip DLL }
         SevenZipDLL := nil;
         if SetupHeader.SevenZipLibraryName <> '' then begin
           SevenZipDLL := TMemoryStream.Create;
-          ReadFileIntoStream(SevenZipDLL, Reader);
+          ReadFileIntoStream(Reader, SevenZipDLL);
         end;
       finally
         Reader.Free;
@@ -3266,7 +3260,7 @@ begin
       Reader := TCompressedBlockReader.Create(SetupFile, TLZMA1Decompressor);
       try
         { File location entries }
-        ReadEntriesWithoutVersion(seFileLocation, SetupHeader.NumFileLocationEntries,
+        ReadEntriesWithoutVersion(Reader, seFileLocation, SetupHeader.NumFileLocationEntries,
           SizeOf(TSetupFileLocationEntry));
       finally
         Reader.Free;
@@ -3339,11 +3333,11 @@ begin
   { Load system's "shfolder.dll", and load it }
   LoadSHFolderDLL;
 
-  { Extract "_isdecmp.dll" to TempInstallDir, and load it }
+  { Save DecompressorDLL stream as "_isdecmp.dll" in TempInstallDir, and load it }
   if SetupHeader.CompressMethod in [cmZip, cmBzip] then
     LoadDecompressorDLL;
 
-  { Extract "_is7z.dll" to TempInstallDir, and load it }
+  { Save SevenZipDll stream as "_is7z.dll" in TempInstallDir, and load it }
   if SetupHeader.SevenZipLibraryName <> '' then
     LoadSevenZipDLL;
 

+ 24 - 16
Projects/Src/Shared.CommonFunc.pas

@@ -746,23 +746,31 @@ end;
 
 function GetTempDir: String;
 { Returns fully qualified path of the temporary directory, with trailing
-  backslash. This does not use the Win32 function GetTempPath, due to platform
-  differences. }
-label 1;
+  backslash. }
+var
+  GetTempPathFunc: function(nBufferLength: DWORD; lpBuffer: LPWSTR): DWORD; stdcall;
+  Buf: array[0..MAX_PATH] of Char;
 begin
-  Result := GetEnv('TMP');
-  if (Result <> '') and DirExists(Result) then
-    goto 1;
-  Result := GetEnv('TEMP');
-  if (Result <> '') and DirExists(Result) then
-    goto 1;
-  { Like Windows 2000's GetTempPath, return USERPROFILE when TMP and TEMP
-    are not set }
-  Result := GetEnv('USERPROFILE');
-  if (Result <> '') and DirExists(Result) then
-    goto 1;
-  Result := GetWinDir;
-1:Result := AddBackslash(PathExpand(Result));
+  { When available, GetTempPath2 is preferred as it returns a private
+    directory (typically C:\Windows\SystemTemp) when running as SYSTEM }
+  GetTempPathFunc := GetProcAddress(GetModuleHandle(kernel32),
+    PAnsiChar('GetTempPath2W'));
+  if not Assigned(GetTempPathFunc) then
+    GetTempPathFunc := GetTempPathW;
+
+  const Res = GetTempPathFunc(SizeOf(Buf) div SizeOf(Buf[0]), Buf);
+  if (Res > 0) and (Res < SizeOf(Buf) div SizeOf(Buf[0])) then begin
+    { The docs say the returned path is fully qualified and ends with a
+      backslash, but let's be really sure! }
+    Result := AddBackslash(PathExpand(Buf));
+    Exit;
+  end;
+
+  { We don't expect GetTempPath to ever fail or claim a larger buffer is
+    needed (docs say maximum possible return value is MAX_PATH+1), but if it
+    does, raise an exception as this function has no return value for failure }
+  raise Exception.CreateFmt('GetTempDir: GetTempPath failed (%u, %u)',
+    [Res, GetLastError]);
 end;
 
 function StringChangeEx(var S: String; const FromStr, ToStr: String;

+ 6 - 2
README.md

@@ -266,8 +266,7 @@ cd /d C:\Program Files (x86)\Embarcadero\Studio\23.0
 	lib/win32/release/Winapi.*.dcu
 ```
 
-Then, upload this encrypted file somewhere public, e.g. by attaching it to a comment
-in a GitHub issue. After that, add this URL as a new repository
+Then, upload this encrypted file somewhere public. After that, add its URL as a new repository
 [secret] (at https://github.com/YOUR-USER-NAME/issrc/settings/secrets/actions), under the name
 `ISSRC_BUILD_ENV_ZIP_URL`, and the password as `ISSRC_BUILD_ENV_ZIP_PASSWORD`.
 
@@ -285,6 +284,11 @@ the name `ISSRC_BUILD_ENV_SYNC_TOKEN`. Finally, indicate that your fork has this
 by adding the topic `has-issrc-build-env-sync-token`. Your fork will now synchronize daily,
 and will automatically run the aforementioned build workflow on changes, if it's configured.
 
+To perform a second unattended build using a different Delphi version, add topic
+`has-issrc-build2-env` and secrets `ISSRC_BUILD2_ENV_ZIP_URL` and
+`ISSRC_BUILD2_ENV_ZIP_PASSWORD`. Unlike the main build, the second build does not produce
+any artifacts.
+
 <!-- Link references -->
 [CONTRIBUTING.md]: <CONTRIBUTING.md>
 [Projects\Bin]: <Projects/Bin>

+ 1 - 1
build-ce.bat

@@ -87,7 +87,7 @@ if exist .\setup-presign.bat (
   echo Presign done
 )
 
-rem  Sign using user's private key
+rem  Sign using user's private key - also see compile.bat
 call .\issig.bat sign Files\ISCmplr.dll Files\ISPP.dll Files\Setup.e32 Files\SetupLdr.e32
 if errorlevel 1 goto failed
 echo ISSigTool sign done

+ 1 - 1
build.bat

@@ -78,7 +78,7 @@ if exist .\setup-presign.bat (
   echo Presign done
 ) 
 
-rem  Sign using user's private key
+rem  Sign using user's private key - also see compile.bat
 call .\issig.bat sign Files\ISCmplr.dll Files\ISPP.dll Files\Setup.e32 Files\SetupLdr.e32
 if errorlevel 1 goto failed
 echo ISSigTool sign done

+ 6 - 0
compile.bat

@@ -89,6 +89,12 @@ cd ..
 if errorlevel 1 goto failed
 
 echo Success!
+
+rem  Sign using user's private key - will be overwritten if called by build.bat
+call .\issig.bat sign Files\ISCmplr.dll Files\ISPP.dll Files\Setup.e32 Files\SetupLdr.e32
+if errorlevel 1 goto failed
+echo ISSigTool sign done
+
 goto exit
 
 :failed

+ 3 - 2
whatsnew.htm

@@ -44,7 +44,7 @@ For conditions of distribution and use, see <a href="files/is/license.txt">LICEN
 
 <p><a name="6.5.0"></a><span class="ver">6.5.0-dev </span><span class="date">(?)</span></p>
 <span class="head2">Improved archive extraction</span>
-<p>Support for extracting archives has been improved. It's now possible to extract password-protected archives, multi-volume archives, and multiple extra archive formats such as .zip.</p>
+<p>It's now possible to extract password-protected archives, multi-volume archives, and multiple extra archive formats such as .zip.</p>
 <p>Additionally the <tt>[Files]</tt> section now supports archive extraction. Writing Pascal Script to extract an archive is no longer necessary.</p>
 <p>All of this is optional and does <i>not</i> increase the size of Setup if not used.</p>
 <ul>
@@ -88,7 +88,7 @@ For conditions of distribution and use, see <a href="files/is/license.txt">LICEN
   </li>
 </ul>
 <span class="head2">Improved file downloads</span>
-<p>Support for downloading files has been improved: the <tt>[Files]</tt> section now supports file downloads. Writing Pascal Script to download a file is no longer necessary and is in fact less efficient since it requires an intermediate temporary file which this new download support doesn't.</p>
+<p>The <tt>[Files]</tt> section now supports file downloads. Writing Pascal Script to download a file is no longer necessary and is in fact less efficient since it requires an intermediate temporary file which this new download support doesn't.</p>
 <ul>
   <li>Updated <tt>[Files]</tt> section:
   <ul>
@@ -234,6 +234,7 @@ issigtool --key-file="MyKey.ispublickey" verify "MyProg.dll"</code></pre>
       <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>
+  <li>When available, Setup now retrieves the temporary directory path using the <tt>GetTempPath2</tt> API, which was first introduced in Windows 11 and later backported to Windows 10 and Windows Server 2016 via monthly updates. When running under the SYSTEM account, <tt>GetTempPath2</tt> returns a private directory (typically <tt>C:\Windows\SystemTemp</tt>), potentially enhancing security. On older versions of Windows or systems that haven't been updated, Setup falls back to the original <tt>GetTempPath</tt> API. (This change adds defense-in-depth; it does not address a known vulnerability.)</li>
   <li>Inno Setup 6.4.3 increased the maximum width of all task dialogs by about 50%, which helps to keep long paths from being truncated with ellipses. It now only does this if the task dialog's content actually contains a path.</li>
   <li>All official translations which still had an UTF-8 BOM had their BOM removed. Using a BOM in UTF-8 encoded files is not needed and not recommended since Inno Setup 6.3.0.</li>
   <li>Inno Setup is now built using Delphi 12.3 Athens instead of Delphi 12.1 Athens. Thanks to Ian Barker from Embarcadero for providing us with a license!</li>