Привет, друзья! Сегодня мы рассмотрим, как использовать Inno Setup для установки файлов дополнений в директорию Program Files и предоставить пользователю ручные инструкции, если целевая директория не найдена.
Описание проблемы
Мы хотим распределить файл, используемый в качестве дополнения другим приложением, с помощью Inno Setup. Если Inno Setup не может найти директорию назначения для дополнения, то он должен установить сам себя в директорию Program Files, предоставив пользователю ручные инструкции.
Решение
Для решения этой задачи мы будем использовать код, предоставленный Tlama в ответе на похожий вопрос: Inno Setup find subfolder.
Сначала давайте разберемся со скриптом, который мы имеем:
[Files]
Source: "C:\mydir\readme.pdf"; DestDir: "{app}"; Flags: ignoreversion
Source: "C:\mydir\stamp.pdf"; DestDir: "{app}"; Flags: ignoreversion
; If found, install the stamp file in the Adobe Acrobat or Reader Stamp directory.
Source: "C:\mydir\stamp.pdf"; DestDir: "{code:StampTargetDir}"; Flags: ignoreversion
[Tasks]
Name: pf; Description: "&All users on this computer."; GroupDescription: "Configure Acrobat stamp plug-in:"; Flags: exclusive
Name: local; Description: "&Only the current user (me)."; GroupDescription: "Configure Acrobat stamp plug-in:"; Flags: exclusive unchecked
Name: none; Description: "&Do not configure stamps (manual setup)."; GroupDescription: "Configure Acrobat stamp plug-in:"; Flags: exclusive unchecked
[Code]
function GetFirstMatchingSubfolder(const Path: string; out Folder: string): Boolean;
var
S: string;
FindRec: TFindRec;
begin
Result := False;
if FindFirst(ExpandConstant(AddBackslash(Path) + '*'), FindRec) then
try
repeat
// *** THIS DOES NOT SEARCH SUBDIRECTORIES ***
if (FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY <> 0) and
(FindRec.Name <> '.') and (FindRec.Name <> '..') and
(FindRec.Name = 'Stamps') then
begin
Result := True;
Folder := AddBackslash(Path) + FindRec.Name;
end;
until
not FindNext(FindRec);
finally
FindClose(FindRec);
end;
end;
function StampTargetDir(Param: String): String;
begin
if IsTaskSelected('pf') then
// *** THIS NEEDS TO BE 'Stamps' DIRECTORY FOUND UNDER {pf}
Result := ExpandConstant('{app}') + '\pf'
else if IsTaskSelected('local') then
// *** THIS NEEDS TO BE 'Stamps' DIRECTORY FOUND UNDER {localappdata}
// Assuming {localappdata} is the user's Application Data Folder
// Typically C:\Documents and Settings\username\Application Data.
Result := ExpandConstant('{app}') + '\local'
else
Result := ExpandConstant('{app}') + '\none'
end;
// *** This procedure is just for testing. The results of
// GetFirstMatchingSubfolder should be used by StampTargetDir
procedure InitializeWizard;
var
S: string;
begin
// *** THIS DOES NOT LIMIT SEARCH TO {pf}\Adobe or {pf}\Acrobat ***
if GetFirstMatchingSubfolder(ExpandConstant('{pf}'), S) then
MsgBox('An extra copy will go in here: ' + S, mbInformation, MB_OK);
end;
Теперь давайте разберемся с каждым пунктом и устраним проблемы в скрипте.
1. Как передать найденную директорию из GetFirstMatchingSubfolder в StampTargetDir (в настоящее время просто отображается диалоговое окно MsgBox)?
Для передачи найденной директории из GetFirstMatchingSubfolder в StampTargetDir мы можем использовать глобальную переменную. Однако, я бы порекомендовал использовать CurStepChanged(ssInstall) вместо InitializeWizard, если вам не нужно получать путь раньше, чем во время фактической установки.
2. Как просканировать все поддиректории под заданным именем директории (например, 'Stamps')?
Мы можем использовать рекурсию в функции GetFirstMatchingSubfolder для сканирования всех поддиректорий.
3. Как ограничить поиск всех поддиректорий (пункт 2) только несколькими именованными поддиректориями, расположенными в {pf} или {localappdata} (например, "Adobe" и "Acrobat")?
Самый чистый способ - запустить GetFirstMatchingSubfolder несколько раз с конкретными корнями (например, дважды - для Adobe и для Acrobat).
4. Как сделать установку файла дополнения в разделе [Files] условной в зависимости от обнаружения директории 'Stamps'?
Мы можем использовать параметр Check для этого.
Теперь давайте обновим скрипт, чтобы решить эти проблемы:
[Files]
Source: "C:\mydir\stamp.pdf"; DestDir: "{code:GetStampsFolderPath}"; \
Check: WasStampsFolderFound; Flags: ignoreversion
[Code]
const
StampsFolderName = 'Stamps';
var
StampsFolderPath: string;
function WasStampsFolderFound(): Boolean;
begin
Result := (StampsFolderPath <> '');
end;
function GetStampsFolderPath(Params: string): string;
begin
Result := StampsFolderPath;
end;
function GetFirstMatchingSubfolderRecursively(const Path: string; Name: string; out Folder: string): Boolean;
var
FindRec: TFindRec;
FolderPath: string;
begin
Result := False;
Log(Format('Searching in %s', [Path]));
if FindFirst(AddBackslash(Path) + '*', FindRec) then
try
repeat
if (FindRec.Attributes and FILE_ATTRIBUTE_DIRECTORY <> 0) then
begin
FolderPath := AddBackslash(Path) + FindRec.Name;
if CompareText(FindRec.Name, Name) = 0 then
begin
Result := True;
Folder := FolderPath;
Log(Format('Match: %s', [Folder]));
end
else
if (FindRec.Name <> '.') and (FindRec.Name <> '..') then
begin
Result := GetFirstMatchingSubfolderRecursively(FolderPath, Name, Folder);
end;
end;
until Result or (not FindNext(FindRec));
finally
FindClose(FindRec);
end;
end;
procedure CurStepChanged(CurStep: TSetupStep);
var
RootPath: string;
begin
Log(Format('CurStepChanged %d', [CurStep]));
if CurStep = ssInstall then
begin
if IsTaskSelected('pf') then
begin
// this should be pf32 or pf64 specifically,
// depending on where Adobe installs the applications
RootPath := ExpandConstant('{pf}\');
end
else
if IsTaskSelected('local') then
begin
RootPath := ExpandConstant('{localappdata}\');
end;
if RootPath = '' then
begin
Log(Format('No task selected, will not search for %s', [StampsFolderName]));
end
else
begin
Log(Format('Searching for %s folder under %s', [StampsFolderName, RootPath]));
if GetFirstMatchingSubfolderRecursively(RootPath + 'Adobe', StampsFolderName, StampsFolderPath) or
GetFirstMatchingSubfolderRecursively(RootPath + 'Acrobat', StampsFolderName, StampsFolderPath) then
begin
Log(Format('Found %s folder at %s', [StampsFolderName, StampsFolderPath]));
end
else
begin
Log(Format('%s folder not found anywhere', [StampsFolderName]));
end;
end;
end;
end;
Теперь, если целевая директория для дополнения не найдена, Inno Setup установит сам себя в директорию Program Files и предоставит пользователю ручные инструкции. Кроме того, если директория 'Stamps' найдена, файл дополнения будет установлен в эту директорию.
Надеюсь, эта статья помогла вам решить проблему установки файлов дополнений с помощью Inno Setup. Удачи!
Использование Inno Setup для установки файлов дополнений в директорию Program Files и предоставления пользователю ручных инструкций, если целевая директория не найдена.
Комментарии и вопросы
Получайте свежие новости и обновления по Object Pascal, Delphi и Lazarus прямо в свой смартфон. Подпишитесь на наш Telegram-канал delphi_kansoftware и будьте в курсе последних тенденций в разработке под Linux, Windows, Android и iOS
Материалы статей собраны из открытых источников, владелец сайта не претендует на авторство. Там где авторство установить не удалось, материал подаётся без имени автора. В случае если Вы считаете, что Ваши права нарушены, пожалуйста, свяжитесь с владельцем сайта.