I have thousand of own installers that requires a critical dll file for uninstallation step, this dll file sizes about 2 mb then to avoid unnecessary disk space (2mb*100 installers) I would like to store the file once in {cf}
then make a hardlink for the next installers that requires that file.
I could create a hardlink in Inno Setup without the need of external apps such as mklink.exe usage?
This is a brief example of what I have, all my installers follow the same "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
As you could see, I'm moving the uninstall.dll to {app}
, but what I would like to do is: If doesn't exists, copy the uninstall.dll file to {cf}\InnoSetup\uninstall.dll
filepath and make a hardlink to {app}\uninstall.dll
, if already exists the file then just make the hardlink, nothing more, I won't still store the uninstall.dll file in {app}\uninstall.dll
, just I want a symbolic reference because the uninstall.dll file should never be uninstalled.
How I could do it?
Inno Setup does not support creating hardlinks natively.
I wouldn't consider the mklink
an external application. It's a built-in Windows tool. So if you do not need to support Windows XP, you can safely rely on it. Or you can fallback to installing the DLL regularly, if the mklink
is not available.
Or use the CreateHardLink
function from the Code
section.
#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;
(Tested on Unicode version of Inno Setup)
And do not forget to delete the file when uninstalling
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;
You can of course use also the [UninstallDelete]
entry. I just like to uninstall the file using the same technology used to install it.
Your question title is "Create a hardlink with Inno Setup".
The CreateHardLink
creates a hardlink. A hardlink is another reference to the same contents. Basically the hardlink is indistinguishable from the original file (even the original file is a hardlink actually). Both original file and the hardlink are just references to the same contents. If you delete the original file (or the new hardlink), you actually remove just one reference to the contents. The contents is still preserved. The contents is removed with the last reference only. The hardlink does not occupy an additional space on the disk (the contents is stored only once).
For details see Hard link article on Wikipedia.
While the mklink
creates a symlink (aka symbolic link) by default. A symlink is like a shortcut, it's a reference to the the original file (not contents). It's a file on its own, that contains a path to the target file. The symlink has a size of its own (occupied by the reference to the target file). If you remove the original file, the symlink still exists (because there's no reference to the symlink from the original file), but becomes invalid (the contents is gone). Again, it's similar to a shortcut.
For details see Symbolic link article on Wikipedia.
You can create a hardlink with the mklink
, if you add the /H
switch:
/H Creates a hard link instead of a symbolic link.
If you want to create the symlink instead of the hardlink, it's a different question (though the answer is simple, use the CreateSymbolicLink
function). Though again, note that the hardlink does not occupy additional space on the disk, what seems to be your concern. So I believe you should keep using the CreateHardLink
function.