问题
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. :-)
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')
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).
[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;
回答1:
To pass the path from
InitializeWizard
toStampTargetDir
, use a global variable. Though I suggest you better useCurStepChanged(ssInstall)
instead ofInitializeWizard
, 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 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;
来源:https://stackoverflow.com/questions/34126214/search-subdirectories-for-inno-setup-destdir