Including Redistribuatble .Net in SilentBootstrapper

Mar 3, 2016 at 5:42 PM
I am currently attempting to use a silent bootstrapper to install a .net dependency in our program for users who may not have internet access. We have a redistributable version of the appropriate .net, but we have no apparent way to redirect the ProjectGroupRef('NetFx451Redist') to our redistributable. How would we go about doing that?
Coordinator
Mar 4, 2016 at 2:05 AM
You will need to use ExePackage. Something similar to this:
var bootstrapper =
        new Bundle("My Product",
            new ExePackage(@"..\redist\dotNetFx40_Full_x86_x64.exe")
            {
                    Name = "Microsoft .NET Framework 4.0",
                    InstallCommand = "/passive /norestart",
                    Permanent = true,
                    Vital = true,
                    DetectCondition = "Netfx4FullVersion AND (NOT VersionNT64 OR Netfx4x64FullVersion)",
                    AttributesDefinition="Compressed=yes"
            },
            new MsiPackage(productMsi) { DisplayInternalUI = true });
...
bootstrapper.WixSourceGenerated += Bootstrapper_WixSourceGenerated;
bootstrapper.Build();
...
static void Bootstrapper_WixSourceGenerated(System.Xml.Linq.XDocument document)
{
    document.Select("Wix/Bundle")
            .AddWixFragment(new XElement(WixExtension.Util.ToXName("RegistrySearch"),
                                        @"Root=HKLM;
                                          Key=SOFTWARE\Microsoft\Net Framework Setup\NDP\v4\Full; 
                                          Value=Version; 
                                          Variable=Netfx4FullVersion".ToXAttributes()),

                            new XElement(WixExtension.Util.ToXName("RegistrySearch"),
                                        @"Root=HKLM;
                                          Key=SOFTWARE\Microsoft\Net Framework Setup\NDP\v4\Full; 
                                          Value=Version; 
                                          Win64=yes;
                                          Variable=Netfx4x64FullVersion".ToXAttributes()) );
}
Though I am not sure silent bootstrapper is the best choice for offline .NET install. Let's say it takes 5 minutes to install .NET. Then it means that after double-clicking the setup.exe user have to wait for 5 minutes with no indication if the setup has tarted. You can use the NoUI sample to modify the silent BA so it shows a message box or a progress bar...
Mar 4, 2016 at 4:57 PM
Thank you for the reply, it fixed up our issue. In regards to the .NET install, on both our development and test environments, the .NET installer fires a visual portion that the silent bootstrapper did not suppress, which displayed the progress bar.
Apr 10, 2016 at 4:14 PM
I have been attempting something similar to this, but I keep getting compile errors:
"The Bundle element contains an unhandled extension element 'RegistrySearchRef'. Please ensure that the extension for elements in the'ttps://schemas.microsoft.com/wix/UtilExtension' namespace has been provided.

Any thoughts on how to resolve this issue?
Coordinator
Apr 11, 2016 at 1:24 AM
Most likely your code doesn't specify that Util extension needs to be included. Try adding this:
bootstrapper.IncludeWixExtension(WixExtension.Util); 
BTW now you can use dedicated UtilRegistrySearch Wix# built-in type instead of composing XML manually:
static void WixSourceGenerated(XDocument document)
{
    doc.Select("Wix/Bundle")
       .AddWixFragment(new UtilRegistrySearch 
                       {
                           Root = RegistryHive.LocalMachine,
                           Key = @"Key=SOFTWARE\Microsoft\Net Framework Setup\NDP\v4\Full",
                           Value = "Version",
                           Variable = "Netfx4FullVersion"
                       }.ToXml());
}
Apr 11, 2016 at 10:56 AM
Edited Apr 11, 2016 at 11:51 AM
Hello, I've also tried to implement this, however I keep getting an error 'command exited with code 255'. I even tried the exact same code from the sample 'WixBootstrapper_NoUI', same as the last code in https://wixsharp.codeplex.com/wikipage?title=Managed%20Setup, but I got the same error. What am I missing?
Thanks.

Edit:
It seems that bootstrapper.Build(); is trying to access the build executable, throwing an System.UnauthorizedAccessException. Apperantly it's trying to delete itself.

Unhandled Exception: System.UnauthorizedAccessException: Access to the path 'C:\Projects\Setup\bin\Debug\setup.exe' is denied.
at System.IO.__Error.WinIOError(Int32 errorCode, String maybeFullPath)
at System.IO.File.InternalDelete(String path, Boolean checkHost)
at System.IO.File.Delete(String path)
at WixSharp.Compiler.Build(Bundle project)
at WixSharp.Bootstrapper.Bundle.Build(String path)
at Setup.Program.Main(String[] args)
Coordinator
Apr 11, 2016 at 12:14 PM
Edited Apr 11, 2016 at 12:16 PM
I assume it is a compiler error you are getting in VS. It might be something that upsets the build script (e.g. unhanded exception).

Just to verify the health of your environment can you please see if you can compile the bootstrapper template. I just tested the default Bootsrtapper template
with bootstrapper.IncludeWixExtension(WixExtension.Util) and bootstrapper.WixSourceGenerated... added. If you can then there is something with the user code and there ways of debugging it. But let's see your environment can handle the simple/default content project content.
Coordinator
Apr 11, 2016 at 12:25 PM
OK I see your EDIT.

It can help if I give you a quick highlight on what exactly is happening during the build.
The first stage is compiling your build script (assembly with static main). This will produce <project_name>.exe in your debug dir. As a post build action (if it was no compiler errors) VS will start your build script (<project_name>.exe), which is supposed to build the final bootstrapper binary (<bundle_name>.exe). Before building it the build script will Any delete the old copy if found. And if the file is locked for whatever reason then the whole process will be aborted.

I thing there is a chance that the file is locked by some previous build attempt or you tried to execute the bootstrapper but it in't exit cleanly. In any canse try to delete it manually and you will see if locking is indeed what happens.
Apr 11, 2016 at 12:56 PM
Edited Apr 11, 2016 at 1:07 PM
Thanks for your reply, I can indeed delete the file, so it's not locked. However, if I rename it (ex: setup_.exe), it seems to work, but I get a warning:

"light.exe : error LGHT0388 : The file name 'setup.exe' creates an insecure bundle. Windows will load unnecessary compatibility shims into a bundle with that file name. These compatibility shims can be DLL hijacked allowing attackers to compromise your customers' computer. Choose a different bundle file name."

I'm running Win10/vs 2015 community edition.

Edit: Changing the assembly name fixed the Exception. Is 'Setup.exe' reserved?
I created a new project with a different name, but I still get the warning. I'm not sure where a file setup.exe is being read.
Coordinator
Apr 11, 2016 at 1:13 PM
Yeah, I've seen this one before. This is the changed behavior delivered with WiX v3.10.2.
You can easily fix it by specifying the new exe name in the bootstrapper.Build("MyProduct.exe").

Oleg Shilo
--------------------------------------------------------------------------------------------
Website: http://www.csscript.net
E-Mail: [email removed]

Apr 11, 2016 at 2:12 PM
Ah, I see. Thanks, that fixed the issue.

I had to change the detection condition to ReleaseVersion>379893 (Checks if the current version installed is 4.5.2 or higher)
https://msdn.microsoft.com/en-us/library/hh925568%28v=vs.110%29.aspx

Not sure about VersionNT64 variable however. It always seems to evaluate to true, and false after the NOT.
Apr 13, 2016 at 11:13 PM
Thanks for the reply. I managed to figure out the include after I posted this, and I was already using the .AddWixFragment. That issue now appears to be gone. However, I now get an error and I am not sure what the cause is or how to go about fixing it.

Now I get the following:

light.exe : error LGHT0001: Failed to save resource. Error: 87

Exception Type: System.IO.IOException
1>
1> Stack Trace:
1> at Microsoft.Deployment.Resources.Resource.Save(IntPtr updateHandle)
1> at Microsoft.Deployment.Resources.ResourceCollection.Save(String file)
1> at Microsoft.Tools.WindowsInstallerXml.Binder.UpdateBurnResources(String bundleTempPath, String outputPath, WixBundleRow bundleInfo)
1> at Microsoft.Tools.WindowsInstallerXml.Binder.BindBundle(Output bundle, String bundleFile)
1> at Microsoft.Tools.WindowsInstallerXml.Binder.Bind(Output output, String file)
1> at Microsoft.Tools.WindowsInstallerXml.Tools.Light.Run(String[] args)

I have not tried to resolve it since the weekend, and may just move away from the idea of using a bootstrapper altogether. When I build a raw bootstrapper in Wix 3.10 it seems to work "ok", I just cannot get it to work using WixSharp.

Thanks/
Coordinator
Apr 14, 2016 at 1:09 AM
Wix# provides a significantly reworked API around building MSI, however for building bootstrapper the interface is almost identical to WiX. Thus Wix# becomes just a convenient candle/light launcher. Meaning that if you could do this with WiX then you definitely should be able to do this with Wix#.

In the situations like yours I usually use Wix# to produce the WiX sources and the conduct the actual troubleshooting on WiX (source + tools).

I suggest you change your build script to call BuildCmd instead of Build:
var batchFile = bootstrapper.BuildCmd();
This will result in the creation of the setup.wxs file (instead of *.exe) and the batch file Build_setup.cmd with the all required commands for WiX tools being properly prepared.

From that moment you can forget about Wix# and treat it as a canonical WiX build that is misbehaving. This way it will become obvious if there is something wrong with Wix#, WiX or the setup definitions (C# or WXS sources)