
Question:
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 <a href="https://stackoverflow.com/users/960757/tlama" rel="nofollow">Tlama</a> for providing some code that was used in a similar problem: <a href="https://stackoverflow.com/q/24784031/850848" rel="nofollow">Inno Setup find subfolder</a>.
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. :-)
<ol><li>How to pass the found directory back to StampTargetDir
(currently just a MsgBox)
How to search all subdirectories under the specified directory name (i.e. 'Stamps')
</li> <li>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")
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).
<pre class="lang-pascal prettyprint-override">[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;
Answer1:<ol><li>
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.
Use recursion in GetFirstMatchingSubfolder
.
The cleanest solution is to run GetFirstMatchingSubfolder
multiple times with specific roots (i.e. twice, for Adobe and for Acrobat)
Use <a href="http://www.jrsoftware.org/ishelp/index.php?topic=scriptcheck" rel="nofollow">Check
parameter</a>.
The code can be like:
<pre class="lang-pascal prettyprint-override">[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;