Исправить, 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. Но после многочисленных попыток у меня появился какой-то рабочий код.
Обратите внимание, что код использует код PowerShell, вызванный с Inno Setup preprocessor. - PowerShell необходим только во время компиляции, а не во время выполнения/установки.
Добавьте этот код где-то в передней части [Code]
раздела:
function CryptStringToBinary(
sz: string; cch: LongWord; flags: LongWord; binary: string; var size: LongWord;
skip: LongWord; flagsused: LongWord): Integer;
external '[email protected] 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 компилятор предел около 100 М символов для строки.Хотя вы на самом деле сначала нажмете ограничение памяти [compile-time] для сценария PowerShell для файлов размером более 20-30 МБ. Несмотря на то, что даже для меньших размеров (более нескольких МБ) производительность во время компиляции сценария PowerShell плоха. Однако сценарий может быть оптимизирован.
Из-за шестнадцатеричного кодирования размер установщика увеличивается в два раза. Это может быть улучшено за счет использования более эффективного кодирования, такого как Base64 (CRYPT_STRING_BASE64
). Раздел кода даже не сжат, по сравнению с файлами, включенными в раздел [Files]
(не проблема для изображений, поскольку они уже сжаты, но, например, имеет значение с DLL).
Код требует Unicode-версию Inno Setup. Вы не должны использовать версию Ansi в любом случае, в 21 веке. Хотя иронично, реализация этого в версии Ansi будет проще. См. my answer to Writing binary file in Inno Setup для использования CryptStringToBinary
, который совместим с версией Inno Setup Ansi и Unicode. Хотя в версии Ansi вы можете фактически использовать двоичную строку вместо шестнадцатеричной строки.
Почему вы ожидаете, что что-то будет извлечено во время удаления вашей программы? Задача деинсталлятора - * удалить * файлы, а не добавлять новые. Вы продолжаете ссылаться на * InstallTopPanel * в своем коде, но вы не ** устанавливаете **, и поэтому * InstallTopPanel * не существует. –
Я предполагаю, что вы создаете специальную форму для удаления в соответствии с [Inno Setup Uninstall только для некоторых компонентов] (http://stackoverflow.com/q/37507369/850848). Я также предполагаю, что 'InstallTopPanel' является вашим настраиваемым элементом управления (а не стандартным' WizardForm.InstallTopPanel'). Если это правильно, дайте понять в своем вопросе, чтобы дать некоторый контекст читателям. –
Да, это настраиваемая форма, и installtoppanel также является настраиваемой панелью при процедуре удаления. – Maverick