Inheritable installer for multiple projects

Apr 24, 2015 at 1:43 PM
Edited Apr 24, 2015 at 2:03 PM
Hi, community!!!

Have a following situation:
  1. I have c#-based projects A, B and C (all are win forms applications). Each one should be provided to end user via separated installer. So for three module I should have three separated installers.
  2. These installers are came under one brand, have same common features like Manufacturer's name, EULA, UI settings, Language, Codepage, logos and so on.
  3. Of course the are have separated GUIDs, Names, OutFileName and other project-specific fields.
So, I have an idea to create c# library which will contain one simple inheritable InstallerBase class. This class will predefine all common fields. And will keep ability to set specific fields. This way i plan to inherit this class by my module-specific installer class and set module-specific fields only (mentioned in paragraph 3).

Which a best way to do like that?

I've create c# library and add WIX# dependencies (it creates setup.cs automatically) and create a InstallerBase class. Then I created c# console app (installer) with same dependencies + library.

I have deleted from library setup.cs and make sure it still have type "ClassLibrary". Then I have create inherited
class1:InstallerBase
and make appropriate changes.
And then when I try to compile - it compiles and tries to run all that two projects and have a following errors:
and for library i have following error:
"This file does not have a program associated with it for performing this action."

and cmd:
<proj folder>\InstallerBase\bin\Debug\InstallerBase.dll" /MBSBUILD:InstallerBase" exited with code 9020
So yes, I have noted that you probably not prepared your library to do thing like I want or may be I do this things wrong.

So please could you tell me which will be best solution for described situation?

Yeah, I can create Interface like IInstaller which will can be consumed by my base library which will not contain any wix# dependencies. But it will be applyable not in every situation, for example:
project.UI = WUI.WixUI_InstallDir; - this can't be applied without references in base library.
So, please let me know about acceptable approach.
Apr 25, 2015 at 3:36 AM
Edited Apr 25, 2015 at 3:37 AM
I actually would go completely different direction. I know we all have our weak spot for inheritance :o) but I don't think it is justifiable for your case.

You don't want your installs to share the same implementation (purpose of Inheritance). You wan them to be completely individual and self sufficient but yet to be initialized in a similar way. And may be just share the common dependencies.

Wix# faced the same challenge and it is solved via CommonTasks. For example "WixSharp.CommonTasks.Tasks.BuildBootstrapper" Why don't you implement your custom CommonTask and implement your initialization routine there and just call it when you need:
public static class CommomTasks
{
    static public void InitAsMyCompanySetup(this Project project)
    {
        //add common dir and files
        //add common documentation
        //add common actions
        ...
        project.Version = Assembly.GetCallingAssembly().Version;
        project.UI = WUI.WixUI_Minimal;        
        
        project.ControlPanelInfo.Comments = "Simple test msi";
        project.ControlPanelInfo.Readme = "https://wixsharp.codeplex.com/manual";
        project.ControlPanelInfo.HelpLink = "https://wixsharp.codeplex.com/support";
        project.ControlPanelInfo.HelpTelephone = "111-222-333-444";
        project.ControlPanelInfo.UrlInfoAbout = "https://wixsharp.codeplex.com/About";
        project.ControlPanelInfo.UrlUpdateInfo = "https://wixsharp.codeplex.com/update";
        project.ControlPanelInfo.ProductIcon = "app_icon.ico";
        project.ControlPanelInfo.Contact = "Product owner";
        project.ControlPanelInfo.Manufacturer = "My Company";
        project.ControlPanelInfo.InstallLocation = "[INSTALLDIR]";
        project.MajorUpgradeStrategy = MajorUpgradeStrategy.Default;
    }
}
And then you can use it as below:
var project = new Project("MyProduct");
project.InitAsMyCompanySetup(); 

project.GUID = new Guid("6f330b47-2577-43ad-9095-1861ba25889b");
...
Apr 25, 2015 at 8:14 AM
Oleg, thank you for advice.

Indeed, I can just use common static class and function instead of using inheritable class.

So the question will be same - how to share this common static class between specific installer projects? I believe it will throw same error in case if I place common class into separate c# library.

Actually, I found dirty solution. I will upload it to GitHub soon as little proof of concept.

In few words: I've created InstallerBase - "console application" type c# project which includes inheritable class with EMPTY start method to resolve wix# build needs. And then create Installer - "console application" c# project which have reference to InstallerBase and can use shared InstallerBase class.
Then I have setup Build dependencies for Installer project and that's it.
Apr 25, 2015 at 8:37 AM
For the error... You will need to have the CommomTasks (or the InstallerBase) assembly built with a plain ClassLibrary project. If you used the NuGet WixSharp project then it has custom build target for executing the TargetPath as a post build step. Thus you need either remove this tartet from the projevct file manualy or recreate the VS ClassLibrary project manually from scratch and just add the Wix# assembly manually (not by NuGet package).

BTW you can always share any routines between VS projects as a source file not an assembly.
Apr 25, 2015 at 8:51 AM
Yes,
i have just added manually WixSharp libraries and it works like a charm.

Please see my PoC on github InheritableWixSharpInstaller if you interested in my approach.

I have used WixSharp 1.0.15.1 but later I plan migrate to 1.0.16.0


Offtop: And BTW, which the better way to let you know about bugs/suggestions? Should I just start another discussion?
Apr 25, 2015 at 10:09 AM
For bugs/suggestions please use Issue tab and just categorize them correspondingly (issue vs feature).

I also had a look at your code. I think you would benefit from the new Project extension methods in the next release.

Due to the API model you chosen you cannot longer use LINQ-like constructors so project. Add*() would relieve some pain :o)
installer.InstallerProject.AddDir(new Dir(dirPath, new Files("*")));

installer.InstallerProject.AddPropery(new Property("Gritting", "Hello World!"),
                                      new Property("Gritting", "Hello World!"));

installer.InstallerProject.AddAction(new ManagedAction(@"ShowGritting"),
                                     new QtCmdLineAction("notepad.exe", "[NOTEPAD_FILE]"));
Apr 25, 2015 at 10:19 AM
I'm new in WixSharp but strongly interesting in this project.

PoC I've created is just for testing if it can be done in inheritable manner.

So yes, with code reusing I will be able to update my installers quickly.

Thanks for your help!