Inno Setup: Run regsvr32 with a specific working directory - dll

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.

Related

Using FireGiant Appx Extension with cmake

I have a Windows application which is built using MSVC and packaged as an .MSI file using WiX. The whole build is managed by cmake and WiX is invoked using the CPackWIX module.
I am now trying to extend the build environment to also build an .APPX package. I am following the official documentation by FireGiant.
After installing the WiX Expansion Pack, I have added the extension FgAppxExtension.wixext by appending it to the variable CPACK_WIX_EXTENSIONS like so:
SET(CPACK_WIX_EXTENSIONS WixUtilExtension FgAppxExtension.wixext)
I have then edited the .wxs source code as indicated here.
The build runs without any errors but creates no .APPX package. It only creates the usual .MSI package. In the wix.log file I see the line:
"C:/Program Files (x86)/WiX Toolset v3.11/bin/light.exe" -nologo -out "F:/dev/MyApp-build/_CPack_Packages/win32/WIX/MyApp-1.15.0+115-default-eb4abec2e9d2+.msi" -ext "FgAppxExtension.wixext" -ext "WixUIExtension" -ext "WixUtilExtension" -cultures:de-DE;en-US "-loc" "C:/dev/MyApp/resources/packaging/win/WIX.Texts.de-DE.wxl" "-loc" "C:/dev/MyApp/resources/packaging/win/WIX.Texts.en-US.wxl" "F:/dev/MyApp-build/_CPack_Packages/win32/WIX/directories.wixobj" "F:/dev/MyApp-build/_CPack_Packages/win32/WIX/files.wixobj" "F:/dev/AusweisApp2-build/_CPack_Packages/win32/WIX/features.wixobj" "F:/dev/MyApp-build/_CPack_Packages/win32/WIX/main.wixobj"
for the .MSI file, but no line for the .APPX package.
The documentation says that after adding a reference to FgAppxExtension.wixext
... the build process will attempt to create AppX packages.
but this does not happen.
Note that adding a wrong extension in the cmake file will result in a build error.
Changing the .wxs source code without adding the extension will also result in an error:
The Product element contains an unhandled extension element 'fga:Appx'.
So I think the FgAppxExtension.wixext extension is loaded correctly, yet no .APPX package is built.
Do you have any hints?
Loading the FgAppxExtension.wixext extension isn't enough to build the .appx package while building the .msi package. FgAppxExtension does that using MSBuild, which isn't in play when using CMake.
When you're not using MSBuild, you can invoke the FireGiant.Appx.exe tool after Light.exe has produced the .msi and .wixpdb files.

How can I use bindpaths to create a WiX Patch?

I'm using cmake/cpack to build my project with WiX.
cmake runs heat.exe (or something similar) which produces files.wxs that contains the files of my project in the following format:
We'll assume a single file named a.txt inside a folder named "bin". The project is built in NewFolder on the Desktop.
<DirectoryRef Id="CM_DP_bin">
<Component Id="CM_CP_bin.a.txt" Guid="*">
<File Id="CM_FP_bin.a.txt" Source="C:/Users/mindlessbot/Desktop/NewFolder/_CPack_Packages/WIX/packageName/bin/a.txt" KeyPath="yes"/>
</Component>
</DirectoryRef>
After the MSI is created, the whole NewFolder is moved in a different directory (on our server). As a result, when I try to create a WiX Patch using the output .wixpdb, I get the following error:
error PYRO0103 : The system cannot find the file 'C:/Users/mindlessbot/Desktop/NewFolder/_CPack_Packages/WIX/packageName/bin/a.txt'
After some googling, I found out that the .wixpdb contains references to the files, which have changed location, so of course it can't find them. I found a thread where someone provided the commands to use bindpaths, however since I'm using cpack I can't directly call them.
So how should I got about doing this?
Some additional info:
My project contains multiple wxs files (not sure if it makes any difference)
The cpack command is:
path/to/cpack.exe -G WIX --config path/to/config.cmake
The patch command is run separately:
torch.exe -p -xi path/to/oldInstaller.wixpdb path/to/newInstaller.wixpdb -out path/to/patch.wixmst
candle.exe path/to/patch.wxs -out path/to/patch.wixobj
light.exe path/to/patch.wixobj -out path/to/patch/wixmsp
pyro.exe path/to/patch.wixmsp -out path/to/patch.msp -t PatchBaselineID path/to/patch/wixmst
In the event that you would like to build your MSIs on one machine, but build the patch on another, I recommend using the .wixout approach rather than relying on the .wixpdb approach. A .wixout file may be generated by the same WiX Toolset CLI tool that is used to build the MSIs, light.exe. The .wixout
Full documentation on the WiX Toolset linker, light.exe, may be found here. The following is an example use of light.exe to build a .wixout file:
"C:\Program Files (x86)\WiX Toolset v3.11\bin\light.exe" "/path/to/Some.wixobj" "/path/to/Another.wixobj" "/path/to/AndYetAnother.wixlib" -bf -xo -out "/path/to/MyInstaller_v1.wixout"
So now let's breakdown what these command line parameters are for:
"/path/to/Some.wixobj" "/path/to/Another.wixobj" "/path/to/AndYetAnother.wixlib" - These are the compiled outputs of WiX source files, they may be either .wixobj files (generated through candle.exe) or .wixlib files (generated through lit.exe, a way of consolidating .wixobj files into one, shareable library).
-bf - This switch causes all of the files to be bound int the resulting .wixout file. This is what removes the need to have the exact folder structure on the target machine when building patches, because the files are carried with the .wixout file.
-xo - This switch tells the linker to output an XML representation of the MSI, instead of the actual MSI. This is required to use the -bf switch.
-out "/path/to/MyInstaller_v1.wixout" - This tells the linker where to output the .wixout file.
Once you have the capability of generating .wixout files, the torch.exe command can be modified to run based on .wixout files instead of .wixpdb files and their associated folder structures. The following is how I would modify your torch.exe command to use .wixout files as opposed to .wixpdb files:
torch.exe -p -xi "path/to/oldInstaller.wixout" "path/to/newInstaller.wixout" -out "path/to/patch.wixmst"
So, all in all I really like this approach, and generally I make my build process produce both an .msi and a .wixout file. This allows us to cache various builds/versions of our installer as .wixout files, and then the process of creating a patch between various versions of the .wixout files becomes relatively easy.

Program Not Using DLL In directory in System Path

I have a Click Once Deployment program that our office uses. 1.5MB of it is actual program. The rest is static DLL's like EPPlus and PDFSharp. I have a few others totaling about 7MB and I'm getting ready to use SyncFusion's Libraries which are 154MB in size.
I decided that I should leave these DLL files out of the Deployment and instead install them to the systems in question. I'm using Inno with modpath.iss to install these.
[Setup]
AppId={{6485E93B-75FC-4613-AFB7-A1800B986F7D}}
AppName="Required DLL Files"
AppVersion="1.0"
DefaultDirName="{pf}\FE Libraries"
OutputBaseFilename="Required DLL Files.exe"
Compression=lzma2/ultra64
SolidCompression=yes
ChangesEnvironment=true
[Languages]
Name: "english"; MessagesFile: "compiler:Default.isl"
[Files]
Source: "Files\*"; DestDir: "{app}"; Flags: "deleteafterinstall"
[Tasks]
Name: modifypath; Description: &Add application directory to your environmental path; Flags: unchecked
[Code]
const
ModPathName = 'modifypath';
ModPathType = 'system';
function ModPathDir(): TArrayOfString;
begin
setArrayLength(Result, 2)
Result[0] := ExpandConstant('{app}');
end;
#include "modpath.iss"
The files are installed to the correct location, and the Path is added to System Environmental.
Location
c:\Program Files (x86)\WOTC-FE Libraries
Path String
c:\Program Files (x86)\WOTC-FE Libraries
And this is an x86 compiled application.
However, the program won't run any functions requiring these DLL files. I get errors that state that the registered DLL file isn't installed.
System.IO.FileNotFoundException: Could not load file or assembly 'EPPlus, Version=4.0.5.0, Culture=neutral, PublicKeyToken=ea159fdaa78159a1' or one of its dependencies. The system cannot find the file specified.
File name: 'EPPlus, Version=4.0.5.0, Culture=neutral, PublicKeyToken=ea159fdaa78159a1'
So am I missing something?

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.

How to create a custom constant in a parameter section

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.