使用 Inno Setup 创建硬链接

Create a hardlink with Inno Setup

我有上千个自己的安装程序,需要一个关键的 dll 文件来进行卸载步骤,这个 dll 文件大小约为 2 mb,然后为了避免不必要的磁盘 space(2mb*100 个安装程序)我想存储在 {cf} 中创建一个文件,然后为下一个需要该文件的安装程序创建一个硬链接。

我可以在 Inno Setup 中创建硬链接,而不需要外部应用程序,例如 mklink.exe usage?

这是我所拥有的一个简短示例,我所有的安装程序都遵循相同的 "structure":

[Files]
; VCL Styles
Source: {tmp}\uninstall.vsf; DestDir: {app}; Flags: ignoreversion
Source: {tmp}\uninstall.dll; DestDir: {app}; Flags: ignoreversion uninsneveruninstall

; Temp files
Source: {tmp}\*; DestDir: {tmp}; Excludes: uninstall.dll, uninstall.vsf; Flags: recursesubdirs createallsubdirs ignoreversion

; Program
Source: {app}\*; DestDir: {app}; Flags: recursesubdirs createallsubdirs ignoreversion

如您所见,我正在将 uninstall.dll 移动到 {app},但我想做的是:如果没有存在,将 uninstall.dll 文件复制到 {cf}\InnoSetup\uninstall.dll 文件路径,并建立到 {app}\uninstall.dll 的硬链接,如果该文件已经存在,则只建立硬链接,没有此外,我不会仍然将 uninstall.dll 文件存储在 {app}\uninstall.dll 中,只是我想要一个符号引用,因为 uninstall.dll 永远不应卸载文件。

我该怎么做?

Inno Setup 不支持本地创建硬盘link。


我不会将 mklink 视为外部应用程序。这是一个 built-in Windows 工具。所以如果你不需要支持 Windows XP,你可以放心地依赖它。或者,如果 mklink 不可用,您可以回退到定期安装 DLL。


或使用 Code 部分中的 CreateHardLink function

#define MyApp "MyApp"
#define UninstallDll "uninstall.dll"

[Files]
Source: "{#UninstallDll}"; DestDir: "{cf}\{#MyApp}"; \
  Flags: ignoreversion uninsneveruninstall

[Code]
function CreateHardLink(lpFileName, lpExistingFileName: string;
  lpSecurityAttributes: Integer): Boolean;
  external 'CreateHardLinkW@kernel32.dll stdcall';

procedure CurStepChanged(CurStep: TSetupStep);
var
  ExistingFile, NewFile: string;
begin
  if CurStep = ssPostInstall then
  begin
    ExistingFile := ExpandConstant('{cf}\{#MyApp}\{#UninstallDll}');
    NewFile := ExpandConstant('{app}\{#UninstallDll}');
    if CreateHardLink(NewFile, ExistingFile, 0) then
    begin
      Log('Hardlink created');
    end
      else
    if FileCopy(ExistingFile, NewFile, False) then
    begin
      { FAT file system? }
      Log('Hardlink could not be created, file copied instead');
    end
      else
    begin
      MsgBox('Cannot install {#UninstallDll}', mbError, MB_OK);
    end;
  end;
end;

(在 Unicode version of Inno Setup 上测试 – Inno Setup 6 的唯一版本)

卸载时不要忘记删除文件:

procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
  if CurUninstallStep = usUninstall then
  begin
    if DeleteFile(ExpandConstant('{app}\{#UninstallDll}')) then
    begin
      Log('File deleted');
    end
      else
    begin
      Log('Cannot delete file');
    end;
  end;
end;

您当然也可以使用 [UninstallDelete] 条目。我只是喜欢使用与安装它相同的技术来卸载该文件。


您的问题标题是"Create a hardlink with Inno Setup".

CreateHardLink创造了一个困难link。 hardlink 是对相同内容的另一个引用。基本上 hardlink 与原始文件没有区别(即使原始文件实际上是 hardlink)。原始文件和 hardlink 都只是对相同内容的引用。如果您删除原始文件(或新的 hardlink),您实际上只删除了对内容的一个引用。内容仍保留。删除的内容仅包含最后一个参考。硬盘link额外占用磁盘space(内容只存储一次)

有关详细信息,请参阅 Hard link article on Wikipedia

虽然 mklink 默认创建一个 symlink(又名符号 link)。 symlink 就像一个快捷方式,它是对原始文件(不是内容)的引用。它本身就是一个文件,其中包含目标文件的路径。 symlink 有自己的大小(被目标文件的引用占用)。如果删除原始文件,symlink 仍然存在(因为原始文件中没有对 symlink 的引用),但变得无效(内容消失了)。同样,它类似于快捷方式。

有关详细信息,请参阅 Symbolic link article on Wikipedia

如果添加 /H 开关,您可以使用 mklink 创建硬 link:

/H Creates a hard link instead of a symbolic link.

如果你想创建 symlink 而不是 hardlink,这是一个不同的问题(尽管答案很简单,使用 CreateSymbolicLink function)。不过,请再次注意,硬盘link 不会在磁盘 上占用额外的space,这似乎是您关心的问题。所以我相信你应该继续使用 CreateHardLink 函数。