如果 DLL 具有 dontcopy 标志,是否可以在卸载程序中调用 DLL 函数?

Possible to call DLL function in uninstaller if DLL has dontcopy flag?

正如标题所说,我的 DLL 中需要一个函数,我需要在卸载时调用它。

DLL是这样包含的

#define myProgData "C:\ProgramData\Foo\Bar"

[Files]
Source: "mydll.dll"; Flags: dontcopy

我在安装时已经使用了一个功能,现在我想知道我是否可以使用相同的 DLL 进行卸载,或者是否必须复制 DLL 以便卸载程序可以访问它?

我已经尝试了一个简单的呼叫,但收到了

Could not call proc - Exception

所以我在找原因。

更新:

我试过从安装程序中复制 DLL,调用效果很好。

更新二: (抱歉回复晚了)

这是脚本的样子

[Files]
Source: "myDll.dll"; Flags: dontcopy;
(...)

[Code]    
function myUninstallFunction(foo: Integer): Boolean;
external 'myFunction@{#myProgData}myDll.dll stdcall uninstallonly';

是这样用的

function InitializeUninstall(): Boolean;
begin
    if myUninstallFunction(1) then
    begin
        MsgBox(ExpandConstant('{cm:uninstallFail}'), mbError, MB_OK);
        Result := false;     
    end;
    (...)
end;

我也尝试过使用另一个事件过程,例如CurUninstallStepChanged(CurUninstallStep: TUninstallStep);.

您不能从卸载程序调用安装程序中嵌入的 DLL,因为在卸载时,卸载程序不知道安装程序的位置(而且它可能不再存在)。

也可以将 DLL 嵌入到卸载程序中,但这需要更多工作。请参阅我对 How keep uninstall files inside uninstaller?

的回答

除此之外,没有比您已经找到的更好的解决方案了:

  • 在某处安装 DLL
  • 并在卸载代码中引用已安装 DLL 的路径。

解释您遇到的行为的一些背景信息:

external 声明中有 files: 前缀可用,这使得 Inno Setup 在需要该功能时自动提取 DLL 并自动删除提取的 DLL。

Pascal Scripting: Using DLLs:

During Setup, a special 'files:' prefix may also be used to instruct Setup to automatically extract one or more DLLs from the [Files] section before loading the first DLL.

示例:

procedure MyDllFuncSetup(hWnd: Integer; lpText, lpCaption: AnsiString; uType: Cardinal);
external 'MyDllFunc@files:MyDll.dll stdcall setuponly';

但它在卸载程序中不起作用。

你可以看到,即使是官方示例CodeDll.iss也使用files:作为安装程序函数,但求助于使用已安装的DLL({app}\)作为卸载程序函数:

[Files]
...
; Install our DLL to {app} so we can access it at uninstall time
; Use "Flags: dontcopy" if you don't need uninstall time access
Source: "MyDll.dll"; DestDir: "{app}"
[Code]
...
procedure MyDllFuncSetup(hWnd: Integer; lpText, lpCaption: AnsiString; uType: Cardinal);
external 'MyDllFunc@files:MyDll.dll stdcall setuponly';

procedure MyDllFuncUninst(hWnd: Integer; lpText, lpCaption: AnsiString; uType: Cardinal);
external 'MyDllFunc@{app}\MyDll.dll stdcall uninstallonly';

甚至 Inno Setup 源代码也证实了 (Projects\main.pas 函数 CodeRunnerOnDllImport):

if Pos('files:', DllName) = 1 then begin
  if IsUninstaller then begin
    { Uninstall doesn't do 'files:' }
    DllName := '';
    ForceDelayLoad := True;

这解释了 “无法调用 proc - 异常”,因为 Inno Setup 的行为就好像甚至没有指定 DLL 名称一样,但是 delayload 标志是那里。卸载程序找不到 DLL,您会收到神秘的错误消息(通常只有 delayload 标志)。

您还可以检查同时使用 files:uninstallonly 是否可以获得

"uninstallonly" cannot be used with "files:"