【问题标题】:Inno Setup - Recurse sub directories without creating those same sub directoriesInno Setup - 递归子目录而不创建相同的子目录
【发布时间】:2016-08-13 01:30:51
【问题描述】:

我经常使用recursesubdirs 标志来遍历多个子目录并提取特定文件或文件类型,而无需单独显式引用每个文件。示例:

Source: C:\kh25\dependencies\*.dll; DestDir: {app}; Flags: recursesubdirs

这会在我的目标{app} 路径中创建与最初检索 DLL 的源完全相同的目录结构。例如,如果我从上面的 C:\kh25\dependencies\test 检索到一个 DLL,那么它将将该 DLL 放在 {app}\test 路径中。

可以通过以下方式修改此行为:

Source: C:\kh25\dependencies\test\*.dll; DestDir: {app}; Flags: recursesubdirs

但显然这意味着我必须单独引用依赖项中的每个子目录。

所以 64,000 美元的问题是如何防止在目标中重新创建相同的目录,而不必显式引用源目录?

【问题讨论】:

    标签: inno-setup


    【解决方案1】:

    使用Inno Setup preprocessor 生成[Files] 部分的条目。

    一种可能(并且相对较好和简单)的解决方案是使用递归宏,例如:

    #pragma parseroption -p-
    
    #define FileEntry(Source) \
        "Source: " + Source + "; DestDir: {app}\n"
    
    #define ProcessFile(Source, FindResult, FindHandle) \
        FindResult \
            ? \
                Local[0] = FindGetFileName(FindHandle), \
                Local[1] = Source + "\\" + Local[0], \
                (Local[0] != "." && Local[0] != ".." \
                    ? (DirExists(Local[1]) ? \
                        ProcessFolder(Local[1]) : FileEntry(Local[1])) \
                    : "") + \
                ProcessFile(Source, FindNext(FindHandle), FindHandle) \
            : \
                ""
    
    #define ProcessFolder(Source) \
        Local[0] = FindFirst(Source + "\\*", faAnyFile), \
        ProcessFile(Source, Local[0], Local[0])
    
    #pragma parseroption -p+
    
    #emit ProcessFolder("C:\kh25\dependencies")
    

    尽管此解决方案有其局限性,并且可能会使预处理器因大量文件或深层目录结构而崩溃(适用于数千个文件)。

    灵感来自answer by @Zlatko KarakašUse Inno Setup PreProcessor to get the files and size of the source path and its subdirs


    更可靠(但丑陋和复杂)的解决方案是使用用户定义的程序。这很复杂,因为预处理器不支持用户定义过程的参数。

    [Files]
    
    #define FindHandle
    #define FindResult 
    #dim InnerMask[65536]
    #define InnerMask[0] ""
    
    #sub ProcessFoundFile
        #define InnerFileName FindGetFileName(FindHandle)
        #define fileName InnerMask[InnerMaskWorkPosition] + InnerFileName
        #if InnerFileName!="." && InnerFileName!=".."
            #if DirExists(FileName)
                #define Public InnerMask[InnerMaskPosition] FileName+"\"
                #define Public InnerMaskPosition InnerMaskPosition + 1
            #else
                Source: {#FileName}; DestDir: {app}
            #endif
        #endif 
    #endsub
    
    #sub ProcessInnerMaskPosition 
        #for { \
            FindHandle = FindResult = \
                FindFirst(InnerMask[InnerMaskWorkPosition]+"*", faAnyFile); \
            FindResult; FindResult = FindNext(FindHandle)} ProcessFoundFile
        #if FindHandle
            #expr FindClose(FindHandle)
        #endif
    #endsub
    
    #sub CollectFiles
        #define Public InnerMaskPosition 1
        #define Public InnerMaskWorkPosition 0
        #for { \
            InnerMaskWorkPosition = 0; InnerMaskWorkPosition < InnerMaskPosition; \
                InnerMaskWorkPosition++} \
                ProcessInnerMaskPosition
        #undef Public InnerMaskPosition
        #undef Public InnerMaskWorkPosition
    #endsub
    
    #expr InnerMask[0]="C:\kh25\dependencies\"
    #expr CollectFiles
    

    answer by @René MartinUse Inno Setup PreProcessor to get the files and size of the source path and its subdirs的递归扫描函数。


    在您的 Inno Setup 脚本的最后添加一个 SaveToFile 调用,也可以查看预处理器生成的内容:

    #expr SaveToFile(AddBackslash(SourcePath) + "Preprocessed.iss")
    

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


    我对这个问题的回答解释了上述两种方法之间的区别:
    Can Inno Setup Preprocessor be used to build a duplicated set of custom messages?

    【讨论】:

    • 谢谢马丁。比我希望的更多的工作,但我想你不可能赢得他们。
    猜你喜欢
    • 1970-01-01
    • 2016-10-23
    • 2017-05-30
    • 1970-01-01
    • 1970-01-01
    • 2017-03-26
    • 1970-01-01
    • 1970-01-01
    • 2011-10-10
    相关资源
    最近更新 更多