Generating Inno Setup file flags programmatically

2019-01-20 05:00发布

问题:

Is it possible in Inno Setup to generate the file flags programmatically? My installer source contains a large number of files within a sizeable directory structure. Currently I've minimized the complexity of the script by adding entire folders at a time. This works fine, however, there are numerous files sprinkled throughout the hierarchy that aren't benefiting from compression (e.g. *.jpg) and are significantly increasing the installer build time. Ideally, I'd like to do something like:

Source: "{#MySrc}\*"; DestDir: "{#MyDst}"; Flags: {code:GetFlags};

Where GetFlags would check the extension of the current file and return "nocompression" for file types that I don't want to compress. Is that possible? I can't seem to find anything in the docs or online that would indicate that it is. If not, is there any other straight forward way to achieve this?

The only other way I can think of to do this is to create an additional file line for each type, like this

Source: "{#MySrc}\*"; DestDir: "{#MyDst}"; Excludes: "*.jpg,*.dds"; Flags: "ignoreversion recursesubdirs";
Source: "{#MySrc}\*.jpg"; DestDir: "{#MyDst}"; Flags: "ignoreversion recursesubdirs nocompression";
Source: "{#MySrc}\*.dds"; DestDir: "{#MyDst}"; Flags: "ignoreversion recursesubdirs nocompression";

While this is doable, I'd need to make this change in several places each time I came across a file type that I decided not to compress. So I'd rather keep the logic in a single place, if possible.

回答1:

Your solution is not bad. We might help you with finding a solution that does not require "change in several places each time", if you give us details.


Anyway, it's possible to generate the [Files] section using preprocessor. This way you can alter the Flags per file type. But the code is complex too. And due to limits of the preprocessor, it won't work with really large directory structures (I've managed to make it working with up to 3500 files).

#pragma parseroption -p-

#define FileFlags(FileName) \
    Local[0] = Lowercase(ExtractFileExt(FileName)), \
    (Local[0] == "jpg" || Local[0] == "dds" ? "nocompression" : "")

#define FileEntry(Source, DestDir) \
    "Source: \"" + Source + "\"; DestDir: \"" + DestDir + "\"; " + \
    "Flags: " + FileFlags(Source) + "\n"

#define ProcessFile(Source, DestDir, FindResult, FindHandle) \
    FindResult \
        ? \
            Local[0] = FindGetFileName(FindHandle), \
            Local[1] = Source + "\\" + Local[0], \
            (Local[0] != "." && Local[0] != ".." \
                ? (DirExists(Local[1]) \
                      ? ProcessFolder(Local[1], DestDir + "\\" + Local[0]) \
                      : FileEntry(Local[1], DestDir)) \
                : "") + \
            ProcessFile(Source, DestDir, FindNext(FindHandle), FindHandle) \
        : \
            ""

#define ProcessFolder(Source, DestDir) \
    Local[0] = FindFirst(Source + "\\*", faAnyFile), \
    ProcessFile(Source, DestDir, Local[0], Local[0])

#pragma parseroption -p+

Modify the FileFlags macro as you need. And use the ProcessFolder macro like:

[Files]

#emit ProcessFolder(MySrc, MyDst)

It will generate a code like:

Source: "C:\source\file.txt"; DestDir: "{app}"; Flags: 
Source: "C:\source\subfolder\file.jpg"; DestDir: "{app}\subfolder"; Flags: nocompression
Source: "C:\source\subfolder\another.txt"; DestDir: "{app}\subfolder"; Flags: 

(with MySrc = C:\source and MyDst = {app})

See Inno Setup: How do I see the output (translation) of the Inno Setup Preprocessor?


Inspired by the answer by @Zlatko Karakaš to Use Inno Setup PreProcessor to get the files and size of the source path and its subdirs.



标签: inno-setup