Подборка полезных примеров из топика по Inno Setup. Составил fty

Вопрос | Ответ
Реально ли из архива .bin, созданного Inno, распаковать отдельные (нужные) файлы или только unpacker’ом весь разархивировать придется?
Для Far и Total Commander есть примочки (см. описание innounp.htm в конце). Или воспользуйся синтаксисом командной строки:
innounp -e setup.exe <нужный файл>
где <нужный файл> со всеми {...}-путями получаем так:
innounp -v setup.exe
setup.exe - естественно то, что нужно распаковать.
---

Распаковать закриптованный инсталлятор:
innounp setup.exe -x -m -f(pass.txt)
Pass узнаем, выдирая плагином compiledcode.bin.
---

Прекрасно выдирается хоть фаром, хоть командной строкой:
innounp -x -m kppp10-0.bin embedded\CompiledCode.bin
---

Извлечь правильный CompiledCode:
innounp -v -m setup.exe
Как сделать, чтобы файлы в секции [Run] запускались по очереди? Т.е. инсталляция второго файла начиналась только после того, как инсталляция первого файла закончилась или отменилась.
У меня в [Run] засунуто два инсталлятора программ. Мне надо, чтобы программа дождалась, пока я не закончу устанавливать первую, а потом уже запустила вторую. А то по умолчанию он ждет, пока запустится первый файл и запускает второй.
Пиши скрипт в секции [Сode]
CreateProcess(...)
WaitForSingleObject(...)
CreateProcess(...)
WaitForSingleObject(...)
и т.п.
Можно ли запустить рег-файлик "невидимым", чтобы без "Вы хотите....", "Данные успешно внесены" и т.д.? Как это изобразить в скрипте?
regedit.exe /s file.reg

В скрипте:
Filename: {sys}\regedit.exe; Parameters: -s {app}\file.reg; WorkingDir: {sys}; StatusMsg: Внесение изменений в реестр...;

А вообще-то для этого есть секция [Registry]...
Данные из reg-файла "тихо" занести в реестр.
WinExec ПУТЬ_К_ФАЙЛУ -s
Как сделать backup реестра (нескольких веток) и сохранить в нужном месте в виде reg-файла?
[Run]
Filename: {sys}\dllcache\regedit.exe; Parameters: -EA {win}\cursors\beeline\backup.reg "HKEY_CURRENT_USER\Control Panel\Cursors"; WorkingDir: {sys}; StatusMsg: Внесение изменений в реестр...;
Мне нужно сделать backup реестра (нескольких веток) и сохранить в нужном месте в виде reg-файла ПЕРЕД ИНСТАЛЛЯЦИЕЙ.
1. Перед инсталяцией - процедурой Procedure BeforeInstall;
Вот пример:
[Code]
var
ResultCode: Integer;
Procedure MyBeforeInstall;
Begin
Exec(ExpandConstant('{pf}\QIP\Skins\{code:GetSkinName}\Smilies\DirRen.exe'), '', '', SW_SHOW, ewWaitUntilTerminated, ResultCode)
end;

[Files]
Source: "C:\123\Animated1\*.ini"; DestDir: "{app}"; BeforeInstall: MyBeforeInstall; Flags: ignoreversion; Components: first

Вот только как в один файл запихать несколько веток я не знаю. Теоретически может как-то так:

copy all.reg+1.reg+2.reg+3.reg

2. Можно также сделать с помощью bat-файла такого содержания:
start /wait regedit /ea Save1.reg "HKEY_CURRENT_USER\Software\Programs1"
start /wait regedit /ea Save2.reg "HKEY_CURRENT_USER\Software\Programs2"
start /wait regedit /ea Save3.reg "HKEY_CURRENT_USER\Software\Programs3"
copy Save1.reg+Save2.reg+Save3.reg
В файл Save1.reg будут скопированы все остальные файлы, что вроде и требовалось.
Как сделать так, чтобы к пути, который инсталлятор ищет в реестре, прибавить еще название нужной папки?
Скажем:
DefaultDirName={reg:HKLM\Software\VST,VSTPluginsPath|{pf}\Vmd}
инсталлятор нашел путь и указал при установке: C:\VstPlugs
как прибавить название папки, чтобы автоматически получилось C:\VstPlugs\Vmd
Можно написать функцию, возвращающую строку. В функции получить путь из реестра и приклеить к нему то, что надо и вернуть как результат.
Тогда, наверное, можно будет написать:

DefaultDirName={code:FunctionRegPath|{pf}\Vmd}

где FunctionRegPath - это имя функции, возвращающей то, что надо.
Мне нужно, чтобы инсталлятор искал в реестре ключ, копировал оттуда значение пути, а потом просто устанавливал этот путь как "корневой" для установочных файлов. Окно выбора папки для установки при этом выводиться ВООБЩЕ не должно (если значения в реестре нет - инсталлятор просто завершает работу).
[Setup]
DefaultDirName={reg:HKLM\Software\My Program, Path}

где будет браться путь из HKLM\Software\My Program , где ключ обозван Path , где в ключе Path хранится путь до того, что тебе надо.
Вот как отключить окно выбора пути установки:

[Setup]
DefaultDirName={pf}\My Program
DisableDirPage=yes

Если же тебе надо, чтобы при отсутствии пути в реестре установка отменялась, то тебе надо задать проверку в реестре наличия ключа Path. Хотя я допускаю, что возможно, если установка не найдет этот ключ в реестре, то она в любом случае отменит сама себя.
Как сделать, чтобы на странице приветствия инсталлятор проверял наличие игры в системе пользователя через реестр, и, если она есть, вместо кнопки "Начать установку" была кнопка "Играть", при нажатии на которую инсталлятор бы вырубался и включался exe игры (путь к exe будет в реестре)?
[Code]
var ResultCode:Integer;
ResultReg:string;
procedure CurPageChanged(CurPageID:Integer);
begin
if CurPageID=wpWelcome then
begin
if RegValueExists(HKEY_LOCAL_MACHINE, 'Software\GSC Game World\STALKER-SHOC','InstallPath') then
If WizardForm.FindComponent('NextButton') is TButton then
TButton(WizardForm.FindComponent('NextButton')).Caption:='Играть';
end;
end;

function NextButtonClick(CurPageID: Integer): Boolean;
begin
if RegValueExists(HKEY_LOCAL_MACHINE, 'Software\GSC Game World\STALKER-SHOC','InstallPath') then
begin
RegQueryStringValue(HKEY_LOCAL_MACHINE, 'Software\GSC Game World\STALKER-SHOC','InstallPath', ResultReg)
Result:=False;
Exec(ResultReg+'\XR_3DA.exe', '', '', SW_SHOW,ewNoWait, ResultCode)
WizardForm.Close;
end
else
Result:=True;
end;

procedure CancelButtonClick(CurPageID: Integer; var Cancel, Confirm: Boolean);
begin
Cancel:=True;
if CurPageID=wpWelcome then
begin
if RegValueExists(HKEY_LOCAL_MACHINE, 'Software\GSC Game World\STALKER-SHOC','InstallPath') then
Confirm:=False;
end;
end;

P.S. Только есть одна проблема - если пользователь удалит игру не через деинсталлятор, а вручную, то потом он её не сможет установить из-за ветки в реестре.
Есть задача:
1. Имеется 4 версии exe файла программы и к каждому свои значения в реестре (установить на компьютер только один).
2. Нужно при установке выбрать один из них и, соответственно, чтобы автоматически прописывалось в реестре именно к этому файлу значение и плюс один файл в системную папку.
[Setup]
AppName=My Program
AppVerName=My Program 1.5
DefaultDirName={pf}\My Program

[Types]
Name: custom; Description: Custom; Flags: iscustom

[Components]
Name: Component1; Description: Component1; Flags: exclusive
Name: Component2; Description: Component2; Flags: exclusive
Name: Component3; Description: Component3; Flags: exclusive
Name: Component4; Description: Component4; Flags: exclusive

[Files]
Source: 1.exe; DestDir: {app}; Components: Component1
Source: 2.exe; DestDir: {app}; Components: Component2
Source: 3.exe; DestDir: {app}; Components: Component3
Source: 4.exe; DestDir: {app}; Components: Component4
Source: system.exe; DestDir: {sys}

[Registry]
Root: HKLM; Subkey: SOFTWARE\My Program; ValueType: String; ValueName: 1; ValueData: {app}\1.exe; Flags: uninsdeletekey; Components: Component1
Root: HKLM; Subkey: SOFTWARE\My Program; ValueType: String; ValueName: 2; ValueData: {app}\2.exe; Flags: uninsdeletekey; Components: Component2
Root: HKLM; Subkey: SOFTWARE\My Program; ValueType: String; ValueName: 3; ValueData: {app}\3.exe; Flags: uninsdeletekey; Components: Component3
Root: HKLM; Subkey: SOFTWARE\My Program; ValueType: String; ValueName: 4; ValueData: {app}\4.exe; Flags: uninsdeletekey; Components: Component4
Можно ли в Inno Setup задать, чтобы установка начиналась только если в реестре присутствует некоторый ключ? Вот готовый скрипт.

#define DateTime GetDateTimeString('ddddd','','')

[Setup]
AppName=CheckRegValue
AppVerName=CheckRegValue and select Component
DefaultDirName={pf}\My Program
OutputBaseFilename=Setup (сборка от {#DateTime})

[Tasks]
Name: eng; Description: Английская версия; Check: CheckKey
Name: rus; Description: Русская версия; Check: not CheckKey

[Code]
Function CheckKey: Boolean;
Begin
if ExpandConstant('{reg:HKLM\Software\LucasArts\Star Wars Empire at War\1.0,CD Key}') = 'fc4c-3d8-05f-d411-uk20' then Result:= True
End;

Function InitializeSetup: Boolean;
Begin
If RegValueExists(HKLM, 'Software\LucasArts\Star Wars Empire at War\1.0\ExePath', ExpandConstant('{#SetupSetting("DefaultDirName")}')) then Result:=
True else MsgBox('Программа ' + '{#SetupSetting("AppName")}' + ' не установлена!', mbInformation, mb_Ok)
End;
У меня с предыдущим примером проблема. Вобщем, сам ключ в реестре присутствует, но все равно светит то сообщение, которое должно быть только если ключа нет. Вариант 1- укажи DefaultDirName равным ExePath в реестре, например:
DefaultDirName={pf}\Star Wars Empire at War

Function InitializeSetup: Boolean; var Str: string; Begin
RegQueryStringValue(HKLM, 'Software\LucasArts\Star Wars Empire at War\1.0', 'ExePath', Str)
If Uppercase(Str) = Uppercase(ExpandConstant('{#SetupSetting("DefaultDirName")}\GameData\sweaw.exe')) then Result:= True else MsgBox('Программа {#SetupSetting("AppName")} не установлена!', mbInformation, mb_Ok)
End;

Второй вариант более универсальный, считывает оба ключа из реестра и не зависит от папки установки:
Function InitializeSetup: Boolean; Begin
If Uppercase(ExpandConstant('{reg:HKLM\Software\Microsoft\Windows\CurrentVersion\Uninstall\{#SetupSetting("AppName")}_is1,InstallLocation}\GameData\sweaw.exe')) = Uppercase(ExpandConstant('{reg:HKLM\Software\LucasArts\Star Wars Empire at War\1.0,ExePath}')) then Result:= True else MsgBox('{#SetupSetting("AppName")} не найдена!', mbInformation, mb_Ok)
End;
А как сделать чтобы ПЕРЕД НАЧАЛОМ ИНСТАЛЛЯЦИИ если система ХР, то запускался File1.exe, а если Vista, то File2.exe?
function InitializeSetup (): Boolean;
var Version: TWindowsVersion;

begin
GetWindowsVersionEx(Version);
if Version.NTPlatform and (Version.Major = 6) and (Version.Minor = 0) then
begin
MsgBox('You OS Windows Vista' ,mbInformation, mb_Ok);
//Exec
Result:= True;
end

begin
GetWindowsVersionEx(Version);
if Version.NTPlatform and (Version.Major = 5) and (Version.Minor = 1) then
begin
MsgBox('You OS Windows XP' ,mbInformation, mb_Ok);
//Exec
Result:= True;
end
end
end;
Как сделать, чтобы после удаления удалились абсолютно ВСЕ ключи, созданные во время установки? | К каждому параметру добавь флаг uninsdeletevalue
Как изменить размер и текст кнопки "Далее" на одной странице, чтобы это изменение не влияло на все другие страницы? Никак. Кнопки Далее, Назад и Отмена находятся на WizardForm, а не на странице. Другими словами, кнопка Далее всего одна.
Максимум, что можно сделать, это изменить размер и текст при переходе на одну страницу и восстановить размер и текст при переходе на следующую или предыдущую.

Возможный вариант:
[Code]
procedure CurPageChanged(CurPageID: Integer);
begin
if CurPageID = wpWelcome then
begin
WizardForm.NextButton.Width:=75
WizardForm.NextButton.Left:=327
end
if CurPageID = wpSelectDir then
begin
WizardForm.BackButton.Left:=180
WizardForm.NextButton.Width:=150
WizardForm.NextButton.Left:=255
WizardForm.NextButton.Caption:='Инициализировать дискету'
end
if CurPageID = wpReady then
begin
WizardForm.NextButton.Width:=75
WizardForm.NextButton.Left:=327
WizardForm.BackButton.Left:=252
end
end;
Как сделать неактивной кнопку 'Далее' на createcustompage?
[Setup]
AppName=My Program
AppVerName=My Program ver.1.5
DefaultDirName={pf}\My Program

[Code]
var
Page: TWizardPage;

procedure InitializeWizard();
begin
Page := CreateCustomPage(wpWelcome, 'Custom wizard page', 'Disable Next button');
end;

procedure CurPageChanged(CurPageID: Integer);
begin
if CurPageID = Page.ID then
WizardForm.NextButton.Enabled:=false;
end;
Как добиться такого, чтобы кнопка "Далее" становилась неактивна, когда не выбран ни один компонент [Components] во время установки? Ведь нет никакого смысла ставить, если ничего не выбрано! Вариант 1:
function NextButtonClick(CurPageID: Integer): Boolean;
begin
Result:= True;
if WizardSelectedComponents(False) = '' then
begin
MsgBox('Ни один из компонентов не выбран!', mbInformation, MB_OK);
Result:= False;
end;
end;

Вариант 2:
procedure ComponentOnClick(Sender: TObject);
begin
if WizardSelectedComponents(False) = '' then
WizardForm.NextButton.Enabled:= False
else WizardForm.NextButton.Enabled:= True;
end;

procedure InitializeWizard();
begin
WizardForm.ComponentsList.OnClick := @ComponentOnClick;
end;

2-ой вариант работает только при выборе компонентов мышкой (обработка нажатия пробела - на ваше усмотрение).
Как в InnoSetup сделать выбор установки компонентов? 1. Нужно определиться, сколько и каких компонентов должно содержаться:
[Components]
Name: main; Description: Программные файлы; Flags: fixed; Types: custom compact full
Name: Component1; Description: Факультатив 1; Flags: checkablealone; Types: full
Name: Component2; Description: Факультатив 2; Flags: checkablealone; Types: full

2. Нужно разложить исходные файлы по каталогам, в каждом из которых ты разместишь файлы того или иного компонента:

C:\temp\MyApp\main
C:\temp\MyApp\comp1
C:\temp\MyApp\comp2

3. Нужно прописать размещение исходных файлов в скрипте, указав для них привязку к тому или иному компоненту:

[Files]
Source: C:\temp\MyApp\main\*; DestDir: {app}; Flags: ignoreversion; Components: main
Source: C:\temp\MyApp\comp1\*; DestDir: {app}; Flags: ignoreversion; Components: Component1
Source: C:\temp\MyApp\comp2\*; DestDir: {app}; Flags: ignoreversion; Components: Component2
Подскажите, откуда взять размер выбранных компонентов на странице wpSelectComponents? Где он хранится? WizardForm.ComponentsList.ItemSubItem[Index: Integer]

Пример:

procedure CurPageChanged(CurPageID: Integer);
var
str: string;
i: integer;
begin
if CurPageID = wpSelectComponents then
begin
for i:= 0 to WizardForm.ComponentsList.Items.Count - 1 do
begin
str:= str + WizardForm.ComponentsList.ItemCaption[i] + ' - size: ' + WizardForm.ComponentsList.ItemSubItem[i] + #10#13;
end;
MsgBox(str, mbInformation, MB_OK);
end;
end;
Мне нужно получить размер места на диске, который нужен для выбранных компонентов. Например, из списка выбрана часть компонентов и Inno Setup пишет внизу страницы, сколько потребуется для них места. Где хранится это число, чтобы использовать его в дальнейшем?
function GetComponentSpace(): Currency;
var
ComponentSpace: string;
StartLen, EndLen, SpaceLen: integer;
begin
ComponentSpace:= SetupMessage(msgComponentsDiskSpaceMBLabel);
StartLen:= Pos('[', ComponentSpace);
EndLen:= Length(ComponentSpace) - Pos(']', ComponentSpace);
ComponentSpace:= WizardForm.ComponentsDiskSpaceLabel.Caption;
SpaceLen:= Length(ComponentSpace) - StartLen - EndLen + 2;
ComponentSpace:= Copy(ComponentSpace, StartLen, SpaceLen);

Result:= StrToFloat(Trim(ComponentSpace));
end;

function NextButtonClick(CurPageID: Integer): Boolean;
begin
if CurPageID = wpSelectComponents then
MsgBox(FloatToStr(GetComponentSpace), mbInformation, MB_OK);
Result:= True;
end;

Можно слегка упростить:

function GetComponentSpace(): Currency;
var
ComponentSpace, LabelSpace: string;
StartLen, EndLen, SpaceLen: integer;
begin
ComponentSpace:= SetupMessage(msgComponentsDiskSpaceMBLabel);
LabelSpace:= WizardForm.ComponentsDiskSpaceLabel.Caption;

StartLen:= Pos('[mb]', ComponentSpace);
SpaceLen:= Length(LabelSpace) - Length(ComponentSpace) + 4;
ComponentSpace:= Copy(LabelSpace, StartLen, SpaceLen);

Result:= StrToFloat(Trim(ComponentSpace));
end;

А можно использовать и другой прием:

[Messages]
ComponentsDiskSpaceMBLabel=[mb]

[Code]
var
Lbl: TLabel;

procedure InitializeWizard();
begin
Lbl := TLabel.Create(WizardForm);
with WizardForm.ComponentsDiskSpaceLabel do
begin
Lbl.Top := Top;
Lbl.Left:= Left;
Lbl.AutoSize := True;
Lbl.Caption := 'Disk space requires (Mb): ';
Lbl.Parent := Parent;
Left:= Lbl.Left + Lbl.Width;
end;
end;

function NextButtonClick(CurPageID: Integer): Boolean;
var
str: string;
begin
if CurPageID = wpSelectComponents then
begin
MsgBox(WizardForm.ComponentsDiskSpaceLabel.Caption, mbInformation, MB_OK);
end;
Result:= True;
end;
Как сделать, чтобы при установке можно было выбрать загрузку приложения вместе с Windows?
[Tasks]
Name: RunMyProgrammInStartup; Description: "Запускать программу при загрузке Windows?";
[Registry]
Root: HKCU; Subkey: "Software\Microsoft\Windows\CurrentVersion\Run\"; ValueType: string; ValueName: "MyProgramm"; ValueData: "{app}\MyProgramm.exe"; Flags: uninsdeletevalue; Tasks: RunMyProgrammInStartup;

Можно и в LOCAL MACHINE записать, но тут уже нужно думать, а надо ли?

[Registry]
Root: HKLM; Subkey: "Software\Microsoft\Windows\CurrentVersion\Run\"; ValueType: string; ValueName: "MyProgramm"; ValueData: "{app}\MyProgramm.exe"; Flags: uninsdeletevalue; Tasks: RunMyProgrammInStartup;
Подскажите, как убрать все окошки с приветствиями и диалогами? Попробовать в разделе [Setup] выставить разные DisableProgramGroupPage=yes, DisableDirPage=yes, DisableFinishedPage=yes, DisableReadyPage=yes, DisableStartupPrompt=yes. Выбирай, что из этого нужно.

Если надо, чтобы совсем без диалогов, щелкнул по сетапу и все, то:

[Setup]
AppName=My Program
AppVerName=My Program 1.5
DefaultDirName={pf}\My Program
DisableDirPage=yes
DisableProgramGroupPage=yes
DisableReadyPage=yes
DisableFinishedPage=yes
OutputBaseFilename=setup
Compression=lzma
SolidCompression=yes

[Files]
Source: "C:\My Program\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs

[Code]
procedure CurPageChanged(CurPageID: Integer);
begin
If CurPageID=wpWelcome then
begin
SendMessage(WizardForm.NEXTBUTTON.Handle, 513, 0, 0)
SendMessage(WizardForm.NEXTBUTTON.Handle, 514, 0, 0)
end;
end;
Мне надо, чтобы изо всех диалоговых окон, типа страницы приветствия, страницы выбора папки установки, страницы выбора ярлыков и т.д., показываемых пользователю при установке готовой программы, выдавалось только одно - диалог выбора папки установки и всё.
[Setup]
AppName=My Program
AppVerName=My Program
DefaultDirName={pf}\My Program
DisableReadyPage=True
DisableFinishedPage=True

[Code]
procedure CurPageChanged(CurPageID: Integer);
begin
If CurPageID=wpWelcome then
begin
SendMessage(WizardForm.NEXTBUTTON.Handle, 513, 0, 0)
SendMessage(WizardForm.NEXTBUTTON.Handle, 514, 0, 0)
end
end;
Как убрать самую первую страницу?
[Code]
procedure CurPageChanged(CurPageID: Integer);
begin
If CurPageID=wpWelcome then
begin
SendMessage(WizardForm.NEXTBUTTON.Handle, 513, 0, 0)
SendMessage(WizardForm.NEXTBUTTON.Handle, 514, 0, 0)
end;
end;
Как сделать, чтобы в конце установки выскакивало окошечко с надписью: "Программа (Имя программы) установлена!", т.к. я отключил страницу конца установки.
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssDone then
MsgBox('Программа ' + '{#SetupSetting("AppName")}' + ' установлена!', mbInformation, MB_OK);
end;
А как для предыдущего случая сделать 2 кнопочки: Ок и Сancel? При нажатии на ОК запускается игра, а на Cancel, соответсвенно, нет.
procedure CurStepChanged(CurStep: TSetupStep);
var
ResultCode: Integer;
begin
if CurStep = ssDone then
if MsgBox('Программа ' + '{#SetupSetting("AppName")}' + ' установлена!' + #10#10#13 + 'Запустить ' + '{#SetupSetting("AppName")}' + '?' , mbInformation, MB_OKCANCEL) = IDOK then
Exec(ExpandConstant('{app}\bin\XR_3DA.exe'), '', '', SW_SHOW, ewNoWait, ResultCode);
end;
Сделал DisableDirPage=true. Как теперь проверять свободное место и выдавать сообщение в случае, если его недостаточно? Можно ли не отключать эту страницу, а просто сделать неактивным выбор папки?
[Setup]
AppName=My Program
AppVerName=My Program version 1.5
DefaultDirName={pf}\My Program

[Code]
procedure InitializeWizard();
begin
WizardForm.DirBrowseButton.Enabled:=False
WizardForm.DirEdit.Enabled:=False
end;
Хочу прикрутить wave, чтобы при установке играла музыка. Но не получается, компилируется, устанавливается, а музыки нет. Для проигрывания wave (без всяких ISSI) следует дописать следующее:
[Files]
Source: "C:\sound.wav"; DestDir: "{tmp}"; Flags: dontcopy

[Code]
function sndPlaySound(lpszSoundName: string; uFlags: cardinal):integer;
external 'sndPlaySoundA@winmm.dll stdcall';

procedure InitializeWizard();
begin
ExtractTemporaryFile(ExpandConstant('sound.wav')); //Извлекаем звуковой файл во временную папку
sndPlaySound(ExpandConstant('{tmp}\sound.wav'), $0001 or $0008); //Проигрываем файл. Здесь указаны параметры для повторного проигрывания. Если мы хотим проиграть файл единожды, удаляем параметр 'or $0008'
end;

Для проигрывания MIDI делаем так:
[Files]
Source: "C:\sound.mid"; DestDir: "{tmp}"; Flags: dontcopy

[Code]
function mciSendString(lpstrCommand: string; lpstrReturnString: string; uReturnLength:integer; hwndCallback:integer):integer;
external 'mciSendStringA@winmm.dll stdcall';

procedure InitializeWizard();
begin
ExtractTemporaryFile(ExpandConstant('sound.mid'));
mciSendString(ExpandConstant('play {tmp}\sound.mid'),'NULL',0,0);
end;

Как сделать повторение воспроизведения midi я не знаю.
Пример скрипта, в котором в секции [Code] реализовано проигрывание музыки в wav и фоновое изображение bmp.
[Files]
Source: "C:\sound.wav"; DestDir: "{tmp}"; Flags: dontcopy
Source: "C:\background.bmp"; DestDir: "{tmp}"; Flags: dontcopy

[Code]
function sndPlaySound(lpszSoundName: string; uFlags: cardinal):integer;
external 'sndPlaySoundA@winmm.dll stdcall';

function GetSystemMetrics(nIndex:Integer):Integer;
external 'GetSystemMetrics@user32.dll stdcall';

procedure InitializeWizard();
var
BackgroundBitmapImage: TBitmapImage;
s:string;
width, height:Integer;
bitmap:TBitmap;
begin
ExtractTemporaryFile('background.bmp');
ExtractTemporaryFile('sound.wav');
sndPlaySound(ExpandConstant('{tmp}\sound.wav'), $0001 or $0008);
WizardForm.Position:=poScreenCenter;
MainForm.BORDERSTYLE:=bsNone;
width:=GetSystemMetrics(61);
height:=GetSystemMetrics(62);
MainForm.Width:=width;
MainForm.Height:=height;
width:=MainForm.ClientWidth;
height:=MainForm.ClientHeight;
s:=ExpandConstant('{tmp}')+'\background.bmp';
BackgroundBitmapImage := TBitmapImage.Create(MainForm);
BackgroundBitmapImage.Bitmap.LoadFromFile(s);
BackgroundBitmapImage.Align := alClient;
BackgroundBitmapImage.Parent := MainForm;
BackgroundBitmapImage.Stretch:=True;
MainForm.Visible:=True;
end;
Как через какую-либо кнопку прекратить воспроизведение звука?
[Files]
Source: compiler:sound.wav; DestDir: "{tmp}"; Flags: dontcopy nocompression

[Code]
function sndPlaySound(lpszSoundName: string; uFlags: cardinal):integer;
external 'sndPlaySoundA@winmm.dll stdcall';

procedure StopSound(Sender: TObject);
begin
sndPlaySound(ExpandConstant(''), $0001 or $0008);
end;

procedure InitializeWizard();
var
ButtonStop: TButton;
begin
ExtractTemporaryFile(ExpandConstant('sound.wav'));
sndPlaySound(ExpandConstant('{tmp}\sound.wav'), $0001 or $0008);

ButtonStop := TButton.Create(WizardForm);
with ButtonStop do
begin
Parent := WizardForm;
Caption :='stop';
Left := ScaleX(8);
Top :=320
Width := ScaleX(43);
Height := ScaleY(33);
TabOrder := 0;
OnClick:=@StopSound
end;
end;
Как вставить в инсталлятор трекерную музыку? Кто вставляет в инсталлятор трекерную музыку, даю свое решение по проигрыванию трекерной музыки через библиотеку BassMod.dll, взять которую можно отсюда: http://un4seen.com/files/bassmod20.zip
Дело в том, что она поддерживает почти все трекерные форматы и проигрывает более корректно некоторые чипы, чем ранее предложенная MiniFMod.dll.
Вот код:
[Files]
Source: "C:\BASSMOD.dll"; DestDir: "{tmp}"; Flags: dontcopy
Source: "C:\music.mod"; DestDir: "{tmp}"; Flags: dontcopy

[Code]
const
BASS_MUSIC_LOOP = 4;

function BASSMOD_Init(device: Integer; freq, flags: DWORD): Boolean;
external 'BASSMOD_Init@files:BASSMOD.dll stdcall delayload';

procedure BASSMOD_MusicFree();
external 'BASSMOD_MusicFree@files:BASSMOD.dll stdcall delayload';

function BASSMOD_MusicLoad(mem: BOOL; f: PChar; offset: DWORD; length: DWORD; flags: DWORD): Boolean;
external 'BASSMOD_MusicLoad@files:BASSMOD.dll stdcall delayload';

function BASSMOD_MusicPlay(): Boolean;
external 'BASSMOD_MusicPlay@files:BASSMOD.dll stdcall delayload';

procedure BASSMOD_Free();
external 'BASSMOD_Free@files:BASSMOD.dll stdcall delayload';

procedure InitializeWizard();
var
hMod: Integer;
Name1: string;
begin
ExtractTemporaryFile(ExpandConstant('BASSMOD.dll'));
ExtractTemporaryFile(ExpandConstant('music.mod'));
if not BASSMOD_Init(-1,44100,0) then begin
MsgBox('BASSMOD не смогла инициализироваться, проигрывание музыки невозможно.', mbInformation, MB_OK)
BASSMOD_Free;
end;
begin
Name1:=ExpandConstant('{tmp}\music.mod');
BASSMOD_MusicFree;
if BASSMOD_MusicLoad(FALSE, PChar(Name1), 0, 0, BASS_MUSIC_LOOP) then
BASSMOD_MusicPlay;
end;
end;

А также смотрим примеры библиотеки для указания дополнительных параметров воспроизведения.
Пример 1 – музыка воспроизводится только при нажатии кнопки «play»
[Setup]
AppName=My Program
AppVerName=My Program 1.5
AppPublisher=My Company, Inc.
DefaultDirName=C:\example

[Files]
Source: BASS.dll; DestDir: " {tmp} "; Flags: dontcopy noencryption
Source: sound.mp3; DestDir: "{tmp}"; Flags: dontcopy noencryption nocompression

[Code]
const
BASS_ACTIVE_STOPPED = 0;
BASS_ACTIVE_PLAYING = 1;
BASS_ACTIVE_STALLED = 2;
BASS_ACTIVE_PAUSED = 3;
BASS_SAMPLE_LOOP = 4;

var
mp3Handle: HWND;
mp3Name: string;

function BASS_Init(device: Integer; freq, flags: DWORD; win: hwnd; CLSID: Integer): Boolean;
external 'BASS_Init@files:BASS.dll stdcall delayload';

function BASS_StreamCreateFile(mem: BOOL; f: PChar; offset: DWORD; length: DWORD; flags: DWORD): DWORD;
external 'BASS_StreamCreateFile@files:BASS.dll stdcall delayload';

function BASS_Start(): Boolean;
external 'BASS_Start@files:BASS.dll stdcall delayload';

function BASS_ChannelPlay(handle: DWORD; restart: BOOL): Boolean;
external 'BASS_ChannelPlay@files:BASS.dll stdcall delayload';

function BASS_ChannelIsActive(handle: DWORD): Integer;
external 'BASS_ChannelIsActive@files:BASS.dll stdcall delayload';

function BASS_ChannelPause(handle: DWORD): Boolean;
external 'BASS_ChannelPause@files:BASS.dll stdcall delayload';

function BASS_Stop(): Boolean;
external 'BASS_Stop@files:BASS.dll stdcall delayload';

function BASS_Pause(): Boolean;
external 'BASS_Pause@files:BASS.dll stdcall delayload';

function BASS_Free(): Boolean;
external 'BASS_Free@files:BASS.dll stdcall delayload';

function InitializeSetup(): Boolean;
begin
ExtractTemporaryFile('BASS.dll');
ExtractTemporaryFile('sound.mp3');
mp3Name := ExpandConstant('{tmp}\sound.mp3');
mp3Handle := BASS_StreamCreateFile(FALSE, PChar(mp3Name), 0, 0, BASS_SAMPLE_LOOP);
Result := True;
end;

procedure PlayButtonOnClick(Sender: TObject);
begin
case BASS_ChannelIsActive(mp3Handle) of
BASS_ACTIVE_PAUSED:
begin
BASS_ChannelPlay(mp3Handle, False);
end;
BASS_ACTIVE_STOPPED:
begin
BASS_Init(-1, 44100, 0, 0, 0);
mp3Handle := BASS_StreamCreateFile(FALSE, PChar(mp3Name), 0, 0, BASS_SAMPLE_LOOP);
BASS_Start();
BASS_ChannelPlay(mp3Handle, False);
end;
end;
end;

procedure PauseButtonOnClick(Sender: TObject);
begin
BASS_ChannelPause(mp3Handle);
end;

procedure StopButtonOnClick(Sender: TObject);
begin
BASS_Stop();
BASS_Free();
end;

procedure InitializeWizard();
var
Name1: string;
PlayButton, PauseButton, StopButton: TButton;
Text: TNewStaticText;
Panel1: TPanel;
begin
WizardForm.Position := poScreenCenter;
WizardForm.CancelButton.BringToFront;
begin
Panel1 := TPanel.Create(WizardForm);
with Panel1 do
begin
Panel1.Parent := WizardForm;
Panel1.Left := ScaleX(1);
Panel1.Top := ScaleY(315);
Panel1.Width := ScaleX(165);
Panel1.Height := ScaleY(46);
Panel1.TabOrder := 0;
Panel1.Color := clWhite;
Panel1.BevelInner := bvLowered;
Panel1.BevelOuter := bvRaised;
Panel1.BorderStyle := bsSingle;

PlayButton := TButton.Create(WizardForm);
PlayButton.Left := 5;
PlayButton.Top := 335;
PlayButton.Width := 50;
PlayButton.Height := 20;
PlayButton.Caption := 'play';
PlayButton.OnClick := @PlayButtonOnClick;
PlayButton.Parent := WizardForm;
PlayButton.Cursor := crHand;

PauseButton := TButton.Create(WizardForm);
PauseButton.Left := 58;
PauseButton.Top := 335;
PauseButton.Width := 50;
PauseButton.Height := 20;
PauseButton.Caption := 'pause';
PauseButton.OnClick := @PauseButtonOnClick;
PauseButton.Parent := WizardForm;
PauseButton.Cursor := crHand;

StopButton := TButton.Create(WizardForm);
StopButton.Left := 111;
StopButton.Top := 335;
StopButton.Width := 50;
StopButton.Height := 20;
StopButton.Caption := 'stop';
StopButton.OnClick := @StopButtonOnClick;
StopButton.Parent := WizardForm;
StopButton.Cursor := crHand;

Text := TNewStaticText.Create(WizardForm);
Text.Caption := 'music';
Text.Parent := WizardForm;
Text.Font.Style := Text.Font.Style + [fsUnderline];
Text.Font.Color := clNavy;
Text.Top := 319;
Text.Left := 71;
Text.Color := clWhite;
end;
end;
end;

procedure DeinitializeSetup();
begin
BASS_Stop();
BASS_Free();
end;
Пример 2 – музыка воспроизводится сразу при запуске
AppName=My Program
AppVerName=My Program 1.5
AppPublisher=My Company, Inc.
DefaultDirName=C:\example

[Files]
Source: BASS.dll; DestDir: " {tmp} "; Flags: dontcopy noencryption
Source: sound.mp3; DestDir: "{tmp}"; Flags: dontcopy noencryption nocompression

[Code]
const
BASS_ACTIVE_STOPPED = 0;
BASS_ACTIVE_PLAYING = 1;
BASS_ACTIVE_STALLED = 2;
BASS_ACTIVE_PAUSED = 3;
BASS_SAMPLE_LOOP = 4;

var
mp3Handle: HWND;
mp3Name: string;

function BASS_Init(device: Integer; freq, flags: DWORD; win: hwnd; CLSID: Integer): Boolean;
external 'BASS_Init@files:BASS.dll stdcall delayload';

function BASS_StreamCreateFile(mem: BOOL; f: PChar; offset: DWORD; length: DWORD; flags: DWORD): DWORD;
external 'BASS_StreamCreateFile@files:BASS.dll stdcall delayload';

function BASS_Start(): Boolean;
external 'BASS_Start@files:BASS.dll stdcall delayload';

function BASS_ChannelPlay(handle: DWORD; restart: BOOL): Boolean;
external 'BASS_ChannelPlay@files:BASS.dll stdcall delayload';

function BASS_ChannelIsActive(handle: DWORD): Integer;
external 'BASS_ChannelIsActive@files:BASS.dll stdcall delayload';

function BASS_ChannelPause(handle: DWORD): Boolean;
external 'BASS_ChannelPause@files:BASS.dll stdcall delayload';

function BASS_Stop(): Boolean;
external 'BASS_Stop@files:BASS.dll stdcall delayload';

function BASS_Pause(): Boolean;
external 'BASS_Pause@files:BASS.dll stdcall delayload';

function BASS_Free(): Boolean;
external 'BASS_Free@files:BASS.dll stdcall delayload';

function InitializeSetup(): Boolean;
begin
ExtractTemporaryFile('BASS.dll');
ExtractTemporaryFile('sound.mp3');
mp3Name := ExpandConstant('{tmp}\sound.mp3');
BASS_Init(-1, 44100, 0, 0, 0);
mp3Handle := BASS_StreamCreateFile(FALSE, PChar(mp3Name), 0, 0, BASS_SAMPLE_LOOP);
BASS_Start();
BASS_ChannelPlay(mp3Handle, False);
Result := True;
end;

procedure PlayButtonOnClick(Sender: TObject);
begin
case BASS_ChannelIsActive(mp3Handle) of
BASS_ACTIVE_PAUSED:
begin
BASS_ChannelPlay(mp3Handle, False);
end;
BASS_ACTIVE_STOPPED:
begin
BASS_Init(-1, 44100, 0, 0, 0);
mp3Handle := BASS_StreamCreateFile(FALSE, PChar(mp3Name), 0, 0, BASS_SAMPLE_LOOP);
BASS_Start();
BASS_ChannelPlay(mp3Handle, False);
end;
end;
end;

procedure PauseButtonOnClick(Sender: TObject);
begin
BASS_ChannelPause(mp3Handle);
end;

procedure StopButtonOnClick(Sender: TObject);
begin
BASS_Stop();
BASS_Free();
end;

procedure InitializeWizard();
var
Name1: string;
PlayButton, PauseButton, StopButton: TButton;
Text: TNewStaticText;
Panel1: TPanel;
begin
WizardForm.Position := poScreenCenter;
WizardForm.CancelButton.BringToFront;
begin
Panel1 := TPanel.Create(WizardForm);
with Panel1 do
begin
Panel1.Parent := WizardForm;
Panel1.Left := ScaleX(1);
Panel1.Top := ScaleY(315);
Panel1.Width := ScaleX(165);
Panel1.Height := ScaleY(46);
Panel1.TabOrder := 0;
Panel1.Color := clWhite;
Panel1.BevelInner := bvLowered;
Panel1.BevelOuter := bvRaised;
Panel1.BorderStyle := bsSingle;

PlayButton := TButton.Create(WizardForm);
PlayButton.Left := 5;
PlayButton.Top := 335;
PlayButton.Width := 50;
PlayButton.Height := 20;
PlayButton.Caption := 'play';
PlayButton.OnClick := @PlayButtonOnClick;
PlayButton.Parent := WizardForm;
PlayButton.Cursor := crHand;

PauseButton := TButton.Create(WizardForm);
PauseButton.Left := 58;
PauseButton.Top := 335;
PauseButton.Width := 50;
PauseButton.Height := 20;
PauseButton.Caption := 'pause';
PauseButton.OnClick := @PauseButtonOnClick;
PauseButton.Parent := WizardForm;
PauseButton.Cursor := crHand;

StopButton := TButton.Create(WizardForm);
StopButton.Left := 111;
StopButton.Top := 335;
StopButton.Width := 50;
StopButton.Height := 20;
StopButton.Caption := 'stop';
StopButton.OnClick := @StopButtonOnClick;
StopButton.Parent := WizardForm;
StopButton.Cursor := crHand;

Text := TNewStaticText.Create(WizardForm);
Text.Caption := 'music';
Text.Parent := WizardForm;
Text.Font.Style := Text.Font.Style + [fsUnderline];
Text.Font.Color := clNavy;
Text.Top := 319;
Text.Left := 71;
Text.Color := clWhite;
end;
end;
end;

procedure DeinitializeSetup();
begin
BASS_Stop();
BASS_Free();
end;
Код, в котором при нажатии на кнопку (только для музыкальных кнопок) меняется рисунок.
[Files]
;Использован рисунок размером 180х20
Source: MusicButton.bmp; DestDir: {tmp}; Flags: dontcopy

[Code]
var
PlayButton, PauseButton, StopButton: TPanel;
PlayImage, PauseImage, StopImage: TBitmapImage;
PlayLabel, PauseLabel, StopLabel: TLabel;

procedure PlayMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if PlayLabel.Enabled then
PlayImage.Left:=-90
end;

procedure PlayMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
PlayImage.Left:=0
end;

procedure PauseMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if PauseLabel.Enabled then
PauseImage.Left:=-120
end;

procedure PauseMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
PauseImage.Left:=-30
end;

procedure StopMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
if StopLabel.Enabled then
StopImage.Left:=-150
end;

procedure StopMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
StopImage.Left:=-60
end;

procedure InitializeWizard();
begin
ExtractTemporaryFile('MusicButton.bmp')

PlayButton:=TPanel.Create(WizardForm)
PlayButton.Left:=33
PlayButton.Top:=328
PlayButton.Width:=30
PlayButton.Height:=20
PlayButton.Cursor:=crHand
PlayButton.ShowHint:=True
PlayButton.Hint:='Воспроизведение музыки'
PlayButton.OnClick:=@PlayButtonOnClick
PlayButton.Parent:=WizardForm

PlayImage:=TBitmapImage.Create(WizardForm)
PlayImage.Left:=0
PlayImage.Top:=0
PlayImage.Width:=180
PlayImage.Height:=20
PlayImage.Enabled:=False
PlayImage.Bitmap.LoadFromFile(ExpandConstant('{tmp}\MusicButton.bmp'))
PlayImage.Parent:=PlayButton

PlayLabel:=TLabel.Create(WizardForm)
PlayLabel.Width:=PlayButton.Width
PlayLabel.Height:=PlayButton.Height
PlayLabel.Autosize:=False
PlayLabel.Transparent:=True
PlayLabel.OnClick:=@PlayButtonOnClick
PlayLabel.OnMouseDown:=@PlayMouseDown
PlayLabel.OnMouseUp:=@PlayMouseUp
PlayLabel.Parent:=PlayButton

PauseButton:=TPanel.Create(WizardForm)
PauseButton.Left:=66
PauseButton.Top:=328
PauseButton.Width:=30
PauseButton.Height:=20
PauseButton.Cursor:=crHand
PauseButton.ShowHint:=True
PauseButton.Hint:='Приостановить музыку'
PauseButton.OnClick:=@PauseButtonOnClick
PauseButton.Parent:=WizardForm

PauseImage:=TBitmapImage.Create(WizardForm)
PauseImage.Left:=-30
PauseImage.Top:=0
PauseImage.Width:=180
PauseImage.Height:=20
PauseImage.Enabled:=False
PauseImage.Bitmap.LoadFromFile(ExpandConstant('{tmp}\MusicButton.bmp'))
PauseImage.Parent:=PauseButton

PauseLabel:=TLabel.Create(WizardForm)
PauseLabel.Width:=PauseButton.Width
PauseLabel.Height:=PauseButton.Height
PauseLabel.Autosize:=False
PauseLabel.Transparent:=True
PauseLabel.OnClick:=@PauseButtonOnClick
PauseLabel.OnMouseDown:=@PauseMouseDown
PauseLabel.OnMouseUp:=@PauseMouseUp
PauseLabel.Parent:=PauseButton

StopButton:=TPanel.Create(WizardForm)
StopButton.Left:=99
StopButton.Top:=328
StopButton.Width:=30
StopButton.Height:=20
StopButton.Cursor:=crHand
StopButton.ShowHint:=True
StopButton.Hint:='Остановить музыку'
StopButton.OnClick:=@StopButtonOnClick
StopButton.Parent:=WizardForm

StopImage:=TBitmapImage.Create(WizardForm)
StopImage.Left:=-60
StopImage.Top:=0
StopImage.Width:=180
StopImage.Height:=20
StopImage.Enabled:=False
StopImage.Bitmap.LoadFromFile(ExpandConstant('{tmp}\MusicButton.bmp'))
StopImage.Parent:=StopButton

StopLabel:=TLabel.Create(WizardForm)
StopLabel.Width:=StopButton.Width
StopLabel.Height:=StopButton.Height
StopLabel.Autosize:=False
StopLabel.Transparent:=True
StopLabel.OnClick:=@StopButtonOnClick
StopLabel.OnMouseDown:=@StopMouseDown
StopLabel.OnMouseUp:=@StopMouseUp
StopLabel.Parent:=StopButton
end;
Код для скина Slate с кнопками управления музыкой в формате MP3
[Setup]
AppName=My Program
AppVerName=My Program 1.5
AppPublisher=My Company, Inc.
DefaultDirName=C:\example

[Files]
Source: BASS.dll; DestDir: " {tmp} "; Flags: dontcopy noencryption
Source: music.mp3; DestDir: "{tmp}"; Flags: dontcopy noencryption nocompression

[Code]
const
BASS_ACTIVE_STOPPED = 0;
BASS_ACTIVE_PLAYING = 1;
BASS_ACTIVE_STALLED = 2;
BASS_ACTIVE_PAUSED = 3;
BASS_SAMPLE_LOOP = 4;

var
mp3Handle: HWND;
mp3Name: string;

function BASS_Init(device: Integer; freq, flags: DWORD; win: hwnd; CLSID: Integer): Boolean;
external 'BASS_Init@files:BASS.dll stdcall delayload';

function BASS_StreamCreateFile(mem: BOOL; f: PChar; offset: DWORD; length: DWORD; flags: DWORD): DWORD;
external 'BASS_StreamCreateFile@files:BASS.dll stdcall delayload';

function BASS_Start(): Boolean;
external 'BASS_Start@files:BASS.dll stdcall delayload';

function BASS_ChannelPlay(handle: DWORD; restart: BOOL): Boolean;
external 'BASS_ChannelPlay@files:BASS.dll stdcall delayload';

function BASS_ChannelIsActive(handle: DWORD): Integer;
external 'BASS_ChannelIsActive@files:BASS.dll stdcall delayload';

function BASS_ChannelPause(handle: DWORD): Boolean;
external 'BASS_ChannelPause@files:BASS.dll stdcall delayload';

function BASS_Stop(): Boolean;
external 'BASS_Stop@files:BASS.dll stdcall delayload';

function BASS_Pause(): Boolean;
external 'BASS_Pause@files:BASS.dll stdcall delayload';

function BASS_Free(): Boolean;
external 'BASS_Free@files:BASS.dll stdcall delayload';

function InitializeSetup(): Boolean;
begin
ExtractTemporaryFile('BASS.dll');
ExtractTemporaryFile('music.mp3');
mp3Name := ExpandConstant('{tmp}\music.mp3');
mp3Handle := BASS_StreamCreateFile(FALSE, PChar(mp3Name), 0, 0, BASS_SAMPLE_LOOP);
Result := True;
end;

procedure PlayButtonOnClick(Sender: TObject);
begin
case BASS_ChannelIsActive(mp3Handle) of
BASS_ACTIVE_PAUSED:
begin
BASS_ChannelPlay(mp3Handle, False);
end;
BASS_ACTIVE_STOPPED:
begin
BASS_Init(-1, 44100, 0, 0, 0);
mp3Handle := BASS_StreamCreateFile(FALSE, PChar(mp3Name), 0, 0, BASS_SAMPLE_LOOP);
BASS_Start();
BASS_ChannelPlay(mp3Handle, False);
end;
end;
end;

procedure PauseButtonOnClick(Sender: TObject);
begin
BASS_ChannelPause(mp3Handle);
end;

procedure StopButtonOnClick(Sender: TObject);
begin
BASS_Stop();
BASS_Free();
end;

procedure InitializeWizard();
var
Name: string;
PlayButton, PauseButton, StopButton: TButton;
Text: TNewStaticText;
Panel: TPanel;
begin
WizardForm.Position := poScreenCenter;
WizardForm.CancelButton.BringToFront;
begin
Panel := TPanel.Create(WizardForm);
with Panel do
begin
Parent := WizardForm;
Left := ScaleX(1);
Top := ScaleY(315);
Width := ScaleX(165);
Height := ScaleY(46);
TabOrder := 0;
Color := clWhite;
BevelInner := bvLowered;
BevelOuter := bvRaised;
BorderStyle := bsSingle;
end
PlayButton := TButton.Create(WizardForm);
with PlayButton do
begin
Left := 5;
Top := 335;
Width := 50;
Height := 20;
Caption := 'Play';
OnClick := @PlayButtonOnClick;
Parent := WizardForm;
Cursor := crHand;
ShowHint := True;
Hint := '&#194;&#238;&#241;&#239;&#240;&#238;&#232;&#231;&#226;&#229;&#228;&#229;&#237; &#232;&#229; &#236;&#243;&#231;&#251;&#234;&#232;';
end
PauseButton := TButton.Create(WizardForm);
with PauseButton do
begin
Left := 58;
Top := 335;
Width := 50;
Height := 20;
Caption := 'Pause';
OnClick := @PauseButtonOnClick;
Parent := WizardForm;
Cursor := crHand;
ShowHint := True;
Hint := '&#207;&#240;&#232;&#238;&#241;&#242;&#224;&#237;&#238;&#226;&#232;&#242;&#252; &#236;&#243;&#231;&#251;&#234;&#243;';
end
StopButton := TButton.Create(WizardForm);
with StopButton do
begin
Left := 111;
Top := 335;
Width := 50;
Height := 20;
Caption := 'Stop';
OnClick := @StopButtonOnClick;
Parent := WizardForm;
Cursor := crHand;
ShowHint := True;
Hint := '&#206;&#241;&#242;&#224;&#237;&#238;&#226;&#232;&#242;&#252; &#236;&#243;&#231;&#251;&#234;&#243;';
end

Text := TNewStaticText.Create(WizardForm);
with Text do
begin
Caption := 'Music Box';
Parent := WizardForm;
Font.Style := Text.Font.Style + [fsUnderline];
Font.Color := clNavy;
Top := 319;
Left := 57;
Color := clWhite;
end
end;
end;

procedure DeinitializeSetup();
begin
BASS_Stop();
BASS_Free();
end;
Как музыку на задний план поставить?
[Files]
Source: Sound.mp3; DestDir: {tmp}; Flags: dontcopy

[Code]
function mciSendString(lpstrCommand: string; lpstrReturnString: string; uReturnLength:integer; hwndCallback:integer):integer;
external 'mciSendStringA@winmm.dll stdcall';

procedure InitializeWizard();
begin
ExtractTemporaryFile(ExpandConstant('Sound.mp3'))
mciSendString(ExpandConstant('play {tmp}\Sound.mp3 repeat'),'NULL',0,0)
end;
Запуск инсталла из командной строки, чтобы было без музыки | Запусти инсталл с параметром /NoMusic=1 и музыки не будет!
Пример, когда картинка из BMP и слайд-шоу из JPG и с параметром WindowVisible=no и они подгоняются под любой размер экрана.
[Setup]
WindowVisible=no

[Files]
Source: "x:\License.rtf"; DestDir: {tmp}; Flags: dontcopy noencryption
Source: "other_files"; DestDir: {tmp};

Source: C:\1.jpg; DestDir: {tmp}; Flags: dontcopy
Source: C:\2.jpg; DestDir: {tmp}; Flags: dontcopy
Source: C:\3.jpg; DestDir: {tmp}; Flags: dontcopy
Source: C:\4.jpg; DestDir: {tmp}; Flags: dontcopy
Source: C:\Fon.bmp; DestDir: {tmp}; Flags: dontcopy

[Code]
const
BACKGROUND = 6; // "5"-по центру, "6"-растянуто на весь экран, "1,2,3,4"-в разных углах экрана
TIMER = 16;
function isxbb_AddImage(Image: PChar; Flags: Cardinal): Integer;
external 'isxbb_AddImage@files:isxbb.dll stdcall';
function isxbb_Init(hWnd: Integer): Integer;
external 'isxbb_Init@files:isxbb.dll stdcall';
function isxbb_StartTimer(Seconds: Integer; Flags: Cardinal): Integer;
external 'isxbb_StartTimer@files:isxbb.dll stdcall';
function isxbb_KillTimer(Flags: Cardinal): Integer;
external 'isxbb_KillTimer@files:isxbb.dll stdcall';
function GetSystemMetrics(nIndex: Integer): Integer;
external 'GetSystemMetrics@user32.dll stdcall';

procedure InitializeWizard();
var
BackgroundBitmapImage: TBitmapImage;
s: string;
License: string;
width, height: Integer;
begin
{********************Для корректного отображения заголовков**********}
WizardForm.Position := poScreenCenter;
{********************Для корректного отображения заголовков**********}
MainForm.BORDERSTYLE := bsNone;
{********************Для корректного отображения rtf файлов**********}
ExtractTemporaryFile('License.rtf');
LoadStringFromFile(ExpandConstant('{tmp}') + '\License.rtf', License)
WizardForm.LicenseMemo.RTFText := License;
{********************Для корректного отображения rtf файлов**********}

width := GetSystemMetrics(0);
height := GetSystemMetrics(1);
MainForm.Width := width;
MainForm.Height := height;
width := MainForm.ClientWidth;
height := MainForm.ClientHeight;
ExtractTemporaryFile('Fon.bmp');
s := ExpandConstant('{tmp}') + '\Fon.bmp';
BackgroundBitmapImage := TBitmapImage.Create(MainForm);
BackgroundBitmapImage.Bitmap.LoadFromFile(s);
BackgroundBitmapImage.Left := 0;
BackgroundBitmapImage.Top := 0;
BackgroundBitmapImage.Width := width;
BackgroundBitmapImage.Height := height;
BackgroundBitmapImage.Parent := MainForm;
BackgroundBitmapImage.Stretch := True;
MainForm.Visible := True;
end;

procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssInstall
then
begin
ExtractTemporaryFile('1.jpg'); //это файлы для слайд-шоу, их может быть и больше
ExtractTemporaryFile('2.jpg');
ExtractTemporaryFile('3.jpg');
isxbb_AddImage(ExpandConstant('{tmp}') + '\1.jpg', BACKGROUND or TIMER);
isxbb_AddImage(ExpandConstant('{tmp}') + '\2.jpg', BACKGROUND or TIMER);
isxbb_AddImage(ExpandConstant('{tmp}') + '\3.jpg', BACKGROUND or TIMER);
isxbb_Init(StrToInt(ExpandConstant('{hwnd}')));
isxbb_StartTimer(3, BACKGROUND) //это таймер для слайд-шоу в секундах
end
else if CurStep = ssPostInstall then
isxbb_KillTimer(BACKGROUND);
end;
А больше 10 секунд слайд можно сделать?
const
BACKGROUND = 5;
TIMER = 21;
Как ни ставлю, один фиг, 10 секунд показывает картинку!
Таймер выставляй в этой строке:
isxbb_StartTimer(10,BackGround)
или замени эту строку на эту:
isxbb_StartTimer(TIMER,BackGround)
и выставляй в константе.
Как сделать, чтобы были свои картинки (отображаются с левой стороны инсталлятора и справа вверху)?
[Setup]
WizardImageFile=C:\картинка.bmp 164x314
WizardSmallImageFile=C:\картинка.bmp 55x55
Можно ли сделать, чтобы синего фона, на который ложится My_Image.bmp, вообще не было видно?
[Setup]
AppName=My Program
AppVerName=My Program version 1.5
DefaultDirName={pf}\My Program
DefaultGroupName=My Program
UninstallDisplayIcon={app}\MyProg.exe
WindowVisible=No

[Types]
Name: "full"; Description: "Full installation"
Name: "compact"; Description: "Compact installation"
Name: "custom"; Description: "Custom installation"; Flags: iscustom

[Components]
Name: "program"; Description: "Program Files"; Types: full compact custom; Flags: fixed
Name: "help"; Description: "Help File"; Types: full
Name: "readme"; Description: "Readme File"; Types: full
Name: "readme\en"; Description: "English"; Flags: exclusive
Name: "readme\de"; Description: "German"; Flags: exclusive

[Files]
Source: "MyProg.exe"; DestDir: "{app}"; Components: program
Source: "MyProg.chm"; DestDir: "{app}"; Components: help
Source: "Readme.txt"; DestDir: "{app}"; Components: readme\en; Flags: isreadme
Source: "Readme-German.txt"; DestName: "Liesmich.txt"; DestDir: "{app}"; Components: readme\de; Flags: isreadme

[Icons]
Name: "{group}\My Program"; Filename: "{app}\MyProg.exe"

[Code]
var
Form: TForm;

function ShowWindow(hWnd: LongWord; nCmdShow: LongWord): LongWord;
external 'ShowWindow@user32.dll stdcall';

procedure FormOnActivate(Sender: TObject);
begin
WizardForm.Show;
end;

function InitializeSetup(): Boolean;
begin
Form := CreateCustomForm();
Form.BorderStyle:= bsNone;
Form.Color:= clGreen;
ShowWindow(Form.Handle, SW_SHOWMAXIMIZED);

Result:= True;
end;

procedure InitializeWizard();
begin
Form.OnActivate:= @FormOnActivate;
end;

procedure DeinitializeSetup();
begin
Form.Free;
end;
Возможно ли как-нибудь сделать фон из JPG картинки и смену JPG картинок во время установки БЕЗ WindowVisible=yes и синей формы с названием проги?
[Setup]
WindowVisible=yes
WindowShowCaption=no
BackColor=$000000

[Files]
Source: C:\isxbb.dll; DestDir: {tmp}; Flags: dontcopy
Source: C:\1.jpg; DestDir: {tmp}; Flags: dontcopy
Source: C:\2.jpg; DestDir: {tmp}; Flags: dontcopy
Source: C:\3.jpg; DestDir: {tmp}; Flags: dontcopy
Source: C:\4.jpg; DestDir: {tmp}; Flags: dontcopy

[Code]
const
BACKGROUND=5; // "5"-по центру, "6"-растянуто на весь экран, "1,2,3,4"-в разных углах экрана
TIMER=16;

function isxbb_AddImage(Image: PChar; Flags: Cardinal): Integer;
external 'isxbb_AddImage@files:isxbb.dll stdcall';
function isxbb_Init(hWnd: Integer): Integer;
external 'isxbb_Init@files:isxbb.dll stdcall';
function isxbb_StartTimer(Seconds: Integer; Flags: Cardinal): Integer;
external 'isxbb_StartTimer@files:isxbb.dll stdcall';
function isxbb_KillTimer(Flags: Cardinal): Integer;
external 'isxbb_KillTimer@files:isxbb.dll stdcall';

procedure InitializeWizard();
begin
ExtractTemporaryFile('1.jpg'); //1.jpg-это фоновый рисунок, он показывается как в начале, так и в конце установки
isxbb_AddImage(ExpandConstant('{tmp}')+'\1.jpg',BACKGROUND);
isxbb_Init(StrToInt(ExpandConstant('{hwnd}')));
end;
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep=ssInstall
then
begin
ExtractTemporaryFile('2.jpg'); //это файлы для слайд-шоу, их может быть и больше
ExtractTemporaryFile('3.jpg');
ExtractTemporaryFile('4.jpg');
isxbb_AddImage(ExpandConstant('{tmp}')+'\2.jpg',BACKGROUND or TIMER);
isxbb_AddImage(ExpandConstant('{tmp}')+'\3.jpg',BACKGROUND or TIMER);
isxbb_AddImage(ExpandConstant('{tmp}')+'\4.jpg',BACKGROUND or TIMER);
isxbb_Init(StrToInt(ExpandConstant('{hwnd}')));
isxbb_StartTimer(3,BACKGROUND) //это таймер для слайд-шоу в секундах
end
else if CurStep=ssPostInstall then
isxbb_KillTimer(BACKGROUND);
end;
А возможно ли сделать без WindowVisible=yes, но cо значением WindowVisible=no? Вот пример - фон из .BMP, а слайд-шоу из .JPG:
[Setup]
WindowVisible=no

[Files]
Source: "x:\License.rtf"; DestDir: {tmp}; Flags: dontcopy noencryption

[Code]

const
BACKGROUND = 6; //"5"-по центру, "6"-растянуто на весь экран, "1,2,3,4"-в разных углах экрана
TIMER = 16;

function isxbb_AddImage(Image: PChar; Flags: Cardinal): Integer;
external 'isxbb_AddImage@files:isxbb.dll stdcall';
function isxbb_Init(hWnd: Integer): Integer;
external 'isxbb_Init@files:isxbb.dll stdcall';
function isxbb_StartTimer(Seconds: Integer; Flags: Cardinal): Integer;
external 'isxbb_StartTimer@files:isxbb.dll stdcall';
function isxbb_KillTimer(Flags: Cardinal): Integer;
external 'isxbb_KillTimer@files:isxbb.dll stdcall';
function GetSystemMetrics(nIndex: Integer): Integer;
external 'GetSystemMetrics@user32.dll stdcall';

procedure InitializeWizard();
var
BackgroundBitmapImage: TBitmapImage;
s: string;
License: string;
width, height: Integer;
begin
{********************Для корректного отображения заголовков**********}
WizardForm.Position := poScreenCenter;
{********************Для корректного отображения заголовков**********}
MainForm.BORDERSTYLE := bsNone;
{********************Для корректного отображения rtf файлов**********}
ExtractTemporaryFile('License.rtf');
LoadStringFromFile(ExpandConstant('{tmp}') + '\License.rtf', License)
WizardForm.LicenseMemo.RTFText := License;
{********************Для корректного отображения rtf файлов**********}

width := GetSystemMetrics(0);
height := GetSystemMetrics(1);
MainForm.Width := width;
MainForm.Height := height;
width := MainForm.ClientWidth;
height := MainForm.ClientHeight;
ExtractTemporaryFile('Fon.bmp');
s := ExpandConstant('{tmp}') + '\Fon.bmp';
BackgroundBitmapImage := TBitmapImage.Create(MainForm);
BackgroundBitmapImage.Bitmap.LoadFromFile(s);
BackgroundBitmapImage.Left := 0;
BackgroundBitmapImage.Top := 0;
BackgroundBitmapImage.Width := width;
BackgroundBitmapImage.Height := height;
BackgroundBitmapImage.Parent := MainForm;
BackgroundBitmapImage.Stretch := True;
MainForm.Visible := True;
end;

procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssInstall
then
begin
ExtractTemporaryFile('1.jpg'); //это файлы для слайд-шоу, их может быть и больше
ExtractTemporaryFile('2.jpg');
ExtractTemporaryFile('3.jpg');
isxbb_AddImage(ExpandConstant('{tmp}') + '\1.jpg', BACKGROUND or TIMER);
isxbb_AddImage(ExpandConstant('{tmp}') + '\2.jpg', BACKGROUND or TIMER);
isxbb_AddImage(ExpandConstant('{tmp}') + '\3.jpg', BACKGROUND or TIMER);
isxbb_Init(StrToInt(ExpandConstant('{hwnd}')));
isxbb_StartTimer(3, BACKGROUND) //это таймер для слайд-шоу в секундах
end
else if CurStep = ssPostInstall then
isxbb_KillTimer(BACKGROUND);
end;
Код, где на фоновом окне в зависимости от разрешения экрана отображается картинка соответствующего размера
[Setup]
AppName=AppName
AppVerName=AppVerName
DefaultDirName={pf}\AppName

[Files]
Source: 640.bmp; DestDir: {tmp}; Flags: dontcopy
Source: 800.bmp; DestDir: {tmp}; Flags: dontcopy
Source: 1024.bmp; DestDir: {tmp}; Flags: dontcopy
Source: 1152.bmp; DestDir: {tmp}; Flags: dontcopy
Source: 1280.bmp; DestDir: {tmp}; Flags: dontcopy
Source: 1600.bmp; DestDir: {tmp}; Flags: dontcopy

[Code]
function GetDC(HWND: DWord): DWord;
external 'GetDC@user32.dll stdcall';

function GetDeviceCaps(DC: DWord; Index: Integer): Integer;
external 'GetDeviceCaps@gdi32.dll stdcall';

function ReleaseDC(HWND: DWord;DC: DWord): Integer;
external 'ReleaseDC@user32.dll stdcall';

function ShowWindow(hWnd: DWord; nCmdShow: Integer): boolean;
external 'ShowWindow@user32.dll stdcall';

function SetWindowLong(hWnd: DWord; nIndex: Integer; dwNewLong: Longint): Longint;
external 'SetWindowLongA@user32.dll stdcall';

procedure InitializeWizard();
var
bgImage : TBitmapImage;
bgImageName: String;
width: integer;
dc: DWord;

begin
bgImage:=TBitmapImage.Create(MainForm)
bgImage.Align:=alClient
bgImage.Stretch:=True
bgImage.Parent:=MainForm

dc:=GetDC(MainForm.Handle)
width:=GetDeviceCaps(dc,8)
ReleaseDC(MainForm.Handle,dc)

if width <=640 then
bgImageName:='640.bmp'

else if width<=800 then
bgImageName:='800.bmp'

else if width<=1024 then
bgImageName:='1024.bmp'

else if width<=1152 then
bgImageName:='1152.bmp'

else if width<=1280 then
bgImageName:='1280.bmp'

else
bgImageName:='1600.bmp'

ExtractTemporaryFile(bgImageName)
bgImage.bitmap.LoadFromFile(expandConstant('{tmp}\'+bgImageName))

SetWindowLong(MainForm.Handle,-16,$80000000)
ShowWindow(Mainform.Handle,SW_SHOWMAXIMIZED)
end;
Пример растягивания одной и той же картинки на страницах Приветствия и Завершения:
[Code]
procedure InitializeWizard();
var
Page: TWizardPage;
begin
WizardForm.WizardBitmapImage.Left := 333; //Страница Приветствия
WizardForm.WelcomeLabel1.Left := 20;
WizardForm.WelcomeLabel2.Left := 20;
WizardForm.WizardBitmapImage2.Left := 333; //Страница Завершения
WizardForm.FinishedLabel.Left := 20;
WizardForm.FinishedHeadingLabel.Left := 20;
WizardForm.RunList.Left := 20;
WizardForm.YesRadio.Left := 20;
WizardForm.NoRadio.Left := 20;
end;
Пример использования двух разных картинок на страницах Приветствия и Завершения, тоже растянутых:
[Files]
Source: C:\BitmapImage2.bmp; DestDir: {tmp}; Flags: dontcopy

[Code]
procedure InitializeWizard();
var b:string;
begin
ExtractTemporaryFile('BitmapImage2.bmp')
b:=ExpandConstant('{tmp}\BitmapImage2.bmp')
with WizardForm do
begin
WizardBitmapImage.Width:=WizardForm.ClientWidth;
WelcomeLabel1.Visible:=False;
WelcomeLabel2.Visible:=False;
WizardBitmapImage2.Bitmap.LoadFromFile(b);
WizardBitmapImage2.Width:=WizardForm.ClientWidth;
FinishedLabel.Visible:=False;
FinishedHeadingLabel.Visible:=False;
end;
end;
Возможно ли:
1.Чтобы в одном инсталляторе можно было использовать 2 разных WizardImageFile для страниц Приветствия и Завершения.
2.Растянуть 2 разных WizardImageFile на страницах Приветствия и Завершения на всю форму.
[Setup]
WizardImageFile=C:\Image1.bmp

[Files]
Source: C:\Image2.bmp; DestDir: {tmp}; Flags: dontcopy

[Code]
var
Image2: TBitmapImage;

procedure InitializeWizard();
var
Page: TWizardPage;
begin
ExtractTemporaryFile('Image2.bmp')
WizardForm.WizardBitmapImage.Width:=497
WizardForm.WelcomeLabel1.Visible:=False
WizardForm.WelcomeLabel2.Visible:=False
WizardForm.WizardBitmapImage2.Visible:=False
WizardForm.FinishedLabel.Visible:=False
WizardForm.FinishedHeadingLabel.Visible:=False
end;

procedure CurPageChanged(CurPageID: Integer);
begin
If CurPageID=wpFinished then
begin
Image2:=TBitmapImage.Create(WizardForm)
with Image2 do begin
Left:=0
Top:=0
Width:=497
Height:=313
Parent:=WizardForm.FinishedPage
Bitmap.LoadFromFile(ExpandConstant('{tmp}')+'\Image2.bmp')
end
end
end;
Как сделать, чтобы картинка не растягивалась, а находилась по центру? Во-первых, убрать растягивание, надо False, а не True:
BackgroundBitmapImage.Stretch:=False;
...А во-вторых, выставить по центру
BackgroundBitmapImage.Center:= True;
Как сделать, чтобы когда идет установка, то была не просто табличка, а во весь экран разворачивался инсталлятор, например, с картинкой той или иной проги?
[Setup]
WindowVisible=yes

[Files]
Source: C:\BackImage.bmp; DestDir: {tmp}; Flags: dontcopy;

[Code]
procedure InitializeWizard();
var
BackImage: TBitmapImage;
s:string;
begin
ExtractTemporaryFile('BackImage.bmp')
s:=ExpandConstant('{tmp}')+'\BackImage.bmp'
BackImage:=TBitmapImage.Create(MainForm)
BackImage.Bitmap.LoadFromFile(s)
BackImage.Align:=alClient
BackImage.Parent:=MainForm
BackImage.Stretch:=True
end;
Как сделать, чтобы в слайд-шоу картинка не растягивалась, а была строго по центру?
Image1.Align:= alClient;
Image1.AutoSize:= True;
Image1.Center:= True;
Image1.Stretch:= False;
Я вместо сплэш-заставки использую видеоролик, и мне нужно, чтобы он отключался примерно на секунду раньше от его полной длины, чтобы не было видно ненужного текста-титров в конце видеоролика.
[Files]
Source: Video.exe; DestDir: {tmp}; Flags: dontcopy
Source: ISTask.dll; Destdir: {tmp}; Flags: dontcopy

[Code]
function KillTask(ExeFileName: string): Integer;
external 'KillTask@files:ISTask.dll stdcall delayload';

procedure initializeWizard();
var
Res:Integer;
begin
WizardForm.Hide;
ExtractTemporaryFile('Video.exe');
Exec(ExpandConstant('{tmp}\Video.exe'),'','',SW_SHOW,ewNoWait,Res);
Sleep(5300);
KillTask('Video.exe')
WizardForm.Show;
end;
Изменение размера страницы с индикатором выполнения установки Изменение размера страницы с индикатором выполнения установки с последующим перемещением ее в угол экрана (например, это имеет значение в игровом инсталляторе, когда вставлено фоновое изображение, и мы хотим видеть основное его содержимое полным и заодно наблюдать за ходом установки).

procedure InitializeWizard();
begin
//Выносим кнопку "Отмена" на передний план
WizardForm.CancelButton.BringToFront;
end;

procedure CurPageChanged(CurPageID: Integer);
begin
if CurPageID=wpInstalling
then
begin
WizardForm.MainPanel.Visible:=False;
WizardForm.Bevel1.Visible:=False;
WizardForm.Width:=ScaleX(395);
WizardForm.Height:=ScaleY(142);
//Здесь смещение страницы установки (в верхний левый угол)
WizardForm.Left:=ScaleX(0);
WizardForm.Top:=ScaleY(0);
{Внимание! Нижеописанные способы смещения работают, только когда вставлено фоновое изображение или WindowVisible=yes}
{Выводит в правом верхнем углу экрана}
//WizardForm.Left:=ScaleX(MainForm.Width-420);
//WizardForm.Top:=ScaleY(MainForm.Left+20);
{Выводит снизу по центру экрана}
//WizardForm.Position:=poScreenCenter;
//WizardForm.Top:=ScaleY(MainForm.Height-170);
{Выводит в нижнем левом углу (как в Doom 3 Resurrection of Evil от 1C)}
//WizardForm.Left:=ScaleX(MainForm.Left+20);
//WizardForm.Top:=ScaleY(MainForm.Height-170);
{Выводит в нижнем правом углу}
//WizardForm.Left:=ScaleX(MainForm.Width-420);
//WizardForm.Top:=ScaleY(MainForm.Height-170);

WizardForm.InnerNotebook.Left:=ScaleX(10);
WizardForm.InnerNotebook.Top:=ScaleY(10);
WizardForm.InnerNotebook.Width:=ScaleX(370);
WizardForm.StatusLabel.Left:=ScaleX(0);
WizardForm.StatusLabel.Top:=ScaleY(0);
WizardForm.StatusLabel.Width:=WizardForm.InnerNotebook.Width;
WizardForm.FileNameLabel.Left:=ScaleX(0);
WizardForm.FileNameLabel.Top:=ScaleY(20);
WizardForm.FileNameLabel.Width:=WizardForm.InnerNotebook.Width;
WizardForm.ProgressGauge.Top:=ScaleY(40);
WizardForm.ProgressGauge.Width:=WizardForm.InnerNotebook.Width;
WizardForm.CancelButton.Left:=ScaleX(154);
WizardForm.CancelButton.Top:=ScaleY(80);
end
if CurPageID=wpFinished
then
begin
WizardForm.Width:=502; {Размер окна по горизонтали}
WizardForm.Height:=392; {Размер окна по вертикали}
WizardForm.Position:=poScreenCenter; {Возврат в исходное состояние}
end
end;
Как изменить размер окна инсталлятора? Хотелось бы его побольше сделать...
[Code]
procedure InitializeWizard();
begin
WizardForm.Width:=640;
WizardForm.Height:=480;
end;

Но это лучше переделывать в файле Setup.e32
Вот интересная реализация рисунка в верхней панели окна мастера:
[Setup]
WizardSmallImageFile=C:\SmallImage.bmp

;Здесь использован рисунок с размерами 497х58
[Сode]
procedure InitializeWizard();
begin
with WizardForm do begin
with MainPanel do
Height := Height - 1;
with WizardSmallBitmapImage do begin
Left := 0;
Top := 0;
Height := 58; //Размер рисунка
Width := 497; //
end;
with PageNameLabel do begin
Width := Width - 497; //Поставьте здесь значения на 0, если хотите вернуть текст
Left := Left + 497; //
end;
with PageDescriptionLabel do begin
Width := Width - 497; //Поставьте здесь значения на 0, если хотите вернуть текст
Left := Left + 497; //
end;
end;
end;
Как увеличить размер второго маленького изображения инсталлятора (WizardSmallImage 55*55)? Хочется пошире вставить картинку...
procedure InitializeWizard();
begin
with WizardForm do
begin
WizardSmallBitmapImage.Left:=WizardForm.WizardSmallBitmapImage.Left-120
WizardSmallBitmapImage.Width:=177
PageNameLabel.Width:=290
PageDescriptionLabel.Width:=280
end
end;
Помогите с кодом, чтобы сделать маленькую страницу с прогресс-баром в правом нижнем углу экрана, типа "Подготовка к установке", как в InstallShield, которая появляется перед страницей приветствия на 5-7 секунд
[Setup]
AppName=My Program
AppVerName=My Program version 1.5
DefaultDirName={pf}\My Program
DisableProgramGroupPage=yes
WindowVisible=yes

[Files]
Source: Files\*.*; DestDir: {app}; Flags: ignoreversion

[Code]
function GetSystemMetrics(nIndex:Integer):Integer;
external 'GetSystemMetrics@user32.dll stdcall';

procedure InitializeWizard();
var
Form: TSetupForm;
ProgressBar: TNewProgressBar;
i: Integer;
begin
Form := CreateCustomForm();
try
with Form do
begin
ClientWidth := ScaleX(256);
ClientHeight := ScaleY(16);
BorderStyle:= bsNone;
Left:= GetSystemMetrics(16) - ClientWidth - ScaleX(12);
Top:= GetSystemMetrics(17) - ClientHeight - ScaleY(12);
end;
ProgressBar := TNewProgressBar.Create(Form);
with ProgressBar do
begin
Left := ScaleX(8);
Top := ScaleX(12);
Width := Form.Width - (2 * Left);
Height := Form.ClientHeight - (2 * Top);
Parent := Form;
Min:= 0;
Max:= 30;
Position := 0;
end;
Form.Show();
for i:= 0 to 30 do
begin
ProgressBar.Position:= i;
Sleep(500);
i:= i + 1;
end;
finally
Form.Free();
end;
end;
Нельзя ли сделать, чтобы во время копирования временных файлов появлялся граббер или "табличка", т.е. чтобы этот процесс было видно?
[Files]
Source: .\Files\*; DestDir: "{tmp}"; BeforeInstall: HideInstallPath; AfterInstall: ShowInstallPath

[Code]
procedure HideInstallPath();
begin
WizardForm.FileNameLabel.Visible := False;
end;
//*******//
procedure ShowInstallPath();
begin
WizardForm.FileNameLabel.Visible := True;
end;
Как задать выполнение нового прогресс-бара? Как заставить его двигаться и изменять скорость его движения? Один из скриптов в примерах описывает выполнение новой страницы прогресса, а не прогресс-бара в отдельности.
Делаем новую полосу прогресса:
[Code]
var
ProgressBar: TNewProgressBar;
procedure CurPageChanged(CurPageID: Integer);
var
i:Integer;
begin
If CurPageID=wpInstalling
then
begin
ProgressBar := TNewProgressBar.Create(WizardForm);
ProgressBar.Left := ScaleY(40);
ProgressBar.Top := ScaleX(180);
ProgressBar.Width := ScaleY(415);
ProgressBar.Height := ScaleX(18);
ProgressBar.Parent := WizardForm;
ProgressBar.Position := 0; //указывает количество заполняемых секторов
end;
begin
If CurPageID=wpFinished
then
ProgressBar.Hide
end;
end;
А возможно ли сделать так, чтобы в новом ProgressBar'e одновременно запускался ProgressBar и Splash.bmp?
[Setup]
AppName=My Program
AppVerName=My Program version 1.5
DefaultDirName={pf}\My Program
DisableProgramGroupPage=yes
WindowVisible=no

[Files]
Source: Files\*.*; DestDir: {app}; Flags: ignoreversion
Source: WizModernSmallImage.bmp; Flags: dontcopy
Source: splash.bmp; Flags: dontcopy

[Code]
function GetSystemMetrics(nIndex:Integer):Integer;
external 'GetSystemMetrics@user32.dll stdcall';

function InitializeSetup(): Boolean;
var
Form, Splash: TSetupForm;
ProgressBar: TNewProgressBar;
CancelButton: TButton;
StaticText: TNewStaticText;
BitmapImage, BitmapImage1: TBitmapImage;
BitmapFileName: String;
i: Integer;
begin
Form := CreateCustomForm();
try
with Form do
begin
ClientWidth := ScaleX(380);
ClientHeight := ScaleY(120);
BorderStyle:= bsDialog;
Left:= GetSystemMetrics(16) - ClientWidth - ScaleX(12);
Top:= GetSystemMetrics(17) - ClientHeight - ScaleY(12);
end;

BitmapFileName := ExpandConstant('{tmp}\WizModernSmallImage.bmp');
ExtractTemporaryFile(ExtractFileName(BitmapFileName));
BitmapImage := TBitmapImage.Create(Form);
BitmapImage.Left := ScaleX(8);
BitmapImage.Top := ScaleY(8);
BitmapImage.AutoSize := True;
BitmapImage.Bitmap.LoadFromFile(BitmapFileName);
BitmapImage.Parent := Form;

StaticText := TNewStaticText.Create(Form);
StaticText.Top := BitmapImage.Top;
StaticText.Left := BitmapImage.Left + BitmapImage.Width + ScaleX(8)
StaticText.Caption := 'Inno Setup is a free installer for Windows programs.' + #10#13 + 'Support for all versions of Windows in use today';
StaticText.AutoSize := True;
StaticText.Parent := Form;

CancelButton := TButton.Create(Form);
CancelButton.Parent := Form;
CancelButton.Width := ScaleX(75);
CancelButton.Height := ScaleY(23);
CancelButton.Left := Form.ClientWidth - ScaleX(75 + 10);
CancelButton.Top := Form.ClientHeight - ScaleY(23 + 10);
CancelButton.Caption := 'Cancel';
CancelButton.ModalResult := mrCancel;
CancelButton.Cancel := True;

ProgressBar := TNewProgressBar.Create(Form);
with ProgressBar do
begin
Height := CancelButton.Height - ScaleY(8);
Width := Form.Width - ScaleX(128);
Top := CancelButton.Top;
Left := BitmapImage.Left;
Parent := Form;
Min:= 0;
Max:= 30;
Position := 0;
end;

Form.ActiveControl := CancelButton;
Form.Show();

Splash := CreateCustomForm;
Splash.BorderStyle := bsNone;
BitmapImage1 := TBitmapImage.Create(Splash);
with BitmapImage1 do begin
AutoSize := True;
Align := alClient;
Left := 0;
Top := 0;
Stretch := True;
Parent := Splash;
end;
ExtractTemporaryFile('Splash.bmp');
BitmapImage1.Bitmap.LoadFromFile(ExpandConstant('{tmp}') + '\Splash.bmp');
Splash.Width := BitmapImage1.Width;
Splash.Height := BitmapImage1.Height;
Splash.Center;
Splash.Show;
BitmapImage1.Refresh;

for i:= 0 to 30 do
begin
ProgressBar.Position:= i;
Form.Repaint;
Sleep(500);
i:= i + 1;
end;
finally
Form.Free();
Splash.Free();
end;
Result:= True;
end;
Если необходимо отображать проценты установки, нет необходимости высчитывать соотношения размеров файлов, так как данные процесса установки уже присутствуют (в WizardForm.ProgressGauge). Их надо только перевести в проценты. В итоге это может выглядеть примерно так:
[Setup]
AppName=AppName
AppVerName=AppVerName
DefaultDirName={pf}\My Program

[Files]
Source: setup.log; DestDir: {app}; AfterInstall: ExtLog()
Source: Files\*; DestDir: {app}; AfterInstall: ExtLog()

[Code]
var
ProgressLabel: TLabel;

procedure ExtLog();
begin
SaveStringToFile(ExpandConstant('{app}\setup.log'), #13#10 + GetDateTimeString('dd/mm/yyyy hh:nn:ss', '-', ':') + ' - ' + ExpandConstant(CurrentFileName), True);
with WizardForm.ProgressGauge do
ProgressLabel.Caption:= IntToStr((Position-Min)/((Max - Min)/100)) + '%';
end;

procedure InitializeWizard();
begin
ProgressLabel := TLabel.Create(WizardForm);
with WizardForm.ProgressGauge do
begin
ProgressLabel.Top := Top + Height + ScaleY(8);
ProgressLabel.Left:= Left + Width/2 - ScaleX(8);
ProgressLabel.Caption := 'TLabel';
ProgressLabel.AutoSize := True;
ProgressLabel.Parent := WizardForm.InstallingPage;
end;
end;

Правда, это можно назвать приемлемым только в случае, если инсталлируется большое кол-во мелких файлов. К сожалению, в Инно нет события изменения состояния прогресс-бара.
Проценты установки во время инсталяции показываются, а можно ли при этом ещё показывать размер копируемого в данный момент файла?
[Setup]
AppName=AppName
AppVerName=AppVerName
DefaultDirName={pf}\My Program

[Files]
Source: Files\*; DestDir: {app}; AfterInstall: Progress()

[Code]
var
ProgressLabel, SizeLabel: TLabel;

procedure Progress();
var
size: integer;

begin
with WizardForm.ProgressGauge do
ProgressLabel.Caption:= IntToStr((Position-Min)/((Max - Min)/100)) + '%';

FileSize(ExpandConstant(CurrentFileName), size);
SizeLabel.Caption:= IntToStr(size) + ' bytes';
end;

procedure InitializeWizard();
begin
ProgressLabel := TLabel.Create(WizardForm);
with WizardForm.ProgressGauge do
begin
ProgressLabel.Top := Top + Height + ScaleY(8);
ProgressLabel.Left:= Left + Width/2 - ScaleX(8);
ProgressLabel.AutoSize := True;
ProgressLabel.Parent := WizardForm.InstallingPage;
end;

SizeLabel := TLabel.Create(WizardForm);
with WizardForm.ProgressGauge do
begin
SizeLabel.Top := Top + Height + ScaleY(8);
SizeLabel.Left:= Left;
SizeLabel.AutoSize := True;
SizeLabel.Parent := WizardForm.InstallingPage;
end;
end;
Пример использования двух процедур:

procedure ProgressChanged(percent: Integer); -- вызывается каждый раз, когда апдейтится прогресс-бар. percent содержит текущее значение прогресс-бара в процентах

MainForm.SetBackImage(str: String); -- позволяет задать в качестве фона *.jpg. Если str содержит пустое значение, картинка убирается.
[Setup]
AppName=My Program
AppVerName=My Program version 1.5
DefaultDirName={pf}\My Program
DefaultGroupName=My Program
UninstallDisplayIcon={app}\MyProg.exe
Compression=lzma
SolidCompression=yes
WindowVisible=yes

[Files]
Source: Files\*.*; DestDir: {app}; Flags: ignoreversion recursesubdirs
Source: Files_ext\1.jpg; Flags: dontcopy
Source: Files_ext\2.jpg; Flags: dontcopy
Source: Files_ext\main.jpg; Flags: dontcopy

[Code]
var
CurPicture: integer;

function InitializeSetup(): Boolean;
begin
ExtractTemporaryFile('1.jpg');
ExtractTemporaryFile('2.jpg');
ExtractTemporaryFile('main.jpg');
Result:= True;
end;

procedure InitializeWizard();
begin
MainForm.SetBackImage(ExpandConstant('{tmp}\main.jpg'));
end;

procedure ProgressChanged(percent: Integer);
var
str: string;
begin
if ((percent > 0) and (percent < 30) and (CurPicture <> 1)) then
begin
str:= ExpandConstant('{tmp}\1.jpg');
MainForm.SetBackImage(str);
CurPicture:= 1;
end else
if ((percent > 30) and (percent < 60) and (CurPicture <> 2)) then
begin
str:= ExpandConstant('{tmp}\2.jpg');
MainForm.SetBackImage(str);
CurPicture:= 2;
end else
if ((percent > 60) and (percent < 100) and (CurPicture <> 3)) then
begin
MainForm.SetBackImage('');
CurPicture:= 3;
end;
end;
Прогресс-бар, показывающий проценты установки
[Setup]
AppName=AppName
AppVerName=AppVerName
DefaultDirName={pf}\My Program

[Files]
Source: Files\*; DestDir: {app}; AfterInstall: ExtLog; Flags: recursesubdirs

[Code]
var
ProgressLabel: TLabel;

procedure ExtLog();
begin
SaveStringToFile(ExpandConstant('{app}\setup.log'), #13#10 + GetDateTimeString('dd/mm/yyyy hh:nn:ss', '-', ':') + ' - ' + ExpandConstant(CurrentFileName), True);
with WizardForm.ProgressGauge do begin
ProgressLabel.Caption:= IntToStr((Position-Min)/((Max - Min)/100)) + '%';
if (Position-Min)/((Max - Min)/100) > 50 then ProgressLabel.Font.Color:= $FFFFFF
end;
end;

procedure InitializeWizard;
begin
ProgressLabel := TLabel.Create(WizardForm);
with WizardForm.ProgressGauge do
begin
ProgressLabel.Top:= Top + Height + ScaleY(8)
ProgressLabel.Left:= Left + Width/2 - ScaleX(8)
ProgressLabel.Caption:= '0%'
ProgressLabel.AutoSize:= True
ProgressLabel.Transparent:= True;
ProgressLabel.Parent:= WizardForm.InstallingPage
end;
end;
Прогресс-бар, показывающий проценты установки и размер
[Setup]
AppName=AppName
AppVerName=AppVerName
DefaultDirName={pf}\My Program

[Files]
Source: Files\*; DestDir: {app}; AfterInstall: Progress()

[Code]
var
ProgressLabel, SizeLabel: TLabel;

procedure Progress();
var
size: integer;

begin
with WizardForm.ProgressGauge do
ProgressLabel.Caption:= IntToStr((Position-Min)/((Max - Min)/100)) + '%';
FileSize(ExpandConstant(CurrentFileName), size);
SizeLabel.Caption:= IntToStr(size) + ' bytes';
end;

procedure InitializeWizard();
begin
ProgressLabel := TLabel.Create(WizardForm);
with WizardForm.ProgressGauge do
begin
ProgressLabel.Top := Top + Height + ScaleY(8);
ProgressLabel.Left:= Left + Width/2 - ScaleX(8);
ProgressLabel.AutoSize := True;
ProgressLabel.Parent := WizardForm.InstallingPage;
end;

SizeLabel := TLabel.Create(WizardForm);
with WizardForm.ProgressGauge do
begin
SizeLabel.Top := Top + Height + ScaleY(8);
SizeLabel.Left:= Left;
SizeLabel.AutoSize := True;
SizeLabel.Parent := WizardForm.InstallingPage;
end;
end;
Но неизвестно, как будут отображаться проценты выполнения, если у пользователя в системе будет установлено другое оформление, и цвет прогресс-бара будет неизвестно какой, поэтому следующий скрипт
[Files]
Source: files\*; DestDir: {app}; AfterInstall: ExtLog(); Flags: recursesubdirs

[Code]
var
ProgressLabel: TLabel;

procedure ExtLog();
begin
with WizardForm.ProgressGauge do begin
ProgressLabel.Caption:=IntToStr((Position-Min)/((Max - Min)/100)) + '%'
end
end;

procedure InitializeWizard;
begin
ProgressLabel:=TLabel.Create(WizardForm)
with WizardForm.ProgressGauge do
begin
ProgressLabel.Top:=4
ProgressLabel.Left:=200
ProgressLabel.Caption:='0%'
ProgressLabel.AutoSize:=True
ProgressLabel.Font.Color:=clWindowText
ProgressLabel.Font.Style:=[fsBold]
ProgressLabel.Transparent:=True
ProgressLabel.Parent:=WizardForm.ProgressGauge
end;
end;
Слайдшоу не по времени, а по процентам
[Setup]
AppName=My Program
AppVerName=My Program
CreateAppDir=No
WindowVisible=Yes

[Files]
Source: innocallback.dll; DestDir: {tmp}; Flags: dontcopy
Source: pic1.bmp; DestDir: {tmp}; Flags: dontcopy
Source: pic2.bmp; DestDir: {tmp}; Flags: dontcopy
Source: pic3.bmp; DestDir: {tmp}; Flags: dontcopy

[Code]
type
TProc=procedure(HandleW, msg, idEvent, TimeSys: LongWord);
var
BackgroundBitmapImage: TBitmapImage;
TimerID: LongWord;

function WrapTimerProc(callback:TProc; paramcount:integer):longword;
external 'wrapcallback@files:innocallback.dll stdcall';
function SetTimer(hWnd: LongWord; nIDEvent, uElapse: LongWord; lpTimerFunc: LongWord): LongWord;
external 'SetTimer@user32.dll stdcall';
function KillTimer(hWnd: LongWord; nIDEvent: LongWord): LongWord;
external 'KillTimer@user32.dll stdcall';
function GetSystemMetrics(nIndex:Integer):Integer;
external 'GetSystemMetrics@user32.dll stdcall';

procedure InitializeWizard();
begin
ExtractTemporaryFile('pic1.bmp')
ExtractTemporaryFile('pic2.bmp')
ExtractTemporaryFile('pic3.bmp')
end;

function PercentProgress(): Integer;
begin
with WizardForm.ProgressGauge do begin
Result:=(Position-Min)/((Max - Min)/100)
end
end;

procedure OnTimer(HandleW, msg, idEvent, TimeSys: LongWord);
var
percent: integer;
begin
percent:=PercentProgress
with BackgroundBitmapImage do begin
if ((percent>0) and (percent<33) and (Tag<>1)) then begin
Bitmap.LoadFromFile(ExpandConstant('{tmp}') + '\pic1.bmp')
Tag:=1
end else
if ((percent>34) and (percent<66) and (Tag<>2)) then begin
Bitmap.LoadFromFile(ExpandConstant('{tmp}') + '\pic2.bmp')
Tag:=2
end else
if ((percent>67) and (percent<100) and (Tag<>3)) then begin
Bitmap.LoadFromFile(ExpandConstant('{tmp}') + '\pic3.bmp')
Tag:=3
end
end
end;

procedure CurPageChanged(CurPageID: Integer);
var
pfunc: LongWord;
Width, Height: Integer;
begin
If CurPageID=wpInstalling
then
begin
pfunc:=WrapTimerProc(@OnTimer, 4)
TimerID:=SetTimer(0, 0, 500, pfunc)
BackgroundBitmapImage:=TBitmapImage.Create(MainForm)
with BackgroundBitmapImage do begin
BackColor:=clBlack
Center:=True
Align:=alClient
Bitmap.LoadFromFile(ExpandConstant('{tmp}') + '\pic1.bmp')
Parent:=MainForm
Tag:=1
end
end
if CurPageID=wpFinished
then
begin
BackgroundBitmapImage.Hide
end
end;

procedure DeinitializeSetup();
begin
KillTimer(0, TimerID)
end;
А на весь экран в этом коде можно сделать или нет? Замени в процедуре procedure CurPageChanged(CurPageID: Integer);:
BackgroundBitmapImage:=TBitmapImage.Create(MainForm)
with BackgroundBitmapImage do begin
BackColor:=clBlack
Center:=True
Align:=alClient
Bitmap.LoadFromFile(ExpandConstant('{tmp}') + '\pic1.bmp')
Parent:=MainForm
Tag:=1
end

на:

BackgroundBitmapImage:=TBitmapImage.Create(MainForm)
with BackgroundBitmapImage do begin
Stretch:=True
Align:=alClient
Bitmap.LoadFromFile(ExpandConstant('{tmp}') + '\pic1.bmp')
Parent:=MainForm
Tag:=1
end

А если добавить нижеуказанное, то картинка будет как и положено, и не надо ничего менять:

procedure InitializeWizard();
var
BackgroundBitmapImage: TBitmapImage;
s:string;
width, height:Integer;
Page: TWizardPage;
Text: TNewStaticText;
Memo: TMemo;
Path: string;
FreeMB, TotalMB: Cardinal;
drives: DWORD;
i: integer;

begin
WizardForm.Position:=poScreenCenter;
MainForm.BORDERSTYLE:=bsNone;
width:=GetSystemMetrics(0)
height:=GetSystemMetrics(1)
MainForm.Width:=width;
MainForm.Height:=height;
width:=MainForm.ClientWidth;
height:=MainForm.ClientHeight;
MainForm.Visible:=True;
MainForm.Left := 0;
MainForm.Top := 0;
Полноэкранный рисунок на фоновом окне и полноэкранное слайд-шоу по процентам:
[Setup]
AppName=My Program
AppVerName=My Program
DefaultDirName=My Program
BackColor=0

[Files]
Source: InnoCallback.dll; DestDir: {tmp}; Flags: dontcopy
Source: BackImage.bmp; DestDir: {tmp}; Flags: dontcopy
Source: 1.bmp; DestDir: {tmp}; Flags: dontcopy
Source: 2.bmp; DestDir: {tmp}; Flags: dontcopy
Source: 3.bmp; DestDir: {tmp}; Flags: dontcopy

[Code]
type
TProc=procedure(HandleW, msg, idEvent, TimeSys: LongWord);
var
BackImage, SlideImage: TBitmapImage;
TimerID: LongWord;
s:string;
Width, Height:Integer;

function WrapTimerProc(callback:TProc; paramcount:integer):longword;
external 'wrapcallback@files:innocallback.dll stdcall';
function SetTimer(hWnd: LongWord; nIDEvent, uElapse: LongWord; lpTimerFunc: LongWord): LongWord;
external 'SetTimer@user32.dll stdcall';
function KillTimer(hWnd: LongWord; nIDEvent: LongWord): LongWord;
external 'KillTimer@user32.dll stdcall';
function GetSystemMetrics(nIndex:Integer):Integer;
external 'GetSystemMetrics@user32.dll stdcall';

procedure InitializeWizard();
begin
WizardForm.Position:=poScreenCenter
Width:=GetSystemMetrics(0)
Height:=GetSystemMetrics(1)
MainForm.BORDERSTYLE:=bsNone
MainForm.Left:=0
MainForm.Top:=0
MainForm.Width:=Width
MainForm.Height:=Height
ExtractTemporaryFile('BackImage.bmp')
s:=ExpandConstant('{tmp}')+'\BackImage.bmp '
BackImage:=TBitmapImage.Create(MainForm)
BackImage.Bitmap.LoadFromFile(s)
BackImage.Align:=alClient
BackImage.Parent:=MainForm
BackImage.Stretch:=True
MainForm.Visible:=True

ExtractTemporaryFile('BackImage.bmp')
ExtractTemporaryFile('1.bmp')
ExtractTemporaryFile('2.bmp')
ExtractTemporaryFile('3.bmp')
end;

function PercentProgress(): Integer;
begin
with WizardForm.ProgressGauge do begin
Result:=(Position-Min)/((Max - Min)/100)
end
end;

procedure OnTimer(HandleW, msg, idEvent, TimeSys: LongWord);
var
percent: integer;
begin
percent:=PercentProgress
with SlideImage do begin
if ((percent>0) and (percent<10) and (Tag<>1)) then begin
Bitmap.LoadFromFile(ExpandConstant('{tmp}') + '\1.bmp')
Tag:=1
end else
if ((percent>11) and (percent<20) and (Tag<>2)) then begin
Bitmap.LoadFromFile(ExpandConstant('{tmp}') + '\2.bmp')
Tag:=2
end else
if ((percent>21) and (percent<100) and (Tag<>3)) then begin
Bitmap.LoadFromFile(ExpandConstant('{tmp}') + '\3.bmp')
Tag:=3
end
end
end;

procedure CurPageChanged(CurPageID: Integer);
var
pfunc: LongWord;
Width, Height: Integer;
begin
If CurPageID=wpInstalling
then
begin
pfunc:=WrapTimerProc(@OnTimer, 4)
TimerID:=SetTimer(0, 0, 500, pfunc)
SlideImage:=TBitmapImage.Create(MainForm)
with SlideImage do begin
Stretch:=True
Align:=alClient
Bitmap.LoadFromFile(ExpandConstant('{tmp}') + '\1.bmp')
Parent:=MainForm
Tag:=1
end
end
if CurPageID=wpFinished
then
begin
SlideImage.Hide
end
end;

procedure DeinitializeSetup();
begin
KillTimer(0, TimerID)
end;
Прогресс-бар как у InstallShield
[Setup]
AppName=My Program
AppVerName=My Program version 1.5
DefaultDirName={pf}\My Program
DisableProgramGroupPage=yes
WindowVisible=yes

[Files]
Source: Files\*.*; DestDir: {app}; Flags: ignoreversion
Source: ..\WizModernSmallImage.bmp; Flags: dontcopy

[Code]
procedure InitializeWizard();
var
Form1: TSetupForm;
StaticText: TNewStaticText;
BitmapImage: TBitmapImage;
BitmapFileName: String;
begin
Form1 := CreateCustomForm();
try
with Form1 do
begin
ClientWidth := ScaleX(380);
ClientHeight := ScaleY(120);
BorderStyle:= bsToolWindow; // или bsDialog, bsNone кому что нравится
BorderIcons:= BorderIcons - [biSystemMenu];
FormStyle:= fsStayOnTop;
Center;
end;

BitmapFileName := ExpandConstant('{tmp}\WizModernSmallImage.bmp');
ExtractTemporaryFile(ExtractFileName(BitmapFileName));
BitmapImage := TBitmapImage.Create(Form1);
BitmapImage.Left := ScaleX(8);
BitmapImage.Top := ScaleY(8);
BitmapImage.AutoSize := True;
BitmapImage.Bitmap.LoadFromFile(BitmapFileName);
BitmapImage.Parent := Form1;

StaticText := TNewStaticText.Create(Form1);
StaticText.Top := BitmapImage.Top;
StaticText.Left := BitmapImage.Left + BitmapImage.Width + ScaleX(8)
StaticText.Caption := 'Inno Setup is a free installer for Windows programs.' + #10#13 + 'Support for all versions of Windows in use today';
StaticText.AutoSize := True;
StaticText.Parent := Form1;

Form1.Show();
Form1.Repaint;
Sleep(2000);
finally
Form1.Free();
end;
end;
Скрытное копирование файлов - только прогресс-бар, никакого мелькания имен файлов 1. Код:
[Files]
Source: .\Files\*; DestDir: "{app}"; BeforeInstall: HideInstallPath; AfterInstall: ShowInstallPath

[Code]
procedure HideInstallPath();
begin
WizardForm.FileNameLabel.Visible := False;
end;
//*******//
procedure ShowInstallPath();
begin
WizardForm.FileNameLabel.Visible := True;
end;

2. Можешь попробовать и так сделать:

procedure InitializeWizard();
begin
WizardForm.FileNameLabel.Visible:= False;
end;
Это отключит отображение файлов вообще.

В первом случае путь скрывается только для тех файлов, для которых заданы указанные процедуры; во втором - путь скрывается для всех файлов. Первый вариант более гибкий, но если надо скрыть путь абсолютно для всех файлов - предпочтительнее второй вариант.

В примере ниже путь будет скрыт только для файлов, копируемых в системную директорию:

[Files]
Source: .\AppFiles\*; DestDir: "{app}"
Source: .\SysFiles\*; DestDir: "{sys}"; BeforeInstall: HideInstallPath; AfterInstall: ShowInstallPath
Source: .\DocFiles\*; DestDir: "{app}"

[Code]
procedure HideInstallPath();
begin
WizardForm.FileNameLabel.Visible := False;
end;
//*******//
procedure ShowInstallPath();
begin
WizardForm.FileNameLabel.Visible := True;
end;
Как можно реализовать, чтобы по ходу инсталляции не было видно прогресс-бара и устанавливаемых файлов?
procedure InitializeWizard();
begin
WizardForm.FilenameLabel.Hide //Прячем извлекаемые файлы
WizardForm.ProgressGauge.Hide //Прячем прогресс-бар
end;
Интерфейс установки, максимально приближенный к InstallShield, реализованный стандартными средствами Inno Setup. Для создания слайд-шоу используется библиотека IsXbb. Используется Splash-заставка.
При запуске инсталлятора отсутствует "мозолящий" глаза синий фон и имя программы.
Здесь хорошо то, что Splash отображается на странице подготовки, как в InstallSield.
[Setup]
DisableProgramGroupPage=yes
WindowShowCaption=no
BackColor=$000000

[Files]
;Рисунок, используемый для отображения на странице подготовки
Source: "C:\Program Files\Inno Setup 5\WizModernSmallImage.bmp"; DestDir: {tmp}; Flags: dontcopy;
;Также используется на странице подготовки как Splash-заставка
Source: "Temp\Splash.bmp"; DestDir: {tmp}; Flags: dontcopy;
;В качестве фона используется изобрaжение в формате .bmp. Уменьшить размер файла (почти без видимых потерь) можно в Adobe Photoshop (Image => Mode => Indexed Color => Palette: Local (_ANY_))
Source: "Temp\Image.bmp"; DestDir: {tmp}; Flags: dontcopy;
;Библиотека для создания слайд-шоу
Source: "Temp\IsXbb.dll"; DestDir: {tmp}; Flags: dontcopy;
;Файлы для слайд-сшоу (их может быть и больше)
Source: "Temp\1.jpg"; DestDir: {tmp}; Flags: dontcopy;
Source: "Temp\2.jpg"; DestDir: {tmp}; Flags: dontcopy;
Source: "Temp\3.jpg"; DestDir: {tmp}; Flags: dontcopy;
Source: "Temp\4.jpg"; DestDir: {tmp}; Flags: dontcopy;
Source: "Temp\5.jpg"; DestDir: {tmp}; Flags: dontcopy;
;Файлы проекта
Source: "Work\*.*"; DestDir: "{app}"; Flags: overwritereadonly ignoreversion recursesubdirs createallsubdirs;

[Code]
const
{"1,2,3,4" - в разных углах, "5" - по центру, "6" - растянуть изображениe}
BACKGROUND=6;
TIMER=16;
function isxbb_AddImage(Image: PChar; Flags: Cardinal): Integer;
external 'isxbb_AddImage@files:isxbb.dll stdcall';
function isxbb_Init(hWnd: Integer): Integer;
external 'isxbb_Init@files:isxbb.dll stdcall';
function isxbb_StartTimer(Seconds: Integer; Flags: Cardinal): Integer;
external 'isxbb_StartTimer@files:isxbb.dll stdcall';
function isxbb_KillTimer(Flags: Cardinal): Integer;
external 'isxbb_KillTimer@files:isxbb.dll stdcall';
function GetSystemMetrics(nIndex:Integer):Integer;
external 'GetSystemMetrics@user32.dll stdcall';

var
Splash: TSetupForm;

procedure InitializeWizard();
var
BackgroundBitmapImage: TBitmapImage;
s: string;
Form: TSetupForm;
Width, Height: Integer;
ProgressBar: TNewProgressBar;
CancelButton: TButton;
StaticText: TNewStaticText;
BitmapImage: TBitmapImage;
BitmapImage1: TBitmapImage;
BitmapFileName: String;
i: Integer;
begin
WizardForm.Position:= poScreenCenter;
MainForm.BORDERSTYLE := bsNone;
Splash:= CreateCustomForm;
Splash.BorderStyle:= bsNone;
BitmapImage1:= TBitmapImage.Create(Splash);
With BitmapImage1 do
begin
AutoSize:= True;
Align:= alClient;
Left:= 0;
Top:= 0;
Stretch:= True;
Parent:= Splash;
end;
ExtractTemporaryFile('Splash.bmp');
BitmapImage1.Bitmap.LoadFromFile(ExpandConstant('{tmp}')+'\Splash.bmp');
Splash.Width:= BitmapImage1.Width;
Splash.Height:= BitmapImage1.Height;
Splash.Center;
Splash.Show;
BitmapImage1.Refresh;
Form:= CreateCustomForm();
try
with Form do
begin
ClientWidth:= ScaleX(380);
ClientHeight:= ScaleY(120);
BorderStyle:= bsDialog;
Left:= GetSystemMetrics(16) - ClientWidth - ScaleX(8);
Top:= GetSystemMetrics(17) - ClientHeight - ScaleY(8);
end;
BitmapFileName:= ExpandConstant('{tmp}\WizModernSmallImage.bmp');
ExtractTemporaryFile(ExtractFileName(BitmapFileName));
BitmapImage:= TBitmapImage.Create(Form);
BitmapImage.Left:= ScaleX(8);
BitmapImage.Top:= ScaleY(8);
BitmapImage.AutoSize:= True;
BitmapImage.Bitmap.LoadFromFile(BitmapFileName);
BitmapImage.Parent:= Form;
StaticText:= TNewStaticText.Create(Form);
StaticText.Top:= BitmapImage.Top;
StaticText.Left:= BitmapImage.Left + BitmapImage.Width + ScaleX(8)
{Надпись, которая будет отображаться на странице подготовки}
StaticText.Caption := ''#10#13'"______" now preparing to install...';
StaticText.AutoSize:= True;
StaticText.Parent:= Form;
CancelButton:= TButton.Create(Form);
CancelButton.Parent:= Form;
CancelButton.Width:= ScaleX(75);
CancelButton.Height:= ScaleY(23);
CancelButton.Left:= Form.ClientWidth - ScaleX(75 + 10);
CancelButton.Top:= Form.ClientHeight - ScaleY(23 + 10);
CancelButton.Caption:= 'Cancel';
CancelButton.ModalResult:= mrCancel;
CancelButton.Cancel:= True;
Form.Caption:= 'Preparing...';
ProgressBar:= TNewProgressBar.Create(Form);
with ProgressBar do
begin
Height:= CancelButton.Height - ScaleY(8);
Width:= Form.Width - ScaleX(128);
Top:= CancelButton.Top;
Left:= BitmapImage.Left;
Parent:= Form;
Min:= 0;
Max:= 30;
Position:= 0;
end;
Form.ActiveControl:= CancelButton;
Form.Show();
for i:= 0 to 30 do
begin
ProgressBar.Position:= i;
Form.Repaint;
Sleep(400);
i:= i + 2;
end;
finally
Form.Free();
Splash.Close;
Width:= GetSystemMetrics(0);
Height:= GetSystemMetrics(1);
MainForm.Width:= width;
MainForm.Height:= height;
Width:= MainForm.ClientWidth;
Height:= MainForm.ClientHeight;
ExtractTemporaryFile('Image.bmp');
s:= ExpandConstant('{tmp}') + '\Image.bmp';
BackgroundBitmapImage:= TBitmapImage.Create(MainForm);
BackgroundBitmapImage.Bitmap.LoadFromFile(s);
BackgroundBitmapImage.Left:= 0;
BackgroundBitmapImage.Top:= 0;
BackgroundBitmapImage.Width:= width;
BackgroundBitmapImage.Height:= height;
BackgroundBitmapImage.Parent:= MainForm;
BackgroundBitmapImage.Stretch:= True;
{Не забудьте прописать здесь и ниже правильные имена и количество файлов для слайд-шоу!}
ExtractTemporaryFile('1.jpg');
ExtractTemporaryFile('2.jpg');
ExtractTemporaryFile('3.jpg');
ExtractTemporaryFile('4.jpg');
ExtractTemporaryFile('5.jpg');
MainForm.Visible := True;
end;
end;

procedure CurStepChanged(CurStep: TSetupStep);
begin
If CurStep=ssInstall
then
begin
isxbb_AddImage(ExpandConstant('{tmp}')+'\1.jpg',BACKGROUND or TIMER);
isxbb_AddImage(ExpandConstant('{tmp}')+'\2.jpg',BACKGROUND or TIMER);
isxbb_AddImage(ExpandConstant('{tmp}')+'\3.jpg',BACKGROUND or TIMER);
isxbb_AddImage(ExpandConstant('{tmp}')+'\4.jpg',BACKGROUND or TIMER);
isxbb_AddImage(ExpandConstant('{tmp}')+'\5.jpg',BACKGROUND or TIMER);
isxbb_Init(StrToInt(ExpandConstant('{hwnd}')));
{Указывается время отображения на экране каждого изображения}
isxbb_StartTimer(8,BACKGROUND)
end
else
If CurStep=ssPostInstall
then
isxbb_KillTimer(BACKGROUND);
end;

procedure CurPageChanged(CurPageID: Integer);
var
Width, Height: Integer;
begin
If CurPageID=wpInstalling
then
begin
{Здесь размер окна установки уменьшается, с него убирается всё лишнее и оно смещается в нижний правый угол экрана (не зависит от разрешения)}
WizardForm.CancelButton.BringToFront;
WizardForm.MainPanel.Visible:= False;
WizardForm.Bevel1.Visible:= False;
{Размер получaемого окна установки}
Width:= ScaleX(395);
Height:= ScaleY(150);
WizardForm.Left:= GetSystemMetrics(16) - Width - ScaleX(5);
WizardForm.Top:= GetSystemMetrics(17) - Height - ScaleY(-50);
WizardForm.Width:= ScaleX(395);
WizardForm.Height:=ScaleY(150);
WizardForm.InnerNotebook.Left:= ScaleX(10);
WizardForm.InnerNotebook.Top:= ScaleY(10);
WizardForm.InnerNotebook.Width:= ScaleX(370);
WizardForm.StatusLabel.Left:= ScaleX(0);
WizardForm.StatusLabel.Top:= ScaleY(0);
WizardForm.StatusLabel.Width:= WizardForm.InnerNotebook.Width;
WizardForm.FileNameLabel.Left:= ScaleX(0);
WizardForm.FileNameLabel.Top:= ScaleY(20);
WizardForm.FileNameLabel.Width:= WizardForm.InnerNotebook.Width;
WizardForm.ProgressGauge.Top:= ScaleY(40);
WizardForm.ProgressGauge.Width:= WizardForm.InnerNotebook.Width;
WizardForm.CancelButton.Left:= ScaleX(154);
WizardForm.CancelButton.Top:= ScaleY(80);
end
if CurPageID=wpFinished
then
begin
{Окно установки принимает стандартный вид}
WizardForm.Width:=502;
WizardForm.Height:=392;
WizardForm.Position:=poScreenCenter;
end
end;
Как изменить текст на странице завершения вместе с названием кнопки? Можно делать по-разному:
1. Ищем текст, который там выводится в Default.isl (и всех остальных) файлах языков и меняем на свой текст.
2. В файлах языков .isl записывам свое сообщение в [CustomMessages] и потом его используем, подменяя стандартное.

Пример. Открываем нужный языковой файл в формате .isl и находим там интересующий нас текст, перед текстом будет переменная, которая и отвечает за отображаемый текст. Заносим эту переменную в свой скрипт в секцию [Messages]. В итоге будет:
[Messages]
WelcomeLabel2=Твой текст
Как можно сделать, чтобы писались те папки, которые выбраны? Каждую базу со всеми каталогами архивируем, например, в 7z. Будет в результате:
archiv1.7z .... archiv10.7z ... archivN.7z.
7zip тащим с собой в инсталляторе. В инсталляторе разархивируем в temp, а потом тупо через
xcopy /Y /R "что копировать" "куда копировать"
копируем все содержимое.
Как написать информацию в нижнем левом углу (как в инсталляторах ZoneOfGames), и внизу на линии, которая отделяет основное окно от кнопок Назад Далее Отмена
[Messages]
BeveledLabel=Твой текcт
Как сделать подпись (желательно для всех страниц)?
[Messages]
BeveledLabel=Copyright 2007 © Microsoft
Как сделать подпись, но не через BeveledLabel, а созданием нового текста?
[Code]
Var
Text: TNewStaticText;

Procedure InitializeWizard();
begin
Text:=TNewStaticText.Create(WizardForm)
Text.Left:=10
Text.Top:=468
Text.Color:=$dbcdcc
Text.Font.Color:=$ab663d
Text.Caption:='Твой текcт'
Text.Parent:=WizardForm
end;
Как на BeveledLabel "повесить" ссылку, чтобы текст по умолчанию не был подчеркнут, а при наведении на текст, он подчеркивался и конечно, хотелось бы, менять цвет шрифта!
procedure BevelLabelClick(Sender: TObject);
var ErrorCode: Integer;
begin
ShellExec('open','http://www.innosetup.com','', '', SW_SHOW, ewNoWait, ErrorCode)
end;

procedure InitializeWizard();
begin
with WizardForm do begin
with BeveledLabel do begin
OnClick:=@BevelLabelClick;
Font.Color:=clBlue;
Enabled:=True;
Cursor:=crHand;
end;
end;
end;

Доступные цвета: clBlack, clMaroon, clGreen, clOlive, clNavy, clPurple, clTeal, clGray, clSilver, clRed, clLime, clYellow, clBlue, clFuchsia, clAqua, clWhite.
Также цвет можно задавать в RGB, например, Font.Color:=8388608;
Но удобнее в 16-ричном виде, например, Font.Color:=$0000FF00;
т.е. в общем случае $00BBGGRR
где:
BB - уровень синего (от 00 до FF)
GG - уровень зеленого (от 00 до FF)
RR - уровень красного (от 00 до FF)

В ISTool можно определить нужный цвет (Options\Внешний вид\Цвет фона\Custom и выбирай нужный тебе цвет).
Также можно использовать Paint (Colors - Edit Colors - Define Custom Colors) плюс виндовый калькулятор для перевода в hex (Calc.exe - View - Scientific).
Как сделать, чтобы ссылка BeveledLabel меняла цвет при наведении курсора и при нажатии?
[Setup]
AppName=AppName
AppVerName=AppVerName
DefaultDirName={pf}\AppName

[Code]
var
MouseLabel,SiteLabel: TLabel;

procedure SiteLabelOnClick(Sender: TObject);
var
ErrorCode: Integer;
begin
ShellExec('open', 'http://forum.ru-board.com', '', '', SW_SHOWNORMAL, ewNoWait, ErrorCode)
end;

procedure SiteLabelMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
SiteLabel.Font.Color:=clRed
end;

procedure SiteLabelMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
SiteLabel.Font.Color:=clBlue
end;

procedure SiteLabelMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
SiteLabel.Font.Color:=clGreen
end;

procedure SiteLabelMouseMove2(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
SiteLabel.Font.Color:=clBlue
end;

procedure InitializeWizard();
begin
MouseLabel:=TLabel.Create(WizardForm)
MouseLabel.Width:=WizardForm.Width
MouseLabel.Height:=WizardForm.Height
MouseLabel.Autosize:=False
MouseLabel.Transparent:=True
MouseLabel.OnMouseMove:=@SiteLabelMouseMove2
MouseLabel.Parent:=WizardForm

SiteLabel:=TLabel.Create(WizardForm)
SiteLabel.Left:=10
SiteLabel.Top:=330
SiteLabel.Cursor:=crHand
SiteLabel.Font.Color:=clBlue
SiteLabel.Caption:='Forum Ru-Board'
SiteLabel.OnClick:=@SiteLabelOnClick
SiteLabel.OnMouseDown:=@SiteLabelMouseDown
SiteLabel.OnMouseUp:=@SiteLabelMouseUp
SiteLabel.OnMouseMove:=@SiteLabelMouseMove
SiteLabel.Parent:=WizardForm
end;
Как добавить на первой странице в нижнем левом углу надпись? Чтобы внизу слева отображался URL и кнопка, при нажатии которой отображалось нужное сообщение:
[Code]
procedure AboutButtonOnClick(Sender: TObject);
begin
MsgBox('Это демо версия программы.', mbInformation, mb_Ok);
end;

procedure URLLabelOnClick(Sender: TObject);
var
ErrorCode: Integer;
begin
ShellExec('open', 'http://www.innosetup.com', '', '', SW_SHOWNORMAL, ewNoWait, ErrorCode);
end;

procedure InitializeWizard();
var
AboutButton, CancelButton: TButton;
URLLabel: TNewStaticText;
BackgroundBitmapImage: TBitmapImage;
BackgroundBitmapText: TNewStaticText;

begin
CancelButton := WizardForm.CancelButton;
AboutButton := TButton.Create(WizardForm);
AboutButton.Left := WizardForm.ClientWidth - CancelButton.Left - CancelButton.Width;
AboutButton.Top := CancelButton.Top;
AboutButton.Width := CancelButton.Width;
AboutButton.Height := CancelButton.Height;
AboutButton.Caption := '&About...';
AboutButton.OnClick := @AboutButtonOnClick;
AboutButton.Parent := WizardForm;

URLLabel := TNewStaticText.Create(WizardForm);
URLLabel.Caption := 'www.innosetup.com';
URLLabel.Cursor := crHand;
URLLabel.OnClick := @URLLabelOnClick;
URLLabel.Parent := WizardForm;
{ Alter Font *after* setting Parent so the correct defaults are inherited first }
URLLabel.Font.Style := URLLabel.Font.Style + [fsUnderline];
URLLabel.Font.Color := clBlue;
URLLabel.Top := AboutButton.Top + AboutButton.Height - URLLabel.Height - 2;
URLLabel.Left := AboutButton.Left + AboutButton.Width + ScaleX(20);

BackgroundBitmapImage := TBitmapImage.Create(MainForm);
BackgroundBitmapImage.Left := 50;
BackgroundBitmapImage.Top := 100;
BackgroundBitmapImage.AutoSize := True;
BackgroundBitmapImage.Bitmap := WizardForm.WizardBitmapImage.Bitmap;
BackgroundBitmapImage.Parent := MainForm;

BackgroundBitmapText := TNewStaticText.Create(MainForm);
BackgroundBitmapText.Left := BackgroundBitmapImage.Left;
BackgroundBitmapText.Top := BackgroundBitmapImage.Top + BackgroundBitmapImage.Height + ScaleY(8);
BackgroundBitmapText.Caption := 'TBitmapImage';
BackgroundBitmapText.Parent := MainForm;
end;

[LangOptions]
TitleFontSize=100
TitleFontName=Monotype Corsiva
Нужно поменять надпись "Распаковка файлов" при копировании файлов...
Нашёл такую вещь, как "StatusExtractFiles" в секции [Messages], но она делает не совсем то, чего я хочу (например при копировании определённых файлов надпись одна, а при копировании других - другая, а там просто меняется вся надпись)...
[Files]
Source: "{src}\*.exe"; DestDir: {app}; BeforeInstall: ChangeCaption('Откиньтесь на спинку кресла и наслаждайтесь!')
Source: "{src}\*.dll"; DestDir: {app}; BeforeInstall: ChangeCaption('Не забудьте зарегистрироваться')

[Code]
procedure ChangeCaption(str: string);
begin
WizardForm.StatusLabel.Caption:= str;
end;
Можно ли сменить иконку у папки, в которую инсталлируется прога?
[Setup]
AppName=My Program
AppVerName=My Program version 1.5
DefaultDirName={pf}\My Program

[Dirs]
Name: {app}; Attribs: system

[Files]
Source: Files\*; DestDir: {app}

[INI]
Filename: {app}\Desktop.ini; Section: ".ShellClassInfo"; Key: "IconFile"; String: "%SystemRoot%\system32\SHELL32.dll"
Filename: {app}\Desktop.ini; Section: ".ShellClassInfo"; Key: "IconIndex"; String: "27"
Можно ли сменить иконку у деинсталлятора?
[Setup]
UninstallFilesDir={app}\uninst

[Icons]
Name: "{app}\Uninstall My Program"; Filename: "{uninstallexe}"; IconFilename: "aaa.exe"

Т.е. деинсталлятор помещать в отдельную папку, а в папке с программой создавать ярлык на деинсталлятор, которому задавать любую нужную иконку.
Как поменять иконку программе в Панель управления - > Установка и удаление программ? В папку с программой нужно положить icon.ico и включить этот файл в скрипт:
[Setup]
UninstallDisplayIcon={app}\icon.ico

[Files]
Source: C:\icon.ico; DestDir: {app}
Как сделать, чтобы программа отображалась в установке\удалении программ? Из хелпа:
[Setup]: CreateUninstallRegKey
но по умолчанию там yes, надо автоматом.
Как сделать, чтобы после установки программы, она не добавлялась в список "Установка и удаление"? | В секции [Setup] добавь строчку CreateUninstallRegKey=no
Как пользоваться функцией DeleteFile? Довольно просто:
DeleteFile('<путь до файла>\гггг.txt');
Если файл есть, функция вернет TRUE, иначе FALSE. Например:
DeleteFile('C:\Documents and Settings\User\Рабочий стол\гггг.txt');
Как можно сделать, чтобы при нажатии на кнопку Отмена инсталлятор автоматически закрывался без потверждения?
procedure CancelButtonClick(CurPageID: Integer; var Cancel, Confirm: Boolean);
begin
Confirm:=False;
Cancel:=True;
end;
Можно ли перед удалением программы, чтобы выдавало сообщение, типа "Если вы не делали резервные копии файлов, то удаление приведёт к неработоспособности программы. Продолжить?" и кнопки "Да" "Нет". Если нажимаешь "Да", то прога удаляется, а если "Нет", то удаление закрывается? | Используй функцию InitializeUninstall. Смотри тот же пример - UninstallCode. Там перед началом удаления выдается сообщение, такое же можешь применить и ты.
Как сделать, чтобы при удалении проги не удалялись некоторые файлы?
[Files]
Source: "нужный.файл"; DestDir: "{app}"; Flags: uninsneveruninstall
Подскажите плиз, параметр\код, чтобы после деинсталяции не появлялось окошко об окончании удаления программы (кнопка "ОК"), но чтобы осталось окно, когда деинсталлер просит о перезагрузке после деинсталяции (кнопка "ДА" и "НЕТ").
[Setup]
UninstallRestartComputer=yes
Как при деинсталляции сделать дополнительный чекбокс "Удалить сохраненные игры?" (удалить не спрашивая можно в секции [UninstallDelete], но нужен чекбокс)?
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
if CurUninstallStep=usDone then
begin
if DirExists(ExpandConstant('{app}\profiles')) then
begin
if MsgBox('Удалить сохраненные игры?',mbconfirmation, mb_yesno) = IDYES then
begin
DelTree(ExpandConstant('{app}'), True, True, True);
end;
end;
end;
end;
Можно ли сделать, чтобы когда папка будет удалена, выдавалось сообщение, что сохраненные игры были удалены?
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
if CurUninstallStep=usDone then
begin
if DirExists(ExpandConstant('{app}\profiles')) then
begin
if MsgBox('Удалить сохраненные игры?',mbconfirmation, mb_yesno) = IDYES then
begin
DelTree(ExpandConstant('{app}'), True, True, True);
MsgBox('сообщение...', mbinformation, mb_ok);
end;
end;
end;
end;
Как сделать, чтобы при удалении проверялось наличие папки сохранений и, если она есть, то только тогда делать запрос на удаление?
[Registry]
Root: HKLM; SubKey: SOFTWARE\Chuvakstepan\Spider-man3; ValueType: string; ValueName: PathGame; ValueData: {app}; Flags: uninsdeletekey

[Code]
/////////// Удаление игровых сохранений
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
var ResultStr:String;
begin
if CurUninstallStep=usPostUninstall then
begin
RegQueryStringValue(HKLM, 'SOFTWARE\Chuvakstepan\Spider-man3', 'UnInstConfirm', ResultStr)
if DirExists(ExpandConstant('{userdocs}')+'\Activision\Spider-Man 3') then
if MsgBox('Удалить сохраненные игры',mbconfirmation, mb_YesNo) = IDYES then
begin
if not DelTree(ExpandConstant('{userdocs}')+'\Activision\Spider-Man 3', True, True, True)
then
MsgBox('Папка не удалена!' #13#13 'Папка не существует или задействована.', mbError, MB_OK);
end;
end;
end;
Почему, если я пишу при установке:
Source: "D:\foldername\*",
не копируются вложенные в эту директорию папки, а только файлы?
Допиши:
Flags: recursesubdirs createallsubdirs
Можно ли сделать как в последних инсталляторах от 1с (такое ещё у InstallShield), когда после установки игры, если ещё раз хочешь запустить установку автоматом, то запускается деинсталлятор? В секции [Setup] генерируешь appid (например AppID={{0872DB47-24CB-4C7F-AC4B-E6EFC27BD244}),
в секцию добавляешь следущее:
[Code]
var
ResultStr:string;
ResultCode: Integer;

function InitializeSetup(): Boolean;
begin
RegQueryStringValue(HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\{0872DB47-24CB-4C7F-AC4B-E6EFC27BD244}_is1', 'UninstallString', ResultStr)
if ResultStr='' then
begin
Result := True;
end
else
ResultStr:=RemoveQuotes(ResultStr);
Exec(ResultStr, '', '', SW_SHOWNORMAL, ewNoWait, ResultCode)
end;
Помогите написать код, который бы проверял, пустая ли папка, в которую устанавливается программа, и если там что-то есть, то все это удалял. Похоже, штатными средствами этого не сделать, а код на паскале написать не получается.

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

Попробуй следующее:
function InitializeSetup :Boolean;
begin
if DirExists(Name) then
DelTree(Name, True, True, True);
end;

Либо именуй процедуру по-своему, а у первого устанавливаемого файла добавляй в хвосте BeforeInstall
[Files]
Source: "MYPROG.EXE"; DestDir: "{app}"; BeforeInstall: MyBeforeInstall
[Сode]
Procedure MyBeforeInstall;
begin
if DirExists(ExpandConstant('{app}')) then
DelTree(ExpandConstant('{app}'), True, True, True);
end;
Какой функцией удалить все содержимое папки, в которую будет устанавливаться программа? function DelTree(const Path: String; const IsDir, DeleteFiles, DeleteSubdirsAlso: Boolean): Boolean;

// Delete all files and directories inside C:\Test

// but leave the directory itself
DelTree('C:\Test\*', False, True, True);

---
Не работает, он ничего не удаляет в папке перед установкой.
Мне нужно чтобы перед началом распаковки файлов инсталлятор удалил все её содержимое и только после этого начал установку (папка для установки может быть любая - выбирается пользователем).
И как сделать, чтобы после удаления инсталлятора, удалилась папка {app} ?
---
[UninstallDelete]
Type: filesandordirs; Name: "{app}"

[Code]
// в NextButtonClick добавляешь
function NextButtonClick(CurPageID: Integer): Boolean;
begin

//добавить эти строчки
if CurPageID = wpReady then
begin
if DirExists({app}) then DelTree('{app}\*', False, True, True);
end;
//

Result := True;
end;
Есть ли в Inno возможность сделать инсталлятор на русском языке? | В папке inno зайди в папку Languages и перенеси файл Russian.isl в корневую папку inno, переименовав его в Default.isl
Мне нужно, чтобы после установки у меня отображалась информация из ртф файла? | InfoAfterFile=C:\In_update_manual.rtf
Мне надо запустить текстовый документ после установки программы?
[Run]
Filename: speed.txt; Description: Запустить; Flags: shellexec
Есть ли в Inno опция (в идеале ключ в командной строке), с помощью которой можно было бы выключать компьютер после завершения процесса компиляции. Или, хотя бы, как сделать так, чтобы после завершения компиляции завершался и сам процесс. Создай батник примерно такого содержания:

compil32 /cc "c:\isetup\samples\my script.iss"
shutdown -s -f -c "Compilation Finished"

... и запускай на компиляцию через этот батник. Это параметры запуска для автоматической компиляции указанного скрипта. Подробнее смотри в хелпе, раздел Other Information - Command Line Compiler Execution.
Можно ли сделать что-то типа trial ограничения на дистрибутив? Т.е. до определённой даты можно запустить инсталляцию, а после уже нет. | Есть функция GetDateTimeString() - вот ее вызываем в initializesetup и проверяем, что там тебе надо.
Для моего дистрибутива надо, чтобы конечная папка именовалась EARTH 2160. Может, кто подскажет, как это форсировать. DefaultDirName={pf} просто так оставь в секции [Setup], а на всех файлах и папках в секции [Files] ставь {app}\Earth2160

[Files]
Source: files.exe; DestDir: {app}\earth2160
Знаю, что ограничение стоит на 2Гб, но, может, есть какой-нибудь способ обойти это?
DiskSpanning=yes
SlicesPerDisk=1
DiskSliceSize=728760320
Мне нужно на три установленные программы (все три запихнуть в один инсталл) разместить ярлыки по разным местам- на одну программу Ярлык повесить в автозагрузку, а на две другие- просто на рабочий стол. Можно сделать по-разному, например, так:
В отдельной папке создаем файл скрипта, рядом с ним создаем папку files, внутри папки files запишем папки со своими прогами, скомпиленный exe будет лежать в папке Output.

А можно просто указать реальные пути Source в секции [Files].
[Setup]
AppName=SomePrograms
AppVerName=SomePrograms 1.0
DefaultDirName={pf}\SomePrograms
OutputBaseFilename=SomePrograms
Compression=lzma/ultra
InternalCompressLevel=ultra
SolidCompression=yes
DisableReadyPage=yes
ShowLanguageDialog=no

[Languages]
Name: en; MessagesFile: compiler:Default.isl
Name: ru; MessagesFile: compiler:Languages\Russian.isl

[CustomMessages]
en.CreateGroupIcons=Create &Program icons
ru.CreateGroupIcons=Создать значки в Главном меню

[Files]
Source: files\program1\*; DestDir: {app}\program1; Flags: ignoreversion recursesubdirs
Source: files\program2\*; DestDir: {app}\program2; Flags: ignoreversion recursesubdirs
Source: files\program3\*; DestDir: {app}\program3; Flags: ignoreversion recursesubdirs

[Icons]
Name: {userdesktop}\Program1; Filename: {app}\program1\program1.exe; Tasks: desktopicon
Name: {userdesktop}\Program2; Filename: {app}\program2\program2.exe; Tasks: desktopicon
Name: {userstartup}\Program3; Filename: {app}\program3\program3.exe; Tasks: startup

;И по желанию можно добавить ярлыки в Главное меню
;Name: {userprograms}\Program1; Filename: {app}\program1\program1.exe; Tasks: programs
;Name: {userprograms}\Program2; Filename: {app}\program2\program2.exe; Tasks: programs
;Name: {userprograms}\Program2; Filename: {app}\program3\program3.exe; Tasks: programs

[Tasks]
Name: programs; Description: {cm:CreateGroupIcons}; GroupDescription: {cm:AdditionalIcons}
Name: desktopicon; Description: {cm:CreateDesktopIcon}; GroupDescription: {cm:AdditionalIcons}
Name: startup; Description: {cm:CreateQuickLaunchIcon}; GroupDescription: {cm:AdditionalIcons}
Как сделать шифрование инсталлятора? А то скачал файл ISCrypt.dll, а как его использовать не знаю... 1. Файл ISCrypt.dll копируешь в каталог Inno Setup
2. В секцию [Setup] добавляешь:
[Setup]
Encryption=yes
Password=12345
Всё, после компиляции инсталлятор будет зашифрован.
Шифровка инсталлятора, используя модуль ISCrypt.dll Представляю свое решение по шифровке инсталлятора, используя модуль ISCrypt.dll, который доступен для скачивания на оф.сайте. Нужно это для того, чтобы обычный пользователь не смог распаковать инсталлятор посредством распаковщика unnounpacker. Смысл такой: задаем пароль для инсталлятора, который автоматически вставляется в поле ввода и посредством специальной функции сама страница нажимается автоматически. Как это делается:
[Setup]
;Модуль ISCrypt.dll должен быть в папке с компилятором
Encryption=yes
;Пароль сами устанавливаем такой, чтобы никто его не смог подобрать, желательно добавить русские символы и сделать пароль подлиннее
Password=xcvcxhv9-8--fhрлджэ\5(*&Y&&^^()U###$%!^&!^%#^(UJ<:LKJJHGG

[Code]
procedure InitializeWizard();
var
//Определяем поле ввода пароля
PasswordEdit: TPasswordEdit;
begin
//Указываем наш пароль
WizardForm.PasswordEdit.Text := 'xcvcxhv9-8--fhрлджэ\5(*&Y&&^^()U###$%!^&!^%#^(UJ<:LKJJHGG';
end;

//При установке юзер не поймает пароль по маске, который может быть расшифрован специальными утилитами.
//Их у меня нет, но о них я слышал, хотя Inno Setup не позволяет копировать пароль по маске
procedure CurPageChanged(CurPageID: Integer);
begin
If CurPageID=wpPassword then
begin
SendMessage(WizardForm.NEXTBUTTON.Handle, 513, 0, 0)
SendMessage(WizardForm.NEXTBUTTON.Handle, 514, 0, 0)
end;
end;

Имейте в виду, что шифруются только основные файлы.
Кстати, открывал зашифрованный архив плагином для Total Commander и удалось извлечь файл CompiledCode.bin, в котором можно посмотреть пароль. Поэтому рекомендую использовать русские символы в пароле - их (пока) не понимает распаковщик, также, если дальнейшие версии распаковщика будут понимать русский язык - рекомендуется использовать в пароле спец-символы, "крякозябли", ASCII из nfo и т.п.
Невзламываемый экзешник (скомпилировать из этого скрипта):
[Setup]
AppName=My Program
AppVerName=My Program version 1.5
DefaultDirName={pf}\My Program
DefaultGroupName=My Program
Encryption=Yes
Password=7T34Ue(rrT

[Files]
Source: "MyProg.exe"; DestDir: "{app}"

[Code]
function ShouldSkipPage(PageID: Integer): Boolean;
begin
if PageID = wpPassword then Result:= True;
end;
Как добавить строчку, чтобы файлик из папки Windows прихватить и потом при инсталляции туда же его положить, это файл конфигурации программы...
[Files]
Source: {win}\files.dll; DestDir: {win}; Flags: ignoreversion
Можно ли сделать, чтобы один файл запуска,(setup), а файлы для установки с CDROM были набором, не упакованные. | Юзай флаг external в секции [Files] - смотри руководство.
Внешние файлы, не включаемые в упакованный дистрибутив
[Files]
Source: "{src}\data\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs external;

В папке data у нас будет находиться, например, полностью распакованная игра на DVD. При создании инсталлятора распакованные файлы игры не будут включаться в дистрибутив, что позволит создать инсталлятор очень быстро. Флаг external указывает инсталлятору искать внешние файлы для копирования. В сам же инсталлятор по усмотрению и по желанию можем добавить и установку компонентов подобным образом, а также внесение требуемых и/или желаемых данных в реестр, фоновое изображение, проигрывание музыки и прочее. Если хотите копирование жестко привязать к диску, то используйте константу {drive:{src}}. При использовании данной константы путь будет взят исключительно из того диска, откуда запущен инсталлятор, а при использовании обычной {src} путь будет взят из директории, где находится инсталлятор (то, что надо во многих случаях). Такой способ интересен и иногда актуален, когда архивы игры не сжимаются или сжимаются незначительно. Также при должном желании можем установить проверки на присутствие определенных файлов для того, чтобы инсталлятор не позволил копирование при их отсутствии.
Скрипт для распаковки 7z sfx-архива
[Files]
Source: "sfx.exe"; DestDir: "{app}"; AfterInstall: MyAfterInstall; Flags: ignoreversion deleteafterinstall

[Code]
procedure MyAfterInstall();
var
ResultCode: Integer;
begin
begin
Exec(ExpandConstant('{app}\sfx.exe'), '-e -aoa -y', '', SW_SHOWNORMAL, ewWaitUntilTerminated, ResultCode);
end
end;
Примеры составления следующей конструкции:
1)setup.exe (сделанный на inno setup)
2)DATARUS.EXE (сделанный с помощью 7-zip)
И расположен sfx архив не внутри, а снаружи.
[Components]
Name: "eng"; Description: "Английская версия"; Flags: exclusive
Name: "rus"; Description: "Русская версия"; Flags: exclusive

[Types]
Name: "custom"; Description: "Выборочная установка"; Flags: iscustom

[Files]
Source: "D:\NFS - Most Wanted\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs
Components: rus; Source: "{src}\Rus\NFSMWRUS.exe"; DestDir: "{app}"; Flags: ignoreversion external deleteafterinstall

[Run]
Filename: "{app}\NFSMWRUS.exe"; WorkingDir: "{app}"; Parameters: "-y"; StatusMsg: "Процесс руссификации..."; Flags: waituntilterminated skipifdoesntexist

----
new.exe -x -y -o C:\TEMP - распакует архив в C:\TEMP без лишних вопросов.
Отдельные извращенцы могут использовать команду SUBST.

---

[Run]
Filename: "{src}\GAME\NFSMW.exe"; WorkingDir: "{src}\GAME"; Parameters: "-y -o""{app}"""; Flags: waituntilterminated

Следовательно, передаем архиву путь для распаковки, выбранный при установке, причем с параметром -y, который, как должно быть известно, отвечает за "тихую" установку, т.е. по умолчанию распаковывает и перезаписывает файлы без запроса. Как показано на примере, файл sfx-архива должен содержать, например, все файлы игры. Причем в секции [Files] этот архив указывать не нужно, можно вообще эту секцию не указывать в скрипте, хотя если вы юзаете дополнительные файлы (руссификация, требуемые системные библиотеки и др.), то их как обычно нужно указать в секции [Files]. С одной стороны, очень даже неплохая реализация установки, 7-zip, признаться, хоть на чуток, но лучше сжимает, чем Inno.

Есть приличные руссификаторы на ZoneOfGames. Так вот, не надо пытаться вскрывать технологию упаковки и процесса руссификации. Инсталляторы защищены от распаковки автораспаковщиком, и глюков при установке и удалении руссификатора не наблюдается. И зачем нам перепаковывать файлы оригинальной руссификации, если их и так можно установить, при этом все копирайты сохраняются:

[Run]
Filename: "{src}\Rus\NfSCarbon.exe"; WorkingDir: "{src}\Rus"; Parameters: "/silent /nocancel /DIR=""{app}"""; Flags: waituntilterminated skipifdoesntexist

В этом случае будет произведена тихая установка руссификации с сохранением резервных копий англоязычных файлов, причем с возможностью их обратного восстановления. Не забываем указать флаг skipifdoesntexist, если запускаемый файл является "выбираемым" при установке. Конечно, лучше реализовать это через секцию [Code], в которой можно указать запуск руссификатора в зависимости от выбранных компонентов, а также создать дополнительный ярлык для удаления руссификации отдельно. Но есть одна проблема...

Все вышеописанное с многочисленными параметрами реализовать в секции [Code] у меня пока не получилось, если вообще возможно, загвоздку составляют параметры. Как известно, в секции [Code] константа {app} имеет вид: ExpandConstant('{app}'). Сильно не экспериментировал, но не получается передать путь для распаковки таким образом, компилятор выдает ошибки, или распаковывает в неверную папку.

В предыдущем случае было реализовано через секцию [Code], здесь - через секцию [Run]: В секции [Run] это тоже можно реализовать, используя параметр Components. Например:
[Types]
Name: "full"; Description: "Full installation"
Name: "compact"; Description: "Compact installation"
Name: "custom"; Description: "Custom installation"; Flags: iscustom

[Components]
Name: "program"; Description: "Program Files"; Types: full compact custom; Flags: fixed
Name: "help"; Description: "Help File"; Types: full
Name: "readme"; Description: "Readme File"; Types: full
Name: "readme\en"; Description: "English"; Flags: exclusive
Name: "readme\ru"; Description: "Russian"; Flags: exclusive

[Run]
Filename: "{src}\Rus\NfSCarbon.exe"; WorkingDir: "{src}\Rus"; Parameters: "/silent /nocancel /DIR=""{app}"""; Components: readme\ru; Flags: waituntilterminated skipifdoesntexist
Как в инсталляторе сделать самораспаковку 7z SFX, секция run не подходит. Нужно, чтобы инсталлятор скопировал самораспаковку, распаковал, удалил её, и только после этого дораспаковывал остальные файлы.
[Setup]
AppName=AppName
AppVerName=AppVerName
DefaultDirName={pf}\My Program

[Files]
Source: Archive.exe; DestDir: {app}; AfterInstall: Unpack(); Flags: ignoreversion
Source: Files\*; DestDir: {app}

[Code]
procedure Unpack();
var
ResultCode: Integer;
begin
Exec(ExpandConstant('{app}\Archive.exe'), '', '', SW_HIDE, ewWaitUntilTerminated, ResultCode);
DeleteFile(ExpandConstant('{app}\Archive.exe'));
end;
Как сделать, чтобы инсталлятор при запуске проверял наличие NET FrameWork и если его не находит, то выводит сообщение типа "NET FrameWork не найден! Продолжить установку?" и кнопки "Да" и "Нет"?
#Include не предлагать...
function InitializeSetup(): Boolean;
begin
Result:=True;
begin
if not RegKeyExists(HKLM, 'SOFTWARE\Microsoft\NET Framework Setup\NDP\v1.1.4322')
or not RegKeyExists(HKLM, 'SOFTWARE\Microsoft\NET Framework Setup\NDP\v2.0.50727')
then
begin
if MsgBox('Attention! On your computer is not found required packages of Microsoft .NET Framework 1.1 or Microsoft .NET Framework 2.0 or both their.'#13#13'Do you want to continue?', mbError, MB_YESNO) = idNo
then
Result:=False;
end;
end;
end;
Надо сделать на странице выбора директории кнопочку "Сброс". Смысл её таков: путь установки по умолчанию, скажем, такой C:\My Company\My Program, а пользователя, допустим, он не устраивает и он выбирает такой путь D:\My Company\My Program, но потом вдруг передумывает и решает всё-таки использовать первоначальный путь. Так вот, чтобы ему самому ничего не пришлось менять и пригодилась бы кнопочка "Сброс". Нажимаешь на неё, и она возвращает путь по умолчанию.
[Setup]
AppName=My Program
AppVerName=My Program version 1.5
DefaultDirName={pf}\My Program

[Files]
Source: Files\*; DestDir: {app}

[Code]
var
RestoreDir: TButton;

procedure ButtonOnClick(Sender: TObject);
begin
WizardForm.DirEdit.Text:= ExpandConstant('{pf}\My Program');
end;

procedure InitializeWizard();
begin
RestoreDir:= TButton.Create(WizardForm);
RestoreDir.Width := WizardForm.DirBrowseButton.Width;
RestoreDir.Height := WizardForm.DirBrowseButton.Height;
RestoreDir.Top := WizardForm.DirBrowseButton.Top + RestoreDir.Height + ScaleX(10);
RestoreDir.Left := WizardForm.DirBrowseButton.Left;
RestoreDir.OnClick := @ButtonOnClick;
RestoreDir.Parent := WizardForm.SelectDirPage;
RestoreDir.Visible:= True;
RestoreDir.Caption := 'Restore Path';
end;
Закрытие окна без предупреждения и проверка на присутствие файла
function NextButtonClick(CurPage: Integer): Boolean;
var
sz:Integer;
s:string;
h:Longint;
begin
Result:=True;
If CurPage=1
then
begin
h:=FindWindowByClassName('My-Program-WINDOW');
If h<>0 then
SendMessage(h, 16, 0, 0); //Вот это и есть закрытие программы
end
else
If CurPage=6 then
//Проверка присутствия определенных файлов в папке с установленной программой на странице выбора папки назначения
begin
If (FileSearch('Main.exe', ExpandConstant('{app}'))='') //ищем файл [Main.exe] в папке {app}.
then
begin
s:='Извините, в директории '+ExpandConstant('{app}')+'' #13 'не обнаружены файлы, подтверждающие подлинность программы.' #13#13 'Пожалуйста, выберите правильный путь для установки обновления.';
MsgBox(s, mbError, mb_Ok);
Result:= False
end;
end;
end;
У меня есть программа: му.ехе. Я её хочу обновить при помощи инсталлятора, т.е. у меня в инсталляторе содержится новая версия му.ехе. Если я её распакую, когда старая запущена, то прога не обновится, типа, невозможно переписать файл. Вот я и хочу, чтобы инсталлятор при запуске проверял, открыта ли прога му.ехе, и если открыта, то выдавать предупреждение, типа, программа сейчас работает, необходимо закрыть её перед обновлением. Закрыть? Да\Нет.
[Setup]
AppName=My Program
AppVerName=My Program version 1.5
DefaultDirName={pf}\My Program
DefaultGroupName=My Program

[Files]
Source: ISTask.dll; DestDir: {tmp}; Flags: dontcopy

[Code]
function KillTask(ExeFileName: string): Integer;
external 'KillTask@files:ISTask.dll stdcall delayload';
function RunTask(FileName: string; bFullpath: Boolean): Boolean;
external 'RunTask@files:ISTask.dll stdcall delayload';

//**************************************************//
function InitializeSetup(): Boolean;
begin
If RunTask('calc.exe', false) then
begin
if MsgBox('Close My Program?', mbInformation, mb_YesNo) = idYes then
begin
KillTask('calc.exe');
Result:= True;
end else
Exit;
end;
Result:=True;
end;
Как создать резервную копию во время установки, и кнопку перед установкой "Создать резервную копию оригинальных файлов" с галочкой?
[Setup]
AppName=My Program
AppVerName=My Program version 1.5
DefaultDirName={pf}\My Program
Compression=lzma
SolidCompression=yes
Uninstallable=no

[Tasks]
Name: arc; Description: "Create backup"

[Files]
Source: Files\*.*; DestDir: {app}; BeforeInstall: CreateBackup

[Code]
var
Page: TInputDirWizardPage;
ArcDir: String;

procedure CreateBackup();
var
SrcFile, DestFile: string;
begin
if IsTaskSelected('arc') then
begin
// if Not DirExists(ArcDir) then CreateDir(ArcDir);
ForceDirectories(ArcDir); // исправлено
SrcFile:= AddBackslash(ExpandConstant('{app}')) + ExtractFileName(CurrentFileName);
DestFile:= AddBackslash(ArcDir) + ExtractFileName(CurrentFileName);
FileCopy(SrcFile, DestFile, False);
end;
end;

function NextButtonClick(CurPageID: Integer): Boolean;
begin
If (CurPageID = Page.ID) then
ArcDir := Page.Values[0];
Result:= True;
end;

function ShouldSkipPage(PageID: Integer): Boolean;
begin
If (PageID = Page.ID) and
(Not IsTaskSelected('arc')) then
Result:= True
else Result:= False;
end;

procedure InitializeWizard();
begin
Page:= CreateInputDirPage(wpSelectTasks, 'Select Backup Location',
'Where should backup files be stored?',
'To continue, click Next.' + #10#13#10#13 +
'If you would like to select a different folder, click Browse.',
False, 'Backup');
Page.Add('');
//Page.Values[0] := ExpandConstant('{sd}\Backup');
Page.Values[0] := AddBackslash(ExpandConstant('{sd}\Backup')) +
GetDateTimeString('yyyy/mm/dd hh:nn', '_', '.' ); // исправлено
end;
Мне надо, чтобы инсталлятор заменил оригинальный файл (например, myprog1.exe) на такой же, но только обновленный, и во время установки в директории программы была сразу создана папка "Backup_Files" (т.е. у пользователя инсталлятор не должен спрашивать ни название папки, ни где размещать ее, а нужно, чтобы инсталлятор создавал все сам автоматически).
[Setup]
AppName=My Program
AppVerName=My Program version 1.5
DefaultDirName={pf}\My Program
Compression=lzma
SolidCompression=yes
Uninstallable=no

[Files]
Source: Files\*.*; DestDir: {app}; BeforeInstall: CreateBackup

[Code]
var
ArcDir: String;

procedure CreateBackup();
var
SrcFile, DestFile: string;
begin
ArcDir:= AddBackslash(ExpandConstant('{app}\Backup')) +
GetDateTimeString('yyyy/mm/dd hh:nn', '_', '.' );
ForceDirectories(ArcDir);
SrcFile:= AddBackslash(ExpandConstant('{app}')) + ExtractFileName(CurrentFileName);
DestFile:= AddBackslash(ArcDir) + ExtractFileName(CurrentFileName);
FileCopy(SrcFile, DestFile, False);
end;

---
Кусочек еще одного скрипта на эту тему:

[Files]
Source: "{app}\Some.file"; DestDir: "{app}\Backup_Files"; Flags: uninsneveruninstall skipifsourcedoesntexist overwritereadonly ignoreversion external;
Как сделать, чтобы при перезаписи оригинальных файлов создавались их резервные копии?
[Components]
Name: "Backup"; Description: "Backup"; Types: full

[Files]
Components: Backup; Source: "MyProg.exe"; DestDir: "{app}"; Flags: ignoreversion; Check: MyProgCheck

[Code]
function MyProgCheck():boolean;
var
s1, s2:string;
begin
Result:=True;
s1:=ExpandConstant('{app}')+'\MyProg.exe';
s2:=ExpandConstant('{app}')+'\Backup';
If FileExists(s1) then
begin
CreateDir(s2);
FileCopy(s1, s2+'\MyProg.exe', False);
end;
end;
Создание резервной копии
procedure CurStepChanged(CurStep: TSetupStep);
begin
if IsTaskSelected('backup') then
if CurStep = ssInstall then
begin
CopyFiles(ExpandConstant('{app}\Data\'),ExpandConstant('{app}\Backup'),('movies000.dat'));
end;
end;

procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
if CurUninstallStep = usPostUninstall then
begin
MoveFiles(ExpandConstant('{app}\Backup\'),ExpandConstant('{app}\Data\'),('movies000.dat'));
RemoveDir(ExpandConstant('{app}\Backup'));
end;
end;
Пример скрипта, автоматически создающего бэкапы в папки с именем по дате/времени. Кол-во бэкапов задается в скрипте. При превышении кол-ва, самые старые будут удалены.
#define MaxBackup 3

[Setup]
AppName=My Program
AppVerName=My Program version 1.5
DefaultDirName={pf}\My Program
Compression=lzma
SolidCompression=yes
Uninstallable=no

[Files]
Source: Files\*.*; DestDir: {app}; BeforeInstall: CreateBackup

[Code]
var
ArcDir: String;
DirNames: TStringList;

procedure CreateBackup();
var
SrcFile, DestFile: string;
begin
ArcDir:= AddBackslash(ExpandConstant('{app}\Backup')) +
GetDateTimeString('yyyy/mm/dd hh:nn', '_', '.' );
ForceDirectories(ArcDir);
SrcFile:= AddBackslash(ExpandConstant('{app}')) + ExtractFileName(CurrentFileName);
DestFile:= AddBackslash(ArcDir) + ExtractFileName(CurrentFileName);
FileCopy(SrcFile, DestFile, False);
end;

procedure GetBackupCount();
var
FindRec: TFindRec;
begin
if FindFirst(ExpandConstant('{app}\Backup\*'), FindRec) then begin
try
DirNames:= TStringList.Create();
DirNames.Sorted:= True;
repeat
if (FindRec.Attributes = FILE_ATTRIBUTE_DIRECTORY) and
(FindRec.Name <> '.') and (FindRec.Name <> '..') then
begin
DirNames.Append(FindRec.Name);
end;
until not FindNext(FindRec);
finally
FindClose(FindRec);
end;
end;
end;

procedure CurStepChanged(CurStep: TSetupStep);
var
i: integer;
begin
if CurStep = ssInstall then
begin
GetBackupCount();
if DirNames.Count >= StrToInt(ExpandConstant('{#MaxBackup}')) then
begin
for i:= DirNames.Count - StrToInt(ExpandConstant('{#MaxBackup}')) downto 0 do
begin
DelTree(ExpandConstant('{app}\Backup\') + DirNames[i], True, True, True);
end;
end;
end;
end;
Как сделать копию файла, к имени которого необходимо добавить дату и время создания копии?
[Setup]
AppName=AppName
AppVerName=AppVerName
DefaultDirName={pf}\My Program

[Files]
Source: Files\*; DestDir: {app}; BeforeInstall: CreateBackup()

[Code]
procedure CreateBackup();
begin
if FileExists(ExpandConstant(CurrentFileName)) then
FileCopy(ExpandConstant(CurrentFileName),
ExpandConstant('{app}\') +
GetDateTimeString('dd/mm/yyyy hh:nn:ss ', '-', '-') +
ExtractFileName(ExpandConstant(CurrentFileName)), True)
end;
Проблема заключается в том, что после удаления, файлы из папки "Install_Rus\Backup" перемещаются обратно. Это ВСЕ правильно, НО также после удаления ОСТАЮТСЯ эти папки "Install_Rus\Backup", при том, что еще в папке "Backup" остается и оригинальный файл, а мне бы хотелось, чтобы этих папок НЕ было (Install_Rus\Backup\Some_name.exe) после удаления.
DeleteFile(ExpandConstant('{app}')+'\Install_Rus\Backup\Some_name.exe')
RemoveDir(ExpandConstant('{app}')+'\Install_Rus\Backup')
RemoveDir(ExpandConstant('{app}')+'\Install_Rus)

---
А в чем проблема? Помимо функции в SHFileOperation.iss, Inno имеет несколько встроенных функций для удаления папок. Например:
#include "SHFileOperation.iss"

[Setup]
AppName=My Program
AppVerName=My Program version 1.5
DefaultDirName={pf}\My Program
DisableProgramGroupPage=yes

[Files]
Source: Files\*.*; DestDir: {app}; Flags: ignoreversion recursesubdirs

[Code]
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssInstall then
begin
CopyDir(ExpandConstant('{app}\'),ExpandConstant('{app}\Backup'));
// или
// MoveDir(ExpandConstant('{app}\'),ExpandConstant('{app}\Backup'));
end;
end;

procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
if CurUninstallStep = usPostUninstall then
begin
MoveDir(ExpandConstant('{app}\Backup\'),ExpandConstant('{app}'));
// RemoveDir удалит только, если папка пустая
RemoveDir(ExpandConstant('{app}\Backup'));
// DelTree использовать не рекомендуется,
// так как будут удалены все вложенные папки!
// DelTree(ExpandConstant('{app}\Backup'), True, True, True);
end;
end;
Возможность копирования\перемещения ФАЙЛОВ
[Files]
Source: "{app}\SomeFile_1.file"; DestDir: "{app}\Backup"; Flags: uninsneveruninstall skipifsourcedoesntexist overwritereadonly ignoreversion external; BeforeInstall: HideInstallPath;
Source: "{app}\SomeFile_2.file"; DestDir: "{app}\Backup"; Flags: uninsneveruninstall skipifsourcedoesntexist overwritereadonly ignoreversion external; AfterInstall: ShowInstallPath;

[Messages]
StatusExtractFiles=Создание конфигурационных файлов...

[Code]
procedure InitializeWizard();
begin
WizardForm.FileNameLabel.Visible:= False;
end;
В этом скрипте при инсталляции в бэкап сохраняются (перемещением) только те файлы, которые инсталлятор заменяет. При удалении, эти же файлы восстанавливаются (тоже перемещением).
Хотя лично мне, перемещение файлов при бэкапе не очень нравится. Да, так быстрее (особенно если файлы большие). Но если в процессе инсталляции что-то рухнет, то есть риск потерять один или несколько файлов.
#include "SHFileOperation.iss"

[Setup]
AppName=My Program
AppVerName=My Program version 1.5
DefaultDirName={pf}\My Program
DisableProgramGroupPage=yes

[Files]
Source: Files\*.*; DestDir: {app}; Flags: ignoreversion recursesubdirs; BeforeInstall: CreateBackup

[Code]
function MoveFile(const srcFile, destFile: PChar):Integer;
external 'MoveFileA@kernel32.dll stdcall';

procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
if CurUninstallStep = usPostUninstall then
begin
MoveDir(ExpandConstant('{app}\Backup\'),ExpandConstant('{app}'));
RemoveDir(ExpandConstant('{app}\Backup\'));
end;
end;

procedure CreateBackup;
var
srcFile, destFile: string;
basePath, shortPath: string;
begin
basePath:= ExpandConstant('{app}');
srcFile:= ExpandConstant(CurrentFileName);
shortPath:= srcFile;
StringChangeEx(shortPath, basePath, '', True);
destFile:= ExpandConstant('{app}\Backup') + shortPath;
ForceDirectories(ExtractFilePath(destFile));
MoveFile(PChar(srcFile), PChar(destFile));
end;
А можно ли сделать, чтобы файлы никуда не перемещались, а переименовались? Например, в MyProg.exe.bak Сохранять просто. Достаточно изменить процедуру CreateBackup :
procedure CreateBackup;
var
srcFile, destFile: string;
begin
srcFile:= ExpandConstant(CurrentFileName);
destFile:= srcFile + '.bak';
MoveFile(PChar(srcFile), PChar(destFile));
end;

А вот для восстановления при деинсталляции, придется прописывать отдельную процедуру.
Полный скрипт, в котором бэкап выполняется переименованием файлов (только тех, которые меняются) в *.bak, а при деинсталляции, файлы восстанавливаются обратным переименованием. Никаких проверок на корректность операций нет. Добавляй сам.
[Setup]
AppName=My Program
AppVerName=My Program version 1.5
DefaultDirName={pf}\My Program
DisableProgramGroupPage=yes

[Files]
Source: Files\*.*; DestDir: {app}; Flags: ignoreversion recursesubdirs; BeforeInstall: CreateBackup

[Code]
procedure CreateBackup;
var
srcFile, destFile: string;
begin
srcFile:= ExpandConstant(CurrentFileName);
destFile:= srcFile + '.bak';
DeleteFile(destFile);
RenameFile(srcFile, destFile);
end;

procedure RestoreBackup(backupDir: string);
var
srcFile, destFile: string;
FSR, DSR: TFindRec;
FindResult: Boolean;
APath: string;
begin
APath := AddBackslash(backupDir);
FindResult := FindFirst(APath + '*.bak', FSR);
try
while FindResult do
begin
if FSR.Attributes and FILE_ATTRIBUTE_DIRECTORY = 0 then
begin
srcFile:= APath + FSR.Name;
destFile:= Copy(srcFile, 0, Length(srcFile)-4);
DeleteFile(destFile);
RenameFile(srcFile, destFile);
end;
FindResult := FindNext(FSR);
end;
FindResult := FindFirst(APath + '*.*', DSR);
while FindResult do
begin
if ((DSR.Attributes and FILE_ATTRIBUTE_DIRECTORY) = FILE_ATTRIBUTE_DIRECTORY) and
not ((DSR.Name = '.') or (DSR.Name = '..')) then
{Recursion} RestoreBackup(APath + DSR.Name);
FindResult := FindNext(DSR);
end;
finally
FindClose(FSR);
FindClose(DSR);
end;
end;

procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
if CurUninstallStep = usPostUninstall then
begin
RestoreBackup(ExpandConstant('{app}'))
end;
end;
Как сделать, чтобы переименование файлов в ‘bak’, происходило только в том случае, если на странице доп. задачи (Tasks) пользователь отметил "Создать резервную копию оригинальных файлов"? | IsTaskSelected (см.в хелпе)
В секции [Files] прописан файл. В случае, если у пользователя такой файл есть, он переименовывается и ставится новый.
[Files]
Source: "{app}\my_program.exe"; DestDir: "{app}"; DestName: "my_program.exe.bak"; Flags: external skipifsourcedoesntexist
;Старый файл который будет переименован
Source: "C:\my_program.exe"; DestDir: "{app}"; Flags: ignoreversion
;Новый файл
Как сделать, чтобы резервировался ini-файл (при отработке секции [INI])? Так как BeforeInstall: CreateBackup в данном случае не работает (при установке вылетает ошибка). В этом варианте можно передавать имя файла как параметр:
[Setup]
AppName=My Program
AppVerName=My Program ver.1.5
DefaultDirName={pf}\My Program

[INI]
Filename: "{app}\MyProg.ini"; Section: "InstallSettings"; Flags: uninsdeletesection; BeforeInstall: CreateBackup('{app}\MyProg.ini')
Filename: "{app}\MyProg.ini"; Section: "InstallSettings"; Key: "InstallPath"; String: "{app}"

...
procedure CreateBackup(filename: string);
var
srcFile, destFile: string;
basePath, shortPath: string;
begin
basePath:= ExpandConstant('{app}');
srcFile:= ExpandConstant(filename);
shortPath:= srcFile;
StringChangeEx(shortPath, basePath, '', True);
destFile:= ExpandConstant('{app}\Backup') + shortPath;
ForceDirectories(ExtractFilePath(destFile));
FileCopy(PChar(srcFile), PChar(destFile), False);
end;
Вопрос по поводу перемещения папок (не копирования) средствами Inno Setup. Как перемещать средствами Inno не знаю, но средствами самой операционки можно.
Чуть ниже вставлен скрипт(SHFileOperation.iss), можно сохранить его в файл и этот файл включить в свой проект (директивой #include "SHFileOperation.iss").
После этого появится возможность использовать 4 функции:
function CopyDir(const fromDir, toDir: string): Boolean;
function MoveDir(const fromDir, toDir: string): Boolean;
function DelDir(dir: string; toRecycle: Boolean): Boolean;
function RenameDir(const fromDir, toDir: string): Boolean;

В скрипте есть краткое описание, но хочу обратить внимание, что в функциях CopyDir и MoveDir есть зависимость от того, указана ли fromDir со слешем или без. В первом случае в toDir будет скопировано/перемещено только содержимое fromDir со всеми файлами у подпапками; во втором, в toDir будет скопирована/перемещена сама fromDir со всеми файлами и подпапками.

DelDir может удалять совсем или в корзину (в зависимости от флага toRecycle).
В случае, если кто-то удалит папку Windows, претензии не принимаются.

Небольшой пример использования SHFileOperation.iss для бекапа:

#include "SHFileOperation.iss"

[Setup]
AppName=My Program
AppVerName=My Program version 1.5
DefaultDirName={pf}\My Program
DisableProgramGroupPage=yes

[Files]
Source: Files\*.*; DestDir: {app}; Flags: ignoreversion recursesubdirs

[Code]
procedure CurStepChanged(CurStep: TSetupStep);
begin
if CurStep = ssInstall then
begin
CopyDir(ExpandConstant('{app}\'),ExpandConstant('{app}\Backup'));
end;
end;

procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
if CurUninstallStep = usPostUninstall then
begin
CopyDir(ExpandConstant('{app}\Backup\'),ExpandConstant('{app}'));
end;
end;

Код (полный):
;***************************************************************;
;****************** SHFileOperation.iss ************************;
;***************************************************************;
;* Include this file in project. Example:
;* #include "SHFileOperation.iss"
;***************************************************************;
;************************ 1 ************************************;
;* function CopyDir(const fromDir, toDir: string): Boolean;
;* Example 1 (without <fromDir> trailing backslash):
;* CopyDir('C:\TMP\MyApp', 'C:\TMP\Backup');
;* Result: C:\TMP\Backup\MyApp\..all <MyApp> subdirs and files
;* Example 2 (with <fromDir> trailing backslash):
;* CopyDir('C:\TMP\MyApp\', 'C:\TMP\Backup');
;* Result: C:\TMP\Backup\..all <MyApp> subdirs and files
;***************************************************************;
;************************ 2 ************************************;
;* function MoveDir(const fromDir, toDir: string): Boolean;
;* Example 1 (without <fromDir> trailing backslash):
;* MoveDir('C:\TMP\MyApp', 'C:\TMP\Backup');
;* Result: C:\TMP\Backup\MyApp\..all <MyApp> subdirs and files
;* Example 2 (with <fromDir> trailing backslash):
;* MoveDir('C:\TMP\MyApp\', 'C:\TMP\Backup');
;* Result: C:\TMP\Backup\..all <MyApp> subdirs and files
;***************************************************************;
;************************ 3 ************************************;
;* function DelDir(dir: string; toRecycle: Boolean): Boolean;
;* If <toRecycle> is True, <dir> deleted in Recycle Bin.
;***************************************************************;
;************************ 4 ************************************;
;* function RenameDir(const fromDir, toDir: string): Boolean;
;***************************************************************;
;***************************************************************;
;***************************************************************;

[Code]
type
TSHFileOpStruct = record
Wnd: HWND;
wFunc: UINT;
pFrom: PChar;
pTo: PChar;
fFlags: Word; // FILEOP_FLAGS;
fAnyOperationsAborted: BOOL;
hNameMappings: HWND; // Pointer;
lpszProgressTitle: PChar; { only used if FOF_SIMPLEPROGRESS }
end;

const
// use in wFunc
{ $EXTERNALSYM FO_MOVE }
FO_MOVE = $0001;
{ $EXTERNALSYM FO_COPY }
FO_COPY = $0002;
{ $EXTERNALSYM FO_DELETE }
FO_DELETE = $0003;
{ $EXTERNALSYM FO_RENAME }
FO_RENAME = $0004;
// use in fFlags
{ $EXTERNALSYM FOF_MULTIDESTFILES }
FOF_MULTIDESTFILES = $0001;
{ $EXTERNALSYM FOF_CONFIRMMOUSE }
FOF_CONFIRMMOUSE = $0002;
{ $EXTERNALSYM FOF_SILENT }
FOF_SILENT = $0004; { don't create progress/report }
{ $EXTERNALSYM FOF_RENAMEONCOLLISION }
FOF_RENAMEONCOLLISION = $0008;
{ $EXTERNALSYM FOF_NOCONFIRMATION }
FOF_NOCONFIRMATION = $0010; { Don't prompt the user. }
{ $EXTERNALSYM FOF_WANTMAPPINGHANDLE }
FOF_WANTMAPPINGHANDLE = $0020; { Fill in
SHFILEOPSTRUCT.hNameMappings
Must be freed using
SHFreeNameMappings }
{ $EXTERNALSYM FOF_ALLOWUNDO }
FOF_ALLOWUNDO = $0040;
{ $EXTERNALSYM FOF_FILESONLY }
FOF_FILESONLY = $0080; { on *.*, do only files }
{ $EXTERNALSYM FOF_SIMPLEPROGRESS }
FOF_SIMPLEPROGRESS = $0100; { means don't show names of files }
{ $EXTERNALSYM FOF_NOCONFIRMMKDIR }
FOF_NOCONFIRMMKDIR = $0200; { don't confirm making any
needed dirs }
{ $EXTERNALSYM FOF_NOERRORUI }
FOF_NOERRORUI = $0400; { don't put up error UI }

function SHFileOperation(const lpFileOp: TSHFileOpStruct):Integer;
external 'SHFileOperation@shell32.dll stdcall';

{****************************************************************}
{****************************************************************}
{****************************************************************}

function BackupDir(const fromDir, toDir: string; IsMove: Boolean): Boolean;
var
fos: TSHFileOpStruct;
_fromDir, _toDir: string;
SR: TFindRec;
res: Boolean;
begin
ForceDirectories(toDir);
if IsMove then
fos.wFunc := FO_MOVE else
fos.wFunc := FO_COPY;
fos.fFlags := FOF_FILESONLY or FOF_SILENT or
FOF_NOCONFIRMATION or FOF_NOCONFIRMMKDIR;
_fromDir:= AddBackslash(fromDir);
_toDir := AddBackslash(toDir);
if (Length(fromDir) = Length(_fromDir)) then
begin
res:= FindFirst(_fromDir + '*', SR);
try
while res do
begin
if (SR.Name <> '') and (SR.Name <> '.') and (SR.Name <> '..') then
begin
if SR.Attributes = FILE_ATTRIBUTE_DIRECTORY then
begin
_fromDir:= _fromDir + SR.Name + #0#0;
_toDir := _toDir + #0#0;
fos.pFrom := PChar(_fromDir);
fos.pTo := PChar(_toDir);
end else
begin
_fromDir:= _fromDir + SR.Name + #0#0;
_toDir := _toDir + SR.Name + #0#0;
fos.pFrom := PChar(_fromDir);
fos.pTo := PChar(_toDir);
end;
Result := (0 = ShFileOperation(fos));
_fromDir:= ExtractFilePath(_fromDir);
_toDir:= ExtractFilePath(_toDir);
end;
res := FindNext(SR);
end;
finally
FindClose(SR);
end;
end else
begin
_fromDir:= RemoveBackslashUnlessRoot(_fromDir) + #0#0;
_toDir := RemoveBackslashUnlessRoot(_toDir) + #0#0;
fos.pFrom := PChar(_fromDir);
fos.pTo := PChar(_toDir);
Result := (0 = ShFileOperation(fos));
end;
end;

{****************************************************************}
function MoveDir(const fromDir, toDir: string): Boolean;
begin
Result := BackupDir(fromDir, toDir, True);
end;

{****************************************************************}
function CopyDir(const fromDir, toDir: string): Boolean;
begin
Result := BackupDir(fromDir, toDir, False);
end;

{****************************************************************}
function DelDir(dir: string; toRecycle: Boolean): Boolean;
var
fos: TSHFileOpStruct;
_dir: string;
begin
_dir:= RemoveBackslashUnlessRoot(dir) + #0#0;
fos.wFunc := FO_DELETE;
fos.fFlags := FOF_SILENT or FOF_NOCONFIRMATION;
if toRecycle then
fos.fFlags := fos.fFlags or FOF_ALLOWUNDO;
fos.pFrom := PChar(_dir);
Result := (0 = ShFileOperation(fos));
end;

{****************************************************************}
function RenameDir(const fromDir, toDir: string): Boolean;
var
fos: TSHFileOpStruct;
_fromDir, _toDir: string;
begin
_fromDir:= RemoveBackslashUnlessRoot(fromDir) + #0#0;
_toDir := RemoveBackslashUnlessRoot(toDir) + #0#0;
fos.wFunc := FO_RENAME;
fos.fFlags := FOF_FILESONLY or FOF_ALLOWUNDO or
FOF_SILENT or FOF_NOCONFIRMATION;
fos.pFrom := PChar(_fromDir);
fos.pTo := PChar(_toDir);
Result := (0 = ShFileOperation(fos));
end;
{****************************************************************}
{****************************************************************}
{****************************************************************}
Пример написания выбора установки (например, русской версии игрушки) через RadioButton
[Files]
;Основные файлы
Source: "Work\*.*"; DestDir: "{app}"; Flags: ignoreversion overwritereadonly
;Файлы руссификатора игры
Source: "Russian\*.*"; DestDir: "{app}"; Check: Russian; Flags: ignoreversion overwritereadonly

[Code]
var
RussianBtn, EnglishBtn: TRadioButton;
ResultCode: Boolean;

procedure CreateTheWizardPages;
var
LangPage: TWizardPage;
begin
LangPage:=CreateCustomPage(wpSelectComponents, 'Language', 'Select Game Language');
RussianBtn:=TRadioButton.Create(LangPage);
RussianBtn.Top:=ScaleY(30);
RussianBtn.Width:=LangPage.SurfaceWidth;
RussianBtn.Height:=ScaleY(17);
RussianBtn.Caption:='Russian';
RussianBtn.Checked:=GetPreviousData('Russian', '1') = '1';
RussianBtn.Parent:=LangPage.Surface;

EnglishBtn:=TRadioButton.Create(LangPage);
EnglishBtn.Top:=RussianBtn.Top + ScaleY(30);
EnglishBtn.Width:=LangPage.SurfaceWidth;
EnglishBtn.Height:=ScaleY(17);
EnglishBtn.Caption:='English';
EnglishBtn.Checked:=GetPreviousData('English', '0') = '1';
EnglishBtn.Parent:=LangPage.Surface;
end;

procedure InitializeWizard();
begin
CreateTheWizardPages;
end;

procedure RegisterPreviousData(PreviousDataKey: Integer);
begin
SetPreviousData(PreviousDataKey, 'Russian', IntToStr(Ord(RussianBtn.Checked)));
SetPreviousData(PreviousDataKey, 'English', IntToStr(Ord(EnglishBtn.Checked)));
end;

function Russian: Boolean;
begin
Result:=RussianBtn.Checked;
end;

function English: Boolean;
begin
Result:=EnglishBtn.Checked;
end;

Функция "English" здесь дана так просто, для виду... Типа, если выберешь "Russian", то устанавливаются файлы руссификатора, а если нет, то просто ставятся основные файлы.
Да, вместо wpSelectComponents можно написать любую страницу и поверх её создастся страница с выбором языка.
Как добавить кнопочку Печать на страницу, где отображается InfoBeforeFile?
[Setup]
AppName=My Program
AppVerName=My Program version 1.5
DefaultDirName={pf}\My Program
DisableProgramGroupPage=yes
InfoBeforeFile=Readme.txt

[Files]
Source: "MyProg.exe"; DestDir: "{app}"

[Code]
var
PrintButton: TButton;

procedure PrintButtonClick(Sender: TObject);
var WordpadLoc: String;
RetCode: Integer;
begin
if MsgBox( 'Do you want to print Info to default printer ?', mbConfirmation, MB_YESNO ) = IDYES then
begin
RegQueryStringValue( HKLM, 'SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\WORDPAD.EXE','', WordpadLoc);
StringChange( WordpadLoc, '%ProgramFiles%', ExpandConstant('{pf}') );
StringChange( WordpadLoc, '"', '');
ExtractTemporaryFile('Readme.txt');
if not Exec( WordPadLoc, ' /p ' + ExpandConstant('{tmp}\Readme.txt') ,
ExpandConstant('{tmp}'), SW_HIDE, false, RetCode ) then
MsgBox('Problems printing Info file !' + IntToStr(RetCode), mbError, mb_Ok)
else
MsgBox('Problems extracting Info file !', mbError, mb_Ok);
end;
end;

procedure CurPageChanged(CurPage: Integer);
begin
if CurPage = wpInfoBefore then
PrintButton.Visible := True
else
PrintButton.Visible := False;
end;

procedure InitializeWizard();
begin
PrintButton := TButton.Create(WizardForm);
PrintButton.Caption := '&Print Info';
PrintButton.Top := WizardForm.BackButton.Top;
PrintButton.Left := WizardForm.BackButton.Left - WizardForm.BackButton.Width - ScaleX(40);
PrintButton.OnClick := @PrintButtonClick;
PrintButton.Parent := WizardForm;
PrintButton.Visible := False;
end;
Скрипт, в котором Репайр восстанавливает удаленные файлы; Модифай - показывает установленные компоненты. Вот рабочий скрипт - все прописывалось строго по инструкции. Но скрипт писал только из любопытства. Реально не использую и подводных камней не знаю.
[Setup]
AppName=My Program
AppVerName=My Program version 1.5
DefaultDirName={pf}\My Program
DisableProgramGroupPage=yes
AppId=MyProgram
AppModifyPath="{app}\UninsHs.exe" /m=MyProgram

[Components]
Name: "main"; Description: "Main Files"; Types: full compact custom; Flags: fixed
Name: "english"; Description: "English"; Types: full; Flags: DisableNoUninstallWarning
Name: "dutch"; Description: "Dutch"; Types: full; Flags: DisableNoUninstallWarning

[Dirs]
Name: "{app}\SRC"

[Files]
Source: "MyProg.exe"; DestDir: "{app}"; Components: main
Source: "Readme.txt"; DestDir: "{app}"; Components: english
Source: "Readme-Dutch.txt"; DestDir: "{app}"; Components: dutch
Source: "UninsHs.exe"; DestDir: "{app}"; Flags: restartreplace

[InstallDelete]
Type: Files; Name: "{app}\Readme.txt"
Type: Files; Name: "{app}\Readme-Dutch.txt"

[UninstallDelete]
Type: filesandordirs; Name: "{app}\SRC"

[Run]
Filename: {app}\UninsHs.exe; Parameters: /r=MyProgram,{language},{srcexe},{app}\SRC\setup.exe; Flags: runminimized runhidden nowait

[Code]
function ShouldSkipPage(CurPage: Integer): Boolean;
begin
if Pos('/SP-', UpperCase(GetCmdTail)) > 0 then
case CurPage of
wpLicense, wpPassword, wpInfoBefore, wpUserInfo,
wpSelectDir, wpSelectProgramGroup, wpInfoAfter:
Result := True;
end;
end;
Как разбить выбор дополнительных задач на две страницы? Чтобы определенные на одной находились, а остальные на другой? | Почитай в хелпе по поводу CreateInputOptionPage.
Можно ли сделать так, чтобы SFX архив не упаковывался Inno Setup, а лежал в одной папке с готовым Setup.exe, чтобы Setup.exe подхватывал его и начинал распаковывать в заданную инсталятором папку. А то SFX сначала распаковывается из Setup.exe и только потом начинается распаковка самого SFX.
[Run]
;Запуск внешних SFX 7-ZIP архивов
;При желании можно установить дополнительные флаги, например, hidewizard скрывает окно инсталлятора при выполнении распаковки архива.
;При запуске устанавливаем параметр -y, который обозначает "Всегда Да" при любых действиях,
параметр -o "{app}" который означает, что надо распаковать в указанную папку. Флаг waituntilterminated должен быть всегда в этом случае:
Filename: "{src}\SFX_ARCHIVE.exe"; WorkingDir: "{src}"; Parameters: "-y -o""{app}"""; StatusMsg: "Распаковка файлов игры..."; Flags: waituntilterminated
Как сделать следующее:
Директория установки программы по выбору пользователя.
К компонентам распаковка не привязана, всё идёт одним куском (т.е. без разделения на компоненты).
Архив может распаковываться в любое время после нажатия на кнопку "установить", т.е. когда устанавливаются все прочие файлы программы, без разницы, когда конкретно.
Содержимое архива должно валиться в директорию устанавливаемой программы. Копировать его туда НЕОБЯЗАТЕЛЬНО. Можно и в tmp, я думал об этом.
Запускаю c флагами nowait skipifsilent, без postinstall архив запускается, когда можно, но появляется окно типа "самораспаковывающийся архив..." чего хотелось бы избежать (использовать RAR?)
Формат архива SFX.
[Setup]
AppName=My Program
AppVerName=My Program version 1.5
DefaultDirName={pf}\My Program

[Files]
Source: "MyProg.exe"; DestDir: "{app}"; Flags: ignoreversion
Source: "archive.exe"; DestDir: "{tmp}"; Flags: ignoreversion

[Run]
Filename: "{tmp}\archive.exe"; Parameters: "-y -o""{app}"""; Flags: waituntilterminated

Для rar будет так:
[Run]
Filename: "{tmp}\archive.exe"; Parameters: " -s -d""{app}"""; Flags: waituntilterminated
Возможно ли на странице приветствия делать ссылки кликабельными?
procedure AboutButtonOnClick(Sender: TObject);
begin
MsgBox('Это демо версия программы.', mbInformation, mb_Ok);
end;

procedure URLLabelOnClick(Sender: TObject);
var
ErrorCode: Integer;
begin
ShellExec('open', 'http://www.innosetup.com', '', '', SW_SHOWNORMAL, ewNoWait, ErrorCode);
end;

procedure InitializeWizard();
var
AboutButton, CancelButton: TButton;
URLLabel: TNewStaticText;
BackgroundBitmapImage: TBitmapImage;
BackgroundBitmapText: TNewStaticText;

begin
CancelButton := WizardForm.CancelButton;
AboutButton := TButton.Create(WizardForm);
AboutButton.Left := WizardForm.ClientWidth - CancelButton.Left - CancelButton.Width;
AboutButton.Top := CancelButton.Top;
AboutButton.Width := CancelButton.Width;
AboutButton.Height := CancelButton.Height;
AboutButton.Caption := '&About...';
AboutButton.OnClick := @AboutButtonOnClick;
AboutButton.Parent := WizardForm;

URLLabel := TNewStaticText.Create(WizardForm);
URLLabel.Caption := 'www.innosetup.com';
URLLabel.Cursor := crHand;
URLLabel.OnClick := @URLLabelOnClick;
URLLabel.Parent := WizardForm;
{ Alter Font *after* setting Parent so the correct defaults are inherited first }
URLLabel.Font.Style := URLLabel.Font.Style + [fsUnderline];
URLLabel.Font.Color := clBlue;
URLLabel.Top := AboutButton.Top + AboutButton.Height - URLLabel.Height - 2;
URLLabel.Left := AboutButton.Left + AboutButton.Width + ScaleX(20);

BackgroundBitmapImage := TBitmapImage.Create(MainForm);
BackgroundBitmapImage.Left := 50;
BackgroundBitmapImage.Top := 100;
BackgroundBitmapImage.AutoSize := True;
BackgroundBitmapImage.Bitmap := WizardForm.WizardBitmapImage.Bitmap;
BackgroundBitmapImage.Parent := MainForm;

BackgroundBitmapText := TNewStaticText.Create(MainForm);
BackgroundBitmapText.Left := BackgroundBitmapImage.Left;
BackgroundBitmapText.Top := BackgroundBitmapImage.Top + BackgroundBitmapImage.Height + ScaleY(8);
BackgroundBitmapText.Caption := 'TBitmapImage';
BackgroundBitmapText.Parent := MainForm;
end;
Код проверки пути установки файлов на наличие в пути русских символов
function NextButtonClick(CurPageID: Integer): Boolean;
var
i,j: integer;
s,c: string;
begin
Result := True;
if CurPageID = wpSelectDir then
begin
c := 'АБВГДЕЁЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯабвгдеёжзийклмнопрстуфхцчшщъыьэюя';
for i:=1 to length(WizardForm.DirEdit.text) do
for j:=1 to length(c) do
begin
if WizardForm.DirEdit.text[i] = c[j] then //{app} содержит русские символы
begin
s := 'В пути установки присутствуют русские буквы, что недопустимо'#13#13'Пожалуйста, повторите ввод.';
MsgBox(s, mbError, mb_Ok);
Result := False ; //запрет перехода на следующую страницу
exit;
end
else Result := True; //разрешаем переход на следующую страницу
end;
end;
end;
Как проверить свободное место на диске? | В хелпе смотри описание функции GetSpaceOnDisk
Как проверить свободное место на диске?
[Setup]
AppName=My Program
AppVerName=My Program version 1.5
DefaultDirName={pf}\My Program

[Files]
Source: Files\*; DestDir: {app}

[Code]
const
NeedSize = 20; //Прописать, сколько мегабайт необходимо

DRIVE_UNKNOWN = 0;
DRIVE_NO_ROOT_DIR = 1;
DRIVE_REMOVEABLE = 2;
DRIVE_FIXED = 3;
DRIVE_REMOTE = 4;
DRIVE_CDROM = 5;
DRIVE_RAMDISK = 6;

function GetLogicalDrives: DWORD;
external 'GetLogicalDrives@kernel32.dll stdcall';

function GetDriveType(nDrive: String): Longint;
external 'GetDriveTypeA@kernel32.dll stdcall';

procedure InitializeWizard();
var
Path: String;
FreeMB, TotalMB: Cardinal;
ListBox: TListBox;
drives: DWORD;
i: integer;
begin
ListBox:= TListBox.Create(WizardForm);
ListBox.Top:= 120;
ListBox.Width:= 300;
ListBox.Height:= ScaleY(90);
ListBox.Parent:= WizardForm.SelectDirPage;

drives:= GetLogicalDrives();
for i:= 0 to 31 do
begin
if (drives and (1 shl i)) > 0 then
begin
Path:= chr(ord('A')+i)+':';
if GetDriveType(Path) = DRIVE_FIXED then
begin
GetSpaceOnDisk(Path, True, FreeMB, TotalMB);
ListBox.Items.Add(Path + ' - Всего: ' + IntToStr(TotalMB) +
'Мб - Свободно: ' + IntToStr(FreeMB) + 'Мб');
end;
end;
end;
end;

function NextButtonClick(CurPageID: Integer): Boolean;
var
Path: String;
FreeMB, TotalMB: Cardinal;
begin
Result:= True;
if CurPageID = wpSelectDir then
begin
Path:= ExtractFileDrive(WizardForm.DirEdit.Text);
GetSpaceOnDisk(Path, True, FreeMB, TotalMB);
if FreeMB < NeedSize then
begin
MsgBox('Недостаточно места на диске!', mbInformation, MB_OK)
Result:= False;
end;
end;
end;
Как можно сделать, чтобы в сообщении "Недостаточно места на диске!" выводилось также и кол-во необходимого для установки места?
function NextButtonClick(CurPageID: Integer): Boolean;
var
Path: String;
FreeMB, TotalMB: Cardinal;
begin
Result:= True;
if CurPageID = wpSelectDir then
begin
Path:= ExtractFileDrive(WizardForm.DirEdit.Text);
GetSpaceOnDisk(Path, True, FreeMB, TotalMB);
if FreeMB < NeedSize then
begin
MsgBox('Для установки приложения необходимо '+ IntTostr(NeedSize)+ ' MB,'#13+ 'а на выбранном Вами диске доступно только '+ IntToStr(FreeMB)+' MB', mbCriticalError, MB_OK)
Result := False;
end;
end;
end;
Как сделать несколько ярлыков в меню Пуск, например, на запуск программы, на файл справки и т.д.? Вот как у меня:
[Icons]
Name: {userdesktop}\S.T.A.L.K.E.R.; Filename: {app}\bin\XR_3DA.exe; Tasks: desktopicon; Flags: createonlyiffileexists; WorkingDir: {app}\bin
Name: {group}\Начать игру; Filename: {app}\bin\XR_3DA.exe; Flags: createonlyiffileexists; WorkingDir: {app}\bin
Name: {group}\Руководство; Filename: {app}\manual.pdf; Flags: createonlyiffileexists
Name: {group}\Трейнер; Filename: {app}\trn.exe; Flags: createonlyiffileexists; WorkingDir: {app}
Name: {group}\Файл Readme; Filename: {app}\ReadMe.txt; Flags: createonlyiffileexists
Name: {group}\Интернет-сайты\Chuvakstepan Inc.; Filename: {app}\website.url; Flags: createonlyiffileexists; Tasks: url
Name: {group}\Интернет-сайты\Сайт игры; Filename: {app}\websitegameSTALKER.url; Flags: createonlyiffileexists; Tasks: url
Name: {group}\{cm:UninstallProgram,игры}; Filename: {uninstallexe}
Как изменить шрифт всех лейблов на другой (verdana, sans serif)?
[Code]
Procedure InitializeWizard();
begin
WizardForm.Font.Name:='MS Sans Serif' // Шрифт
WizardForm.Font.Style:=[fsBold] // Стиль шрифта
WizardForm.Font.Color:=clBlack // Цвет шрифта
end;
Это понятно, но у меня есть свой шрифт TTF. Как его поставить на WizardForm? Дело в том, что Inno устанавливает шрифты после установки.
Но если ты хочешь, чтобы отображался твой шрифт, то как вариант можно сделать так:
Сначала создай сайлент-инсталл шрифта:
[Setup]
AppName=AppName
AppVerName=AppVerName
CreateAppDir=False
DisableProgramGroupPage=True
UsePreviousGroup=False
AppendDefaultGroupName=False
DisableFinishedPage=True
DisableReadyPage=True
Uninstallable=False
OutputBaseFilename=font

[Files]
Source: ZOMBI.TTF; DestDir: {fonts}; FontInstall: Ds Zombie Cyr; Flags: onlyifdoesntexist uninsneveruninstall

[Code]
procedure InitializeWizard();
begin
WizardForm.Hide
end;

procedure CurPageChanged(CurPageID: Integer);
begin
If CurPageID=wpWelcome then
begin
SendMessage(WizardForm.NEXTBUTTON.Handle, 513, 0, 0)
SendMessage(WizardForm.NEXTBUTTON.Handle, 514, 0, 0)
end
end;

Потом создавай свой инсталл и включай в него инсталл шрифта:
[Setup]
AppName=AppName
AppVerName=AppVerName
DefaultDirName={pf}\AppName

[Files]
Source: font.exe; DestDir: {tmp}; Flags: dontcopy

[Code]
Function InitializeSetup(): Boolean;
var
Res: Integer;
begin
ExtractTemporaryFile('font.exe')
Exec(ExpandConstant('{tmp}\font.exe'),'','',SW_SHOWNORMAL,ewWaitUntilTerminated,Res)
Result:=True
end;

procedure InitializeWizard();
begin
WizardForm.Font.Name:='Ds Zombie Cyr'
end;
Мне нужно использовать в коде procedure InitializeWizard(); не один раз, а при компиляции мне пишет, что это можно использовать только один раз, как быть? Просто вписывай значения из исходного procedure InitializeWizard уже без этой строчки:
[Code]
procedure InitializeWizard
begin
типа код вставки музыки
end;
begin
типа код вставки фонового рисунка
end;
Вот интересный код (анимация):
[Setup]
appname=AnimateWindow
appvername=AnimateWindow
createappdir=no
uninstallable=no

[Code]
const
AW_FADE_IN = $00080000;
AW_FADE_OUT = $00090000;
AW_SLIDE_IN_LEFT = $00040001;
AW_SLIDE_OUT_LEFT = $00050002;
AW_SLIDE_IN_RIGHT = $00040002;
AW_SLIDE_OUT_RIGHT = $00050001;
AW_SLIDE_IN_TOP = $00040004;
AW_SLIDE_OUT_TOP = $00050008;
AW_SLIDE_IN_BOTTOM = $00040008;
AW_SLIDE_OUT_BOTTOM = $00050004;
AW_DIAG_SLIDE_IN_TOPLEFT = $00040005;
AW_DIAG_SLIDE_OUT_TOPLEFT = $0005000a;
AW_DIAG_SLIDE_IN_TOPRIGHT = $00040006;
AW_DIAG_SLIDE_OUT_TOPRIGHT = $00050009;
AW_DIAG_SLIDE_IN_BOTTOMLEFT = $00040009;
AW_DIAG_SLIDE_OUT_BOTTOMLEFT = $00050006;
AW_DIAG_SLIDE_IN_BOTTOMRIGHT = $0004000a;
AW_DIAG_SLIDE_OUT_BOTTOMRIGHT = $00050005;
AW_EXPLODE = $00040010;
AW_IMPLODE = $00050010;

function AnimateWindow(hWnd: HWND; dwTime: DWORD; dwFlags: DWORD): Boolean;
external 'AnimateWindow@user32 stdcall';

procedure OnShow(Sender: TObject);
begin
AnimateWindow(WizardForm.Handle,1000,AW_EXPLODE);
WizardForm.NextButton.OnClick(WizardForm.NextButton);
WizardForm.BackButton.OnClick(WizardForm.BackButton);
end;

procedure InitializeWizard();
begin
WizardForm.OnShow:=@OnShow;
end;

procedure CancelButtonClick(CurPageID: Integer; var Cancel, Confirm: Boolean);
begin
Confirm:=False;
AnimateWindow(WizardForm.Handle,1000,AW_IMPLODE);
Cancel:=True;
end;
А можно, чтобы анимация (AW_IMPLODE или тому подобное) отображалась, если нажимаешь и на кнопку "Завершить" (окончания установки)? Добавь это:
function NextButtonClick(CurPageID: Integer): Boolean;
begin
Result:=True;
if CurPageID=wpFinished then
AnimateWindow(WizardForm.Handle,1000,AW_IMPLODE);
end;
Спецэффекты:
[Setup]
AppName=My Program
AppVerName=My Program v.1.2
DefaultDirName={pf}\My Program

[Code]
const
TransparentPercent = 80; // процент прозрачности

WS_EX_LAYERED = $80000;
WS_EX_TRANSPARENT = $20;
LWA_COLORKEY = 1;
LWA_ALPHA = 2;
GWL_EXSTYLE = (-20);

function SetLayeredWindowAttributes(hwnd: HWND; crKey: TColor; bAlpha: BYTE; dwFlags: DWORD): Boolean;
external 'SetLayeredWindowAttributes@user32.dll stdcall';

function GetWindowLong(Wnd: HWnd; Index: Integer): Longint;
external 'GetWindowLongA@user32.dll stdcall';

function SetWindowLong(Wnd: HWnd; Index: Integer; NewLong: Longint): Longint;
external 'SetWindowLongA@user32.dll stdcall';

Procedure InitializeWizard();
begin
SetWindowLong(WizardForm.Handle, GWL_EXSTYLE, GetWindowLong(WizardForm.Handle, GWL_EXSTYLE) or WS_EX_LAYERED);
SetLayeredWindowAttributes(WizardForm.Handle, 0, (255 * TransparentPercent) / 100, LWA_ALPHA);
end;

Интересный эффект дает и такое использование:

Procedure InitializeWizard();
begin
WizardForm.ReadyMemo.Color:= clRed;
SetWindowLong(WizardForm.Handle, GWL_EXSTYLE, GetWindowLong(WizardForm.Handle, GWL_EXSTYLE) or WS_EX_LAYERED);
SetLayeredWindowAttributes(WizardForm.Handle, clRed, (255 * TransparentPercent) / 100, LWA_COLORKEY);
end;
Как сделать, чтобы при выборе пункта "Установить" и нажатии "Далее", запускалась дополнительная программа, находящаяся в дистрибутиве?
[Setup]
AppName=My Program
AppVerName=My Program ver.1.5
DefaultDirName={pf}\My Program

[Tasks]
Name: fbrinst; Description: "Install Firebird"

[Files]
Source: Files\*.bmp; DestDir: {app}
Source: FBirdSetup.exe; DestDir: {tmp}; Tasks: fbrinst; Flags: deleteafterinstall

[Run]
Filename: {tmp}\FBirdSetup.exe; Description: "Launch Firebird Setup"; Tasks: fbrinst
А как сделать, чтобы сначала была установка Firebird, а уже потом продолжался ход установки основной программы?
[Setup]
AppName=My Program
AppVerName=My Program ver.1.5
DefaultDirName={pf}\My Program

[Tasks]
Name: fbrinst; Description: "Install Firebird"

[Files]
Source: FBirdSetup.exe; DestDir: {tmp}; Tasks: fbrinst; AfterInstall: SetupFBird; Flags: deleteafterinstall
Source: Files\*.bmp; DestDir: {app}

[Code]
procedure SetupFBird();
var
ResultCode: Integer;
begin
Exec(ExpandConstant('{tmp}\FBirdSetup.exe'), '', '', SW_SHOWNORMAL, ewWaitUntilTerminated, ResultCode);
end;
Вот решение той же задачи (сначала установка Firebird):
[Setup]
AppName=My Program
AppVerName=My Program ver.1.5
DefaultDirName={pf}\My Program

[Files]
Source: FBirdSetup.exe; Flags: dontcopy
Source: Files\*.bmp; DestDir: {app}

[Code]
var
FirebirdInst: TInputOptionWizardPage;
IsFbrInstalled: Boolean;

procedure InitializeWizard;
begin
IsFbrInstalled:= False;

FirebirdInst := CreateInputOptionPage(wpWelcome, 'Firebird 2.0', '', '', True, False);
FirebirdInst.Add('Установить');
FirebirdInst.Add('Уже установлен');
case GetPreviousData('FirebirdInst', '') of 'Установить': FirebirdInst.SelectedValueIndex := 0;
'Уже установлен': FirebirdInst.SelectedValueIndex := 1;
else
FirebirdInst.SelectedValueIndex := 0;
end;
end;

function NextButtonClick(CurPageID: Integer): Boolean;
var
ResultCode: Integer;
begin
Result:= True;
if (CurPageID = FirebirdInst.ID) and (FirebirdInst.Values[0]) then
begin
ExtractTemporaryFile('FBirdSetup.exe');
Exec(ExpandConstant('{tmp}\FBirdSetup.exe'), '', '', SW_SHOWNORMAL, ewWaitUntilTerminated, ResultCode);
IsFbrInstalled:= True;
end;
end;

function ShouldSkipPage(PageID: Integer): Boolean;
begin
if PageID = FirebirdInst.ID then
Result:= IsFbrInstalled
else
Result:= False;
end;
Поддерживает ли Inno изменение внешнего курсора?
Const
GCL_HCURSOR = (-12);
OCR_NORMAL = 32512;

var
OldCursor, NewCursor: Longint;

function LoadCursorFromFile(FileName: String): Longint;
external 'LoadCursorFromFileA@user32 stdcall';

function SetClassLong(hWnd: HWND; Index, NewLong: Longint): Longint;
external 'SetClassLongA@user32 stdcall';

function SetCursor(Cursor: Longint): Longint;
external 'SetCursor@user32 stdcall';

function SetSystemCursor(Cursor, CurType: Longint): Longint;
external 'SetSystemCursor@user32 stdcall';

function GetCursor(): Longint;
external 'GetCursor@user32 stdcall';

procedure InitializeWizard;
begin
OldCursor:= GetCursor;
NewCursor:= LoadCursorFromFile('C:\TEMP\BeOS2.cur');
SetSystemCursor(NewCursor, OCR_NORMAL);
end;

procedure DeinitializeSetup();
begin
SetSystemCursor(OldCursor, OCR_NORMAL);
end;

Либо изменить курсор только для отдельных типов компонент:

procedure InitializeWizard;
begin
NewCursor:= LoadCursorFromFile('C:\TEMP\BeOS2.cur');
OldCursor:= SetClassLong(WizardForm.NextButton.Handle, GCL_HCURSOR, NewCursor);
end;
Возможность проверки файловой системы [FAT32, NTFS] выбранного локального диска
[Setup]
AppName=My Program
AppVerName=My Program ver.1.5
DefaultDirName={pf}\My Program

[Code]
Const
BufferLen = 50;

function GetVolumeInformation(PathName, VolumeName: PChar; VolumeNameSize, VolumeSerialNumber, MaxComponentLength, FileSystemFlags: Longint;
FileSystemName: PChar; FileSystemNameSize: Longint): Longint;
external 'GetVolumeInformationA@kernel32.dll stdcall';

procedure InitializeWizard;
var
VolumeName,
FileSystemName : string;
VolumeSerialNo : Longint;
MaxComponentLength,
FileSystemFlags : Longint;
begin
VolumeName:= StringOfChar( ' ', BufferLen );
FileSystemName:= StringOfChar( ' ', BufferLen );

GetVolumeInformation('C:\', VolumeName, BufferLen-1, VolumeSerialNo,
MaxComponentLength,
FileSystemFlags,
FileSystemName,
BufferLen-1);
MsgBox(FileSystemName, mbInformation, MB_OK);
end;
А как сделать, чтобы при выборе одного из дисков происходила проверка выбранного [FAT32, NTFS], а не при запуске. Получение имени файловой системы оформляешь в виде функции. Например:

function GetFileSystemName(Path: string): string;
var
VolumeName,
FileSystemName : string;
VolumeSerialNo : Longint;
MaxComponentLength,
FileSystemFlags : Longint;
begin
VolumeName:= StringOfChar( ' ', BufferLen );
FileSystemName:= StringOfChar( ' ', BufferLen );

GetVolumeInformation(Path, VolumeName, BufferLen-1, VolumeSerialNo,
MaxComponentLength,
FileSystemFlags,
FileSystemName,
BufferLen-1);
Result:= Trim(FileSystemName);
end;

... и в нужное тебе место вставляешь проверку:
if GetFileSystemName(NewLetter + ':\') = 'NTFS' then
..........................

Также может быть, например, так:

procedure ListBoxOnClick(Sender: TObject);
var
NewLetter, OldString: string;
i: Integer;
begin
for i := 0 to ListBox.Items.Count - 1 do
begin
if ListBox.Selected[i] then
begin
NewLetter := Copy(ListBox.Items[i], 0, 1);
if GetFileSystemName(NewLetter + ':\') = 'NTFS' then
begin
OldString := Copy(WizardForm.DirEdit.Text, 2, Length(WizardForm.DirEdit.Text));
WizardForm.DirEdit.Text := NewLetter + OldString;
end else
begin
MsgBox('For NTFS Only!' + #10#13 + 'Selected drive has ' + GetFileSystemName(NewLetter + ':\') + ' file system.', mbInformation, MB_OK);
end;
end;
end;
end;
Есть пакет из трех программ с раздельными exe-файлами. Как сделать, чтобы после установки можно было только одну из трех выбрать на запуск?
[Files]
Source: My Program 1.exe; destdir: {app}; flags: ignoreversion
Source: My Program 2.exe; destdir: {app}; flags: ignoreversion
Source: My Program 3.exe; destdir: {app}; flags: ignoreversion

[Code]
var
RadioButton1: TRadioButton;
RadioButton2: TRadioButton;
RadioButton3: TRadioButton;

procedure InitializeWizard();
begin
RadioButton1 := TRadioButton.Create(WizardForm.FinishedPage);
with RadioButton1 do
begin
Parent := WizardForm.FinishedHeadingLabel.Parent;
Caption := 'Launch My Program 1';
Left := ScaleX(180);
Top := ScaleY(120);
Width := ScaleX(177);
Height := ScaleY(17);
TabOrder := 0;
end;

RadioButton2 := TRadioButton.Create(WizardForm.FinishedPage);
with RadioButton2 do
begin
Parent := WizardForm.FinishedHeadingLabel.Parent;
Caption := 'Launch My Program 2';
Left := ScaleX(180);
Top := ScaleY(145);
Width := ScaleX(177);
Height := ScaleY(17);
TabOrder := 1;
end;

RadioButton3 := TRadioButton.Create(WizardForm.FinishedPage);
with RadioButton3 do
begin
Parent := WizardForm.FinishedHeadingLabel.Parent;
Caption := 'Launch My Program 3';
Left := ScaleX(180);
Top := ScaleY(170);
Width := ScaleX(177);
Height := ScaleY(17);
TabOrder := 2;
end;
end;

function NextButtonClick(CurPageID: Integer): Boolean;
var ResultCode: Integer;
begin
Result:=True;
if CurPageID=wpFinished then
begin
if RadioButton1.Checked then
Exec(ExpandConstant('{app}\My Program 1.exe'), '', '', SW_SHOW,ewNoWait, ResultCode)
else
if RadioButton2.Checked then
Exec(ExpandConstant('{app}\My Program 2.exe'), '', '', SW_SHOW,ewNoWait, ResultCode)
else
if RadioButton3.Checked then
Exec(ExpandConstant('{app}\My Program 3.exe'), '', '', SW_SHOW,ewNoWait, ResultCode)
end
end;
Как сделать, чтобы деинсталлятор удалял всю папку, даже с новыми файлами и папками, которые не прописаны первым инсталлятором?
[UninstallDelete]
Type: filesandordirs; Name: "{app}"

Или так:
[Code]
procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
if CurUninstallStep=usPostUninstall then
begin
DelTree(ExpandConstant('{app}'), True, True, True);
RemoveDir(ExpandConstant('{app}'));
end;
end;
Как сделать, чтобы путь установки вместо {app} был своим собственным? В разделе [Files] в строке Source: .........; DestDir: {app}\.......

вместо:
DestDir: {app}\.....

пишешь:
DestDir: {code:MyPath}\.....

а в коде прописываешь функцию, которая будет возвращать требуемый путь. Например:

function MyPath(Param: String): String;
begin
Result := ExpandConstant('{pf}');
end;

путь составляешь как тебе надо - исходя из выбранного диска и т.д.
Как сделать, чтобы в зависимости от того, какой компонент выбран, показывать или скрывать следующую форму?
function WizardSelectedComponents(const Descriptions: Boolean): String;
function IsComponentSelected(const Components: String): Boolean;
Код, который будет закрывать процессы перед началом удаления руссификатора.
[Setup]
AppName=My Program
AppVerName=My Program ver.1.5
DefaultDirName={pf}\My Program

[Files]
Source: "ISTask.dll"; DestDir: "{app}"

[Code]
function KillTask(ExeFileName: string): Integer;
external 'KillTask@files:ISTask.dll stdcall delayload setuponly';

function RunTask(FileName: string; bFullpath: Boolean): Boolean;
external 'RunTask@files:ISTask.dll stdcall delayload setuponly';

function KillTaskA(ExeFileName: string): Integer;
external 'KillTask@{app}\ISTask.dll stdcall delayload uninstallonly';

function RunTaskA(FileName: string; bFullpath: Boolean): Boolean;
external 'RunTask@{app}\ISTask.dll stdcall delayload uninstallonly';

function InitializeSetup(): Boolean;
begin
If RunTask('calc.exe', false) then
begin
if MsgBox('Программа установки руссификатора обнаружила, что программа'#13'для которой установится руссификатор запущена в данный момент. '#13#13' Закрыть программу?'#13#13 +
'"Да" - закроет и не сохранит измененные настройки в программе.' #13#13 +
'"Нет" - продолжит установку без закрытия. (Настоятельно рекомендуется нажать Да)', mbError, mb_YesNo) = idYes then
begin
KillTask('calc.exe');
Result := True;
end else
Exit;
end;
Result := True;
begin
If RunTask('notepad.exe', false) then
begin
KillTask('notepad.exe');
Result := True;
end else
Exit;
end;
end;

function InitializeUninstall(): Boolean;
begin
If RunTaskA('calc.exe', false) then
begin
if MsgBox('Программа установки русификатора обнаружила, что программа'#13'для которой установится русификатор запушена в данный момент. '#13#13' Закрыть программу?'#13#13 +
'"Да" - закроет и не сохранит измененные настройки в программе.' #13#13 +
'"Нет" - продолжит установку без закрытия. (Настоятельно рекомендуется нажать Да)', mbError, mb_YesNo) = idYes then
begin
KillTaskA('calc.exe');
Result := True;
end else
Exit;
end;
Result := True;
begin
If RunTaskA('notepad.exe', false) then
begin
KillTaskA('notepad.exe');
Result := True;
end else
Exit;
end;
end;
Как можно остановить виндовый сервис, а затем запустить его? net stop имя_сервиса
net start имя_сервиса
Как сделать WizardForm - "Always on top"?
[Setup]
AppName=My Program
AppVerName=My Program ver.1.5
DefaultDirName={pf}\My Program

[Code]
Const
HWND_TOP = 0;
HWND_TOPMOST = -1;
HWND_NOTOPMOST = -2;
SWP_NOSIZE = $1;
SWP_NOMOVE = $2;
SWP_NOZORDER = $4;
SWP_NOREDRAW = $8;
SWP_NOACTIVATE = $10;
SWP_FRAMECHANGED = $20;
SWP_SHOWWINDOW = $40;
SWP_HIDEWINDOW = $80;
SWP_NOCOPYBITS = $100;
SWP_NOOWNERZORDER = $200;
SWP_DRAWFRAME = SWP_FRAMECHANGED;
SWP_NOREPOSITION = SWP_NOOWNERZORDER;

function SetWindowPos(hWnd, hWndInsertAfter,
X, Y, cx, cy, wFlags: Longint):Boolean;
external 'SetWindowPos@user32.dll stdcall';

procedure InitializeWizard;
begin
SetWindowPos(WizardForm.Handle, HWND_TOPMOST, 0, 0, 0, 0,
SWP_NOSIZE or SWP_NOMOVE or SWP_SHOWWINDOW);
end;
Как избавиться от запроса подтверждения выхода из инсталлятора? Добавь в скрипт следующее:
procedure CancelButtonClick(CurPageID: Integer; var Cancel, Confirm: Boolean);
begin
Confirm:=False;
end;
Как перенести неумещающийся текст на следующую строку?
[Setup]
AppName=AppName
AppVerName=AppVerName
DefaultDirName={pf}\AppName

[Code]
var
Panel: TPanel;
Text: TNewStaticText;

procedure InitializeWizard();
begin
Panel:=TPanel.Create(WizardForm)
Panel.Left:=3
Panel.Top:=315
Panel.Width:=245
Panel.Height:=44
Panel.BevelInner:=bvLowered
Panel.Color:=12639424
Panel.Parent:=WizardForm

Text:=TNewStaticText.Create(WizardForm)
Text.Left:=2
Text.Top:=2
Text.Width:=242
Text.Height:=38
Text.AutoSize:=False
Text.WordWrap:=True
Text.Caption:='действительно на панели не переносится но как вариант можно сделать так'
Text.Parent:=Panel
end;
Как сделать вторую страницу дополнительных задач (следом за первой) и перенести часть кнопок (чекбоксов) на новую?
[Setup]
AppName=My Program
AppVerName=My Program ver.1.5
DefaultDirName={pf}\My Program

[Tasks]
Name: desktopicon; Description: "Create a &desktop icon"; GroupDescription: "Additional icons:"
Name: desktopicon\common; Description: "For all users"; GroupDescription: "Additional icons:"; Flags: exclusive
Name: desktopicon\user; Description: "For the current user only"; GroupDescription: "Additional icons:"; Flags: exclusive unchecked
Name: quicklaunchicon; Description: "Create a &Quick Launch icon"; GroupDescription: "Additional icons:"; Flags: unchecked
Name: associate; Description: "&Associate files"; GroupDescription: "Other tasks:"; Flags: unchecked

[Code]
var
Page: TInputOptionWizardPage;
IsRegisteredUser: Boolean;

procedure InitializeWizard();
begin
Page := CreateInputOptionPage(wpSelectTasks,
'License Information', 'Are you a registered user?',
'If you are a registered user, please check the box below, then click Next.',
False, False);

Page.Add('I am a registered user');
Page.Values[0] := False;
end;
Как объединить секцию [Code] из предыдущего примера и команды раздела [Tasks]?
var
Page: TInputOptionWizardPage;
IsRegisteredUser: Boolean;
procedure InitializeWizard();
begin
Page := CreateInputOptionPage(wpSelectTasks,
'License Information', 'Are you a registered user?',
'If you are a registered user, please check the box below, then click Next.',
False, False);

{0} Page.Add('Исправить ошибку page2chm v.2.7 RC1 с Opera v.9.10 и выше');
{1} Page.Add('Исправить кодировку русских символов в оболочке Windows');
{2} Page.Add('Использовать доступное поле множественного поиска');
{3} Page.Add('Сокращать длинные названия кнопок и панелей в середине имени');
{4} Page.Add('Включить сохранение страниц');
{5} Page.Add('Включить рекомендуемую кодировку текста');

Page.Values[0] := True;
end;
Как сделать, чтобы дополнительно создать новую страницу и туда перенести задачи раздела [Tasks], чтобы при их выборе происходило копирование в ini-файл, в зависимости от того, что выбрано (из чекбоксов)? В секции [INI] вместо параметра Tasks: используй параметр Check:.
Т.е. выглядеть это будет примерно так:
[Setup]
AppName=My Program
AppVerName=My Program v.1.2
DefaultDirName={pf}\My Program

[Files]
Source: "MyProg.ini"; DestDir: "{app}"

[INI]
Filename: {app}\opera6.ini; Section: User Prefs; Key: Save With Images Use Subfolder; String: 1; Check: CheckOption(4); Flags: uninsdeleteentry
Filename: {app}\opera6.ini; Section: User Prefs; Key: Force Encoding; String: AUTODETECT-RU; Check: CheckOption(5); Flags: uninsdeleteentry
Filename: {app}\opera6.ini; Section: User Prefs; Key: Title; Check: CheckOption(0); String: ; Flags: uninsdeleteentry
Filename: {app}\opera6.ini; Section: User Prefs; Key: Use Integrated Search; String: 1; Check: CheckOption(2); Flags: uninsdeleteentry
Filename: {app}\opera6.ini; Section: User Prefs; Key: Ellipsis In Center; String: 1; Check: CheckOption(3); Flags: uninsdeleteentry

[Code]
var
Page: TInputOptionWizardPage;
IsRegisteredUser: Boolean;
procedure InitializeWizard();
begin
Page := CreateInputOptionPage(wpSelectTasks,
'License Information', 'Are you a registered user?',
'If you are a registered user, please check the box below, then click Next.',
False, False);

{0} Page.Add('Исправить ошибку page2chm v.2.7 RC1 с Opera v.9.10 и выше');
{1} Page.Add('Исправить кодировку русских символов в оболочке Windows');
{2} Page.Add('Использовать доступное поле множественного поиска');
{3} Page.Add('Сокращать длинные названия кнопок и панелей в середине имени');
{4} Page.Add('Включить сохранение страниц');
{5} Page.Add('Включить рекомендуемую кодировку текста');

Page.Values[0] := True;
end;

function CheckOption(OptionNum: integer): Boolean;
begin
Result:= Page.Values[OptionNum];
end;
Как сделать, чтобы отмеченные данные на этой странице вносились на страницу wpReady?
var
Page: TInputOptionWizardPage;

procedure InitializeWizard();
begin
Page := CreateInputOptionPage(wpSelectTasks,
'License Information', 'Are you a registered user?',
'If you are a registered user, please check the box below, then click Next.',
False, False);

Page.Add('I am a registered user');
Page.Add('Install Acrobat Reader');
Page.Values[0] := False;
end;

procedure CurPageChanged(CurPageID: Integer);
begin
if CurPageID = wpReady then
begin
if Page.Values[0] then
WizardForm.ReadyMemo.Lines.Add('Confirm registration');
if Page.Values[1] then
WizardForm.ReadyMemo.Lines.Add('Install Acrobat Reader');
end;
end;
Как сделать, чтобы дополнительные задачи разбивались на группы?
var
Page: TInputOptionWizardPage;

procedure InitializeWizard();
begin
Page := CreateInputOptionPage(wpSelectTasks,
'License Information', 'Are you a registered user?',
'If you are a registered user, please check the box below, then click Next.',
False, False);

Page.AddEx('I am a registered user', 0, False);
Page.AddEx('Install Acrobat Reader', 1, False);
Page.AddEx('Install Documentation', 1, False);
end;
Запуск/остановку службы в самом простом виде можно реализовать примерно так (здесь стоп/старт службы Windows Time). Использовать надо не имя службы, а выводимое имя.
var
res: integer;

function InitializeSetup(): Boolean;
begin
Exec('net', 'stop "Windows Time"', '', SW_HIDE, ewWaitUntilTerminated, res);
Result:= True;
end;

procedure DeinitializeSetup();
begin
Exec('net', 'start "Windows Time"', '', SW_HIDE, ewWaitUntilTerminated, res);
end;

Если не получается, то можно попробовать из командной строки:
net stop "Windows Time"
Запуск/остановка службы, работает нормально как во время установки, так и при удалении.
function InitializeSetup(): Boolean;
var
res: integer;
begin
Exec('net', 'stop "O&O Defrag"', '', SW_HIDE, ewWaitUntilTerminated, res);
Result:= True;
end;

procedure DeinitializeSetup();
var
res: integer;
begin
Exec('net', 'start "O&O Defrag"', '', SW_HIDE, ewWaitUntilTerminated, res);
end;

function InitializeUninstall(): Boolean;
var
res: integer;
begin
Exec('net', 'stop "O&O Defrag"', '', SW_HIDE, ewWaitUntilTerminated, res);
Result:= True;
end;

procedure DeinitializeUninstall();
var
res: integer;
begin
Exec('net', 'start "O&O Defrag"', '', SW_HIDE, ewWaitUntilTerminated, res);
end;
Как сделать, чтобы папка, в которую устанавливается программа, меняла иконку?
[Setup]
AppName=AppName
AppVerName=AppVerName
DefaultDirName={pf}\My Program

[Dirs]
Name: "{app}"; Attribs: system; AfterInstall: CreateIni();

[Files]
Source: Files\icon.ico; DestDir: {app}

[Code]
procedure CreateIni();
begin
SaveStringsToFile(ExpandConstant('{app}\Desktop.ini'), ['[.ShellClassInfo]',
'IconFile=%SystemRoot%\system32\SHELL32.dll',
'IconIndex=27'], False)
end;
Как сделать, чтобы при установке копировался файл, потом проходит время, заданное в скрипте, и копируется другой, и так далее?
[Setup]
AppName=AppName
AppVerName=AppVerName
DefaultDirName=C:\AppName

[Files]
Source: Files\*; DestDir: {app}; BeforeInstall: MySleep

[Code]
const
SleepTime = 2000;

procedure MySleep();
begin
Sleep(SleepTime);
end;
Как проверить наличие определённого файла в папке назначения после нажатия кнопки "Установить"?
[Code]
function NextButtonClick(CurPage: Integer): Boolean;
var
s:string;
begin
Result:=True;
If CurPage=5 then
begin
If FileSearch('www.sss', ExpandConstant('{app}'))='' then
begin
s:='В каталоге '+ExpandConstant('{app}')+' файл www.sss отсутствует!';
MsgBox(s, mbError, mb_Ok);
Result:=False;
end;
end;
end;

Здесь CurPage=5. Определить CurPage можно в отладке. Запускаешь процесс инсталляции в InnoSetup клавишей F7, когда шаг доходит до строки CurPage, наводишь на нее курсор, всплывающая подсказка покажет значение CurPage.
Как отключить кнопку минимизации инсталятора?
[Code]
procedure InitializeWizard();
begin
WizardForm.BorderIcons:=[biSystemMenu]
end;
Как сделать, чтобы при установке в папке директории создавался лог копируемых файлов? Запусти инсталлятор с параметром /LOG="filename"

Если надо, чтобы лог создавался в дирректории устанавливаемой программы, то тогда лог не будет удален при деинсталляции. В этом случае можно пустой файл лога включить в сам инсталлятор. Примерно так:
[Setup]
AppName=AppName
AppVerName=AppVerName
DefaultDirName={pf}\My Program

[Files]
Source: setup.log; DestDir: {app}; AfterInstall: ExtLog()
Source: Files\*; DestDir: {app}; AfterInstall: ExtLog()

[Code]
procedure ExtLog();
begin
SaveStringToFile(ExpandConstant('{app}\setup.log'), #13#10 + GetDateTimeString('dd/mm/yyyy hh:nn:ss', '-', ':') + ' - ' + ExpandConstant(CurrentFileName), True);
end;
Есть четыре разных инсталлятора программного обеспечения (установка сервера, его настройка, автоматический апгрейд, разворачивание базы). Каждая из этих составляющих требует перезагрузки компьютера. Как сделать, чтобы после перезагрузки инсталлятор продолжал инсталляцию с того момента, на котором ушел на перезагруз? Создаешь 4 отдельных инсталлятора (от общего инсталлятора придется отказаться). Первый прописывает в HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\RunOnce запуск второго, второй - третьего, третий - четвертого.
А в реестр лучше писать только тогда, когда действительно надо. Например, когда закончен первый этап и осталось только перегрузить, вывести сообщение типа "Для завершения установки требуется перегрузка. Перегрузить сейчас?" и две кнопки ОК, Отмена. Вне зависимости от ответа пользователя, прописать ключ в реестр, но при ОК еще и дать команду на рестарт. Тогда не надо будет и удалять.
Как сделать, чтобы полностью были видны имена всех файлов?
[Setup]
AppName=MaxTextLength
AppVerName=MaxTextLength
CreateAppDir=false

[Code]
var string: string;
const MaxLength = 48;

Procedure InitializeWizard;
Begin
string:= ' Test max string Length 1234567890абвгдежзийклмнопрстуфхцчшщъыьэюяёАБВГДЕЖЗИЙКЛМНОПРСТУФХЦЧШЩЪЫЬЭЮЯЁ';
string:= ' ...' + Copy(string, Length(string)-MaxLength, MaxLength);
MsgBox(string + #10#13 ' MaxLength = ' + IntToStr(MaxLength), mbInformation, mb_Ok);
End;
Как проверить, стоит ли атрибут 'Только для чтения' у текстового файла и, если стоит, то убрать его? Вот два решения:
Решение через FindFirst :
function SetFileAttributes(lpFileName: string; dwFileAttributes: integer): integer;
external 'SetFileAttributesA@kernel32.dll stdcall';

procedure InitializeWizard();
var
FileName: string;
SR: TFindRec;
begin
FileName:= 'C:\TEMP\aaa.txt';
FindFirst(FileName, SR);

if (SR.Attributes and FILE_ATTRIBUTE_READONLY) = FILE_ATTRIBUTE_READONLY then
SetFileAttributes(FileName, FILE_ATTRIBUTE_NORMAL);
FindClose(SR);
end;

Решение через GetFileAttributes :
function GetFileAttributes(lpFileName: string): integer;
external 'GetFileAttributesA@kernel32.dll stdcall';

function SetFileAttributes(lpFileName: string; dwFileAttributes: integer): integer;
external 'SetFileAttributesA@kernel32.dll stdcall';

procedure InitializeWizard();
var
FileName: string;
begin
FileName:= 'C:\TEMP\aaa.txt';
if (GetFileAttributes(FileName) and FILE_ATTRIBUTE_READONLY) = FILE_ATTRIBUTE_READONLY then
SetFileAttributes(FileName, FILE_ATTRIBUTE_NORMAL);
end;
Листбокс с картинкой
[Setup]
AppName=My Program
AppVerName=My Program [Version]
DefaultDirName={pf}\My Program

[Files]
Source: Files\*; DestDir: {app}
Source: Image.bmp; DestDir: {app}

[Code]
var
Form: TSetupForm;
ExtraFilesList: TMemo;
CancelButton, DelButton: TButton;
UpImage, DownImage, Image: TBitmapImage;
UpPanel, DownPanel: TPanel;
NameLabel, DescriptionLabel, BeforeListBoxLabel: TLabel;
DownTextLabel: TLabel;

function InitializeUninstall(): Boolean;
begin
FileCopy(ExpandConstant('{app}\Image.bmp'),
ExpandConstant('{tmp}\Image.bmp'), True);
Result := True;
end;

procedure FillListBox(const fromDir, fileMask: string; Level: Byte);
var
FSR, DSR: TFindRec;
FindResult: Boolean;
APath: String;
MainLen: Integer;
i: Integer;
begin
MainLen:= Length(ExpandConstant('{app}'));
APath := AddBackslash(fromDir);
FindResult := FindFirst(APath + fileMask, FSR);
try
while FindResult do
begin
if FSR.Attributes and FILE_ATTRIBUTE_DIRECTORY = 0 then
begin
{files} i:= ExtraFilesList.Lines.Add(Copy(APath + FSR.Name, MainLen+2, Length(APath + FSR.Name)));
end;
FindResult := FindNext(FSR);
end;
FindResult := FindFirst(APath + '*.*', DSR);
while FindResult do
begin
if ((DSR.Attributes and FILE_ATTRIBUTE_DIRECTORY) = FILE_ATTRIBUTE_DIRECTORY) and
not ((DSR.Name = '.') or (DSR.Name = '..')) then
begin
{Recursion} FillListBox(APath + DSR.Name, fileMask, Level+1);
end;
FindResult := FindNext(DSR);
end;
finally
FindClose(FSR);
FindClose(DSR);
end;
end;

procedure DeleteFiles();
begin
DelTree(ExpandConstant('{app}'), True, True, True);
end;

procedure BrowseRemainedFiles();
begin
Form := CreateCustomForm;
Form.ClientWidth := ScaleX(504);
Form.ClientHeight := ScaleY(358);
Form.Caption := 'Paradise - InstallShield Wizard';
Form.Center;

UpImage := TBitmapImage.Create(Form);
UpImage.Top := ScaleY(0);
UpImage.Left := ScaleX(0);
UpImage.Width := Form.ClientWidth;
UpImage.Height := ScaleY(59);
UpImage.BackColor := clWhite;
UpImage.Parent := Form;

Image := TBitmapImage.Create(Form);
Image.Top := ScaleY(0);
Image.Width := ScaleX(142);
Image.Left := Form.ClientWidth - Image.Width;
Image.Height := ScaleY(59);
Image.Bitmap.LoadFromFile(ExpandConstant('{tmp}\Image.bmp'));
Image.Parent := Form;

DownImage := TBitmapImage.Create(Form);
DownImage.Top := ScaleY(61);
DownImage.Left := ScaleX(0);
DownImage.Width := Form.ClientWidth;
DownImage.Height := Form.ClientHeight - DownImage.Top;
DownImage.BackColor := $EEE9EB;
DownImage.Parent := Form;

UpPanel := TPanel.Create(Form);
UpPanel.Top := ScaleY(59);
UpPanel.Width := Form.ClientWidth;
UpPanel.Height := ScaleY(2);
UpPanel.BevelOuter := bvLowered;
UpPanel.Parent := Form;

NameLabel := TLabel.Create(Form);
NameLabel.Top := ScaleY(5);
NameLabel.Left := ScaleX(16);
NameLabel.Font.Style := [fsBold];
NameLabel.Caption := 'Внимание!';
NameLabel.Color := clWhite;
NameLabel.Parent := Form;

DescriptionLabel := TLabel.Create(Form);
DescriptionLabel.Top := ScaleY(24);
DescriptionLabel.Left := ScaleX(25);
DescriptionLabel.Caption := 'Папка установки содержит посторонние файлы. Удалить их?';
DescriptionLabel.Color := clWhite;
DescriptionLabel.Parent := Form;

BeforeListBoxLabel := TLabel.Create(Form);
BeforeListBoxLabel.Top := ScaleY(68);
BeforeListBoxLabel.Left := ScaleX(25);
BeforeListBoxLabel.Caption := 'Если Вы уверены, что хотите удалить папку установки со всеми указанными файлами,'#13 'нажмите Да.'
BeforeListBoxLabel.Color := $EEE9EB;
BeforeListBoxLabel.Parent := Form;

DownPanel := TPanel.Create(Form);
DownPanel.Left := ScaleX(65);
DownPanel.Top := ScaleY(308);
DownPanel.Width := ScaleX(435);
DownPanel.Height := ScaleY(2);
DownPanel.BevelOuter := bvLowered;
DownPanel.Parent := Form;

DownTextLabel := TLabel.Create(Form);
DownTextLabel.Top := ScaleY(302);
DownTextLabel.Caption := ' InstallShield';
DownTextLabel.Font.Color := $99A8AC;
DownTextLabel.Color := $EEE9EB;
DownTextLabel.Parent := Form;

ExtraFilesList := TMemo.Create(Form);
ExtraFilesList.Left := ScaleX(25);
ExtraFilesList.Top := ScaleY(108);
ExtraFilesList.Width := Form.ClientWidth - ScaleX(50);
ExtraFilesList.Height := ScaleY(180);
ExtraFilesList.Color := $EEE9EB;
ExtraFilesList.Parent := Form;

CancelButton := TButton.Create(Form);
CancelButton.Parent := Form;
CancelButton.Width := ScaleX(75);
CancelButton.Height := ScaleY(23);
CancelButton.Left := Form.ClientWidth - CancelButton.Width - ScaleX(20);
CancelButton.Top := Form.ClientHeight - ScaleY(23 + 10);
CancelButton.Caption := 'Нет';
CancelButton.ModalResult := mrCancel;
CancelButton.Cancel := True;

DelButton := TButton.Create(Form);
DelButton.Parent := Form;
DelButton.Width := ScaleX(75);
DelButton.Height := ScaleY(23);
DelButton.Left := CancelButton.Left - DelButton.Width - ScaleX(10);
DelButton.Top := Form.ClientHeight - ScaleY(23 + 10);
DelButton.Caption := 'Да';
DelButton.ModalResult := mrOk;

Form.ActiveControl := CancelButton;

FillListBox(ExpandConstant('{app}'), '*', 1);

if ExtraFilesList.Lines.Count = 0 then
DeleteFiles()
else
if Form.ShowModal() = mrOk then DeleteFiles();
end;

procedure CurUninstallStepChanged(CurUninstallStep: TUninstallStep);
begin
if DirExists(ExpandConstant('{app}')) and (CurUninstallStep = usPostUninstall) then
BrowseRemainedFiles();
end;
Подсчёт длительности установки (по времени старта и завершения)
[Setup]
AppName=My Program
AppVerName=My Program version 1.5
DefaultDirName={pf}\My Program

[Code]
type TSystemTime = record wYear, wMonth, wDayOfWeek, wDay, wHour, wMinute, wSecond, wMilliseconds: Word; end;
var StartTime, Time: TSystemTime; StartFileTime, FileTime: TFileTime; TLabel: TNewStaticText;

function GetLocalTime(var lpSystemTime: TSystemTime): Boolean; external 'GetLocalTime@kernel32.dll stdcall';
function SystemTimeToFileTime(const lpSystemTime: TSystemTime; var lpFileTime: TFileTime): Boolean; external 'SystemTimeToFileTime@kernel32.dll stdcall';
function FileTimeToSystemTime(const lpFileTime: TFileTime; var lpSystemTime: TSystemTime): Boolean; external 'FileTimeToSystemTime@kernel32.dll stdcall';

Function GetWorkTime: String;
Begin
GetLocalTime(Time) {время завершения установки}
SystemTimeToFileTime(Time, FileTime)
SystemTimeToFileTime(StartTime, StartFileTime)

// здесь необходимо использовать 64-битовую арифметику ULARGE_INTEGER
FileTime.dwLowDateTime:= FileTime.dwLowDateTime - StartFileTime.dwLowDateTime
FileTime.dwHighDateTime:= FileTime.dwHighDateTime - StartFileTime.dwHighDateTime

FileTimeToSystemTime(FileTime, Time)
Result:= 'Длительность: ' + IntToStr(Time.wHour) + ' час, ' + IntToStr(Time.wMinute) + ' мин, ' + FloatToStr((Time.wSecond*1000 + Time.wMilliseconds)/1000) + ' сек.'
End;

Procedure CurPageChanged(CurPageID: Integer);
Begin
if CurPageID = wpFinished then TLabel.Caption:= TLabel.Caption + #13#10 + GetWorkTime;
End;

Procedure InitializeWizard;
Begin
GetLocalTime(StartTime) {время начала установки}
TLabel:= TNewStaticText.Create(WizardForm);
TLabel.Top:= WizardForm.CancelButton.Top;
TLabel.Left:= WizardForm.ClientWidth - WizardForm.CancelButton.Left - WizardForm.CancelButton.Width;
TLabel.Parent:= WizardForm;
TLabel.Caption:= 'Время старта: ' + IntToStr(StartTime.wHour) + ' час, ' + IntToStr(StartTime.wMinute) + ' мин, ' + FloatToStr((StartTime.wSecond*1000 + StartTime.wMilliseconds)/1000) + ' сек.' ;
End;
Подсчёт длительности установки (второй вариант):
[Setup]
AppName=My Program
AppVerName=My Program version 1.5
DefaultDirName={pf}\My Program

[Code]
type TSystemTime = record wYear, wMonth, wDayOfWeek, wDay, wHour, wMinute, wSecond, wMilliseconds: Word; end;
var StartTime, Time: TSystemTime; TLabel: TNewStaticText;

function GetLocalTime(var lpTime: TSystemTime): Boolean; external 'GetLocalTime@kernel32.dll stdcall';

Function GetWorkTime: String;
Begin
GetLocalTime(Time) {время завершения установки}
if Time.wHour < StartTime.wHour then begin
Time.wHour:= 24 - StartTime.wHour + Time.wHour
end else begin
Time.wHour:= Time.wHour - StartTime.wHour
end
if Time.wMinute < StartTime.wMinute then begin
Time.wMinute:= 60 - StartTime.wMinute + Time.wMinute
Time.wHour:= Time.wHour - 1
end else begin
Time.wMinute:= Time.wMinute - StartTime.wMinute
end
if Time.wSecond < StartTime.wSecond then begin
Time.wSecond:= 60 - StartTime.wSecond + Time.wSecond
Time.wMinute:= Time.wMinute - 1
end else begin
Time.wSecond:= Time.wSecond - StartTime.wSecond
end
if Time.wMilliseconds < StartTime.wMilliseconds then begin
Time.wMilliseconds:= 1000 - StartTime.wMilliseconds + Time.wMilliseconds
Time.wSecond:= Time.wSecond - 1
end else begin
Time.wMilliseconds:= Time.wMilliseconds - StartTime.wMilliseconds
end
Result:= 'Длительность: ' + IntToStr(Time.wHour) + ' час, ' + IntToStr(Time.wMinute) + ' мин, ' + FloatToStr((Time.wSecond*1000 + Time.wMilliseconds)/1000) + ' сек.'
End;

Procedure CurPageChanged(CurPageID: Integer);
Begin
if CurPageID = wpFinished then TLabel.Caption:= TLabel.Caption + #13#10 + GetWorkTime;
End;

Procedure InitializeWizard;
Begin
GetLocalTime(StartTime) {время начала установки}
TLabel:= TNewStaticText.Create(WizardForm);
TLabel.Top:= WizardForm.CancelButton.Top;
TLabel.Left:= WizardForm.ClientWidth - WizardForm.CancelButton.Left - WizardForm.CancelButton.Width;
TLabel.Parent:= WizardForm;
TLabel.Caption:= 'Время старта: ' + IntToStr(StartTime.wHour) + ' час, ' + IntToStr(StartTime.wMinute) + ' мин, ' + FloatToStr((StartTime.wSecond*1000 + StartTime.wMilliseconds)/1000) + ' сек.' ;
End;
Пример записи в бинарник определенной последовательности байт?
[Setup]
AppName=My Program
AppVerName=My Program v.1.2
DefaultDirName={pf}\My Program

[Code]
procedure WriteToFile;
var
FS: TFileStream;
str: string;
begin
str:= Chr(0)+Chr(10)+Chr(23)+Chr(255)+Chr(30)+Chr(250);

FS := TFileStream.Create('c:\temp\Test.bin',
fmCreate or fmOpenWrite or fmShareDenyWrite);
try
FS.WriteBuffer(str, Length(str));
finally
FS.Free;
end;
end;

procedure InitializeWizard();
begin
WriteToFile;
end;
Как после установки ассоциировать расширение .abc с программой {app}\1.exe ???
[Registry]
Root: HKLM; Subkey: "Software\Classes\.w3m"; ValueType: string; ValueName: ""; ValueData: "WorldEdit.Scenario"; Flags: uninsdeletevalue
Root: HKLM; Subkey: "Software\Classes\WorldEdit.Scenario\DefaultIcon"; ValueType: string; ValueName: ""; ValueData: "{app}\WorldEdit.exe,2"; Flags: uninsdeletevalue
Root: HKLM; Subkey: "Software\Classes\WorldEdit.Scenario\shell\open\command"; ValueType: string; ValueName: ""; ValueData: "{app}\World Editor.exe ""%1"""; Flags: uninsdeletevalue

Здесь создается ассоциация файлов формата *.w3m с программой World Editor.exe.
Как на wpSelectProgramGroup сделать две TRadioButton, первая - создает ярлыки для всех пользователей, вторая - создать ярлыки только для пользователя, который запустил setup?
[Setup]
AppName=My Program
AppVerName=My Program v.1.2
DefaultDirName={pf}\My Program
DefaultGroupName=My Program

[Files]
Source: "MyProg.exe"; DestDir: "{app}"

[Icons]
Name: "{code:MyConst}\My Program"; Filename: "{app}\MyProg.exe"

[Code]
var
CheckListBox: TNewCheckListBox;

function MyConst(Param: String): String;
begin
if CheckListBox.Checked[1] then
Result := ExpandConstant('{commonprograms}')
else
Result := ExpandConstant('{userprograms}');
end;

procedure InitializeWizard();
begin
CheckListBox := TNewCheckListBox.Create(WizardForm);
CheckListBox.Top := WizardForm.GroupEdit.Top + WizardForm.GroupEdit.Height + ScaleY(28);
CheckListBox.Width := WizardForm.GroupEdit.Width;
CheckListBox.Height := ScaleY(97);
CheckListBox.BorderStyle := bsNone;
CheckListBox.ParentColor := True;
CheckListBox.MinItemHeight := WizardForm.TasksList.MinItemHeight;
CheckListBox.ShowLines := False;
CheckListBox.WantTabs := True;
CheckListBox.Parent := WizardForm.SelectProgramGroupPage;
CheckListBox.AddGroup('Create shortcuts', '', 0, nil);
CheckListBox.AddRadioButton('For All Users', '', 0, True, True, nil);
CheckListBox.AddRadioButton('For Current User Only', '', 0, False, True, nil);
end;
Скрипт для установки архивов, записанных на двух DVD. На примере показано извлечение из 7z SFX-архивов.
[Setup]
AppName=My Program
AppVerName=My Program 1.5
DefaultDirName={pf}\My Program
OutputBaseFilename=setup
Compression=none
OutputDir=C:\Output
SolidCompression=no

[Files]
;На диске рядом с инсталлятором размещаем папку EmptyFiles, в которую помещаем "файлы-пустышки" игры.
;Сначала выполняется первый архив (последовательность AfterInstall должна быть такой)
Source: "{src}\EmptyFiles\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs external; AfterInstall: InstallFirstArchive
;А затем второй
Source: "{src}\EmptyFiles\*"; DestDir: "{app}"; Flags: ignoreversion recursesubdirs createallsubdirs external; AfterInstall: CheckSelectedDisk

[Code]
//На странице установки отключаем подтверждающее сообщение (чтобы не было проблем с откатом)
procedure CancelButtonClick(CurPage: Integer; var Cancel, Confirm: Boolean);
begin
Cancel:=True;
If CurPage=12 then
begin
Confirm:=False;
end;
end;

//Устанавливаем первый 7z SFX (Pack1.exe) архив, находящийся на первом диске (рядом с инсталлятором)
//Никаких сообщений об ошибках и т.д. не применяем, т.к. вся ответственность должна лежать на распространителе
procedure InstallFirstArchive;
var
res:Integer;
s,s1:string;
begin
s:=ExpandConstant('{app}');
s1:=ExpandConstant('{src}')+'\Pack1.exe';
Exec(s1, '-y -o"'+ s + '"', '', SW_SHOWNORMAL, ewWaitUntilTerminated, Res);
end;

//Затем выводим соответствующее сообщение для вставки второго диска со вторым архивом
procedure CheckSelectedDisk;
var
res:Integer;
s,s2:string;
Confirm: Boolean;
begin
s:=ExpandConstant('{app}');
s2:=ExpandConstant('{src}')+'\Pack2.exe';
//Если второго архива рядом нету (мало ли, в будущем игра будет записана на двуслойном диске)
if not Exec(s2, '-y -o"'+ s + '"', '', SW_SHOWNORMAL, ewWaitUntilTerminated, Res) then
//то тогда выводим сообщение
case MsgBox('Для дальнейшей установки требуется файл '''+ s2 +'''!'#13#13 +
'Вставьте второй DVD, содержащий архив, и нажмите "OK".' #13#13 +
'Нажмите "Отмена", чтобы прекратить дальнейшую установку.', mbInformation, MB_OKCANCEL)
of IDCANCEL:
begin
//Выполняем откат действий при отмене
Confirm:=False;
WizardForm.CancelButton.OnClick(WizardForm.CancelButton);
end
IDOK:
begin
CheckSelectedDisk;
end;
end;
end;
Нужно, чтобы файл File1.cfg копировался только на определенной машине (проверка имени компьютера и пользователя), а если компьютер не прошел проверку, то копируется только File2.cfg. Как сделать, чтобы конкретная процедура выполнялась на конкретной машине (имя компьютера у меня Comp, а имя пользователя boss911)?
[Setup]
AppName=My Program
AppVerName=My Program v.1.2
DefaultDirName={pf}\My Program

[Files]
Source: C:\Prog\File1.cfg; DestDir: {userappdata}; Check: CheckComputerName
Source: C:\Prog\File2.cfg; DestDir: {userappdata}; Check: Not CheckComputerName

[Code]
function CheckComputerName(): Boolean;
begin
Result:= (Uppercase(GetComputerNameString) =
Uppercase('Comp')) and
(Uppercase(GetUserNameString) =
Uppercase('boss911'));
end;
Извлечение файлов происходит с задержками, т.к. файлов много и они маленькие, проходит приличное время, чтобы найти то, что выбрали. Инсталлятор пролистывает всю первую папку, только потом переходит к нужной! Как это обойти? Для старых версий Inno Setup:
В секции Setup нужно добавить параметр:
[Setup]
SolidCompression=no

Непрерывное сжатие можно не отключать в новых версиях Inno Setup. Если файлы перечислены по порядку (т.е. сначала файлы первой папки, потом файлы второй папки), то к первому файлу второй папки нужно применить флаг solidbreak:
[Setup]
AppName=MyProgram
AppVerName=MyProgram
DefaultDirName={pf}\MyProgram

[Files]
Source: Folder1\*; DestDir: {app}\Folder1; Components: Folder1; Flags: recursesubdirs
Source: Folder2\*; DestDir: {app}\Folder2; Components: Folder2; Flags: recursesubdirs solidbreak

[Components]
Name: Folder1; Description: Folder1
Name: Folder2; Description: Folder2
Подскажите почему в этом примере папка Reality не удаляется, хотя она пустая?
[Registry]
Root: HKLM; Subkey: "SOFTWARE\Reality\Earth"; Flags: uninsdeletekey
Root: HKLM; Subkey: "SOFTWARE\Reality"; Flags: uninsdeletekeyifempty
В процессе деинсталляции ключи реестра удаляются строго в обратной последовательности их добавления при установке программы (при наличии соответствующих флагов). Поэтому в твоём случае должно быть:
[Registry]
Root: HKLM; Subkey: "SOFTWARE\Reality"; Flags: uninsdeletekeyifempty
Root: HKLM; Subkey: "SOFTWARE\Reality\Earth"; Flags: uninsdeletekey
Как заставить Inno Setup засовывать в инсталлятор скрытые файлы, он их почему-то игнорирует? В секции [Files] добавь Attribs: hidden.
Еще способ - запусти ISTool, открой секцию "Файлы и каталоги" и перетащи туда свою папку "sourceDir".
Некоторые игры, у которых запускаемый exe не в корне игры, а где-нибудь в папке, при запуске с создаваемых InnoSetup ярлыков (и на столе, и в программах) вылетают и\или показывают сообщения об ошибке. Надо кое-что дописать после {app}... Вот пример для Bioshock`а:
Name: {group}\BioShock; Filename: {app}\Builds\Release\Bioshock.exe; WorkingDir: {app}\Builds\Release
Здесь ехе расположен не в корне, а в ..\{app}\Builds\Release\