How to create a custom constant in a parameter section - variables

For example, I would like to create a variable to store some directory in the [Files] section, like this: mydir=CustomDir; so I can reference it later when I'm importing my files
Source: "{mydir}\MyProg.exe"; DestDir: "{app}";
Source: "{mydir}\MyProg.chm"; DestDir: "{app}";
I want to do this because later on I can easily change the directory of my importing files, and for other customizations in other parts.
Is there something in Inno that allow me to do that?

You can do this using the Inno Setup Preprocessor.
That is good for compile-time constants. If you wanted to set a variable at install-time, you could use Inno Setup's Pascal scripting.

Related

How to define a dynamic preprocessor in wix for heat generated files

I am trying to package the binaries of an external application in my installer. This external application is managed by another department. There can be multiple versions installed and in multiple locations (ie Program Files and Program Files (x86)). There is a batch file that can find the latest version installed.
What I am trying to do is to dynamically define a preprocessor that matches the location of this external app.
Here is how I proceed.
In the Pre-build Event Command Line of the wix project, I call a batch file.
This batch file finds the path to the external app (ie C:\Program Files (x86)\Foo company\Bar program v3.4) and saves it in an environment variable (%EXTERNAL_APP_PATH%).
Then I call heat with: call "%WIX%bin\heat.exe" dir "%EXTERNAL_APP_PATH%" -cg ExternalAppBinaryFiles -dr INSTALLBINDIR -sreg -srd -var var.ExternalAppBinariesSourceDir -ag -sfrag -out "heat_generated.wxs"
Then I generate a custom file heat_var_ExternalAppBinariesSourceDir.wxs whose content looks like the following:
<?xml version="1.0" encoding="utf-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi">
<?define ExternalAppBinariesSourceDir = "C:\Program Files (x86)\Foo company\Bar program v3.4" ?>
</Wix>
When building the project, I get the following error: heat_generated.wxs(6,0): error CNDL0150: Undefined preprocessor variable '$(var.ExternalAppBinariesSourceDir)'.
I was expecting that file heat_var_ExternalAppBinariesSourceDir.wxs which define this preprocessor variable would be sufficient for the heat generated file. Mostly because I do include heat_var_ExternalAppBinariesSourceDir.wxs in my project files.
My understanding is that heat generated files only resolves preprocessor variables from "global preprocessor variables" defined in the project properties (under Build section, label "Define preprocessor variables").
If I define this preprocessor variable as ExternalAppBinariesSourceDir=C:\Program Files (x86)\Foo company\Bar program v3.4 in the project properties, the solution builds with no error.
However, I do have to hardcode the path which is the opposite of "dynamically find the path of my application".
A possible solution would be to add a custom include file (*.wxi) in the generated heat file. Is there a way to force my heat generated file to include another file? This way I could generate a custom include file with the preprocessor variable defined.
Maybe I am not using heat as intended. If I omit the -var var.ExternalAppBinariesSourceDir part in the command line, the Source attribute of <File> elements are prefixed with SourceDir\.
The result is a build fail with the following error: error LGHT0103: The system cannot find the file 'SourceDir\myapp.exe'.
Is there a way to have absolute paths for Source attributes in a heat generated file?
I would like to keep the process as lite as possible for people that build the installer. For example, double-click the solution file in File Explorer, the solution opens in Visual Studio, right-click the Wix setup project and select Build.
I have looked at many other wix example. I have not found people that have the same use case as mine. Most use cases hardcode a preprocessor with a relative path to the binaries from the project files. Some suggest to change the arguments to candle.exe/light.exe, but like I said, I build from Visual Studio and does not call light.exe or candle.exe directly.
I suspect that I should be able to specify "search paths" for resolving paths that are prefixed with SourceDir\. Looking at my project properties in Visual Studio, there is a "paths" section, but it is all grayed out. Again, I will need to be able to specify dynamic search paths. The problem is still the same. Also search paths might be problematic if multiple directories have the same filename. This is often problematic when packaging a dll with a standard name.
I am using Visual Studio 2017 and Wix Toolset 3.11.
If you want to use an environment variable as the base for your files, you have a few options. Both MSBuild and WiX provide ways to access environment variables directly:
In MSBuild, environment variables are straight-up available as properties. So you could use $(EXTERNAL_APP_PATH) in your .wixproj and get the path. In particular, you could use it in a DefineConstants property in your .wixproj like:
<PropertyGroup>
<DefineConstants>
$(DefineConstants);
ExternalAppBinariesSourceDir=$(EXTERNAL_APP_PATH)
</DefineConstants>
</PropertyGroup>
In WiX, you can directly reference environment variables in the preprocessor using $(env.EXTERNAL_APP_PATH). That will accomplish the same as the above but without using $(var.ExternalAppBinariesSourceDir) as an intermediary.
The option I would choose is a combination of the above two. I'd use BindPaths (a WiX feature designed to allow you to specify where your files are found) along with the MSBuild support for environment variables by adding the following item to your .wixproj:
<ItemGroup>
<BindInputPath Include="$(EXTERNAL_APP_PATH)" />
</ItemGroup>
Then all the file sources rooted in SourceDir\ will automatically search the list of BindInputPaths from your .wixproj to be found.
The latter option is the most powerful and flexible. But any of the above should get you what you want... assuming you want to use the environment variable. Modifying the above to use an MSBuild property from the command line (or other options) should not be hard either.

WiX Burn: Create custom log file name for MsiPackage?

When Burn runs an MSI installer, using MsiPackage, I'd like the MSI's log file to have a custom name, like MyProductName.log. I'd also like to append to an existing log file (with same name).
In InstallShield's Basic MSI Project's Release view there is an entry "MSI Command-Line Arguments" where you can enter a custom log file name:
/l+* "%TEMP%\MyProductName.log"
The "+" will append the log to an existing file.
Burn can pass public properties to the MSI, but I don't see a way to do what I want.
It looks like I'll need to write code (custom Burn bootstrapper) to run after the MsiPackage is installed (or uninstalled) to copy the contents of the log file (in the Burn variable defined in LogPathVariable) to the file with the custom name.
You can use the LogPathVariable attribute of the MsiPackage element to provide a custom log file name ...
See: http://wixtoolset.org/documentation/manual/v3/xsd/wix/msipackage.html
Also: https://support.firegiant.com/hc/en-us/articles/230912207-Pass-Properties-to-MsiPackage-from-Bundle-
To do what I needed, I wrote a simple bootstrapper, which became more complicated as I addressed things like passing installer properties to the bootstrapper, giving warnings if installing an x86 installer on an x64 OS (we encourage customers to use and x64 installer), etc.

Inno Setup: Run regsvr32 with a specific working directory

I'm trying to register a number of DLL's as part of my installer. I'm using the regserver flag, and it works perfectly for most of the DLL's. However, one DLL fails to register. It tries to load other DLL's and fails if it can't find them in the current directory. It registers cleanly if regsvr32 is run manually from the {app} directory.
Is there any way to set the working directory for the regserver flag? Or the whole installer?
For now, I'm working round it via a [Run] entry:
[Run]
;Register components that are "special"
Filename: "{sys}\Regsvr32.exe"; Parameters: "/s Awkward.dll"; \
WorkingDir: "{app}"; StatusMsg: "Registering components ... "; \
Flags: runhidden;
But this is not ideal, as I suspect I also ought to add an [UninstallRun] section and add an unregister command. I'd hoped I could do:
[Files]
Source: "{#mysrc}\Awkward.dll"; DestDir: "{app}"; Flags: regserver; \
WorkingDir: "{app}"
Is there an easier way to register/unregister from a specific directory?
You cannot. The regsvr32.exe that Inno Setup runs internally to (un)register DLLs is explicitly run from a system directory (typically the C:\Windows\System32).
Your workaround is the best way.
Just add an equivalent [UninstallRun] entry to unregister the DLL:
[UninstallRun]
Filename: "{sys}\regsvr32.exe"; Parameters: "/u /s Awkward.dll";
WorkingDir: "{app}"; Flags: runhidden;
Or even better, fix the DLL not to rely on a working directory. You can use the LOAD_WITH_ALTERED_SEARCH_PATH flag for the LoadLibraryEx.
See also Dynamic-Link Library Search Order.

Use WiX or Inno Setup to bundle the installation of several MSI files

I use cx-freeze to create an MSI installer for a Python application. Let's call it application "A". It depends on another application "B". I would like my installer for "A" to include and run the MSI installer for "B". How can I create a bootstrapping/chaining installer using Inno Setup or the WiX toolset?
Here is a basic Inno Setup script that bundles two MSI installations into a single setup program. Since the installer only exists to install MSI files, there is no need for an application directory. To avoid creating the application directory, use "CreateAppDir=no". (thanks TLama!)
[Setup]
AppName=My Bundle Installer
AppVersion=0.1
DefaultDirName={pf}\MyCo\MyBundle
DefaultGroupName=My Bundle Group
Uninstallable=no
CreateAppDir=no
[Files]
Source: "A.msi"; DestDir: "{tmp}"
Source: "B.msi"; DestDir: "{tmp}"
[Run]
Filename: "msiexec.exe"; Parameters: "/i ""{tmp}\A.msi"""
Filename: "msiexec.exe"; Parameters: "/i ""{tmp}\B.msi"""
You'll need to use a bootstrapper/chainer. For example, the WiX toolset provides a concept called a Bundle that can combine multiple packages into a single installation.

Settings file to be used in WIX and InstallShield

I've create a setup with WIX and i have a wxi file where i define some properties for the installer. Some of them are read by a custom action and used there. So the variables defined in the wxi file are set as some basic properties values in the main file.
Config File:
<?define MyVariable="fileName.txt" ?>
Main File:
<Property Id="MyVariableProperty" Value="$(var.MyVariable)"/>
Now i want to create the same setup but using InstallShiled, and i want to use the same file with all the settings, or a similar one in order to avoid duplicating the same information.
My question is how can this be achieved ? What kind of file i should use in order to be able to read the values from it and set them as properties without any custom actions involved, in both WIX and InstallShield.
Thanks.
This is a build automation issue and I know 2 paths to solve it.
1) Place the properties in merge modules and then use product configurations and release flags to drive which module gets merged into the installer.
2) Write a build step that parses the XPIs out of the wxs/wxi and updates the installer project. This can be done with the IS COM Automation Interface, DTF ( Binary ISM ) and XPath DOM ( XML ISM ).