1

I am attempting to use Inno Setup to distribute a file used as a plug-in by another application. If it cannot find the plug-in destination, it should still install itself into the Program Files directory, providing the user with manual instructions.

Hats off to Tlama for providing some code that was used in a similar problem: Inno Setup find subfolder.

The follow script lays out the basic setup I am hoping to achieve, with comment where the script is incomplete. I'm just in over my head. :-)

  1. How to pass the found directory back to StampTargetDir (currently just a MsgBox)

  2. How to search all subdirectories under the specified directory name (i.e. 'Stamps')

  3. How to limit the search of all subdirectories (#2) to just a few named subdirectories living in {pf} or {localappdata} (i.e. "Adobe" and "Acrobat")

  4. Make the file plug-in installation under [Files] conditional on finding the 'Stamps' directory.

P.S. I know searching has some obvious disadvantages. However the "Stamps" directory is unlikely to be used in other areas (see #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;
Community
  • 1
  • 1
gnurob
  • 25
  • 4
  • Not sure I understand. Are you trying to find "Stamps" folder under any "Adobe" folder in Program Files? Doesn't the "Stamps" folder have a fixed location under the "Adobe" folders? Do you really need to search it dynamically? – Martin Prikryl Dec 07 '15 at 08:41
  • I wish! The Acrobat stamp folder is usually under \Program Files\Acrobat\plug-ins\Annotations\Stamps\ but versions 9 and below include the version number in the folder name, like \Program Files\Adobe\Acrobat\[version]\Stamps. Reader also version names, like Program Files\Adobe\Reader 11.0\Reader\plug_ins\Annotations\Stamps. If I had no other choice, I'd fix the directory to Acrobat\plug-ins\Annotations\Stamps\, but would still be left the problem of #4. – gnurob Dec 07 '15 at 12:49

1 Answers1

2
  1. To pass the path from InitializeWizard to StampTargetDir, use a global variable. Though I suggest you better use CurStepChanged(ssInstall) instead of InitializeWizard, unless you need the path earlier than during the actual installation.

  2. Use recursion in GetFirstMatchingSubfolder.

  3. The cleanest solution is to run GetFirstMatchingSubfolder multiple times with specific roots (i.e. twice, for Adobe and for Acrobat)

  4. Use Check parameter.

The code can be like:

[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;
Martin Prikryl
  • 188,800
  • 56
  • 490
  • 992
  • 1
    Excellent, you solved this, and it is a far more reliable approach than I could have hoped for. And, after more than a week of struggling with this, you have no idea how happy I am! Thank you! – gnurob Dec 08 '15 at 02:22