在卸载期间使用以下代码
BitmapImage := TBitmapImage.Create(InstallTopPanel);
BitmapImage.AutoSize := True;
BitmapImage.Bitmap.LoadFromFile(ExpandConstant( '{tmp}\WizardSmallImageFile.bmp') );
BitmapImage.Parent := InstallTopPanel;
BitmapImage.Top := (InstallTopPanel.ClientHeight - 58) / 2;
BitmapImage.Left := InstallTopPanel.ClientWidth - 55 - 10;
我收到错误:
异常:无法打开文件。 C:\用户\某某\应用程序数据\本地的\ Temp \是-U3Q8P.tmp \ WizardSmallImageFile.Bmp。 找不到档案。
我在调用ExtractTemporaryFile
之前尝试使用LoadFromFile
,这在卸载期间不受支持。
ExtractTemporaryFile('WizardSmallImageFile.bmp');
那么,问题是,如何在卸载期间查看图像或具体WizardSmallImageFile
?
答案 0 :(得分:4)
正确,ExtractTemporaryFile
从安装程序中提取文件。因此,它不能在卸载程序中工作,因为安装程序不再可用。
另请注意,无论如何,您无法从安装程序中提取WizardSmallImageFile
directive引用的文件。你必须添加自己的副本。
如果在卸载过程中需要使用某个文件,则必须在安装程序中安装它,然后在卸载程序中使用已安装的副本。
[Files]
Source: "WizardSmallImageFile.bmp"; DestDir: "{app}";
[Code]
function InitializeUninstall(): Boolean;
begin
...
BitmapImage := TBitmapImage.Create(...);
...
BitmapImage.Bitmap.LoadFromFile(ExpandConstant('{app}\WizardSmallImageFile.bmp'));
...
end;
如果您不想安装文件,可以将图像数据嵌入代码中。
不幸的是,在处理二进制数据时,Unicode Inno Setup非常有限,因为它倾向于尝试将所有内容转换为UTF-8。但经过多次尝试,我最终得到了一些有效的代码。
请注意,代码使用从Inno Setup preprocessor调用的PowerShell代码 - 仅在编译时需要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
preprocessor macro在编译时(或者更确切地说,在预处理时)将文件转换为十六进制字符串,如:
'4D5A50000200000004000F00FFFF0000B800000....'
在运行时,您将十六进制字符串与一些函数WriteBinaryStringToStream
,StreamFromBinaryString
,LoadBitmapFromBinaryString
或SaveBinaryStringToFile
一起使用。
在您的情况下,您将使用:
LoadBitmapFromBinaryString(
BitmapImage.Bitmap, {#FileToBinaryString("C:\path\WizModernSmallImage.bmp")});
在编译时,它会转换为如下代码:
LoadBitmapFromBinaryString(
BitmapImage.Bitmap, '4D5A50000200000004000F00FFFF0000B800000....');
预处理器/ Pascal编译器对字符串的限制大约为100M字符。虽然对于大于约20-30 MB的文件,您实际上会首先达到PowerShell脚本的[编译时]内存限制。虽然对于较小的大小(大于几MB),但PowerShell脚本的编译时性能很差。尽管如此,该脚本可以进行优化。
由于十六进制编码,安装程序的大小增加了两倍。这可以通过使用一些更有效的编码来改进,例如Base64(CRYPT_STRING_BASE64
)。与[Files]
部分中包含的文件相比,代码部分甚至没有被压缩(对于图像来说不是问题,因为它们已经被压缩,但是例如对DLL有所不同)。
该代码需要Unicode版本的Inno Setup。在21世纪,你不应该使用Ansi版本。虽然具有讽刺意味的是,在Ansi版本中实现这一点会更容易。有关使用与Anso和Unicode版Inno Setup兼容的CryptStringToBinary
,请参阅my answer to Writing binary file in Inno Setup。虽然在Ansi版本中,您实际上可以使用二进制字符串,而不是十六进制字符串。