有什么方法可以让卸载文件(JPEG、DLL、PNG...)保留在unins000.exe
? 如果有,请出示代码。
2 回答
没有任何方法可以做到这一点。Inno 卸载引擎不能包含嵌入文件。
但另一方面,它也没有特别需要这样做 - 您可以安装它需要的任何文件(如果您想保持整洁,则安装到 app 文件夹的子文件夹中)。
安装文件嵌入到安装程序中的唯一真正原因是它使下载更容易。卸载程序没有这个借口。
Inno Setup 不支持嵌入文件。
但是通过一些创意,您可以将文件嵌入到代码中(以某种常量的形式)。
不幸的是,Unicode Inno Setup 在处理二进制数据时非常有限,因为它倾向于尝试将所有内容都转换为 UTF-8。但是经过多次尝试,我最终得到了一些工作代码(使用从Inno Setup 预处理器调用的 PowerShell 代码)。
将此代码添加到您的部分前面的某处[Code]
:
function CryptStringToBinary(
sz: string; cch: LongWord; flags: LongWord; binary: string; var size: LongWord;
skip: LongWord; flagsused: LongWord): Integer;
external 'CryptStringToBinaryW@crypt32.dll stdcall';
const
CRYPT_STRING_HEX = $04;
procedure WriteBinaryStringToStream(S: string; Stream: TStream);
var
Buffer: string;
Size: LongWord;
begin
SetLength(Buffer, (Length(S) div 4) + 1);
Size := Length(S) div 2;
if (CryptStringToBinary(S, Length(S), CRYPT_STRING_HEX, Buffer, Size, 0, 0) = 0) or
(Size <> Length(S) div 2) then
begin
RaiseException('Error decoding binary string');
end;
Stream.WriteBuffer(Buffer, Size);
end;
function StreamFromBinaryString(S: string): TStream;
begin
Result := TStringStream.Create('');
WriteBinaryStringToStream(S, Result);
Result.Position := 0;
end;
procedure LoadBitmapFromBinaryString(Bitmap: TBitmap; S: string);
var
Stream: TStream;
begin
Stream := StreamFromBinaryString(S);
try
Bitmap.LoadFromStream(Stream);
finally
Stream.Free;
end;
end;
procedure SaveBinaryStringToFile(FileName: string; S: string);
var
Stream: TStream;
begin
Stream := TFileStream.Create(FileName, fmCreate);
try
WriteBinaryStringToStream(S, Stream);
finally
Stream.Free;
end;
end;
#define FileToBinaryString(str FileName) \
Local[4] = ExtractFileName(FileName), \
Local[0] = AddBackslash(GetEnv("TEMP")) + Local[4] + ".pas", \
Local[1] = \
"-ExecutionPolicy Bypass -Command """ + \
"Write-Host 'Generating code for " + Local[4] + "'; " + \
"$bytes = [System.IO.File]::ReadAllBytes('" + FileName + "'); " + \
"$s = '''' + (($bytes | foreach { $_.ToString('X2') }) -join '') + ''''; " + \
"Set-Content -Path '" + Local[0] + "' -Value $s;" + \
"""", \
Exec("powershell.exe", Local[1], SourcePath, , SW_HIDE), \
Local[2] = FileOpen(Local[0]), \
Local[3] = FileRead(Local[2]), \
FileClose(Local[2]), \
DeleteFileNow(Local[0]), \
Local[3]
然后您可以使用FileToBinaryString
预处理器宏在编译时(或更准确地说,在预处理时)将文件转换为十六进制字符串,例如:
'4D5A50000200000004000F00FFFF0000B8000....'
在运行时,您可以将十六进制字符串与某些函数WriteBinaryStringToStream
、StreamFromBinaryString
或.LoadBitmapFromBinaryString
SaveBinaryStringToFile
因此,例如要将位图加载到TBitmapImage
,请使用:
LoadBitmapFromBinaryString(
BitmapImage.Bitmap, {#FileToBinaryString("C:\path\WizModernSmallImage.bmp")});
在编译时,这将转换为如下代码:
LoadBitmapFromBinaryString(
BitmapImage.Bitmap, '4D5A50000200000004000F00FFFF0000B8000....');
要提取 DLL,请使用:
SaveBinaryStringToFile(
ExpandConstant('{tmp}\InnoCallback.dll'), {#FileToBinaryString("InnoCallback.dll")});
要使用在运行时提取的 DLL,您必须使用delayload
标志:
function WrapTimerProc(callback:TTimerProc; paramcount:integer):longword;
external 'wrapcallback@{tmp}\innocallback.dll stdcall delayload';
预处理器/Pascal 编译器对一个字符串有大约 100M 个字符的限制。尽管对于大于约 20-30 MB 的文件,您实际上会首先达到 PowerShell 脚本的 [编译时] 内存限制。尽管即使对于较小的大小(大于几 MB),PowerShell 脚本的编译时性能也很差。该脚本可以显着优化。
由于十六进制编码,安装程序的大小增加了一倍。这可以通过使用一些更有效的编码来改进,比如 Base64 ( CRYPT_STRING_BASE64
)。与该[Files]
部分中包含的文件相比,代码部分甚至没有被压缩(对于图像来说不是问题,因为它们已经被压缩,但例如与 DLL 不同)。
该解决方案最初是为问题Inno Setup: Reading a file from installer during uninstallation开发的。
该代码需要 Inno Setup 的 Unicode 版本。使用最新的 Inno Setup 6,无论如何它都是唯一可用的版本。即使你使用 Inno Setup 5,你也不应该在 21 世纪使用 Ansi 版本。尽管具有讽刺意味的是,在 Ansi 版本中实现这一点要容易得多。有关使用与Inno Setup的 Ansi 和 Unicode 版本兼容的方法,请参阅我对在 Inno Setup 中编写二进制文件的回答。CryptStringToBinary
尽管在 Ansi 版本中,您实际上可以使用二进制字符串而不是十六进制字符串。