Как сохранить файлы удаления внутри деинсталлятора?

Есть ли способ сохранить файлы удаления (JPEG, DLL, PNG ...) внутри unins000.exe? Если да, то покажите код.


person Andrezork    schedule 13.02.2013    source источник
comment
Это лучше подходит для SuperUser?   -  person Piccolo    schedule 13.02.2013
comment
@boj Нет, это вопрос развития.   -  person Deanna    schedule 13.02.2013


Ответы (2)


Нет никакого способа сделать это. Механизм удаления Inno не может содержать встроенные файлы.

Но, с другой стороны, в этом нет особой необходимости - вы можете просто установить любые файлы, которые ему требуются (в подпапку папки приложения, если вы хотите, чтобы все было в порядке).

Единственная реальная причина, по которой установочные файлы встроены в программу установки, заключается в том, что она упрощает загрузку. У деинсталлятора нет такого оправдания.

person Miral    schedule 13.02.2013
comment
Привет, Мирал, спасибо за помощь. - person Andrezork; 13.02.2013
comment
На самом деле, проявив немного творчества, можно найти выход. См. мой ответ. - person Martin Prikryl; 12.07.2016
comment
@MartinPrikryl Верно, но попытки сделать это обычно перевешивают пользу. Проще просто установить файлы. Тем не менее, баллы за творчество. :) - person Miral; 13.07.2016

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 :

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 вы можете использовать двоичную строку вместо шестнадцатеричной.

person Martin Prikryl    schedule 12.07.2016