0

In my Inno Setup code, I need some dlls during the setup install only.

These dlls are extracted in the user temporary folder {tmp} by the external declarations (using the files: keyword).

As these DLL files are loaded when the setup terminates. The removing of the temporary folder fails at the end of the setup and the log file contains the following error message:

Failed to remove temporary directory: C:\Users\<UserName>\AppData\Local\Temp\is-XXXX.tmp

So I tried to unload and delete these dlls with UnloadDll() at the end of the setup. (From the DeinitializeSetup() procedure)

Unfortunately the dll file deletion fails, so I think the UnloadDll() calls didn't work for a mysterious reason. I get the following log:

2018-03-23 10:42:50.583   Deinitializing Setup.
2018-03-23 10:42:50.584   Unable to delete C:\Users\<UserName>\AppData\Local\Temp\is-XXXX.tmp\SetupUtilities.dll
2018-03-23 10:42:52.619   Failed to remove temporary directory: C:\Users\<UserName>\AppData\Local\Temp\is-XXXX.tmp
2018-03-23 10:42:52.624   Log closed.

What am I doing wrong ?

[Files]
Source: "Libraries\unzipper.dll"; Flags: dontcopy;
Source: "Utilities\bin\Release\SetupUtilities.dll"; Flags: dontcopy;
Source: "Components\DirectX_Redist_SciChart_19Feb15.zip"; DestDir: {tmp}; Flags: ignoreversion; AfterInstall: InstallDirectX

[code]
procedure unzip(src, target: AnsiString);
    external 'unzip@files:unzipper.dll stdcall delayload';  

function IsDirectX10Installed_(): boolean;
    external 'IsDirectX10Installed@files:SetupUtilities.dll stdcall delayload';

function HasDirectX10CapableGpu_(): boolean;
    external 'HasDirectX10CapableGpu@files:SetupUtilities.dll stdcall delayload';

function IsDirectXDependenciesInstalled_(): boolean;
    external 'CheckDirectXDependencies@files:SetupUtilities.dll stdcall delayload';

function IsDirectXDependenciesInstalled(): Boolean;
begin
Result :=False;
  Result:= IsDirectXDependenciesInstalled_();
end;

function HasDirectX10CapableGpu(): Boolean;
begin
Result :=False;
  Result:= HasDirectX10CapableGpu_();
end;  

procedure InstallDirectX();
var
  ResultCodeDirectXInstallation: Integer;
begin
  if not HasDirectX10CapableGpu then
  begin
    MsgBox('Your GPU is not compatible with the DirectX10 runtime.3D statistics will not be avalaible.', mbError, MB_OK);
  end else
  begin
    if IsDirectXDependenciesInstalled then
    begin
      Log('DirectX is already installed');
    end else
    begin
      unzip(ExpandConstant('{tmp}\DirectX_Redist_SciChart_19Feb15.zip'), ExpandConstant('{tmp}'));
      ResultCodeDirectXInstallation := RunInstallation('Installing DirectX ...', '{tmp}\DXSETUP.exe', '/silent', False);
      if not ResultCodeDirectXInstallation = 0 then
      begin
        MsgBox('An error occured during the DirectX installation.', mbError, MB_OK);
      end;
    end;
  end;
end;

// Called when setup is terminated.
procedure DeinitializeSetup();
var UnzipperDllFileName, SetupUtilitiesDllFileName: string;
begin
  UnzipperDllFileName := ExpandConstant('{tmp}\unzipper.dll')
  SetupUtilitiesDllFileName := ExpandConstant('{tmp}\SetupUtilities.dll')

  // Unload the DLLs
  UnloadDLL(UnzipperDllFileName);
  UnloadDLL(SetupUtilitiesDllFileName);

  // Now we can delete the DLLs
  if not DeleteFile(UnzipperDllFileName) then
  begin
    Log('Unable to delete ' + UnzipperDllFileName);
  end;
  if not DeleteFile(SetupUtilitiesDllFileName) then
  begin
    Log('Unable to delete ' + SetupUtilitiesDllFileName);
  end;
end;
Andrew Truckle
  • 17,769
  • 16
  • 66
  • 164
Bug Raptor
  • 261
  • 6
  • 15
  • 1
    Is that .NET DLL? + Do you get the problem both with `unzipper.dll` and `SetupUtilities.dll`, or with one of them only? + We need [mcve]. I'm pretty sure you have posted more code than needed to reproduce the problem. – Martin Prikryl Mar 23 '18 at 10:45
  • Yes, it's a proprietary .NET DLL calling basic Windows functions to check if DirectX is already installed. I thought the problem was the same with unzipper.dll and SetupUtilities.dll But I just checked and I was wrong ! Actually, since Directx was already installed on my machine, the unzipper.dll was not loaded by the given code, so only SetupUtilities.dll remains in the temporary folder. But I just tried to use the unzip() function and, the unzipper.dll (which is not a .Net dll) is correctly unloaded and deleted at the end of the install. So that's probably the point ! – Bug Raptor Mar 23 '18 at 12:01
  • I understand this issue was already asked here: https://stackoverflow.com/questions/28388095/unload-a-net-dll-from-an-unmanaged-process A solution is proposed by launching a separate process (.bat) to delete the dll from another process... I think that's a bit tricky... No other solution ? – Bug Raptor Mar 23 '18 at 12:11
  • No other solution. My [comprehensive answer to the duplicate question](https://stackoverflow.com/q/28388095/850848#41531880) is only a year old. No new technique has emerged meanwhile. Obviously, you can implement a plain (non-.NET) DLL instead. – Martin Prikryl Mar 23 '18 at 12:33
  • Regarding more accurately your solution I find it actually elegant and functionning perfectly. I implemented it in my application. Thank you for your help ! – Bug Raptor Mar 23 '18 at 12:55
  • 1
    Obviously ! Just done. – Bug Raptor Mar 23 '18 at 12:57

0 Answers0