我正在研究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;
答案 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
创建一个分离的后台进程,该进程在卸载程序退出后运行。# 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研究员好运!