0
votes

I have created a WIX bootstrapper application exe which installs an msi. Currently the UI will display install or uninstall based on the status of the application in the user's machine. User can then press this button to start the installation. Now I want this process to happen automatically. It should start installing/uninstalling as soon as the user double clicks on the exe. The UI will only be displaying the progress. Is this possible? Below is my bootstrapper bundle.wxs.

<?xml version="1.0" encoding="UTF-8"?>
<Wix xmlns="http://schemas.microsoft.com/wix/2006/wi" xmlns:util="http://schemas.microsoft.com/wix/UtilExtension" xmlns:bal="http://schemas.microsoft.com/wix/BalExtension">
  <Bundle Name="Kube Installer" Version="1.0.0.0" Manufacturer="Zone24x7" UpgradeCode="C82A383C-751A-43B8-90BF-A250F7BC2863">
    <BootstrapperApplicationRef Id="ManagedBootstrapperApplicationHost" >
      <Payload SourceFile="..\CustomBA\BootstrapperCore.config"/>
      <Payload SourceFile="..\CustomBA\bin\Release\CustomBA.dll"/>
      <Payload SourceFile="..\CustomBA\bin\Release\GalaSoft.MvvmLight.WPF4.dll"/>
      <Payload SourceFile="C:\Program Files (x86)\WiX Toolset v3.8\SDK\Microsoft.Deployment.WindowsInstaller.dll"/>
    </BootstrapperApplicationRef>
    <WixVariable Id="WixMbaPrereqLicenseUrl" Value=""/>
    <WixVariable Id="WixMbaPrereqPackageId" Value=""/>
    <Chain>
      <MsiPackage SourceFile="..\KubeInstaller\bin\Release\KubeInstaller.msi" Id="KubeInstallationPackageId" Cache="yes" Visible="no"/>
    </Chain>

  </Bundle>


</Wix>

Below is my ViewModel class which does the checking of the installation state and enables the relevant button accordingly.

public class MainViewModel : ViewModelBase
    {
        //constructor
        public MainViewModel(BootstrapperApplication bootstrapper)
        {

            this.IsThinking = false;

            this.Bootstrapper = bootstrapper;
            this.Bootstrapper.ApplyComplete += this.OnApplyComplete;
            this.Bootstrapper.DetectPackageComplete += this.OnDetectPackageComplete;
            this.Bootstrapper.PlanComplete += this.OnPlanComplete;

            this.Bootstrapper.CacheAcquireProgress += (sender, args) =>
            {
                this.cacheProgress = args.OverallPercentage;
                this.Progress = (this.cacheProgress + this.executeProgress) / 2;
            };
            this.Bootstrapper.ExecuteProgress += (sender, args) =>
            {
                this.executeProgress = args.OverallPercentage;
                this.Progress = (this.cacheProgress + this.executeProgress) / 2;
            };
        }

        #region Properties

        private bool installEnabled;
        public bool InstallEnabled
        {
            get { return installEnabled; }
            set
            {
                installEnabled = value;
                RaisePropertyChanged("InstallEnabled");
            }
        }

        private bool uninstallEnabled;
        public bool UninstallEnabled
        {
            get { return uninstallEnabled; }
            set
            {
                uninstallEnabled = value;
                RaisePropertyChanged("UninstallEnabled");
            }
        }

        private bool isThinking;
        public bool IsThinking
        {
            get { return isThinking; }
            set
            {
                isThinking = value;
                RaisePropertyChanged("IsThinking");
            }
        }

        private int progress;
        public int Progress
        {
            get { return progress; }
            set
            {
                this.progress = value;
                RaisePropertyChanged("Progress");
            }
        }

        private int cacheProgress;
        private int executeProgress;

        public BootstrapperApplication Bootstrapper { get; private set; }

        #endregion //Properties

        #region Methods

        private void InstallExecute()
        {
            IsThinking = true;
            Bootstrapper.Engine.Plan(LaunchAction.Install);
        }

        private void UninstallExecute()
        {
            IsThinking = true;
            Bootstrapper.Engine.Plan(LaunchAction.Uninstall);
        }

        private void ExitExecute()
        {
            CustomBA.BootstrapperDispatcher.InvokeShutdown();
        }

        /// <summary>
        /// Method that gets invoked when the Bootstrapper ApplyComplete event is fired.
        /// This is called after a bundle installation has completed. Make sure we updated the view.
        /// </summary>
        private void OnApplyComplete(object sender, ApplyCompleteEventArgs e)
        {
            IsThinking = false;
            InstallEnabled = false;
            UninstallEnabled = false;
            this.Progress = 100;
        }

        /// <summary>
        /// Method that gets invoked when the Bootstrapper DetectPackageComplete event is fired.
        /// Checks the PackageId and sets the installation scenario. The PackageId is the ID
        /// specified in one of the package elements (msipackage, exepackage, msppackage,
        /// msupackage) in the WiX bundle.
        /// </summary>
        private void OnDetectPackageComplete(object sender, DetectPackageCompleteEventArgs e)
        {
            if (e.PackageId == "KubeInstallationPackageId")
            {
                if (e.State == PackageState.Absent)
                    InstallEnabled = true;

                else if (e.State == PackageState.Present)
                    UninstallEnabled = true;
            }
        }

        /// <summary>
        /// Method that gets invoked when the Bootstrapper PlanComplete event is fired.
        /// If the planning was successful, it instructs the Bootstrapper Engine to 
        /// install the packages.
        /// </summary>
        private void OnPlanComplete(object sender, PlanCompleteEventArgs e)
        {
            if (e.Status >= 0)
                Bootstrapper.Engine.Apply(System.IntPtr.Zero);
        }

        #endregion //Methods

        #region RelayCommands

        private RelayCommand installCommand;
        public RelayCommand InstallCommand
        {
            get
            {
                if (installCommand == null)
                    installCommand = new RelayCommand(() => InstallExecute(), () => InstallEnabled == true);

                return installCommand;
            }
        }

        private RelayCommand uninstallCommand;
        public RelayCommand UninstallCommand
        {
            get
            {
                if (uninstallCommand == null)
                    uninstallCommand = new RelayCommand(() => UninstallExecute(), () => UninstallEnabled == true);

                return uninstallCommand;
            }
        }

        private RelayCommand exitCommand;
        public RelayCommand ExitCommand
        {
            get
            {
                if (exitCommand == null)
                    exitCommand = new RelayCommand(() => ExitExecute());

                return exitCommand;
            }
        }

        #endregion //RelayCommands
    }
1

1 Answers

1
votes

I don't see where you're starting the Detect process, so my assumption is that you're doing that somewhere else. But, it does look like you're enabling the buttons in your OnDetectPackageComplete method. Instead, you could just call Plan() (or call your InstallExecute or UninstallExecute wrappers) from your OnDetectPackageComplete method. So once the detection phase is completed, you'd immediate go into the Plan phase, which you've already wired up in your OnPlanComplete method to jump into the Apply phase, giving you the behavior you desire.