Inno Setup:在卸载过程中从安装程序读取文件 [英] Inno Setup: Reading a file from installer during uninstallation

查看:60
本文介绍了Inno Setup:在卸载过程中从安装程序读取文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在卸载过程中使用以下代码

Using the following code during uninstall

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:\ users \ xyz \ AppData \ Local \ Temp \ is-U3Q8P.tmp \ WizardSmallImageFile.Bmp. 找不到文件.

Exception : can not open file. C:\users\xyz\AppData\Local\Temp\is-U3Q8P.tmp\WizardSmallImageFile.Bmp. File not found.

在调用LoadFromFile之前,我也尝试使用ExtractTemporaryFile,这在卸载期间不受支持.

I tried also to use ExtractTemporaryFile before I call LoadFromFile which is not supported during uninstall.

ExtractTemporaryFile('WizardSmallImageFile.bmp');

那么,问题是,如何在卸载过程中查看图像,或者特别是WizardSmallImageFile?

So, the question, how to view an image or specifically WizardSmallImageFile during uninstall?

推荐答案

正确,ExtractTemporaryFile从安装程序中提取文件.因此,由于该安装程序不再可用,因此无法在卸载程序中使用.

Correct, the ExtractTemporaryFile extracts files from the installer. Therefore it cannot work in the uninstaller as the installer is not available anymore.

还请注意,您不能提取 WizardSmallImageFile指令引用的文件从安装程序.您必须添加自己的副本.

Also note that you cannot extract the file referenced to by the WizardSmallImageFile directive from the installer anyway. You have to add your own copy.

如果在卸载过程中需要使用某些文件,则必须将其安装在安装程序中,然后在卸载程序中使用已安装的副本.

If you need to use some file during uninstallation, you have to install it in the installer and then use the installed copy in the uninstaller.

[Files]
Source: "WizardSmallImageFile.bmp"; DestDir: "{app}";

[Code]

function InitializeUninstall(): Boolean;
begin
  ...
  BitmapImage := TBitmapImage.Create(...);
  ...
  BitmapImage.Bitmap.LoadFromFile(ExpandConstant('{app}\WizardSmallImageFile.bmp'));
  ...
end;


如果不想安装文件就可以将图像数据嵌入代码中.


If you want to do without installing the file, you can embed the image data into the code.

不幸的是,在处理二进制数据时,Unicode Inno设置非常有限,因为它倾向于尝试将所有内容都转换为UTF-8.但是经过无数次尝试,我最终得到了一些有效的代码.

Unfortunately the Unicode Inno Setup is quite limited when dealing with binary data as it tends to try to convert everything to UTF-8. But after numerous tries I've ended up with some working code.

请注意,该代码使用从 Inno Setup预处理器调用的PowerShell代码-编译时需要PowerShell仅限时间,而不是运行时/安装时.

Note that the code uses a PowerShell code invoked from Inno Setup preprocessor - The PowerShell is needed on compile-time only, not on run/install-time.

将此代码添加到[Code]部分前面的某个位置:

Add this code somewhere to the front of your [Code] section:

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 预处理器宏进行转换编译时(或更确切地说,在预处理时)为十六进制字符串的文件,如:

And then you can use the FileToBinaryString preprocessor macro to convert a file on compile-time (or more precisely, when pre-processing) to a hex string like:

'4D5A50000200000004000F00FFFF0000B800000....'

在运行时,将十六进制字符串与某些功能WriteBinaryStringToStreamStreamFromBinaryStringLoadBitmapFromBinaryStringSaveBinaryStringToFile一起使用.

On runtime, you use the hex string with some of the functions WriteBinaryStringToStream, StreamFromBinaryString, LoadBitmapFromBinaryString or SaveBinaryStringToFile.

在您的情况下,您将使用:

In your case you will use:

LoadBitmapFromBinaryString(
  BitmapImage.Bitmap, {#FileToBinaryString("C:\path\WizModernSmallImage.bmp")});

在编译时,它会转换为类似以下代码:

On compile-time, this gets converted to a code like:

LoadBitmapFromBinaryString(
  BitmapImage.Bitmap, '4D5A50000200000004000F00FFFF0000B800000....');


预处理器/Pascal编译器的字符串限制为大约100M个字符.尽管实际上,对于大于约20-30 MB的文件,您实际上会首先达到PowerShell脚本的[编译时]内存限制.尽管即使是较小的大小(大于几个MB),PowerShell脚本的编译时性能也很差.不过,该脚本可以进行显着优化.

由于十六进制编码,安装程序的大小增加了两倍.这可以通过使用一些更有效的编码来改善,例如Base64(CRYPT_STRING_BASE64).与[Files]部分中包含的文件相比,代码部分甚至都没有被压缩(图像已经压缩,这对图像来说不是问题,但是例如与DLL有所不同).

Due to the hex encoding, the size of the installer increases twice as much. This could be improved by using some more efficient encoding, like Base64 (CRYPT_STRING_BASE64). The code section is not even compressed too, comparing to files included with the [Files] section (not a problem for images as these are compressed already, but makes a difference with DLLs for example).

代码需要Inno Setup的Unicode版本.无论如何,在21世纪,您都不应使用Ansi版本.尽管具有讽刺意味的是,在Ansi版本中实施此操作会更容易.请参阅我对在Inno Setup中编写二进制文件的回答,以了解与Ansi和Inno安装程序的Unicode版本.尽管在Ansi版本中,您实际上可以使用二进制字符串而不是十六进制字符串.

The code requires the Unicode version of Inno Setup. You should not use the Ansi version anyway, in the 21st century. Though ironically, implementing this in the Ansi version would be way easier. See my answer to Writing binary file in Inno Setup for a use of the CryptStringToBinary that's compatible with both Ansi and Unicode version of Inno Setup. Though in the Ansi version you can actually do with a binary string, instead of a hex string.

这篇关于Inno Setup:在卸载过程中从安装程序读取文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆