70282

Search subdirectories for Inno Setup DestDir

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)

</li> <li>

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")

</li> <li>

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

</li> </ol>

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.

</li> <li>

Use recursion in GetFirstMatchingSubfolder.

</li> <li>

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

</li> <li>

Use <a href="http://www.jrsoftware.org/ishelp/index.php?topic=scriptcheck" rel="nofollow">Check parameter</a>.

</li> </ol>

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;

Recommend

  • How can I build my jar file so that users who use the library will be able to see the javadoc in Ecl
  • Azure UploadDirectoryAsync doesn't overwrite existing files if changed
  • javah NullPointerException while using ANT in Eclipse Indigo
  • Looping files in bash
  • Why Mysql Server Configuration Not Configure Server Password when Reinstalling Setup file?
  • ISCC - /D compiler-parameter seems to have no effect
  • Excluding some source files from javadoc generation using ANT [duplicate]
  • Why is installing the json 1.8.6 gem on Windows 8 not working?
  • Deleting/replacing characters delimited by commas
  • Inno Setup: How to put the installer itself in the installed program
  • Process a set of files from a source directory to a destination directory in Python
  • Access subdomain session from main domain
  • Load unistall icon from exe file in the inno setup
  • make m4 see macro when macro ends with same character as string following macro
  • Gradle Thrift Plugin by Example
  • Rails gemfile editing
  • How can I install Lib::XML on ActiveState Perl 5.20?
  • GetFinalPathNameByHandle() without prepended '\\\\?\\'
  • Unable to use dot layout (graphviz as a library)
  • Cannot connect to native local socket on android 5.1
  • GitHub default README markup
  • Is it possible to run clang with llc flags
  • Is there a way to dynamically embed PDF Files in a JSP pulled from the file system?
  • Creating PDF from TIFF image using iText
  • Clear activity stack before launching another activity
  • Zoom in and out of jPanel
  • Firefox Extension - Monitor refresh and change of tab
  • Saving Changes After In-App Purchase Has Been Purchased
  • Counter field in MS Access, how to generate?
  • Javascript + PHP Encryption with pidCrypt
  • Symfony2: How to get request parameter
  • Websockets service method fails during R startup
  • To display the title for the current loaction in map in iphone
  • Akka Routing: Reply's send to router ends up as dead letters
  • jqPlot EnhancedLegendRenderer plugin does not toggle series for Pie charts
  • How do I rollback to a specific git commit
  • Is there a mandatory requirement to switch app.yaml?
  • Why can't I rebase on to an ancestor of source changesets if on a different branch?
  • Busy indicator not showing up in wpf window [duplicate]