使用Inno Setup从注册表读取多路径实现文件复制的问题
解决Inno Setup中AutoCAD多版本多路径的文件复制问题
我在Inno Setup的[Files]区段中尝试将字体文件复制到AutoCAD各版本的对应目录,但每个AutoCAD版本(如R21.0)在注册表中对应多个子项路径,当前的GetDir函数仅返回其中一个路径,导致文件只复制到一个目录,无法覆盖所有实例。
原[Files]代码:
[Files] Source: "Fonts\*"; DestDir: {code:GetDir|R21.0}; Source: "Fonts\*"; DestDir: {code:GetDir|R22.0}; Source: "Fonts\*"; DestDir: {code:GetDir|R23.1}; Source: "Fonts\*"; DestDir: {code:GetDir|R24.0}; Source: "Fonts\*"; DestDir: {code:GetDir|R24.1};
原GetDir函数:
function GetDir(AcadVerNames: string): String; var AcadRegKey, sAcadLoc: String; begin RootKeyU := HKEY_CURRENT_USER_64; if RegGetSubkeyNames(RootKey, 'SOFTWARE\Autodesk\AutoCAD' + '\' + AcadVerNames, AcadVerKeysTemp) then begin for I := 0 to GetArrayLength(AcadVerKeysTemp)-1 do begin RegQueryStringValue(RootKeyU, 'SOFTWARE\Autodesk\AutoCAD' + '\' + AcadVerNames + '\' + AcadVerKeysTemp[I] , 'RootFolder', sAcadLoc); end; end; Result := sAcadLoc + '\Fonts'; end;
问题根源
Inno Setup的[Files]区段中,{code:...}回调仅能返回单个字符串路径,因此即使函数遍历了多个注册表子项,最终只会返回最后一次循环得到的路径,无法实现多路径复制。
解决方案:手动遍历路径并复制文件
通过在安装阶段手动收集所有AutoCAD版本的Fonts路径,然后逐个复制文件,实现多路径覆盖。
步骤1:定义全局变量
在脚本的[Code]区段顶部定义全局数组,用于存储所有找到的Fonts路径:
var AcadFontPaths: TArrayOfString; I: Integer;
步骤2:编写路径收集函数
创建函数遍历注册表子项,收集所有对应版本的Fonts路径:
procedure CollectAcadFontPaths(AcadVerNames: string); var AcadVerKeysTemp: TArrayOfString; sAcadLoc: String; begin RootKeyU := HKEY_CURRENT_USER_64; // 查询当前AutoCAD版本下的所有子项 if RegGetSubkeyNames(RootKey, 'SOFTWARE\Autodesk\AutoCAD\' + AcadVerNames, AcadVerKeysTemp) then begin for I := 0 to GetArrayLength(AcadVerKeysTemp)-1 do begin // 尝试读取RootFolder值,成功则添加到路径数组 if RegQueryStringValue(RootKeyU, 'SOFTWARE\Autodesk\AutoCAD\' + AcadVerNames + '\' + AcadVerKeysTemp[I], 'RootFolder', sAcadLoc) then begin SetArrayLength(AcadFontPaths, GetArrayLength(AcadFontPaths) + 1); AcadFontPaths[GetArrayLength(AcadFontPaths)-1] := sAcadLoc + '\Fonts'; end; end; end; end;
步骤3:在安装阶段执行复制
利用CurStepChanged事件,在安装步骤中收集所有路径并复制文件:
procedure CurStepChanged(CurStep: TSetupStep); var FontSourcePath, DestPath, FilePath: String; FindRec: TFindRec; begin if CurStep = ssInstall then begin // 初始化路径数组 SetArrayLength(AcadFontPaths, 0); // 收集所有需要处理的AutoCAD版本路径 CollectAcadFontPaths('R21.0'); CollectAcadFontPaths('R22.0'); CollectAcadFontPaths('R23.1'); CollectAcadFontPaths('R24.0'); CollectAcadFontPaths('R24.1'); // 获取源字体文件路径 FontSourcePath := ExpandConstant('{src}\Fonts'); // 遍历源目录下的所有文件 if FindFirst(FontSourcePath + '\*', FindRec) then begin repeat // 跳过目录,只处理文件 if (FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY) = 0 then begin FilePath := FontSourcePath + '\' + FindRec.Name; // 复制到每个目标Fonts目录 for I := 0 to GetArrayLength(AcadFontPaths)-1 do begin DestPath := AcadFontPaths[I]; // 确保目标目录存在 if not DirExists(DestPath) then CreateDir(DestPath); // 复制文件(False表示覆盖已存在的文件) FileCopy(FilePath, DestPath + '\' + FindRec.Name, False); end; end; until not FindNext(FindRec); FindClose(FindRec); end; end; end;
步骤4:移除原[Files]区段
因为已经通过代码手动处理文件复制,原[Files]中的相关条目可以删除,避免重复复制。
额外说明
- 如果需要复制Fonts目录下的子目录及其中的文件,需要修改遍历逻辑,添加递归处理目录的代码。
- 可以根据需求添加错误处理,比如复制失败时记录日志或提示用户。
- 注册表根键可以根据系统位数调整(如
HKEY_LOCAL_MACHINE或HKEY_CURRENT_USER_32),确保能正确读取到AutoCAD的安装路径。
内容的提问来源于stack exchange,提问作者bahman jafari
相关产品推荐
相关产品推荐

