oleg-shilo / wixsharp

Framework for building a complete MSI or WiX source code by using script files written with C# syntax.
MIT License
1.12k stars 175 forks source link

How to set or use Launchcondition Action in Wix# #1641

Closed Torchok19081986 closed 1 month ago

Torchok19081986 commented 2 months ago

morning, i struggle on create msi, where i can perform launchcondition action after appsearch. Following scenario : before Plugin starts installation, it should check if mainprogramm installed and if so, check also .exe fileversion if this not versions, comes from me , are not equals cancel installation. i done some research


public class Program
{
    static void Main()
    {
        var project = new ManagedProject("MyProduct",
                         new Dir(@"%ProgramFiles%\My Company\My Product",
                             new File("Program.cs")));

        project.GUID = new Guid("9d84f407-58c5-485d-985d-451b21f51598");

        //custom set of standard UI dialogs
        project.ManagedUI = new ManagedUI();

        project.ManagedUI.InstallDialogs.Add<WelcomeDialog>()
                                        .Add<LicenceDialog>()
                                        .Add<SetupTypeDialog>()
                                        .Add<FeaturesDialog>()
                                        .Add<InstallDirDialog>()
                                        .Add<ProgressDialog>()
                                        .Add<ExitDialog>();

        project.ManagedUI.ModifyDialogs.Add<MaintenanceTypeDialog>()
                                       .Add<FeaturesDialog>()
                                       .Add<ProgressDialog>()
                                       .Add<ExitDialog>();

        //project.SourceBaseDir = "<input dir path>";
        //project.OutDir = "<output dir path>";
        var launchCondition = new LaunchCondition();
        launchCondition.Value = "Vesion of Installed App";
        launchCondition.Message = "Application not installed or Condition are not fulfilled.";

        project.LaunchConditions.Add(launchCondition); <-- ??? posiblity to Add CustomAction 

        project.BuildMsi();
    }
}

public static class CusotmActions
{
    [CustomAction]
    public static ActionResult SetLaunchCondition(Session session)
    {
        return ActionResult.Success;
    }

    [CustomAction]
    public static ActionResult RegSearch(Session session)
    {
        var appKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\application").GetValue("ProgramDir").ToString();

        if (string.IsNullOrEmpty(appKey))
        {
            return ActionResult.Failure;
        }

        session["INSTALLDIR"] = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\applicationRegs").GetValue("ProgramDir").ToString();

        session["APPVERSION"] = FileVersionInfo.GetVersionInfo(session["INSTALLDIR"] + "\\app.exe").FileVersion;

        Version version = Version.Parse(session["APPVERSION"]);

        if(version.Major != 1 && version.Minor != 2)
        {
            return ActionResult.Failure;
        }

        return ActionResult.Success;
    }
}

WixToolset v4 info : https://wixtoolset.org/docs/schema/wxs/launchconditions/

for any suggestions or code , thanks.

oleg-shilo commented 2 months ago

project.Load += ... event is scheduled before AppSearch, so you can do your checking and then either abort or allow further installation. You do not have to use LaunchConditions, that don't really allow you use anything beyond simle WiX runtime constants checking.

Load          -> When.Before, Step.AppSearch, Execute.Immediate
Torchok19081986 commented 2 months ago

thanks for quick answer, oleg. Any idea, how add cancel installation message if conditions are not fullfilled ? something like shell.customdesriptionerror = "Application is not installed or versions are equal fir plugin " ? This property is exists only in exitdialog.

Torchok19081986 commented 2 months ago

found it on Load Event and just tested.


try
{
    var appKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\application").GetValue("ProgramDir").ToString();

    if (string.IsNullOrEmpty(appKey))
    {
        e.ManagedUI.Shell.CustomErrorDescription = "Programm not installed.";
        e.ManagedUI.Shell.ErrorDetected = true;
    }

    e.Session["INSTALLDIR"] = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\applicationRegs").GetValue("ProgramDir").ToString();

    e.Session["APPVERSION"] = FileVersionInfo.GetVersionInfo(e.Session["INSTALLDIR"] + "\\app.exe").FileVersion;

    Version version = Version.Parse(e.Session["APPVERSION"]);

    if (version.Major != 1 && version.Minor != 2)
    {
        e.ManagedUI.Shell.CustomErrorDescription = "Condition for Installation not fullfilled.";
        e.ManagedUI.Shell.ErrorDetected = true;
    }
}
catch(Exception ex) <--- This Exception executed.
{
    e.ManagedUI.Shell.CustomErrorDescription = "Exception " + ex.ToString();
    e.ManagedUI.Shell.ErrorDetected = true;
}

i also added extra DefaulDeferedProperty APPVERSION to

project.DefaultDeferredProperties = ",APPVERSION";

appears shomehow, only exeception , not Condition for Installation not fullfilled. Versions of exe are not 1.2, but 24.3.15.20511. Any Idea why?

also even i remove this code from Load Event - i see nullref exception and msi error 1602 in windows EventLog. Now i curious. 😵‍💫😵‍💫😵‍💫😵‍💫

Torchok19081986 commented 2 months ago

i think i run in issue. Created new wix Sharp v3 - Custom UI Project. Wait for nuget restore and rebuild project , without changes. Msi is created, but if start it on testsystem appears See the end of this message for details on invoking just-in-time (JIT) debugging instead of this dialog box.

** Exception Text ** System.NullReferenceException: Object reference not set to an instance of an object. at WixSharp_Setup3.Dialogs.WelcomeDialog.ResetLayout() at WixSharp_Setup3.Dialogs.WelcomeDialog.WelcomeDialog_Load(Object sender, EventArgs e) at System.Windows.Forms.Form.OnLoad(EventArgs e) at System.Windows.Forms.Form.OnCreateControl() at System.Windows.Forms.Control.CreateControl(Boolean fIgnoreVisible) at System.Windows.Forms.Control.CreateControl() at System.Windows.Forms.Control.WmShowWindow(Message& m) at System.Windows.Forms.Control.WndProc(Message& m) at System.Windows.Forms.ScrollableControl.WndProc(Message& m) at System.Windows.Forms.Form.WmShowWindow(Message& m) at System.Windows.Forms.Form.WndProc(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.OnMessage(Message& m) at System.Windows.Forms.Control.ControlNativeWindow.WndProc(Message& m) at System.Windows.Forms.NativeWindow.Callback(IntPtr hWnd, Int32 msg, IntPtr wparam, IntPtr lparam)

** Loaded Assemblies ** mscorlib Assembly Version: 4.0.0.0 Win32 Version: 4.8.4749.0 built by: NET48REL1LAST_B CodeBase: file:///C:/Windows/Microsoft.NET/Framework/v4.0.30319/mscorlib.dll

Microsoft.Deployment.WindowsInstaller Assembly Version: 3.0.0.0 Win32 Version: 3.14.0.6526 CodeBase: file:///C:/Users/administrator.TESTDOM/AppData/Local/Temp/2/MSI14977/Microsoft.Deployment.WindowsInstaller.DLL

WixSharp.UI Assembly Version: 1.25.2.0 Win32 Version: 1.25.2.0 CodeBase: file:///C:/Users/administrator.TESTDOM/AppData/Local/Temp/2/MSI14977/WixSharp.UI.DLL

WixSharp Assembly Version: 1.25.2.0 Win32 Version: 1.25.2.0 CodeBase: file:///C:/Users/administrator.TESTDOM/AppData/Local/Temp/2/MSI14977/WixSharp.DLL

System.Windows.Forms Assembly Version: 4.0.0.0 Win32 Version: 4.8.4739.0 built by: NET48REL1LAST_B CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Windows.Forms/v4.0_4.0.0.0__b77a5c561934e089/System.Windows.Forms.dll

System Assembly Version: 4.0.0.0 Win32 Version: 4.8.4749.0 built by: NET48REL1LAST_B CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System/v4.0_4.0.0.0__b77a5c561934e089/System.dll

System.Drawing Assembly Version: 4.0.0.0 Win32 Version: 4.8.4390.0 built by: NET48REL1LAST_C CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Drawing/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.Drawing.dll

System.Core Assembly Version: 4.0.0.0 Win32 Version: 4.8.4749.0 built by: NET48REL1LAST_B CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Core/v4.0_4.0.0.0__b77a5c561934e089/System.Core.dll

WixSharp Setup3 Assembly Version: 1.9.19.2024 Win32 Version: 1.9.19.2024 CodeBase: file:///C:/Users/administrator.TESTDOM/AppData/Local/Temp/2/MSI14977/WixSharp%20Setup3.EXE

System.Xml.Linq Assembly Version: 4.0.0.0 Win32 Version: 4.8.3761.0 built by: NET48REL1 CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Xml.Linq/v4.0_4.0.0.0__b77a5c561934e089/System.Xml.Linq.dll

System.Xml Assembly Version: 4.0.0.0 Win32 Version: 4.8.3761.0 built by: NET48REL1 CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Xml/v4.0_4.0.0.0__b77a5c561934e089/System.Xml.dll

System.Configuration Assembly Version: 4.0.0.0 Win32 Version: 4.8.4190.0 built by: NET48REL1LAST_B CodeBase: file:///C:/Windows/Microsoft.Net/assembly/GAC_MSIL/System.Configuration/v4.0_4.0.0.0__b03f5f7f11d50a3a/System.Configuration.dll

** JIT Debugging ** To enable just-in-time (JIT) debugging, the .config file for this application or computer (machine.config) must have the jitDebugging value set in the system.windows.forms section. The application must also be compiled with debugging enabled.

For example:

When JIT debugging is enabled, any unhandled exception will be sent to the JIT debugger registered on the computer rather than be handled by this dialog box.

also tried on current system, work pc, same error. 😧😧😧😧

Torchok19081986 commented 2 months ago

i checked my originall project for creation msi. i had added


public static class CustomActions
{
    [CustomAction]
    public static ActionResult SetWVToolDir(Session session)
    {
        try
        {
            //x64 - 64 Bit
            session["INSTALLDIR"] = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\app").GetValue("ModuleDir").ToString();

            string path = session["INSTALLDIR"];

            session["DIR2"] = path + @"\Extension\Addins";

            return ActionResult.Success;
        }
        catch (Exception)
        {
            return ActionResult.Failure;
        }
    }

    [CustomAction]
    public static ActionResult SetExtensionManualsDir(Session session)
    {
        session["INSTALLDIR"] = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\App").GetValue("ModuleDir").ToString();
        string path = session["INSTALLDIR"];
        session["DIR3"] = path + @"\Extension\Addins\Manuals";
        return ActionResult.Success;
    }
}

this code works for setting installdr property, but on Load Event apears nullreference Exception. Is Load Event broken or something wrong with it ?

I invistigate some research further, Looks like in Custom UI Template ResetLayout Method is broken. After i commented in each dialog this method out, now it works.

Any recent changes in Custom UI Template ?

oleg-shilo commented 2 months ago

add cancel installation message if conditions are not fullfilled ?

Off the top of my head, you just set result to the user-exit. you can also logg the details to the session log.

args.result = UserExit;
session.Log();

As for ResetLayout. Indeed, I think it was a fix in the latest release of the template. Ensure you are using the latest: image

Torchok19081986 commented 2 months ago

thanks, again. I just checked. VS 2022 doesnt show any Updates for WixSharp Template, i intalled latest template version on my work machine.

Screenshot 2024-09-19 144902

is this somehow related to changes in https://github.com/oleg-shilo/wixsharp/issues/1490 ?

oleg-shilo commented 2 months ago

Yes, it is related. Unfortunately, the original defect has crippled back to the template. Maintaining two editions WiX4 and WiX3 comes with the risks. In this case, I accidentally used the binaryId of WiX4 in the WiX3 template during the packaging.

Since it happened a second time I am converting this in the CI defect.

In the meantime please use this simple workaround that will be the essence of the future fix. In the all void *Dialog_Load(object sender, EventArgs e) methods use this routine for initializing the image:

image.Image = Runtime.Session.GetResourceBitmap("WixSharpUI_Bmp_Dialog") ??
              Runtime.Session.GetResourceBitmap("WixUI_Bmp_Dialog");
Torchok19081986 commented 2 months ago

morning, i tested recent, 30 min ago, workaround works. Many thanks.