Inno Setup:UnloadDLL在卸载时不起作用

时间:2017-07-13 13:08:44

标签: dll inno-setup uninstall delete-file

我正在研究Inno Setup脚本,在卸载过程中我调用自定义DLL来执行一些Revert操作。不幸的是,在卸载完成后,尽管我调用了UnloadDLL和DeleteFile,但DLL及其依赖项并未被删除。 为什么UnloadDLL会失败? 是否有可能使用LoadLibrary加载DLL动态?我已经看到了一些与此有关的功能,但它们都被弃用了。

以下是代码:

function Revert(param: String): cardinal;
external 'Revert@{app}\Revert.dll cdecl delayload uninstallonly';

procedure RevertAll();
var
    param: String;
    dataDirectory: String;
    temp: String;
    i: Integer;
begin
    dataDirectory := ExpandConstant('{commonappdata}\MyAppData');
    StringChangeEx(dataDirectory, '\', '\\', True);
    param := '{"dataDirectory": "' + dataDirectory + '", "registryPath" : "SOFTWARE\\MyReg\\Key"}';

    Revert(param);

    temp := ExpandConstant('{app}\Revert.dll');
    for i := 0 to 10 do
    begin
        UnloadDLL(temp);
        Sleep(500);

        if DeleteFile(temp) then
            break;
end;

procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
    if (CurUninstallStep = usUninstall) then
    begin
        RevertAll();
    end 
end;

2 个答案:

答案 0 :(得分:1)

不确定什么是真正的问题,但是使用Windows API手动卸载DLL:

function GetModuleHandle(moduleName: String): LongWord;
external 'GetModuleHandleW@kernel32.dll stdcall';

function FreeLibrary(module: LongWord): Integer;
external 'FreeLibrary@kernel32.dll stdcall';

var
  lib: LongWord; 
  res: integer;

repeat
  lib := GetModuleHandle('Revert.dll');
  res := FreeLibrary(lib);
until res = 0;

答案 1 :(得分:1)

鉴于要删除软件时尝试删除DLL导致我迷失了多少根头发,我想贡献一点。 我尝试了几件事,最后做了以下事情:

case CurUninstallStep of
      usUninstall:
        begin
          Exec('powershell.exe', ExpandConstant('-NoExit -ExecutionPolicy Bypass Start-Job -FilePath {%TEMP}\mySoft\CleanUtils.ps1 -ArgumentList {%TEMP}\mySoft\'), '', SW_HIDE, ewNoWait, ErrorCode);
          Exec('powershell.exe', ExpandConstant('-NoExit -ExecutionPolicy Bypass -Command "Start-Job -ScriptBlock {{ Remove-Item -Recurse -Force {%TEMP}\mySoft"'), '', SW_HIDE, ewNoWait, ErrorCode);
        end;
    end;

一些注意事项:

  • 尽管尽我所能,UnloadDLL也不对我有用。 DLL根本不会被InnoSetup删除
  • 第一个Exec调用PowerShell Shell。注意-NoExit。否则,作业将直接退出而不运行。
  • StartJob创建一个分离的后台进程,该进程在卸载程序退出后运行。
  • 第一条指令执行以下PowerShell脚本:
# Input directory
$temp_dir=$args[0]

Get-ChildItem "$temp_dir" -Force -Filter "*.dll" |
  Foreach-Object {
    $file = $_.FullName

    while (Test-Path($file) )
    {
      try
      {
          remove-item -Recurse -Force $file
      }
      catch
      {
          Start-Sleep -seconds 5
      }
    }
  }

该脚本遍历DLL列表,并删除文件夹中的所有DLL。 第二个Exec删除父文件夹。我本可以将该指令放入Powershell脚本中,但是我怀疑我最终会遇到相同的问题,即PowerShell需要该文件,因此永无休止。 关于第二个Exec,另一个区别是通过-Command选项调用作业。否则,我将遇到以下错误:

Start-Job : Cannot bind parameter 'ScriptBlock'. Cannot convert the "-encodedCommand" value of type "System.String" to type "System.Management.Automation.ScriptBlock".
At line:1 char:11
+ Start-Job -ScriptBlock -encodedCommand IABHAGUAdAAtAFAAcgBvAGMAZQBzAH ...
+           ~~~~~~~~~~~~
    + CategoryInfo          : InvalidArgument: (:) [Start-Job], ParameterBindingException
    + FullyQualifiedErrorId : CannotConvertArgumentNoMessage,Microsoft.PowerShell.Commands.StartJobCommand

这远非完美,但这是我尝试一堆不同的东西近一个星期(!)后能想到的最好的结果。

祝所有Inno研究员好运!