2016-05-31 5 views
2

Используя следующий код во время удаленияSetup Inno: Чтение файла с установщиком во время удаления

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; 

Я получаю сообщение об ошибке:

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

Я попробовал также использовать ExtractTemporaryFile, прежде чем я называю LoadFromFile который не поддерживается при удалении.

ExtractTemporaryFile('WizardSmallImageFile.bmp'); 

Таким образом, вопрос о том, как просматривать изображения или конкретно WizardSmallImageFile во время удаления?

+0

Почему вы ожидаете, что что-то будет извлечено во время удаления вашей программы? Задача деинсталлятора - * удалить * файлы, а не добавлять новые. Вы продолжаете ссылаться на * InstallTopPanel * в своем коде, но вы не ** устанавливаете **, и поэтому * InstallTopPanel * не существует. –

+0

Я предполагаю, что вы создаете специальную форму для удаления в соответствии с [Inno Setup Uninstall только для некоторых компонентов] (http://stackoverflow.com/q/37507369/850848). Я также предполагаю, что 'InstallTopPanel' является вашим настраиваемым элементом управления (а не стандартным' WizardForm.InstallTopPanel'). Если это правильно, дайте понять в своем вопросе, чтобы дать некоторый контекст читателям. –

+0

Да, это настраиваемая форма, и installtoppanel также является настраиваемой панелью при процедуре удаления. – Maverick

ответ

3

Исправить, 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] 

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

+0

Это правильно, и я также подумал об этом, но я не хотел распространять внутренние файлы ресурсов для процедуры удаления в папке назначения приложения. В последнем случае ошибка исключения будет повышена, если пользователь вручную удалит изображение и, конечно, я этого не хочу. Как я могу понять, на вопрос не может быть ответино ограничение, которое я поставил. – Maverick

+0

Просто проверьте, существует ли файл и не загружайте изображение, если это не так. Не обязательно, чтобы деинсталлятор работал в конце концов. –

+0

О первой рекомендации это вариант. О втором, если я хорошо понимаю, вы рекомендуете использовать строку в качестве буфера данных, а затем вспоминать эти данные с помощью TStringStream и подключать ее с помощью класса растрового изображения. Это звучит неплохо, но у меня нет навыков в паскале, чтобы закодировать это. Я буду искать в Интернете, и я решаю, не является ли это стратегией избытка. – Maverick

Смежные вопросы