Есть ли способ сохранить файлы удаления (JPEG, DLL, PNG ...) внутри unins000.exe
? Если да, то покажите код.
Как сохранить файлы удаления внутри деинсталлятора?
Ответы (2)
Нет никакого способа сделать это. Механизм удаления Inno не может содержать встроенные файлы.
Но, с другой стороны, в этом нет особой необходимости - вы можете просто установить любые файлы, которые ему требуются (в подпапку папки приложения, если вы хотите, чтобы все было в порядке).
Единственная реальная причина, по которой установочные файлы встроены в программу установки, заключается в том, что она упрощает загрузку. У деинсталлятора нет такого оправдания.
Inno Setup не имеет встроенной поддержки для встраивания файлов.
Но проявив некоторую изобретательность, вы можете встроить файлы в код (в виде некоторой константы).
К сожалению, Unicode Inno Setup довольно ограничен при работе с двоичными данными, так как имеет тенденцию пытаться преобразовать все в UTF-8. Но после многочисленных попыток у меня получился рабочий код (с использованием кода PowerShell, вызванного из препроцессора Inno Setup а>).
Добавьте этот код в начало раздела [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
макрос препроцессора для преобразования файла при компиляции- время (точнее, при предварительной обработке) в шестнадцатеричную строку вроде:
'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
a >:
function WrapTimerProc(callback:TTimerProc; paramcount:integer):longword;
external 'wrapcallback@{tmp}\innocallback.dll stdcall delayload';
У компилятора препроцессора / Паскаля ограничение на строку составляет около 100 миллионов символов. Хотя на самом деле вы сначала достигнете предела памяти [времени компиляции] сценария PowerShell для файлов размером более 20-30 МБ. Хотя даже для меньших размеров (больше нескольких МБ) производительность сценария PowerShell во время компиляции оставляет желать лучшего. Однако сценарий можно значительно оптимизировать.
Из-за шестнадцатеричной кодировки размер установщика увеличивается вдвое. Это можно улучшить, используя более эффективную кодировку, например Base64 (CRYPT_STRING_BASE64
). Раздел кода также не сжат, по сравнению с файлами, включенными в раздел [Files]
(это не проблема для изображений, поскольку они уже сжаты, но имеет значение, например, для библиотек DLL).
Это решение изначально было разработано для ответа на вопрос Inno Setup: чтение файла из установщика во время удаления.
Для кода требуется Unicode-версия Inno Setup. В любом случае это единственная доступная версия с последней версией Inno Setup 6. Даже если вы используете Inno Setup 5, вам все равно не следует использовать версию Ansi в 21 веке. Как ни странно, реализовать это в версии Ansi было бы намного проще. См. мой ответ на запись двоичного файла в Inno Setup для использования CryptStringToBinary
, совместимого как с версией Ansi, так и с версией Unicode из Inno Setup. Хотя в версии Ansi вы можете использовать двоичную строку вместо шестнадцатеричной.