如果 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:"
正如标题所说,我的 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:"