Including MSM merge modules in a Wix# installer - how to? What am I doing wrong?

Mar 4, 2015 at 5:48 AM
So I decided to create a merge module for the NUnit Test runner, to include in some diagnostics deployments. It seems to generate the MSM just fine. However, when I try to include it in my main installer, I get the exception shown below.

This is my first go-round with using Merge Modules in Wix# and it seemed like a good idea to package the NUnit test runner that way, as I intend to use it in multiple installers.

"
Here is the MSM code:
using System;
using WixSharp;


namespace NUnitTestRunner
{
    using System.IO;

    using File = WixSharp.File;

    internal class Script
    {
        const string NUnitFolder = @"C:\dolutolytfs01\DEV\Enterprise\Common\NUnit\bin";

        private const string NUnitTestRunnerFolder = "NUnitTestRunner";
        public static void Main(string[] args)
        {

            var project = new Project
                (
                "NUnitTestRunner",
                new Dir
                    (@"%ProgramFiles%\" + NUnitTestRunnerFolder,
                        new File(Path.Combine(NUnitFolder, "nunit.exe")),
                        new File(Path.Combine(NUnitFolder, "nunit.exe.config")),
                        new File(Path.Combine(NUnitFolder, "nunit-console.exe")),
                        new File(Path.Combine(NUnitFolder, "nunit-console.exe.config")),
                        new File(Path.Combine(NUnitFolder, "nunit-x86.exe")),
                        new File(Path.Combine(NUnitFolder, "nunit-x86.exe.config")),
                        new File(Path.Combine(NUnitFolder, "nunit-console-x86.exe")),
                        new File(Path.Combine(NUnitFolder, "nunit-console-x86.exe.config")),
                        new File(Path.Combine(NUnitFolder, "nunit-agent.exe")),
                        new File(Path.Combine(NUnitFolder, "nunit-agent.exe.config")),
                        new File(Path.Combine(NUnitFolder, "Framework", "nunit.framework.dll")),
                        new File(Path.Combine(NUnitFolder, "Framework", "nunit.framework.xml")),
                        new File(Path.Combine(NUnitFolder, "Lib", "nunit.core.dll")),
                        new File(Path.Combine(NUnitFolder, "Lib", "nunit.core.interfaces.dll")),
                        new File(Path.Combine(NUnitFolder, "Lib", "nunit.uiexception.dll")),
                        new File(Path.Combine(NUnitFolder, "Lib", "nunit.uikit.dll")),
                        new File(Path.Combine(NUnitFolder, "Lib", "nunit.util.dll")),
                        new File(Path.Combine(NUnitFolder, "Lib", "nunit-gui-runner.dll"))
                    )
                );

            project.UI = WUI.WixUI_ProgressOnly;
            project.Manufacturer = "NUnit Project";

            Compiler.BuildMsm(project);

            Console.ReadLine();
        }
    }
}
I get this exception:
{"Only WixSharp.FileShortcut,WixSharp.FileAssociation and WixSharp.ServiceInstaller items can be added to WixSharp.ServiceInstaller"}
            Feature featureA = new Feature("Feature A");
            Feature featureB = new Feature("Feature B");

            var project = new Project
                (
                "SetupLettersDiagnostics",
                new Dir
                    (@"%ProgramFiles%\" + LettersDiagnosticsSubFolder, 
                        new File(featureA,Path.Combine(MyBinariesFolder, "VerifyLettersSetup.dll")),
                        new File(featureA,Path.Combine(MyBinariesFolder, "LettersDiagnostics.dll")),
                        new File(featureA,Path.Combine(MyBinariesFolder, "WindowsPCDiagnosticsHelpers.dll")),
                        new File(featureA,Path.Combine(MyFilesFolder, "RunLettersDiagnostics.bat"), 
                            new FileShortcut("Run Letters Diagnostics", @"%ProgramMenu%\Letters PC Diagnostics"),
                            new FileShortcut("Run Letters Diagnostics", "%Desktop%")),
                        new File(featureA,Path.Combine(NUnitFolder, "nunit.exe")),
                        new File(featureA,Path.Combine(NUnitFolder, "nunit.exe.config")),
                        new File(featureA,Path.Combine(NUnitFolder, "nunit-console.exe")),
                        new File(featureA,Path.Combine(NUnitFolder, "nunit-console.exe.config")),
                        new File(featureA,Path.Combine(NUnitFolder, "nunit-x86.exe")),
                        new File(featureA,Path.Combine(NUnitFolder, "nunit-x86.exe.config")),
                        new File(featureA,Path.Combine(NUnitFolder, "nunit-console-x86.exe")),
                        new File(featureA,Path.Combine(NUnitFolder, "nunit-console-x86.exe.config")),
                        new File(featureA,Path.Combine(NUnitFolder, "nunit-agent.exe")),
                        new File(featureA,Path.Combine(NUnitFolder, "nunit-agent.exe.config")),
                        new File(featureA,Path.Combine(NUnitFolder, "Framework", "nunit.framework.dll")),
                        new File(featureA,Path.Combine(NUnitFolder, "Framework", "nunit.framework.xml")),
                        new File(featureA,Path.Combine(NUnitFolder, "Lib", "nunit.core.dll")),
                        new File(featureA,Path.Combine(NUnitFolder, "Lib", "nunit.core.interfaces.dll")),
                        new File(featureA,Path.Combine(NUnitFolder, "Lib", "nunit.uiexception.dll")),
                        new File(featureA,Path.Combine(NUnitFolder, "Lib", "nunit.uikit.dll")),
                        new File(featureA,Path.Combine(NUnitFolder, "Lib", "nunit.util.dll")),
                        new File(featureA,Path.Combine(NUnitFolder, "Lib", "nunit-gui-runner.dll")),
                        new File(featureA,Path.Combine(NUnitFolder, "Lib", "nunit-console-runner.dll"),
                        new Merge(featureB, myNUnitTestRunnerMergeFile)
                        ) 

                    ),
                new ManagedAction("RunLettersPCDiagnostics", Return.ignore, When.After, Step.InstallFinalize, Condition.Installed));
               // This also fails
                new Merge(myNUnitTestRunnerMergeFile);
I've tried two ways of including the Merge statement, BOTH of which are shown above, but I only tried them one at a time. As far as I know, the Merge that is in the "Dir" constructor, following all the "File" entries is the "more correct" way.

However, no matter which way I do this, I get the same exception at MSI (attempted) run-and-build time, every time.

Again, I get this exception:
{"Only WixSharp.FileShortcut,WixSharp.FileAssociation and WixSharp.ServiceInstaller items can be added to WixSharp.ServiceInstaller"}

I am not telling it anywhere that my installer is a "ServiceInstaller"; it isn't, or at least, not on purpose. Ideas for making this build and pull in the Merge Module and work successfully?
Mar 13, 2015 at 5:27 AM
Edited Mar 14, 2015 at 12:33 AM
The formatting let you down. This is the code you are effectively executing:
new Project("SetupLettersDiagnostics",
            new Dir(@"%ProgramFiles%\test",
                    new File(featureA, Path.Combine("", "nunit.exe")),
                    ...
                    new File(featureA, Path.Combine("", "Lib", "nunit-console-runner.dll"),
                             new Merge(featureB, "MyMergeModule.msm"))));
The fix is to move Merge one level up (into the Dir constructor)

Unfortunately the File constructor arguments validation routine has a bug, which leads to the malformed message:
"Only {0}, {1} and {2} items can be added to {2}"
//instead of
"Only {0}, {1} and {2} items can be added to {3}"
The correct message should be: "Only WixSharp.FileShortcut, WixSharp.FileAssociation and WixSharp.ServiceInstaller items can be added to WixSharp.File"

The error message problem is corrected and the fix will be available in the next release.
Mar 13, 2015 at 11:13 PM
Yes!! That fixed the issue I was having. THANK YOU!!

Moving the Merge outside, into the Dir constructor, as above made the Merge part work successfully. I must not have paid close enough attention to other Merge examples. Shades of Lisp and its endless parentheses!! Now I can get rid of the unnecessary feature A/B stuff too; I had added that trying to diagnose/work around the issue. The modified code below now works.
            var project = new Project
                (
                "SetupLettersDiagnostics",
                new Dir
                    (@"%ProgramFiles%\" + LettersDiagnosticsSubFolder, 
                        new File(featureA,Path.Combine(MyBinariesFolder, "VerifyLettersSetup.dll")),
                        new File(featureA,Path.Combine(MyBinariesFolder, "LettersDiagnostics.dll")),
                        new File(featureA,Path.Combine(MyBinariesFolder, "WindowsPCDiagnosticsHelpers.dll")),
                        new File(featureA,Path.Combine(MyFilesFolder, "RunLettersDiagnostics.bat"), 
                            new FileShortcut("Run Letters Diagnostics", @"%ProgramMenu%\Letters PC Diagnostics"),
                            new FileShortcut("Run Letters Diagnostics", "%Desktop%")),
                        new File(featureA,Path.Combine(NUnitFolder, "nunit.exe")),
                        new File(featureA,Path.Combine(NUnitFolder, "nunit.exe.config")),
                        new File(featureA,Path.Combine(NUnitFolder, "nunit-console.exe")),
                        new File(featureA,Path.Combine(NUnitFolder, "nunit-console.exe.config")),
                        new File(featureA,Path.Combine(NUnitFolder, "nunit-x86.exe")),
                        new File(featureA,Path.Combine(NUnitFolder, "nunit-x86.exe.config")),
                        new File(featureA,Path.Combine(NUnitFolder, "nunit-console-x86.exe")),
                        new File(featureA,Path.Combine(NUnitFolder, "nunit-console-x86.exe.config")),
                        new File(featureA,Path.Combine(NUnitFolder, "nunit-agent.exe")),
                        new File(featureA,Path.Combine(NUnitFolder, "nunit-agent.exe.config")),
                        new File(featureA,Path.Combine(NUnitFolder, "Framework", "nunit.framework.dll")),
                        new File(featureA,Path.Combine(NUnitFolder, "Framework", "nunit.framework.xml")),
                        new File(featureA,Path.Combine(NUnitFolder, "Lib", "nunit.core.dll")),
                        new File(featureA,Path.Combine(NUnitFolder, "Lib", "nunit.core.interfaces.dll")),
                        new File(featureA,Path.Combine(NUnitFolder, "Lib", "nunit.uiexception.dll")),
                        new File(featureA,Path.Combine(NUnitFolder, "Lib", "nunit.uikit.dll")),
                        new File(featureA,Path.Combine(NUnitFolder, "Lib", "nunit.util.dll")),
                        new File(featureA,Path.Combine(NUnitFolder, "Lib", "nunit-gui-runner.dll")),
                        new File(featureA,Path.Combine(NUnitFolder, "Lib", "nunit-console-runner.dll")
                        ),
                        new Merge(featureB, myNUnitTestRunnerMergeFile)
                    ),
                new ManagedAction("RunLettersPCDiagnostics", Return.ignore, When.After, Step.InstallFinalize, Condition.Installed));