sortfilesbyextension Flag behaving strange

125 views
Skip to first unread message

RC World

unread,
Sep 6, 2026, 7:16:44 PMSep 6
to innosetup
Hello All,

I recently started playing around with the `sortfilesbyextension` flag in the [files] section of the Inno Setup configuration script.

What I'm observing is the following:

Besides increasing the installer's compression, which is desirable, I've noticed that the installer freezes for a few minutes when copying files from the setup file to the destination machine if this file is located in the application's root directory.

Is this behavior expected or is something wrong?

Thanks!

Gavin Lambert

unread,
Sep 7, 2026, 9:02:37 PMSep 7
to innosetup
Since you're using `sortfilesbyextension` I presume you're also using `solidcompression`.  The latter can cause slow performance if it needs to access files out of order.  While I would expect that `sortfilesbyextension` itself takes this into account, if you're also accessing files another way (e.g. in [Code]) then this can trigger performance issues.

If you need more specific advice then you may need to make an MCVE that demonstrates the problem.

RC World

unread,
Sep 8, 2026, 12:50:12 PM (13 days ago) Sep 8
to inno...@googlegroups.com
Yes, you are correct. I'm indeed using solidcompression. OK, so if I understand correctly, solid compression saves files sorting by path, so when decompressing it does sequentially. That's why delay is imperceptible. So, when sortfilesbyextension is also used, the installer must parse the whole setup.bin file to extract the file.

Is this correct?
If so, sortfilesbyextension is only useful in small setup apps...

--
You received this message because you are subscribed to a topic in the Google Groups "innosetup" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/innosetup/kQ2sYLPFDDY/unsubscribe.
To unsubscribe from this group and all its topics, send an email to innosetup+...@googlegroups.com.
To view this discussion visit https://groups.google.com/d/msgid/innosetup/d0aff149-189e-4dae-8f0e-57c164d93cf2n%40googlegroups.com.

Martijn Laan - Inno Setup

unread,
Sep 8, 2026, 1:22:03 PM (13 days ago) Sep 8
to inno...@googlegroups.com
Op 8-9-2026 om 18:49 schreef RC World:
so if I understand correctly, solid compression saves files sorting by path, so when decompressing it does sequentially. That's why delay is imperceptible. So, when sortfilesbyextension is also used, the installer must parse the whole setup.bin file to extract the file.

Is this correct?

No, sorry, that isn't correct.

You're likely using ExtractTemporaryFile in an inefficient way, but as Gavin said, you need to post an example that demonstrates the issue.

I also didn't fully understand your initial post. It mentions "this file", but it's not clear to me which file you mean.

Greetings,
Martijn
Message has been deleted

RC World

unread,
Sep 8, 2026, 10:44:01 PM (13 days ago) Sep 8
to innosetup
OK... I've done some testing and the culprit is the line :
   Source: "BGM.mp3"; Flags: dontcopy

Seems to me that whenever I add this line to the script, it takes longer to extract determined files, hanging the setup process for a couple of minutes.

Mr.   Martijn pointed this already, but I dont know how can I circumvent this.

Is there any other syntax to the flag above?


On Tuesday, September 8, 2026 at 6:51:37 PM UTC-3 RC World wrote:
OK, following is a sample of the ISS script:
 
#Define MyAppName "MyApp"
#Define MyAppVersion "v1.0"
#Define MyAppVerName MyAppName + " " + MyAppVersion
#Define MyAppSetup "MyApp"
#Define MyAppEXE "Start.exe"
#Define MyAppId "{0CEDCA6D-38E3-44B0-80C3-07A5DF02EA30}"

[Setup]
AppId={{#MyAppId}
AppName={#MyAppName}
AppVersion={#MyAppVersion}
AppVerName={#MyAppVerName}
DefaultDirName={commonpf}\{#MyAppName}
DefaultGroupName={#MyAppName}
OutputDir=C:\
OutputBaseFilename={#MyAppSetup}_Setup
SetupIconFile=SetupUnInstall.ico
WizardStyle=Classic Dynamic
WizardImageFile=Wizard.png
WizardImageFileDynamicDark=Wizard.png
WizardSmallImageFile=WizardSmall.png
WizardSmallImageFileDynamicDark=WizardSmall.png
UninstallDisplayIcon={app}\SetupUnInstall.ico
Compression=lzma2/ultra64
InternalCompressLevel=ultra64
CompressionThreads=2
LZMAAlgorithm=1
LZMADictionarySize=1048576
LZMAMatchFinder=BT
LZMANumBlockThreads=1
LZMANumFastBytes=273
LZMAUseSeparateProcess=Yes
SolidCompression=Yes
UsedUserAreasWarning=No
ShowLanguageDialog=No
DiskSpanning=Yes
DisableWelcomePage=No
MissingRunOnceIdsWarning=No
RestartIfNeededByRun=No
InfoBeforeFile=ReadMe.rtf

[Files]
Source: "*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs overwritereadonly sortfilesbyextension

[Icons]
Name: "{group}\{#MyAppName}"; Filename: "{app}\{#MyAppEXE}"
Name: "{group}\UnInstall {#MyAppName}"; Filename: "{uninstallexe}"


The [files] section adds all files and subdirs from the application to be installed. They consist in a number of .exe, .doc, wav and a zip file. The zip file resides ath the top of the application root, othes are scattered around the subdirs. The installer is around 9gb spawning some disks...

Gavin Lambert

unread,
Sep 9, 2026, 4:47:53 AM (13 days ago) Sep 9
to innosetup
On Wednesday, September 9, 2026 at 2:44:01 PM UTC+12 RC World wrote:
OK... I've done some testing and the culprit is the line :
   Source: "BGM.mp3"; Flags: dontcopy

Seems to me that whenever I add this line to the script, it takes longer to extract determined files, hanging the setup process for a couple of minutes.

That line didn't appear in your prior post, so it's hard to tell from context.  There are likely other sections that you haven't shared which are contributing to the problem.

There's quite a few settings you have that would do nothing in the script you've provided, which is why I suspect that there's more you've omitted.  Be especially suspicious of any [Code], but there might be other things that could affect it.

It's important to not just provide excerpts of your script; test whether those excerpts actually still demonstrate the issue or not.  If not, add in more of your original script until they do; then you'll at least have a better idea of what change appears to be triggering the issue.

But, my amazing crystal ball says that since you've used the "dontcopy" flag it means that you're using ExtractTemporaryFile on it somewhere in your [Code].  If you do this while using SolidCompression, then you *also* need to either list this as the first [Files] entry or you need to add the "solidbreak" flag to it.

RC World

unread,
Sep 9, 2026, 4:14:45 PM (12 days ago) Sep 9
to innosetup
I'm sorry that I'm being too minimalist trying to explain my problem. Having a hard time figururing out which information is relevant and which are not, trying not to be repetitive and providing useless information.

Below is some more context from my script hoping that will be more helpfull:
[Files]
Source: "bass.dll"; Flags: dontcopy
Source: "BGM.mp3"; Flags: dontcopy
Source: "On.png"; Flags: dontcopy
Source: "Off.png"; Flags: dontcopy

Source: "*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs overwritereadonly sortfilesbyextension

[Code]
const
  BASS_SAMPLE_LOOP = 4;
  BASS_ACTIVE_STOPPED = 0;
  BASS_ACTIVE_PLAYING = 1;
  BASS_ACTIVE_STALLED = 2;
  BASS_ACTIVE_PAUSED = 4;
  BASS_UNICODE = $80000000;
  BASS_CONFIG_GVOL_STREAM = 5;

#ifndef UNICODE
  EncodingFlag = 0;
#else
  EncodingFlag = BASS_UNICODE;
#endif

//-----------------------------------------------------------------------------------------------------------------------------
// Procedure to play music and put sound off/on Button on Wizard
Var
  SoundStream : DWORD;
  SpeakerImage : TBitmapImage;

Function BASS_Init(device: LongInt; freq, flags: DWORD; win: HWND; clsid: Cardinal): BOOL;
  external 'BASS_Init@files:bass.dll stdcall';
Function BASS_StreamCreateFile(mem: BOOL; f: string; offset1: DWORD; offset2: DWORD; length1: DWORD; length2: DWORD; flags: DWORD): DWORD;
  external 'BASS_StreamCreateFile@files:bass.dll stdcall';
Function BASS_Start: BOOL;
  external 'BASS_Start@files:bass.dll stdcall';
Function BASS_Pause: BOOL;
  external 'BASS_Pause@files:bass.dll stdcall';
Function BASS_ChannelPlay(handle: DWORD; restart: BOOL): BOOL;
  external 'BASS_ChannelPlay@files:bass.dll stdcall';
Function BASS_SetConfig(option: DWORD; value: DWORD ): BOOL;
  external 'BASS_SetConfig@files:bass.dll stdcall';
Function BASS_ChannelIsActive(handle: DWORD): DWORD;
  external 'BASS_ChannelIsActive@files:bass.dll stdcall';
Function BASS_Free: BOOL;
  external 'BASS_Free@files:bass.dll stdcall';

Procedure SpeakerImageOnClick(Sender: TObject);
Begin
  Case BASS_ChannelIsActive(SoundStream) Of
    BASS_ACTIVE_PLAYING: If BASS_Pause Then SpeakerImage.PngImage.LoadFromFile(ExpandConstant('{tmp}\off.png'));
    BASS_ACTIVE_PAUSED: If BASS_Start Then SpeakerImage.PngImage.LoadFromFile(ExpandConstant('{tmp}\on.png'));
  End;
End;

//-----------------------------------------------------------------------------------------------------------------------------
// Procedure to initialize and draw main WizardForm
Procedure InitializeWizard;
Begin
// Extract the PNG file to a temporary location
// ExtractTemporaryFile(ExtractFileName(ExpandConstant('{tmp}\on.png')));
// ExtractTemporaryFile(ExtractFileName(ExpandConstant('{tmp}\off.png')));
ExtractTemporaryFile('BGM.mp3');
ExtractTemporaryFile('On.png');
ExtractTemporaryFile('Off.png');
  If BASS_Init(-1, 44100, 0, 0, 0) Then
  Begin
    SoundStream := BASS_StreamCreateFile(False, ExpandConstant('{tmp}\BGM.mp3'), 0, 0, 0, 0, EncodingFlag or BASS_SAMPLE_LOOP);
    BASS_SetConfig(BASS_CONFIG_GVOL_STREAM, 2500);
    BASS_ChannelPlay(SoundStream, False);
    // Create the TBitmapImage object
    SpeakerImage := TBitmapImage.Create(WizardForm);
    // Load the PNG file
    SpeakerImage.PngImage.LoadFromFile(ExpandConstant('{tmp}\on.png'));
    // Configure and display the image
    SpeakerImage.Cursor := crHand;
    SpeakerImage.OnClick := @SpeakerImageOnClick;
    SpeakerImage.Parent := WizardForm;
    SpeakerImage.Left := 10;
    SpeakerImage.Width := 36;
    SpeakerImage.Height := 36;
    SpeakerImage.Top := WizardForm.ClientHeight - SpeakerImage.Bitmap.Height - 4;
  End;
End;

//-----------------------------------------------------------------------------------------------------------------------------
// Procedure to cleanup Inno setup and release BASS.DLL from memory
Procedure DeinitializeSetup;
Begin
  BASS_Free;
End;

I hope this makes sense...

Thanks again for you patience

Gavin Lambert

unread,
Sep 9, 2026, 9:14:46 PM (12 days ago) Sep 9
to innosetup
On Thursday, September 10, 2026 at 8:14:45 AM UTC+12 RC World wrote:
I'm sorry that I'm being too minimalist trying to explain my problem. Having a hard time figururing out which information is relevant and which are not, trying not to be repetitive and providing useless information.

Below is some more context from my script hoping that will be more helpfull:
[Files]
Source: "bass.dll"; Flags: dontcopy
Source: "BGM.mp3"; Flags: dontcopy
Source: "On.png"; Flags: dontcopy
Source: "Off.png"; Flags: dontcopy

Source: "*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs overwritereadonly sortfilesbyextension

So, the first thing that I would recommend is to put your background music files (all four) into a completely different source location from the rest of your source files -- you're likely getting some weirdness currently from the files having two entries -- one explicit and one as part of the wildcard.  This will work, but also means that these files will get copied to {app} too, which may not be intended.  Since you haven't specified SourceDir it also means that you're installing the Inno script source itself, which definitely seems unintended.

My suggestion is to do something like:

[Files]
Source: Music\bass.dll; ...
...
Source: App\*; DestDir: {app}; ...

And move your source files accordingly.

If you do actually want to install the music files to {app} as well, then still keep them in the separate folder but remove "dontcopy" and add DestDir: {app}.

Secondly, when it comes time to install the first file to {app} it has to seek past those first four files first, which may take a while if they're large.  As previously noted, you should add the "solidbreak" flag somewhere; probably the best place would be to create a new empty dummy text file and add:

; put this just above the App\* wildcard entry
Source: dummy.txt; Flags: dontcopy solidbreak

RC World

unread,
Sep 10, 2026, 10:54:40 AM (11 days ago) Sep 10
to innosetup
OK, I did what you suggested and the installer ran perfectly.

I went a little further and replaced flags:dontcopy with DestDir:{app}, leaving the rest of the script original, and the result was the same, it ran perfectly.
I don't know if this approach will be a problem in a long run, tho.

I believe that flags:dontcopy and  sortfilesbyextension don't go very well together.

Anyway, thank you for your time and interest in helping me.

I really appreciate it...

Martijn Laan - Inno Setup

unread,
Sep 10, 2026, 12:43:48 PM (11 days ago) Sep 10
to innosetup
Hi,

Op 10-9-2026 om 16:54 schreef RC World:

I went a little further and replaced flags:dontcopy with DestDir:{app}, leaving the rest of the script original, and the result was the same, it ran perfectly.
I don't know if this approach will be a problem in a long run, tho.

I believe that flags:dontcopy and  sortfilesbyextension don't go very well together.

Those flags actually work fine together. What DestDir: {app} does in your case is cancel out the second extraction that Gavin mentioned, since the file is already there and will therefore be extracted one time only, instead of a second time out of order like before your change.

When using solid compression, you should always avoid extracting files out of order, or use solidbreak instead, as Gavin advised.

Greetings,
Martijn

RC World

unread,
Sep 10, 2026, 2:43:30 PM (11 days ago) Sep 10
to innosetup
Hello,

It is clear now. Will keep this in mind to avoid running into trouble next time.

Thanks to all!!!

Gavin Lambert

unread,
Sep 10, 2026, 8:44:52 PM (11 days ago) Sep 10
to innosetup
On Friday, September 11, 2026 at 4:43:48 AM UTC+12 Martijn Laan - Inno Setup wrote:
What DestDir: {app} does in your case is cancel out the second extraction that Gavin mentioned, since the file is already there and will therefore be extracted one time only, instead of a second time out of order like before your change.

When using solid compression, you should always avoid extracting files out of order, or use solidbreak instead, as Gavin advised.

I think technically what was going wrong in the original script was this:

1. There were two entries for the music files, one explicitly written and one as part of the wildcard entry.  (This would result in the file being installed twice *except that* the first was marked as dontcopy.)
2. Since there are two entries with the same Source path, Inno stores the compressed data for that file only once, to avoid making the installer larger with redundant data.  Since the explicit entry was first, the data was stored first (and not sorted by extension), and the second entry just points back to the first entry's data.
3. The ExtractTemporaryFile calls found the data near the start and it executed quickly.
4. During the actual install, it hit the first entry for the file and skipped it because it was dontcopy, then started extracting and installing all the other files.  When encountering the second entry for the music files, it had to go seek back to the start of the compressed data because it was stored over there instead, then afterwards it had to seek back to where it left off (which would require re-decompressing all the other files, hence very slow).  And since there are three different extensions in the music files, this occurs in multiple places.

#4 is a bit of speculation, but it would make sense if it worked this way.  Perhaps Inno should implicitly add solidbreak on an entry following a deduplicated-data entry, as a quick workaround?

Gavin Lambert

unread,
Sep 10, 2026, 8:50:27 PM (11 days ago) Sep 10
to innosetup
Mere moments ago, quoth I:
Perhaps Inno should implicitly add solidbreak on an entry following a deduplicated-data entry, as a quick workaround?

Or another option might be to keep the previous decompression stream around when having to seek elsewhere so that it can resume where it left off instead of regenerating it. 
Reply all
Reply to author
Forward
0 new messages