Поиск подкаталогов для Inno Setup DestDir

Я пытаюсь использовать Inno Setup для распространения файла, используемого в качестве подключаемого модуля другим приложением. Если он не может найти место назначения подключаемого модуля, он все равно должен установить себя в каталог Program Files, предоставив пользователю ручные инструкции.

Снимаю шляпу перед Tlama за предоставление некоторого кода, который использовался в аналогичной проблеме: Inno Setup найти подпапку.

В следующем сценарии изложены основные настройки, которых я надеюсь достичь, с комментариями в тех случаях, когда сценарий неполный. Я просто не в себе. :-)

  1. Как передать найденный каталог обратно в StampTargetDir (в настоящее время просто MsgBox)

  2. Как выполнить поиск во всех подкаталогах с указанным именем каталога (например, «Штампы»)

  3. Как ограничить поиск во всех подкаталогах (#2) несколькими именованными подкаталогами, находящимися в {pf} или {localappdata} (например, «Adobe» и «Acrobat»)

  4. Сделайте установку подключаемого модуля файла под [Files] обусловленной нахождением каталога «Штампы».

P.S. Я знаю, что поиск имеет некоторые очевидные недостатки. Однако маловероятно, что каталог «Штампы» будет использоваться в других областях (см. №3).

[Files]
; Install all the files in a user specified location.
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;

person gnurob    schedule 07.12.2015    source источник
comment
Не уверен, что понимаю. Вы пытаетесь найти папку Stamps в любой папке Adobe в Program Files? Разве папка Stamps не имеет фиксированного местоположения в папках Adobe? Вам действительно нужен динамический поиск?   -  person Martin Prikryl    schedule 07.12.2015
comment
Хотел бы я! Папка штампов Acrobat обычно находится в папке \Program Files\Acrobat\plug-ins\Annotations\Stamps\, но версии 9 и ниже включают номер версии в имя папки, например \Program Files\Adobe\Acrobat[версия]\Stamps. Reader также называет версии, например Program Files\Adobe\Reader 11.0\Reader\plug_ins\Annotations\Stamps. Если бы у меня не было другого выбора, я бы исправил каталог в Acrobat\plug-ins\Annotations\Stamps\, но все равно остался бы с проблемой #4.   -  person gnurob    schedule 07.12.2015


Ответы (1)


  1. Чтобы передать путь от InitializeWizard к StampTargetDir, используйте глобальную переменную. Хотя я предлагаю вам лучше использовать CurStepChanged(ssInstall) вместо InitializeWizard, если вам не нужен путь раньше, чем во время фактической установки.

  2. Используйте рекурсию в GetFirstMatchingSubfolder.

  3. Самое чистое решение — запускать GetFirstMatchingSubfolder несколько раз с определенными корнями (т. е. дважды, для Adobe и для Acrobat).

  4. Используйте параметр 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;
person Martin Prikryl    schedule 07.12.2015
comment
Отлично, вы решили эту проблему, и это гораздо более надежный подход, чем я мог надеяться. И, после более чем недели борьбы с этим, вы не представляете, как я счастлив! Спасибо! - person gnurob; 08.12.2015