From 62352fabd541aaa9d0a2c957c4bdd4b9c682df9c Mon Sep 17 00:00:00 2001 From: Sean Hall Date: Wed, 11 Dec 2019 19:34:47 +1100 Subject: Import files from BootstrapperCore repo. --- .../BaseBootstrapperApplicationFactory.cs | 16 + src/WixToolset.Mba.Core/BootstrapperApplication.cs | 1591 ++++++++++++++++ .../BootstrapperApplicationData.cs | 63 + .../BootstrapperApplicationFactory.cs | 86 + .../BootstrapperApplicationFactoryAttribute.cs | 35 + src/WixToolset.Mba.Core/BootstrapperCommand.cs | 107 ++ .../BootstrapperSectionGroup.cs | 29 + src/WixToolset.Mba.Core/BundleInfo.cs | 67 + src/WixToolset.Mba.Core/Engine.cs | 516 ++++++ src/WixToolset.Mba.Core/EventArgs.cs | 1903 ++++++++++++++++++++ src/WixToolset.Mba.Core/Exceptions.cs | 145 ++ src/WixToolset.Mba.Core/HostSection.cs | 47 + .../IBootstrapperApplicationData.cs | 12 + .../IBootstrapperApplicationFactory.cs | 52 + src/WixToolset.Mba.Core/IBootstrapperCommand.cs | 63 + src/WixToolset.Mba.Core/IBundleInfo.cs | 16 + .../IDefaultBootstrapperApplication.cs | 65 + src/WixToolset.Mba.Core/IEngine.cs | 176 ++ src/WixToolset.Mba.Core/IPackageInfo.cs | 20 + src/WixToolset.Mba.Core/IVariables.cs | 27 + src/WixToolset.Mba.Core/NativeMethods.cs | 37 + src/WixToolset.Mba.Core/PackageInfo.cs | 181 ++ .../SupportedFrameworkElement.cs | 47 + .../SupportedFrameworkElementCollection.cs | 36 + .../WixToolset.BootstrapperCore.config | 26 + src/balutil/inc/IBootstrapperApplicationFactory.h | 14 + 26 files changed, 5377 insertions(+) create mode 100644 src/WixToolset.Mba.Core/BaseBootstrapperApplicationFactory.cs create mode 100644 src/WixToolset.Mba.Core/BootstrapperApplication.cs create mode 100644 src/WixToolset.Mba.Core/BootstrapperApplicationData.cs create mode 100644 src/WixToolset.Mba.Core/BootstrapperApplicationFactory.cs create mode 100644 src/WixToolset.Mba.Core/BootstrapperApplicationFactoryAttribute.cs create mode 100644 src/WixToolset.Mba.Core/BootstrapperCommand.cs create mode 100644 src/WixToolset.Mba.Core/BootstrapperSectionGroup.cs create mode 100644 src/WixToolset.Mba.Core/BundleInfo.cs create mode 100644 src/WixToolset.Mba.Core/Engine.cs create mode 100644 src/WixToolset.Mba.Core/EventArgs.cs create mode 100644 src/WixToolset.Mba.Core/Exceptions.cs create mode 100644 src/WixToolset.Mba.Core/HostSection.cs create mode 100644 src/WixToolset.Mba.Core/IBootstrapperApplicationData.cs create mode 100644 src/WixToolset.Mba.Core/IBootstrapperApplicationFactory.cs create mode 100644 src/WixToolset.Mba.Core/IBootstrapperCommand.cs create mode 100644 src/WixToolset.Mba.Core/IBundleInfo.cs create mode 100644 src/WixToolset.Mba.Core/IDefaultBootstrapperApplication.cs create mode 100644 src/WixToolset.Mba.Core/IEngine.cs create mode 100644 src/WixToolset.Mba.Core/IPackageInfo.cs create mode 100644 src/WixToolset.Mba.Core/IVariables.cs create mode 100644 src/WixToolset.Mba.Core/NativeMethods.cs create mode 100644 src/WixToolset.Mba.Core/PackageInfo.cs create mode 100644 src/WixToolset.Mba.Core/SupportedFrameworkElement.cs create mode 100644 src/WixToolset.Mba.Core/SupportedFrameworkElementCollection.cs create mode 100644 src/WixToolset.Mba.Core/WixToolset.BootstrapperCore.config create mode 100644 src/balutil/inc/IBootstrapperApplicationFactory.h (limited to 'src') diff --git a/src/WixToolset.Mba.Core/BaseBootstrapperApplicationFactory.cs b/src/WixToolset.Mba.Core/BaseBootstrapperApplicationFactory.cs new file mode 100644 index 00000000..e9b60929 --- /dev/null +++ b/src/WixToolset.Mba.Core/BaseBootstrapperApplicationFactory.cs @@ -0,0 +1,16 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.BootstrapperCore +{ + public abstract class BaseBootstrapperApplicationFactory : IBootstrapperApplicationFactory + { + public IBootstrapperApplication Create(IBootstrapperEngine pEngine, ref Command command) + { + IEngine engine = new Engine(pEngine); + IBootstrapperCommand bootstrapperCommand = command.GetBootstrapperCommand(); + return this.Create(engine, bootstrapperCommand); + } + + protected abstract IBootstrapperApplication Create(IEngine engine, IBootstrapperCommand bootstrapperCommand); + } +} diff --git a/src/WixToolset.Mba.Core/BootstrapperApplication.cs b/src/WixToolset.Mba.Core/BootstrapperApplication.cs new file mode 100644 index 00000000..c08a60c7 --- /dev/null +++ b/src/WixToolset.Mba.Core/BootstrapperApplication.cs @@ -0,0 +1,1591 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.BootstrapperCore +{ + using System; + using System.Runtime.InteropServices; + using System.Threading; + + /// + /// The default bootstrapper application. + /// + [ClassInterface(ClassInterfaceType.None)] + public abstract class BootstrapperApplication : MarshalByRefObject, IDefaultBootstrapperApplication + { + /// + /// Specifies whether this bootstrapper should run asynchronously. The default is true. + /// + protected readonly bool asyncExecution; + + /// + /// Gets the for interaction with the engine. + /// + protected readonly IEngine engine; + + private bool applying; + + /// + /// Creates a new instance of the class. + /// + protected BootstrapperApplication(IEngine engine) + { + this.engine = engine; + this.applying = false; + this.asyncExecution = true; + } + + /// + /// Fired when the engine is starting up the bootstrapper application. + /// + public event EventHandler Startup; + + /// + /// Fired when the engine is shutting down the bootstrapper application. + /// + public event EventHandler Shutdown; + + /// + /// Fired when the system is shutting down or user is logging off. + /// + /// + /// To prevent shutting down or logging off, set to + /// true; otherwise, set it to false. + /// By default setup will prevent shutting down or logging off between + /// and . + /// Derivatives can change this behavior by overriding + /// or handling . + /// If contains + /// the bootstrapper cannot prevent the shutdown and only has a few seconds to save state or perform any other + /// critical operations before being closed by the operating system. + /// This event may be fired on a different thread. + /// + public event EventHandler SystemShutdown; + + /// + /// Fired when the overall detection phase has begun. + /// + public event EventHandler DetectBegin; + + /// + /// Fired when a forward compatible bundle is detected. + /// + public event EventHandler DetectForwardCompatibleBundle; + + /// + /// Fired when the update detection phase has begun. + /// + public event EventHandler DetectUpdateBegin; + + /// + /// Fired when the update detection has found a potential update candidate. + /// + public event EventHandler DetectUpdate; + + /// + /// Fired when the update detection phase has completed. + /// + public event EventHandler DetectUpdateComplete; + + /// + /// Fired when a related bundle has been detected for a bundle. + /// + public event EventHandler DetectRelatedBundle; + + /// + /// Fired when the detection for a specific package has begun. + /// + public event EventHandler DetectPackageBegin; + + /// + /// Fired when a package was not detected but a package using the same provider key was. + /// + public event EventHandler DetectCompatibleMsiPackage; + + /// + /// Fired when a related MSI package has been detected for a package. + /// + public event EventHandler DetectRelatedMsiPackage; + + /// + /// Fired when an MSP package detects a target MSI has been detected. + /// + public event EventHandler DetectTargetMsiPackage; + + /// + /// Fired when a feature in an MSI package has been detected. + /// + public event EventHandler DetectMsiFeature; + + /// + /// Fired when the detection for a specific package has completed. + /// + public event EventHandler DetectPackageComplete; + + /// + /// Fired when the detection phase has completed. + /// + public event EventHandler DetectComplete; + + /// + /// Fired when the engine has begun planning the installation. + /// + public event EventHandler PlanBegin; + + /// + /// Fired when the engine has begun planning for a related bundle. + /// + public event EventHandler PlanRelatedBundle; + + /// + /// Fired when the engine has begun planning the installation of a specific package. + /// + public event EventHandler PlanPackageBegin; + + /// + /// Fired when the engine plans a new, compatible package using the same provider key. + /// + public event EventHandler PlanCompatibleMsiPackageBegin; + + /// + /// Fired when the engine has completed planning the installation of a specific package. + /// + public event EventHandler PlanCompatibleMsiPackageComplete; + + /// + /// Fired when the engine is about to plan the target MSI of a MSP package. + /// + public event EventHandler PlanTargetMsiPackage; + + /// + /// Fired when the engine is about to plan a feature in an MSI package. + /// + public event EventHandler PlanMsiFeature; + + /// + /// Fired when the engine has completed planning the installation of a specific package. + /// + public event EventHandler PlanPackageComplete; + + /// + /// Fired when the engine has completed planning the installation. + /// + public event EventHandler PlanComplete; + + /// + /// Fired when the engine has begun installing the bundle. + /// + public event EventHandler ApplyBegin; + + /// + /// Fired when the engine is about to start the elevated process. + /// + public event EventHandler ElevateBegin; + + /// + /// Fired when the engine has completed starting the elevated process. + /// + public event EventHandler ElevateComplete; + + /// + /// Fired when the engine has changed progress for the bundle installation. + /// + public event EventHandler Progress; + + /// + /// Fired when the engine has encountered an error. + /// + public event EventHandler Error; + + /// + /// Fired when the engine has begun registering the location and visibility of the bundle. + /// + public event EventHandler RegisterBegin; + + /// + /// Fired when the engine has completed registering the location and visibility of the bundle. + /// + public event EventHandler RegisterComplete; + + /// + /// Fired when the engine has begun removing the registration for the location and visibility of the bundle. + /// + public event EventHandler UnregisterBegin; + + /// + /// Fired when the engine has completed removing the registration for the location and visibility of the bundle. + /// + public event EventHandler UnregisterComplete; + + /// + /// Fired when the engine has begun caching the installation sources. + /// + public event EventHandler CacheBegin; + + /// + /// Fired when the engine has begun caching a specific package. + /// + public event EventHandler CachePackageBegin; + + /// + /// Fired when the engine has begun acquiring the installation sources. + /// + public event EventHandler CacheAcquireBegin; + + /// + /// Fired when the engine has progress acquiring the installation sources. + /// + public event EventHandler CacheAcquireProgress; + + /// + /// Fired by the engine to allow the BA to change the source + /// using or . + /// + public event EventHandler ResolveSource; + + /// + /// Fired when the engine has completed the acquisition of the installation sources. + /// + public event EventHandler CacheAcquireComplete; + + /// + /// Fired when the engine begins the verification of the acquired installation sources. + /// + public event EventHandler CacheVerifyBegin; + + /// + /// Fired when the engine complete the verification of the acquired installation sources. + /// + public event EventHandler CacheVerifyComplete; + + /// + /// Fired when the engine has completed caching a specific package. + /// + public event EventHandler CachePackageComplete; + + /// + /// Fired after the engine has cached the installation sources. + /// + public event EventHandler CacheComplete; + + /// + /// Fired when the engine has begun installing packages. + /// + public event EventHandler ExecuteBegin; + + /// + /// Fired when the engine has begun installing a specific package. + /// + public event EventHandler ExecutePackageBegin; + + /// + /// Fired when the engine executes one or more patches targeting a product. + /// + public event EventHandler ExecutePatchTarget; + + /// + /// Fired when Windows Installer sends an installation message. + /// + public event EventHandler ExecuteMsiMessage; + + /// + /// Fired when Windows Installer sends a files in use installation message. + /// + public event EventHandler ExecuteFilesInUse; + + /// + /// Fired when the engine has completed installing a specific package. + /// + public event EventHandler ExecutePackageComplete; + + /// + /// Fired when the engine has completed installing packages. + /// + public event EventHandler ExecuteComplete; + + /// + /// Fired when the engine has completed installing the bundle. + /// + public event EventHandler ApplyComplete; + + /// + /// Fired by the engine while executing on payload. + /// + public event EventHandler ExecuteProgress; + + /// + /// Fired when the engine is about to launch the preapproved executable. + /// + public event EventHandler LaunchApprovedExeBegin; + + /// + /// Fired when the engine has completed launching the preapproved executable. + /// + public event EventHandler LaunchApprovedExeComplete; + + /// + /// Entry point that is called when the bootstrapper application is ready to run. + /// + protected abstract void Run(); + + /// + /// Called by the engine on startup of the bootstrapper application. + /// + /// Additional arguments for this event. + protected virtual void OnStartup(StartupEventArgs args) + { + EventHandler handler = this.Startup; + if (null != handler) + { + handler(this, args); + } + + if (this.asyncExecution) + { + this.engine.Log(LogLevel.Verbose, "Creating BA thread to run asynchronously."); + Thread uiThread = new Thread(this.Run); + uiThread.Name = "UIThread"; + uiThread.SetApartmentState(ApartmentState.STA); + uiThread.Start(); + } + else + { + this.engine.Log(LogLevel.Verbose, "Creating BA thread to run synchronously."); + this.Run(); + } + } + + /// + /// Called by the engine to uninitialize the BA. + /// + /// Additional arguments for this event. + protected virtual void OnShutdown(ShutdownEventArgs args) + { + EventHandler handler = this.Shutdown; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the system is shutting down or the user is logging off. + /// + /// Additional arguments for this event. + /// + /// To prevent shutting down or logging off, set to + /// true; otherwise, set it to false. + /// By default setup will prevent shutting down or logging off between + /// and . + /// Derivatives can change this behavior by overriding + /// or handling . + /// If contains + /// the bootstrapper cannot prevent the shutdown and only has a few seconds to save state or perform any other + /// critical operations before being closed by the operating system. + /// This method may be called on a different thread. + /// + protected virtual void OnSystemShutdown(SystemShutdownEventArgs args) + { + EventHandler handler = this.SystemShutdown; + if (null != handler) + { + handler(this, args); + } + else if (null != args) + { + // Allow requests to shut down when critical or not applying. + bool critical = EndSessionReasons.Critical == (EndSessionReasons.Critical & args.Reasons); + args.Cancel = !critical && this.applying; + } + } + + /// + /// Called when the overall detection phase has begun. + /// + /// Additional arguments for this event. + protected virtual void OnDetectBegin(DetectBeginEventArgs args) + { + EventHandler handler = this.DetectBegin; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the update detection phase has begun. + /// + /// Additional arguments for this event. + protected virtual void OnDetectForwardCompatibleBundle(DetectForwardCompatibleBundleEventArgs args) + { + EventHandler handler = this.DetectForwardCompatibleBundle; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the update detection phase has begun. + /// + /// Additional arguments for this event. + protected virtual void OnDetectUpdateBegin(DetectUpdateBeginEventArgs args) + { + EventHandler handler = this.DetectUpdateBegin; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Fired when the update detection has found a potential update candidate. + /// + /// Additional arguments for this event. + protected virtual void OnDetectUpdate(DetectUpdateEventArgs args) + { + EventHandler handler = this.DetectUpdate; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the update detection phase has completed. + /// + /// Additional arguments for this event. + protected virtual void OnDetectUpdateComplete(DetectUpdateCompleteEventArgs args) + { + EventHandler handler = this.DetectUpdateComplete; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when a related bundle has been detected for a bundle. + /// + /// Additional arguments for this event. + protected virtual void OnDetectRelatedBundle(DetectRelatedBundleEventArgs args) + { + EventHandler handler = this.DetectRelatedBundle; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the detection for a specific package has begun. + /// + /// Additional arguments for this event. + protected virtual void OnDetectPackageBegin(DetectPackageBeginEventArgs args) + { + EventHandler handler = this.DetectPackageBegin; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when a package was not detected but a package using the same provider key was. + /// + /// Additional arguments for this event. + protected virtual void OnDetectCompatibleMsiPackage(DetectCompatibleMsiPackageEventArgs args) + { + EventHandler handler = this.DetectCompatibleMsiPackage; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when a related MSI package has been detected for a package. + /// + /// Additional arguments for this event. + protected virtual void OnDetectRelatedMsiPackage(DetectRelatedMsiPackageEventArgs args) + { + EventHandler handler = this.DetectRelatedMsiPackage; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when an MSP package detects a target MSI has been detected. + /// + /// Additional arguments for this event. + protected virtual void OnDetectTargetMsiPackage(DetectTargetMsiPackageEventArgs args) + { + EventHandler handler = this.DetectTargetMsiPackage; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when an MSI feature has been detected for a package. + /// + /// Additional arguments for this event. + protected virtual void OnDetectMsiFeature(DetectMsiFeatureEventArgs args) + { + EventHandler handler = this.DetectMsiFeature; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the detection for a specific package has completed. + /// + /// Additional arguments for this event. + protected virtual void OnDetectPackageComplete(DetectPackageCompleteEventArgs args) + { + EventHandler handler = this.DetectPackageComplete; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the detection phase has completed. + /// + /// Additional arguments for this event. + protected virtual void OnDetectComplete(DetectCompleteEventArgs args) + { + EventHandler handler = this.DetectComplete; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine has begun planning the installation. + /// + /// Additional arguments for this event. + protected virtual void OnPlanBegin(PlanBeginEventArgs args) + { + EventHandler handler = this.PlanBegin; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine has begun planning for a prior bundle. + /// + /// Additional arguments for this event. + protected virtual void OnPlanRelatedBundle(PlanRelatedBundleEventArgs args) + { + EventHandler handler = this.PlanRelatedBundle; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine has begun planning the installation of a specific package. + /// + /// Additional arguments for this event. + protected virtual void OnPlanPackageBegin(PlanPackageBeginEventArgs args) + { + EventHandler handler = this.PlanPackageBegin; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine plans a new, compatible package using the same provider key. + /// + /// Additional arguments for this event. + protected virtual void OnPlanCompatibleMsiPackageBegin(PlanCompatibleMsiPackageBeginEventArgs args) + { + EventHandler handler = this.PlanCompatibleMsiPackageBegin; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine has completed planning the installation of a specific package. + /// + /// Additional arguments for this event. + protected virtual void OnPlanCompatibleMsiPackageComplete(PlanCompatibleMsiPackageCompleteEventArgs args) + { + EventHandler handler = this.PlanCompatibleMsiPackageComplete; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine is about to plan the target MSI of a MSP package. + /// + /// Additional arguments for this event. + protected virtual void OnPlanTargetMsiPackage(PlanTargetMsiPackageEventArgs args) + { + EventHandler handler = this.PlanTargetMsiPackage; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine is about to plan an MSI feature of a specific package. + /// + /// Additional arguments for this event. + protected virtual void OnPlanMsiFeature(PlanMsiFeatureEventArgs args) + { + EventHandler handler = this.PlanMsiFeature; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when then engine has completed planning the installation of a specific package. + /// + /// Additional arguments for this event. + protected virtual void OnPlanPackageComplete(PlanPackageCompleteEventArgs args) + { + EventHandler handler = this.PlanPackageComplete; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine has completed planning the installation. + /// + /// Additional arguments for this event. + protected virtual void OnPlanComplete(PlanCompleteEventArgs args) + { + EventHandler handler = this.PlanComplete; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine has begun installing the bundle. + /// + /// Additional arguments for this event. + protected virtual void OnApplyBegin(ApplyBeginEventArgs args) + { + EventHandler handler = this.ApplyBegin; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine is about to start the elevated process. + /// + /// Additional arguments for this event. + protected virtual void OnElevateBegin(ElevateBeginEventArgs args) + { + EventHandler handler = this.ElevateBegin; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine has completed starting the elevated process. + /// + /// Additional arguments for this event. + protected virtual void OnElevateComplete(ElevateCompleteEventArgs args) + { + EventHandler handler = this.ElevateComplete; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine has changed progress for the bundle installation. + /// + /// Additional arguments for this event. + protected virtual void OnProgress(ProgressEventArgs args) + { + EventHandler handler = this.Progress; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine has encountered an error. + /// + /// Additional arguments for this event. + protected virtual void OnError(ErrorEventArgs args) + { + EventHandler handler = this.Error; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine has begun registering the location and visibility of the bundle. + /// + /// Additional arguments for this event. + protected virtual void OnRegisterBegin(RegisterBeginEventArgs args) + { + EventHandler handler = this.RegisterBegin; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine has completed registering the location and visilibity of the bundle. + /// + /// Additional arguments for this event. + protected virtual void OnRegisterComplete(RegisterCompleteEventArgs args) + { + EventHandler handler = this.RegisterComplete; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine has begun removing the registration for the location and visibility of the bundle. + /// + /// Additional arguments for this event. + protected virtual void OnUnregisterBegin(UnregisterBeginEventArgs args) + { + EventHandler handler = this.UnregisterBegin; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine has completed removing the registration for the location and visibility of the bundle. + /// + /// Additional arguments for this event. + protected virtual void OnUnregisterComplete(UnregisterCompleteEventArgs args) + { + EventHandler handler = this.UnregisterComplete; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine begins to cache the installation sources. + /// + /// + protected virtual void OnCacheBegin(CacheBeginEventArgs args) + { + EventHandler handler = this.CacheBegin; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called by the engine when it begins to cache a specific package. + /// + /// + protected virtual void OnCachePackageBegin(CachePackageBeginEventArgs args) + { + EventHandler handler = this.CachePackageBegin; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine begins to cache the container or payload. + /// + /// + protected virtual void OnCacheAcquireBegin(CacheAcquireBeginEventArgs args) + { + EventHandler handler = this.CacheAcquireBegin; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine has progressed on caching the container or payload. + /// + /// + protected virtual void OnCacheAcquireProgress(CacheAcquireProgressEventArgs args) + { + EventHandler handler = this.CacheAcquireProgress; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called by the engine to allow the BA to change the source + /// using or . + /// + /// Additional arguments for this event. + protected virtual void OnResolveSource(ResolveSourceEventArgs args) + { + EventHandler handler = this.ResolveSource; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine completes caching of the container or payload. + /// + /// + protected virtual void OnCacheAcquireComplete(CacheAcquireCompleteEventArgs args) + { + EventHandler handler = this.CacheAcquireComplete; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine has started verify the payload. + /// + /// + protected virtual void OnCacheVerifyBegin(CacheVerifyBeginEventArgs args) + { + EventHandler handler = this.CacheVerifyBegin; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine completes verification of the payload. + /// + /// + protected virtual void OnCacheVerifyComplete(CacheVerifyCompleteEventArgs args) + { + EventHandler handler = this.CacheVerifyComplete; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine completes caching a specific package. + /// + /// + protected virtual void OnCachePackageComplete(CachePackageCompleteEventArgs args) + { + EventHandler handler = this.CachePackageComplete; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called after the engine has cached the installation sources. + /// + /// Additional arguments for this event. + protected virtual void OnCacheComplete(CacheCompleteEventArgs args) + { + EventHandler handler = this.CacheComplete; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine has begun installing packages. + /// + /// Additional arguments for this event. + protected virtual void OnExecuteBegin(ExecuteBeginEventArgs args) + { + EventHandler handler = this.ExecuteBegin; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine has begun installing a specific package. + /// + /// Additional arguments for this event. + protected virtual void OnExecutePackageBegin(ExecutePackageBeginEventArgs args) + { + EventHandler handler = this.ExecutePackageBegin; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine executes one or more patches targeting a product. + /// + /// Additional arguments for this event. + protected virtual void OnExecutePatchTarget(ExecutePatchTargetEventArgs args) + { + EventHandler handler = this.ExecutePatchTarget; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when Windows Installer sends an installation message. + /// + /// Additional arguments for this event. + protected virtual void OnExecuteMsiMessage(ExecuteMsiMessageEventArgs args) + { + EventHandler handler = this.ExecuteMsiMessage; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when Windows Installer sends a file in use installation message. + /// + /// Additional arguments for this event. + protected virtual void OnExecuteFilesInUse(ExecuteFilesInUseEventArgs args) + { + EventHandler handler = this.ExecuteFilesInUse; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine has completed installing a specific package. + /// + /// Additional arguments for this event. + protected virtual void OnExecutePackageComplete(ExecutePackageCompleteEventArgs args) + { + EventHandler handler = this.ExecutePackageComplete; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine has completed installing packages. + /// + /// Additional arguments for this event. + protected virtual void OnExecuteComplete(ExecuteCompleteEventArgs args) + { + EventHandler handler = this.ExecuteComplete; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called when the engine has completed installing the bundle. + /// + /// Additional arguments for this event. + protected virtual void OnApplyComplete(ApplyCompleteEventArgs args) + { + EventHandler handler = this.ApplyComplete; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called by the engine while executing on payload. + /// + /// Additional arguments for this event. + protected virtual void OnExecuteProgress(ExecuteProgressEventArgs args) + { + EventHandler handler = this.ExecuteProgress; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called by the engine before trying to launch the preapproved executable. + /// + /// Additional arguments for this event. + protected virtual void OnLaunchApprovedExeBegin(LaunchApprovedExeBeginArgs args) + { + EventHandler handler = this.LaunchApprovedExeBegin; + if (null != handler) + { + handler(this, args); + } + } + + /// + /// Called by the engine after trying to launch the preapproved executable. + /// + /// Additional arguments for this event. + protected virtual void OnLaunchApprovedExeComplete(LaunchApprovedExeCompleteArgs args) + { + EventHandler handler = this.LaunchApprovedExeComplete; + if (null != handler) + { + handler(this, args); + } + } + + #region IBootstrapperApplication Members + + int IBootstrapperApplication.OnStartup() + { + StartupEventArgs args = new StartupEventArgs(); + this.OnStartup(args); + + return args.HResult; + } + + int IBootstrapperApplication.OnShutdown(ref BOOTSTRAPPER_SHUTDOWN_ACTION action) + { + ShutdownEventArgs args = new ShutdownEventArgs(action); + this.OnShutdown(args); + + action = args.Action; + return args.HResult; + } + + int IBootstrapperApplication.OnSystemShutdown(EndSessionReasons dwEndSession, ref bool fCancel) + { + SystemShutdownEventArgs args = new SystemShutdownEventArgs(dwEndSession, fCancel); + this.OnSystemShutdown(args); + + fCancel = args.Cancel; + return args.HResult; + } + + int IBootstrapperApplication.OnDetectBegin(bool fInstalled, int cPackages, ref bool fCancel) + { + DetectBeginEventArgs args = new DetectBeginEventArgs(fInstalled, cPackages, fCancel); + this.OnDetectBegin(args); + + fCancel = args.Cancel; + return args.HResult; + } + + int IBootstrapperApplication.OnDetectForwardCompatibleBundle(string wzBundleId, RelationType relationType, string wzBundleTag, bool fPerMachine, long version, ref bool fCancel, ref bool fIgnoreBundle) + { + DetectForwardCompatibleBundleEventArgs args = new DetectForwardCompatibleBundleEventArgs(wzBundleId, relationType, wzBundleTag, fPerMachine, version, fCancel, fIgnoreBundle); + this.OnDetectForwardCompatibleBundle(args); + + fCancel = args.Cancel; + fIgnoreBundle = args.IgnoreBundle; + return args.HResult; + } + + int IBootstrapperApplication.OnDetectUpdateBegin(string wzUpdateLocation, ref bool fCancel, ref bool fSkip) + { + DetectUpdateBeginEventArgs args = new DetectUpdateBeginEventArgs(wzUpdateLocation, fCancel, fSkip); + this.OnDetectUpdateBegin(args); + + fCancel = args.Cancel; + fSkip = args.Skip; + return args.HResult; + } + + int IBootstrapperApplication.OnDetectUpdate(string wzUpdateLocation, long dw64Size, long dw64Version, string wzTitle, string wzSummary, string wzContentType, string wzContent, ref bool fCancel, ref bool fStopProcessingUpdates) + { + DetectUpdateEventArgs args = new DetectUpdateEventArgs(wzUpdateLocation, dw64Size, dw64Version, wzTitle, wzSummary, wzContentType, wzContent, fCancel, fStopProcessingUpdates); + this.OnDetectUpdate(args); + + fCancel = args.Cancel; + fStopProcessingUpdates = args.StopProcessingUpdates; + return args.HResult; + } + + int IBootstrapperApplication.OnDetectUpdateComplete(int hrStatus, ref bool fIgnoreError) + { + DetectUpdateCompleteEventArgs args = new DetectUpdateCompleteEventArgs(hrStatus, fIgnoreError); + this.OnDetectUpdateComplete(args); + + fIgnoreError = args.IgnoreError; + return args.HResult; + } + + int IBootstrapperApplication.OnDetectRelatedBundle(string wzProductCode, RelationType relationType, string wzBundleTag, bool fPerMachine, long version, RelatedOperation operation, ref bool fCancel) + { + DetectRelatedBundleEventArgs args = new DetectRelatedBundleEventArgs(wzProductCode, relationType, wzBundleTag, fPerMachine, version, operation, fCancel); + this.OnDetectRelatedBundle(args); + + fCancel = args.Cancel; + return args.HResult; + } + + int IBootstrapperApplication.OnDetectPackageBegin(string wzPackageId, ref bool fCancel) + { + DetectPackageBeginEventArgs args = new DetectPackageBeginEventArgs(wzPackageId, fCancel); + this.OnDetectPackageBegin(args); + + fCancel = args.Cancel; + return args.HResult; + } + + int IBootstrapperApplication.OnDetectCompatibleMsiPackage(string wzPackageId, string wzCompatiblePackageId, long dw64CompatiblePackageVersion, ref bool fCancel) + { + DetectCompatibleMsiPackageEventArgs args = new DetectCompatibleMsiPackageEventArgs(wzPackageId, wzCompatiblePackageId, dw64CompatiblePackageVersion, fCancel); + this.OnDetectCompatibleMsiPackage(args); + + fCancel = args.Cancel; + return args.HResult; + } + + int IBootstrapperApplication.OnDetectRelatedMsiPackage(string wzPackageId, string wzUpgradeCode, string wzProductCode, bool fPerMachine, long version, RelatedOperation operation, ref bool fCancel) + { + DetectRelatedMsiPackageEventArgs args = new DetectRelatedMsiPackageEventArgs(wzPackageId, wzUpgradeCode, wzProductCode, fPerMachine, version, operation, fCancel); + this.OnDetectRelatedMsiPackage(args); + + fCancel = args.Cancel; + return args.HResult; + } + + int IBootstrapperApplication.OnDetectTargetMsiPackage(string wzPackageId, string wzProductCode, PackageState patchState, ref bool fCancel) + { + DetectTargetMsiPackageEventArgs args = new DetectTargetMsiPackageEventArgs(wzPackageId, wzProductCode, patchState, fCancel); + this.OnDetectTargetMsiPackage(args); + + fCancel = args.Cancel; + return args.HResult; + } + + int IBootstrapperApplication.OnDetectMsiFeature(string wzPackageId, string wzFeatureId, FeatureState state, ref bool fCancel) + { + DetectMsiFeatureEventArgs args = new DetectMsiFeatureEventArgs(wzPackageId, wzFeatureId, state, fCancel); + this.OnDetectMsiFeature(args); + + fCancel = args.Cancel; + return args.HResult; + } + + int IBootstrapperApplication.OnDetectPackageComplete(string wzPackageId, int hrStatus, PackageState state) + { + DetectPackageCompleteEventArgs args = new DetectPackageCompleteEventArgs(wzPackageId, hrStatus, state); + this.OnDetectPackageComplete(args); + + return args.HResult; + } + + int IBootstrapperApplication.OnDetectComplete(int hrStatus) + { + DetectCompleteEventArgs args = new DetectCompleteEventArgs(hrStatus); + this.OnDetectComplete(args); + + return args.HResult; + } + + int IBootstrapperApplication.OnPlanBegin(int cPackages, ref bool fCancel) + { + PlanBeginEventArgs args = new PlanBeginEventArgs(cPackages, fCancel); + this.OnPlanBegin(args); + + fCancel = args.Cancel; + return args.HResult; + } + + int IBootstrapperApplication.OnPlanRelatedBundle(string wzBundleId, RequestState recommendedState, ref RequestState pRequestedState, ref bool fCancel) + { + PlanRelatedBundleEventArgs args = new PlanRelatedBundleEventArgs(wzBundleId, recommendedState, pRequestedState, fCancel); + this.OnPlanRelatedBundle(args); + + pRequestedState = args.State; + fCancel = args.Cancel; + return args.HResult; + } + + int IBootstrapperApplication.OnPlanPackageBegin(string wzPackageId, RequestState recommendedState, ref RequestState pRequestedState, ref bool fCancel) + { + PlanPackageBeginEventArgs args = new PlanPackageBeginEventArgs(wzPackageId, recommendedState, pRequestedState, fCancel); + this.OnPlanPackageBegin(args); + + pRequestedState = args.State; + fCancel = args.Cancel; + return args.HResult; + } + + int IBootstrapperApplication.OnPlanCompatibleMsiPackageBegin(string wzPackageId, string wzCompatiblePackageId, long dw64CompatiblePackageVersion, RequestState recommendedState, ref RequestState pRequestedState, ref bool fCancel) + { + PlanCompatibleMsiPackageBeginEventArgs args = new PlanCompatibleMsiPackageBeginEventArgs(wzPackageId, wzCompatiblePackageId, dw64CompatiblePackageVersion, recommendedState, pRequestedState, fCancel); + this.OnPlanCompatibleMsiPackageBegin(args); + + pRequestedState = args.State; + fCancel = args.Cancel; + return args.HResult; + } + + int IBootstrapperApplication.OnPlanCompatibleMsiPackageComplete(string wzPackageId, string wzCompatiblePackageId, int hrStatus, PackageState state, RequestState requested, ActionState execute, ActionState rollback) + { + PlanCompatibleMsiPackageCompleteEventArgs args = new PlanCompatibleMsiPackageCompleteEventArgs(wzPackageId, wzCompatiblePackageId, hrStatus, state, requested, execute, rollback); + this.OnPlanCompatibleMsiPackageComplete(args); + + return args.HResult; + } + + int IBootstrapperApplication.OnPlanTargetMsiPackage(string wzPackageId, string wzProductCode, RequestState recommendedState, ref RequestState pRequestedState, ref bool fCancel) + { + PlanTargetMsiPackageEventArgs args = new PlanTargetMsiPackageEventArgs(wzPackageId, wzProductCode, recommendedState, pRequestedState, fCancel); + this.OnPlanTargetMsiPackage(args); + + pRequestedState = args.State; + fCancel = args.Cancel; + return args.HResult; + } + + int IBootstrapperApplication.OnPlanMsiFeature(string wzPackageId, string wzFeatureId, FeatureState recommendedState, ref FeatureState pRequestedState, ref bool fCancel) + { + PlanMsiFeatureEventArgs args = new PlanMsiFeatureEventArgs(wzPackageId, wzFeatureId, recommendedState, pRequestedState, fCancel); + this.OnPlanMsiFeature(args); + + pRequestedState = args.State; + fCancel = args.Cancel; + return args.HResult; + } + + int IBootstrapperApplication.OnPlanPackageComplete(string wzPackageId, int hrStatus, PackageState state, RequestState requested, ActionState execute, ActionState rollback) + { + var args = new PlanPackageCompleteEventArgs(wzPackageId, hrStatus, state, requested, execute, rollback); + this.OnPlanPackageComplete(args); + + return args.HResult; + } + + int IBootstrapperApplication.OnPlanComplete(int hrStatus) + { + PlanCompleteEventArgs args = new PlanCompleteEventArgs(hrStatus); + this.OnPlanComplete(args); + + return args.HResult; + } + + int IBootstrapperApplication.OnApplyBegin(int dwPhaseCount, ref bool fCancel) + { + this.applying = true; + + ApplyBeginEventArgs args = new ApplyBeginEventArgs(dwPhaseCount, fCancel); + this.OnApplyBegin(args); + + fCancel = args.Cancel; + return args.HResult; + } + + int IBootstrapperApplication.OnElevateBegin(ref bool fCancel) + { + ElevateBeginEventArgs args = new ElevateBeginEventArgs(fCancel); + this.OnElevateBegin(args); + + fCancel = args.Cancel; + return args.HResult; + } + + int IBootstrapperApplication.OnElevateComplete(int hrStatus) + { + ElevateCompleteEventArgs args = new ElevateCompleteEventArgs(hrStatus); + this.OnElevateComplete(args); + + return args.HResult; + } + + int IBootstrapperApplication.OnProgress(int dwProgressPercentage, int dwOverallPercentage, ref bool fCancel) + { + ProgressEventArgs args = new ProgressEventArgs(dwProgressPercentage, dwOverallPercentage, fCancel); + this.OnProgress(args); + + fCancel = args.Cancel; + return args.HResult; + } + + int IBootstrapperApplication.OnError(ErrorType errorType, string wzPackageId, int dwCode, string wzError, int dwUIHint, int cData, string[] rgwzData, Result nRecommendation, ref Result pResult) + { + ErrorEventArgs args = new ErrorEventArgs(errorType, wzPackageId, dwCode, wzError, dwUIHint, rgwzData, nRecommendation, pResult); + this.OnError(args); + + pResult = args.Result; + return args.HResult; + } + + int IBootstrapperApplication.OnRegisterBegin(ref bool fCancel) + { + RegisterBeginEventArgs args = new RegisterBeginEventArgs(fCancel); + this.OnRegisterBegin(args); + + fCancel = args.Cancel; + return args.HResult; + } + + int IBootstrapperApplication.OnRegisterComplete(int hrStatus) + { + RegisterCompleteEventArgs args = new RegisterCompleteEventArgs(hrStatus); + this.OnRegisterComplete(args); + + return args.HResult; + } + + int IBootstrapperApplication.OnCacheBegin(ref bool fCancel) + { + CacheBeginEventArgs args = new CacheBeginEventArgs(fCancel); + this.OnCacheBegin(args); + + fCancel = args.Cancel; + return args.HResult; + } + + int IBootstrapperApplication.OnCachePackageBegin(string wzPackageId, int cCachePayloads, long dw64PackageCacheSize, ref bool fCancel) + { + CachePackageBeginEventArgs args = new CachePackageBeginEventArgs(wzPackageId, cCachePayloads, dw64PackageCacheSize, fCancel); + this.OnCachePackageBegin(args); + + fCancel = args.Cancel; + return args.HResult; + } + + int IBootstrapperApplication.OnCacheAcquireBegin(string wzPackageOrContainerId, string wzPayloadId, CacheOperation operation, string wzSource, ref bool fCancel) + { + CacheAcquireBeginEventArgs args = new CacheAcquireBeginEventArgs(wzPackageOrContainerId, wzPayloadId, operation, wzSource, fCancel); + this.OnCacheAcquireBegin(args); + + fCancel = args.Cancel; + return args.HResult; + } + + int IBootstrapperApplication.OnCacheAcquireProgress(string wzPackageOrContainerId, string wzPayloadId, long dw64Progress, long dw64Total, int dwOverallPercentage, ref bool fCancel) + { + CacheAcquireProgressEventArgs args = new CacheAcquireProgressEventArgs(wzPackageOrContainerId, wzPayloadId, dw64Progress, dw64Total, dwOverallPercentage, fCancel); + this.OnCacheAcquireProgress(args); + + fCancel = args.Cancel; + return args.HResult; + } + + int IBootstrapperApplication.OnResolveSource(string wzPackageOrContainerId, string wzPayloadId, string wzLocalSource, string wzDownloadSource, BOOTSTRAPPER_RESOLVESOURCE_ACTION recommendation, ref BOOTSTRAPPER_RESOLVESOURCE_ACTION action, ref bool fCancel) + { + ResolveSourceEventArgs args = new ResolveSourceEventArgs(wzPackageOrContainerId, wzPayloadId, wzLocalSource, wzDownloadSource, action, recommendation, fCancel); + this.OnResolveSource(args); + + action = args.Action; + fCancel = args.Cancel; + return args.HResult; + } + + int IBootstrapperApplication.OnCacheAcquireComplete(string wzPackageOrContainerId, string wzPayloadId, int hrStatus, BOOTSTRAPPER_CACHEACQUIRECOMPLETE_ACTION recommendation, ref BOOTSTRAPPER_CACHEACQUIRECOMPLETE_ACTION action) + { + CacheAcquireCompleteEventArgs args = new CacheAcquireCompleteEventArgs(wzPackageOrContainerId, wzPayloadId, hrStatus, recommendation, action); + this.OnCacheAcquireComplete(args); + + action = args.Action; + return args.HResult; + } + + int IBootstrapperApplication.OnCacheVerifyBegin(string wzPackageId, string wzPayloadId, ref bool fCancel) + { + CacheVerifyBeginEventArgs args = new CacheVerifyBeginEventArgs(wzPackageId, wzPayloadId, fCancel); + this.OnCacheVerifyBegin(args); + + fCancel = args.Cancel; + return args.HResult; + } + + int IBootstrapperApplication.OnCacheVerifyComplete(string wzPackageId, string wzPayloadId, int hrStatus, BOOTSTRAPPER_CACHEVERIFYCOMPLETE_ACTION recommendation, ref BOOTSTRAPPER_CACHEVERIFYCOMPLETE_ACTION action) + { + CacheVerifyCompleteEventArgs args = new CacheVerifyCompleteEventArgs(wzPackageId, wzPayloadId, hrStatus, recommendation, action); + this.OnCacheVerifyComplete(args); + + action = args.Action; + return args.HResult; + } + + int IBootstrapperApplication.OnCachePackageComplete(string wzPackageId, int hrStatus, BOOTSTRAPPER_CACHEPACKAGECOMPLETE_ACTION recommendation, ref BOOTSTRAPPER_CACHEPACKAGECOMPLETE_ACTION action) + { + CachePackageCompleteEventArgs args = new CachePackageCompleteEventArgs(wzPackageId, hrStatus, recommendation, action); + this.OnCachePackageComplete(args); + + action = args.Action; + return args.HResult; + } + + int IBootstrapperApplication.OnCacheComplete(int hrStatus) + { + CacheCompleteEventArgs args = new CacheCompleteEventArgs(hrStatus); + this.OnCacheComplete(args); + + return args.HResult; + } + + int IBootstrapperApplication.OnExecuteBegin(int cExecutingPackages, ref bool fCancel) + { + ExecuteBeginEventArgs args = new ExecuteBeginEventArgs(cExecutingPackages, fCancel); + this.OnExecuteBegin(args); + + args.Cancel = fCancel; + return args.HResult; + } + + int IBootstrapperApplication.OnExecutePackageBegin(string wzPackageId, bool fExecute, ref bool fCancel) + { + ExecutePackageBeginEventArgs args = new ExecutePackageBeginEventArgs(wzPackageId, fExecute, fCancel); + this.OnExecutePackageBegin(args); + + fCancel = args.Cancel; + return args.HResult; + } + + int IBootstrapperApplication.OnExecutePatchTarget(string wzPackageId, string wzTargetProductCode, ref bool fCancel) + { + ExecutePatchTargetEventArgs args = new ExecutePatchTargetEventArgs(wzPackageId, wzTargetProductCode, fCancel); + this.OnExecutePatchTarget(args); + + fCancel = args.Cancel; + return args.HResult; + } + + int IBootstrapperApplication.OnExecuteProgress(string wzPackageId, int dwProgressPercentage, int dwOverallPercentage, ref bool fCancel) + { + ExecuteProgressEventArgs args = new ExecuteProgressEventArgs(wzPackageId, dwProgressPercentage, dwOverallPercentage, fCancel); + this.OnExecuteProgress(args); + + fCancel = args.Cancel; + return args.HResult; + } + + int IBootstrapperApplication.OnExecuteMsiMessage(string wzPackageId, InstallMessage messageType, int dwUIHint, string wzMessage, int cData, string[] rgwzData, Result nRecommendation, ref Result pResult) + { + ExecuteMsiMessageEventArgs args = new ExecuteMsiMessageEventArgs(wzPackageId, messageType, dwUIHint, wzMessage, rgwzData, nRecommendation, pResult); + this.OnExecuteMsiMessage(args); + + pResult = args.Result; + return args.HResult; + } + + int IBootstrapperApplication.OnExecuteFilesInUse(string wzPackageId, int cFiles, string[] rgwzFiles, Result nRecommendation, ref Result pResult) + { + ExecuteFilesInUseEventArgs args = new ExecuteFilesInUseEventArgs(wzPackageId, rgwzFiles, nRecommendation, pResult); + this.OnExecuteFilesInUse(args); + + pResult = args.Result; + return args.HResult; + } + + int IBootstrapperApplication.OnExecutePackageComplete(string wzPackageId, int hrStatus, ApplyRestart restart, BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION recommendation, ref BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION pAction) + { + ExecutePackageCompleteEventArgs args = new ExecutePackageCompleteEventArgs(wzPackageId, hrStatus, restart, recommendation, pAction); + this.OnExecutePackageComplete(args); + + pAction = args.Action; + return args.HResult; + } + + int IBootstrapperApplication.OnExecuteComplete(int hrStatus) + { + ExecuteCompleteEventArgs args = new ExecuteCompleteEventArgs(hrStatus); + this.OnExecuteComplete(args); + + return args.HResult; + } + + int IBootstrapperApplication.OnUnregisterBegin(ref bool fCancel) + { + UnregisterBeginEventArgs args = new UnregisterBeginEventArgs(fCancel); + this.OnUnregisterBegin(args); + + fCancel = args.Cancel; + return args.HResult; + } + + int IBootstrapperApplication.OnUnregisterComplete(int hrStatus) + { + UnregisterCompleteEventArgs args = new UnregisterCompleteEventArgs(hrStatus); + this.OnUnregisterComplete(args); + + return args.HResult; + } + + int IBootstrapperApplication.OnApplyComplete(int hrStatus, ApplyRestart restart, BOOTSTRAPPER_APPLYCOMPLETE_ACTION recommendation, ref BOOTSTRAPPER_APPLYCOMPLETE_ACTION pAction) + { + ApplyCompleteEventArgs args = new ApplyCompleteEventArgs(hrStatus, restart, recommendation, pAction); + this.OnApplyComplete(args); + + this.applying = false; + + pAction = args.Action; + return args.HResult; + } + + int IBootstrapperApplication.OnLaunchApprovedExeBegin(ref bool fCancel) + { + LaunchApprovedExeBeginArgs args = new LaunchApprovedExeBeginArgs(fCancel); + this.OnLaunchApprovedExeBegin(args); + + fCancel = args.Cancel; + return args.HResult; + } + + int IBootstrapperApplication.OnLaunchApprovedExeComplete(int hrStatus, int processId) + { + LaunchApprovedExeCompleteArgs args = new LaunchApprovedExeCompleteArgs(hrStatus, processId); + this.OnLaunchApprovedExeComplete(args); + + return args.HResult; + } + + int IBootstrapperApplication.BAProc(BOOTSTRAPPER_APPLICATION_MESSAGE message, IntPtr pvArgs, IntPtr pvResults, IntPtr pvContext) + { + switch (message) + { + default: + return NativeMethods.E_NOTIMPL; + } + } + + void IBootstrapperApplication.BAProcFallback(BOOTSTRAPPER_APPLICATION_MESSAGE message, IntPtr pvArgs, IntPtr pvResults, ref int phr, IntPtr pvContext) + { + } + + #endregion + } +} diff --git a/src/WixToolset.Mba.Core/BootstrapperApplicationData.cs b/src/WixToolset.Mba.Core/BootstrapperApplicationData.cs new file mode 100644 index 00000000..a17f1a05 --- /dev/null +++ b/src/WixToolset.Mba.Core/BootstrapperApplicationData.cs @@ -0,0 +1,63 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.BootstrapperCore +{ + using System; + using System.IO; + using System.Xml.XPath; + + public class BootstrapperApplicationData : IBootstrapperApplicationData + { + public const string DefaultFileName = "BootstrapperApplicationData.xml"; + public const string XMLNamespace = "http://wixtoolset.org/schemas/v4/2010/BootstrapperApplicationData"; + + public static readonly DirectoryInfo DefaultFolder; + public static readonly FileInfo DefaultFile; + + static BootstrapperApplicationData() + { + DefaultFolder = new DirectoryInfo(AppDomain.CurrentDomain.BaseDirectory); + DefaultFile = new FileInfo(Path.Combine(DefaultFolder.FullName, DefaultFileName)); + } + + public FileInfo BADataFile { get; private set; } + + public IBundleInfo Bundle { get; private set; } + + public BootstrapperApplicationData() : this(DefaultFile) { } + + public BootstrapperApplicationData(FileInfo baDataFile) + { + this.BADataFile = baDataFile; + + using (FileStream fs = this.BADataFile.OpenRead()) + { + this.Bundle = BundleInfo.ParseBundleFromStream(fs); + } + } + + public static string GetAttribute(XPathNavigator node, string attributeName) + { + XPathNavigator attribute = node.SelectSingleNode("@" + attributeName); + + if (attribute == null) + { + return null; + } + + return attribute.Value; + } + + public static bool? GetYesNoAttribute(XPathNavigator node, string attributeName) + { + string attributeValue = GetAttribute(node, attributeName); + + if (attributeValue == null) + { + return null; + } + + return attributeValue.Equals("yes", StringComparison.InvariantCulture); + } + } +} diff --git a/src/WixToolset.Mba.Core/BootstrapperApplicationFactory.cs b/src/WixToolset.Mba.Core/BootstrapperApplicationFactory.cs new file mode 100644 index 00000000..28430bb8 --- /dev/null +++ b/src/WixToolset.Mba.Core/BootstrapperApplicationFactory.cs @@ -0,0 +1,86 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.BootstrapperCore +{ + using System; + using System.Configuration; + using System.Reflection; + using System.Runtime.InteropServices; + + /// + /// Entry point for the MBA host to create and return the IBootstrapperApplication implementation to the engine. + /// + [ClassInterface(ClassInterfaceType.None)] + public sealed class BootstrapperApplicationFactory : MarshalByRefObject, IBootstrapperApplicationFactory + { + /// + /// Creates a new instance of the class. + /// + public BootstrapperApplicationFactory() + { + } + + /// + /// Loads the bootstrapper application assembly and creates an instance of the IBootstrapperApplication. + /// + /// IBootstrapperEngine provided for the bootstrapper application. + /// Command line for the bootstrapper application. + /// Bootstrapper application via interface. + /// The bootstrapper application assembly + /// does not define the . + public IBootstrapperApplication Create(IBootstrapperEngine pEngine, ref Command command) + { + // Get the wix.boostrapper section group to get the name of the bootstrapper application assembly to host. + var section = ConfigurationManager.GetSection("wix.bootstrapper/host") as HostSection; + if (null == section) + { + throw new MissingAttributeException(); // TODO: throw a more specific exception than this. + } + + // Load the BA's IBootstrapperApplicationFactory. + var baFactoryType = BootstrapperApplicationFactory.GetBAFactoryTypeFromAssembly(section.AssemblyName); + var baFactory = (IBootstrapperApplicationFactory)Activator.CreateInstance(baFactoryType); + if (null == baFactory) + { + throw new InvalidBootstrapperApplicationFactoryException(); + } + + var ba = baFactory.Create(pEngine, ref command); + return ba; + } + + /// + /// Locates the and returns the specified type. + /// + /// The assembly that defines the IBootstrapperApplicationFactory implementation. + /// The bootstrapper application factory . + private static Type GetBAFactoryTypeFromAssembly(string assemblyName) + { + Type baFactoryType = null; + + // Load the requested assembly. + Assembly asm = AppDomain.CurrentDomain.Load(assemblyName); + + // If an assembly was loaded and is not the current assembly, check for the required attribute. + // This is done to avoid using the BootstrapperApplicationFactoryAttribute which we use at build time + // to specify the BootstrapperApplicationFactory assembly in the manifest. + if (!Assembly.GetExecutingAssembly().Equals(asm)) + { + // There must be one and only one BootstrapperApplicationFactoryAttribute. + // The attribute prevents multiple declarations already. + var attrs = (BootstrapperApplicationFactoryAttribute[])asm.GetCustomAttributes(typeof(BootstrapperApplicationFactoryAttribute), false); + if (null != attrs) + { + baFactoryType = attrs[0].BootstrapperApplicationFactoryType; + } + } + + if (null == baFactoryType) + { + throw new MissingAttributeException(); + } + + return baFactoryType; + } + } +} diff --git a/src/WixToolset.Mba.Core/BootstrapperApplicationFactoryAttribute.cs b/src/WixToolset.Mba.Core/BootstrapperApplicationFactoryAttribute.cs new file mode 100644 index 00000000..781d4ea1 --- /dev/null +++ b/src/WixToolset.Mba.Core/BootstrapperApplicationFactoryAttribute.cs @@ -0,0 +1,35 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.BootstrapperCore +{ + using System; + + /// + /// Identifies the bootstrapper application factory class. + /// + /// + /// This required assembly attribute identifies the bootstrapper application factory class. + /// + [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = false)] + public sealed class BootstrapperApplicationFactoryAttribute : Attribute + { + private Type bootstrapperApplicationFactoryType; + + /// + /// Creates a new instance of the class. + /// + /// The of the BA factory. + public BootstrapperApplicationFactoryAttribute(Type bootstrapperApplicationFactoryType) + { + this.bootstrapperApplicationFactoryType = bootstrapperApplicationFactoryType; + } + + /// + /// Gets the type of the bootstrapper application factory class to create. + /// + public Type BootstrapperApplicationFactoryType + { + get { return this.bootstrapperApplicationFactoryType; } + } + } +} diff --git a/src/WixToolset.Mba.Core/BootstrapperCommand.cs b/src/WixToolset.Mba.Core/BootstrapperCommand.cs new file mode 100644 index 00000000..bbd10e1d --- /dev/null +++ b/src/WixToolset.Mba.Core/BootstrapperCommand.cs @@ -0,0 +1,107 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.BootstrapperCore +{ + using System; + using System.ComponentModel; + using System.Runtime.InteropServices; + + public sealed class BootstrapperCommand : IBootstrapperCommand + { + private readonly string commandLine; + + public BootstrapperCommand( + LaunchAction action, + Display display, + Restart restart, + string commandLine, + int cmdShow, + ResumeType resume, + IntPtr splashScreen, + RelationType relation, + bool passthrough, + string layoutDirectory) + { + this.Action = action; + this.Display = display; + this.Restart = restart; + this.commandLine = commandLine; + this.CmdShow = cmdShow; + this.Resume = resume; + this.SplashScreen = splashScreen; + this.Relation = relation; + this.Passthrough = passthrough; + this.LayoutDirectory = layoutDirectory; + } + + public LaunchAction Action { get; } + + public Display Display { get; } + + public Restart Restart { get; } + + public string[] CommandLineArgs => GetCommandLineArgs(this.commandLine); + + public int CmdShow { get; } + + public ResumeType Resume { get; } + + public IntPtr SplashScreen { get; } + + public RelationType Relation { get; } + + public bool Passthrough { get; } + + public string LayoutDirectory { get; } + + /// + /// Gets the command line arguments as a string array. + /// + /// + /// Array of command line arguments. + /// + /// The command line could not be parsed into an array. + /// + /// This method uses the same parsing as the operating system which handles quotes and spaces correctly. + /// + public static string[] GetCommandLineArgs(string commandLine) + { + if (null == commandLine) + { + return new string[0]; + } + + // Parse the filtered command line arguments into a native array. + int argc = 0; + + // CommandLineToArgvW tries to treat the first argument as the path to the process, + // which fails pretty miserably if your first argument is something like + // FOO="C:\Program Files\My Company". So give it something harmless to play with. + IntPtr argv = NativeMethods.CommandLineToArgvW("ignored " + commandLine, out argc); + + if (IntPtr.Zero == argv) + { + // Throw an exception with the last error. + throw new Win32Exception(); + } + + // Marshal each native array pointer to a managed string. + try + { + // Skip "ignored" argument/hack. + string[] args = new string[argc - 1]; + for (int i = 1; i < argc; ++i) + { + IntPtr argvi = Marshal.ReadIntPtr(argv, i * IntPtr.Size); + args[i - 1] = Marshal.PtrToStringUni(argvi); + } + + return args; + } + finally + { + NativeMethods.LocalFree(argv); + } + } + } +} diff --git a/src/WixToolset.Mba.Core/BootstrapperSectionGroup.cs b/src/WixToolset.Mba.Core/BootstrapperSectionGroup.cs new file mode 100644 index 00000000..7721c027 --- /dev/null +++ b/src/WixToolset.Mba.Core/BootstrapperSectionGroup.cs @@ -0,0 +1,29 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.BootstrapperCore +{ + using System; + using System.Configuration; + + /// + /// Handler for the wix.bootstrapper configuration section group. + /// + public class BootstrapperSectionGroup : ConfigurationSectionGroup + { + /// + /// Creates a new instance of the class. + /// + public BootstrapperSectionGroup() + { + } + + /// + /// Gets the handler for the mba configuration section. + /// + [ConfigurationProperty("host")] + public HostSection Host + { + get { return (HostSection)base.Sections["host"]; } + } + } +} diff --git a/src/WixToolset.Mba.Core/BundleInfo.cs b/src/WixToolset.Mba.Core/BundleInfo.cs new file mode 100644 index 00000000..51c2d268 --- /dev/null +++ b/src/WixToolset.Mba.Core/BundleInfo.cs @@ -0,0 +1,67 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.BootstrapperCore +{ + using System; + using System.Collections.Generic; + using System.IO; + using System.Xml; + using System.Xml.XPath; + + public class BundleInfo : IBundleInfo + { + public bool PerMachine { get; internal set; } + public string Name { get; internal set; } + public string LogVariable { get; internal set; } + public IDictionary Packages { get; internal set; } + + internal BundleInfo() + { + this.Packages = new Dictionary(); + } + + public void AddRelatedBundleAsPackage(DetectRelatedBundleEventArgs e) + { + var package = PackageInfo.GetRelatedBundleAsPackage(e.ProductCode, e.RelationType, e.PerMachine, e.Version); + this.Packages.Add(package.Id, package); + } + + public static IBundleInfo ParseBundleFromStream(Stream stream) + { + XPathDocument manifest = new XPathDocument(stream); + XPathNavigator root = manifest.CreateNavigator(); + return ParseBundleFromXml(root); + } + + public static IBundleInfo ParseBundleFromXml(XPathNavigator root) + { + BundleInfo bundle = new BundleInfo(); + + XmlNamespaceManager namespaceManager = new XmlNamespaceManager(root.NameTable); + namespaceManager.AddNamespace("p", BootstrapperApplicationData.XMLNamespace); + XPathNavigator bundleNode = root.SelectSingleNode("/p:BootstrapperApplicationData/p:WixBundleProperties", namespaceManager); + + if (bundleNode == null) + { + throw new Exception("Failed to select bundle information."); + } + + bool? perMachine = BootstrapperApplicationData.GetYesNoAttribute(bundleNode, "PerMachine"); + if (perMachine.HasValue) + { + bundle.PerMachine = perMachine.Value; + } + + bundle.Name = BootstrapperApplicationData.GetAttribute(bundleNode, "DisplayName"); + + bundle.LogVariable = BootstrapperApplicationData.GetAttribute(bundleNode, "LogPathVariable"); + + foreach (var package in PackageInfo.ParsePackagesFromXml(root)) + { + bundle.Packages.Add(package.Id, package); + } + + return bundle; + } + } +} diff --git a/src/WixToolset.Mba.Core/Engine.cs b/src/WixToolset.Mba.Core/Engine.cs new file mode 100644 index 00000000..ad62134f --- /dev/null +++ b/src/WixToolset.Mba.Core/Engine.cs @@ -0,0 +1,516 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.BootstrapperCore +{ + using System; + using System.ComponentModel; + using System.Runtime.InteropServices; + using System.Security; + using System.Text; + + /// + /// Container class for the interface. + /// + public sealed class Engine : IEngine + { + // Burn errs on empty strings, so declare initial buffer size. + private const int InitialBufferSize = 80; + private static readonly string normalizeVersionFormatString = "{0} must be less than or equal to " + UInt16.MaxValue; + + private IBootstrapperEngine engine; + private Variables numericVariables; + private Variables secureStringVariables; + private Variables stringVariables; + private Variables versionVariables; + + /// + /// Creates a new instance of the container class. + /// + /// The to contain. + internal Engine(IBootstrapperEngine engine) + { + this.engine = engine; + + // Wrap the calls to get and set numeric variables. + this.numericVariables = new Variables( + delegate(string name) + { + long value; + int ret = this.engine.GetVariableNumeric(name, out value); + if (NativeMethods.S_OK != ret) + { + throw new Win32Exception(ret); + } + + return value; + }, + delegate(string name, long value) + { + this.engine.SetVariableNumeric(name, value); + }, + delegate(string name) + { + long value; + int ret = this.engine.GetVariableNumeric(name, out value); + + return NativeMethods.E_NOTFOUND != ret; + } + ); + + // Wrap the calls to get and set string variables using SecureStrings. + this.secureStringVariables = new Variables( + delegate(string name) + { + var pUniString = this.getStringVariable(name, out var length); + try + { + return this.convertToSecureString(pUniString, length); + } + finally + { + if (IntPtr.Zero != pUniString) + { + Marshal.FreeCoTaskMem(pUniString); + } + } + }, + delegate(string name, SecureString value) + { + IntPtr pValue = Marshal.SecureStringToCoTaskMemUnicode(value); + try + { + this.engine.SetVariableString(name, pValue); + } + finally + { + Marshal.FreeCoTaskMem(pValue); + } + }, + delegate(string name) + { + return this.containsVariable(name); + } + ); + + // Wrap the calls to get and set string variables. + this.stringVariables = new Variables( + delegate(string name) + { + int length; + IntPtr pUniString = this.getStringVariable(name, out length); + try + { + return Marshal.PtrToStringUni(pUniString, length); + } + finally + { + if (IntPtr.Zero != pUniString) + { + Marshal.FreeCoTaskMem(pUniString); + } + } + }, + delegate(string name, string value) + { + IntPtr pValue = Marshal.StringToCoTaskMemUni(value); + try + { + this.engine.SetVariableString(name, pValue); + } + finally + { + Marshal.FreeCoTaskMem(pValue); + } + }, + delegate(string name) + { + return this.containsVariable(name); + } + ); + + // Wrap the calls to get and set version variables. + this.versionVariables = new Variables( + delegate(string name) + { + long value; + int ret = this.engine.GetVariableVersion(name, out value); + if (NativeMethods.S_OK != ret) + { + throw new Win32Exception(ret); + } + + return LongToVersion(value); + }, + delegate(string name, Version value) + { + long version = VersionToLong(value); + this.engine.SetVariableVersion(name, version); + }, + delegate(string name) + { + long value; + int ret = this.engine.GetVariableVersion(name, out value); + + return NativeMethods.E_NOTFOUND != ret; + } + ); + } + + public IVariables NumericVariables + { + get { return this.numericVariables; } + } + + public int PackageCount + { + get + { + int count; + this.engine.GetPackageCount(out count); + + return count; + } + } + + public IVariables SecureStringVariables + { + get { return this.secureStringVariables; } + } + + public IVariables StringVariables + { + get { return this.stringVariables; } + } + + public IVariables VersionVariables + { + get { return this.versionVariables; } + } + + public void Apply(IntPtr hwndParent) + { + this.engine.Apply(hwndParent); + } + + public void CloseSplashScreen() + { + this.engine.CloseSplashScreen(); + } + + public void Detect() + { + this.Detect(IntPtr.Zero); + } + + public void Detect(IntPtr hwndParent) + { + this.engine.Detect(hwndParent); + } + + public bool Elevate(IntPtr hwndParent) + { + int ret = this.engine.Elevate(hwndParent); + + if (NativeMethods.S_OK == ret || NativeMethods.E_ALREADYINITIALIZED == ret) + { + return true; + } + else if (NativeMethods.E_CANCELLED == ret) + { + return false; + } + else + { + throw new Win32Exception(ret); + } + } + + public string EscapeString(string input) + { + int capacity = InitialBufferSize; + StringBuilder sb = new StringBuilder(capacity); + + // Get the size of the buffer. + int ret = this.engine.EscapeString(input, sb, ref capacity); + if (NativeMethods.E_INSUFFICIENT_BUFFER == ret || NativeMethods.E_MOREDATA == ret) + { + sb.Capacity = ++capacity; // Add one for the null terminator. + ret = this.engine.EscapeString(input, sb, ref capacity); + } + + if (NativeMethods.S_OK != ret) + { + throw new Win32Exception(ret); + } + + return sb.ToString(); + } + + public bool EvaluateCondition(string condition) + { + bool value; + this.engine.EvaluateCondition(condition, out value); + + return value; + } + + public string FormatString(string format) + { + int capacity = InitialBufferSize; + StringBuilder sb = new StringBuilder(capacity); + + // Get the size of the buffer. + int ret = this.engine.FormatString(format, sb, ref capacity); + if (NativeMethods.E_INSUFFICIENT_BUFFER == ret || NativeMethods.E_MOREDATA == ret) + { + sb.Capacity = ++capacity; // Add one for the null terminator. + ret = this.engine.FormatString(format, sb, ref capacity); + } + + if (NativeMethods.S_OK != ret) + { + throw new Win32Exception(ret); + } + + return sb.ToString(); + } + + public void LaunchApprovedExe(IntPtr hwndParent, string approvedExeForElevationId, string arguments) + { + this.LaunchApprovedExe(hwndParent, approvedExeForElevationId, arguments, 0); + } + + public void LaunchApprovedExe(IntPtr hwndParent, string approvedExeForElevationId, string arguments, int waitForInputIdleTimeout) + { + this.engine.LaunchApprovedExe(hwndParent, approvedExeForElevationId, arguments, waitForInputIdleTimeout); + } + + public void Log(LogLevel level, string message) + { + this.engine.Log(level, message); + } + + public void Plan(LaunchAction action) + { + this.engine.Plan(action); + } + + public void SetUpdate(string localSource, string downloadSource, long size, UpdateHashType hashType, byte[] hash) + { + this.engine.SetUpdate(localSource, downloadSource, size, hashType, hash, null == hash ? 0 : hash.Length); + } + + public void SetLocalSource(string packageOrContainerId, string payloadId, string path) + { + this.engine.SetLocalSource(packageOrContainerId, payloadId, path); + } + + public void SetDownloadSource(string packageOrContainerId, string payloadId, string url, string user, string password) + { + this.engine.SetDownloadSource(packageOrContainerId, payloadId, url, user, password); + } + + public int SendEmbeddedError(int errorCode, string message, int uiHint) + { + int result = 0; + this.engine.SendEmbeddedError(errorCode, message, uiHint, out result); + return result; + } + + public int SendEmbeddedProgress(int progressPercentage, int overallPercentage) + { + int result = 0; + this.engine.SendEmbeddedProgress(progressPercentage, overallPercentage, out result); + return result; + } + + public void Quit(int exitCode) + { + this.engine.Quit(exitCode); + } + + internal sealed class Variables : IVariables + { + // .NET 2.0 does not support Func or Action. + internal delegate T Getter(string name); + internal delegate void Setter(string name, T value); + + private Getter getter; + private Setter setter; + private Predicate contains; + + internal Variables(Getter getter, Setter setter, Predicate contains) + { + this.getter = getter; + this.setter = setter; + this.contains = contains; + } + + public T this[string name] + { + get { return this.getter(name); } + set { this.setter(name, value); } + } + + public bool Contains(string name) + { + return this.contains(name); + } + } + + /// + /// Gets whether the variable given by exists. + /// + /// The name of the variable to check. + /// True if the variable given by exists; otherwise, false. + internal bool containsVariable(string name) + { + int capacity = 0; + IntPtr pValue = IntPtr.Zero; + int ret = this.engine.GetVariableString(name, pValue, ref capacity); + + return NativeMethods.E_NOTFOUND != ret; + } + + /// + /// Gets the variable given by as a string. + /// + /// The name of the variable to get. + /// The length of the Unicode string. + /// The value by a pointer to a Unicode string. Must be freed by Marshal.FreeCoTaskMem. + /// An error occurred getting the variable. + internal IntPtr getStringVariable(string name, out int length) + { + int capacity = InitialBufferSize; + bool success = false; + IntPtr pValue = Marshal.AllocCoTaskMem(capacity * UnicodeEncoding.CharSize); + try + { + // Get the size of the buffer. + int ret = this.engine.GetVariableString(name, pValue, ref capacity); + if (NativeMethods.E_INSUFFICIENT_BUFFER == ret || NativeMethods.E_MOREDATA == ret) + { + // Don't need to add 1 for the null terminator, the engine already includes that. + pValue = Marshal.ReAllocCoTaskMem(pValue, capacity * UnicodeEncoding.CharSize); + ret = this.engine.GetVariableString(name, pValue, ref capacity); + } + + if (NativeMethods.S_OK != ret) + { + throw Marshal.GetExceptionForHR(ret); + } + + // The engine only returns the exact length of the string if the buffer was too small, so calculate it ourselves. + for (length = 0; length < capacity; ++length) + { + if(0 == Marshal.ReadInt16(pValue, length * UnicodeEncoding.CharSize)) + { + break; + } + } + + success = true; + return pValue; + } + finally + { + if (!success && IntPtr.Zero != pValue) + { + Marshal.FreeCoTaskMem(pValue); + } + } + } + + /// + /// Initialize a SecureString with the given Unicode string. + /// + /// Pointer to Unicode string. + /// The string's length. + internal SecureString convertToSecureString(IntPtr pUniString, int length) + { + if (IntPtr.Zero == pUniString) + { + return null; + } + + SecureString value = new SecureString(); + short s; + char c; + for (int charIndex = 0; charIndex < length; charIndex++) + { + s = Marshal.ReadInt16(pUniString, charIndex * UnicodeEncoding.CharSize); + c = (char)s; + value.AppendChar(c); + s = 0; + c = (char)0; + } + return value; + } + + public static long VersionToLong(Version version) + { + // In Windows, each version component has a max value of 65535, + // so we truncate the version before shifting it, which will overflow if invalid. + long major = (long)(ushort)version.Major << 48; + long minor = (long)(ushort)version.Minor << 32; + long build = (long)(ushort)version.Build << 16; + long revision = (long)(ushort)version.Revision; + + return major | minor | build | revision; + } + + public static Version LongToVersion(long version) + { + int major = (int)((version & ((long)0xffff << 48)) >> 48); + int minor = (int)((version & ((long)0xffff << 32)) >> 32); + int build = (int)((version & ((long)0xffff << 16)) >> 16); + int revision = (int)(version & 0xffff); + + return new Version(major, minor, build, revision); + } + + /// + /// Verifies that VersionVariables can pass on the given Version to the engine. + /// If the Build or Revision fields are undefined, they are set to zero. + /// + public static Version NormalizeVersion(Version version) + { + if (version == null) + { + throw new ArgumentNullException("version"); + } + + int major = version.Major; + int minor = version.Minor; + int build = version.Build; + int revision = version.Revision; + + if (major > UInt16.MaxValue) + { + throw new ArgumentOutOfRangeException("version", String.Format(normalizeVersionFormatString, "Major")); + } + if (minor > UInt16.MaxValue) + { + throw new ArgumentOutOfRangeException("version", String.Format(normalizeVersionFormatString, "Minor")); + } + if (build > UInt16.MaxValue) + { + throw new ArgumentOutOfRangeException("version", String.Format(normalizeVersionFormatString, "Build")); + } + if (build == -1) + { + build = 0; + } + if (revision > UInt16.MaxValue) + { + throw new ArgumentOutOfRangeException("version", String.Format(normalizeVersionFormatString, "Revision")); + } + if (revision == -1) + { + revision = 0; + } + + return new Version(major, minor, build, revision); + } + } +} diff --git a/src/WixToolset.Mba.Core/EventArgs.cs b/src/WixToolset.Mba.Core/EventArgs.cs new file mode 100644 index 00000000..9e8e6ecc --- /dev/null +++ b/src/WixToolset.Mba.Core/EventArgs.cs @@ -0,0 +1,1903 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.BootstrapperCore +{ + using System; + using System.Collections.Generic; + using System.Collections.ObjectModel; + + /// + /// Base class for BA classes. + /// + [Serializable] + public abstract class HResultEventArgs : EventArgs + { + /// + /// Creates a new instance of the class. + /// + public HResultEventArgs() + { + } + + /// + /// Gets or sets the of the operation. This is passed back to the engine. + /// + public int HResult { get; set; } + } + + /// + /// Base class for cancellable BA classes. + /// + [Serializable] + public abstract class CancellableHResultEventArgs : HResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + public CancellableHResultEventArgs(bool cancelRecommendation) + { + this.Cancel = cancelRecommendation; + } + + /// + /// Gets or sets whether to cancel the operation. This is passed back to the engine. + /// + public bool Cancel { get; set; } + } + + /// + /// Base class for classes that must return a . + /// + [Serializable] + public abstract class ResultEventArgs : HResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// Recommended result from engine. + /// The result to return to the engine. + public ResultEventArgs(Result recommendation, Result result) + { + this.Recommendation = recommendation; + this.Result = result; + } + + /// + /// Gets the recommended of the operation. + /// + public Result Recommendation { get; private set; } + + /// + /// Gets or sets the of the operation. This is passed back to the engine. + /// + public Result Result { get; set; } + } + + /// + /// Base class for classes that receive status from the engine. + /// + [Serializable] + public abstract class StatusEventArgs : HResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The return code of the operation. + public StatusEventArgs(int hrStatus) + { + this.Status = hrStatus; + } + + /// + /// Gets the return code of the operation. + /// + public int Status { get; private set; } + } + + /// + /// Base class for classes that receive status from the engine and return an action. + /// + public abstract class ActionEventArgs : StatusEventArgs + { + /// + /// + /// The return code of the operation. + /// Recommended action from engine. + /// The action to perform. + public ActionEventArgs(int hrStatus, T recommendation, T action) + : base(hrStatus) + { + this.Recommendation = recommendation; + this.Action = action; + } + + /// + /// Gets the recommended action from the engine. + /// + public T Recommendation { get; private set; } + + /// + /// Gets or sets the action to be performed. This is passed back to the engine. + /// + public T Action { get; set; } + } + + /// + /// Additional arguments used when startup has begun. + /// + [Serializable] + public class StartupEventArgs : HResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + public StartupEventArgs() + { + } + } + + /// + /// Additional arguments used when shutdown has begun. + /// + [Serializable] + public class ShutdownEventArgs : HResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + public ShutdownEventArgs(BOOTSTRAPPER_SHUTDOWN_ACTION action) + { + this.Action = action; + } + + /// + /// The action for OnShutdown. + /// + public BOOTSTRAPPER_SHUTDOWN_ACTION Action { get; set; } + } + + /// + /// Additional arguments used when the system is shutting down or the user is logging off. + /// + /// + /// To prevent shutting down or logging off, set to + /// true; otherwise, set it to false. + /// By default setup will prevent shutting down or logging off between + /// and . + /// If contains + /// the bootstrapper cannot prevent the shutdown and only has a few seconds to save state or perform any other + /// critical operations before being closed by the operating system. + /// + [Serializable] + public class SystemShutdownEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The reason the application is requested to close or being closed. + /// The recommendation from the engine. + public SystemShutdownEventArgs(EndSessionReasons reasons, bool cancelRecommendation) + : base(cancelRecommendation) + { + this.Reasons = reasons; + } + + /// + /// Gets the reason the application is requested to close or being closed. + /// + /// + /// To prevent shutting down or logging off, set to + /// true; otherwise, set it to false. + /// If contains + /// the bootstrapper cannot prevent the shutdown and only has a few seconds to save state or perform any other + /// critical operations before being closed by the operating system. + /// + public EndSessionReasons Reasons { get; private set; } + } + + /// + /// Additional arguments used when the overall detection phase has begun. + /// + [Serializable] + public class DetectBeginEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// Specifies whether the bundle is installed. + /// The number of packages to detect. + /// The recommendation from the engine. + public DetectBeginEventArgs(bool installed, int packageCount, bool cancelRecommendation) + : base(cancelRecommendation) + { + this.Installed = installed; + this.PackageCount = packageCount; + } + + /// + /// Gets whether the bundle is installed. + /// + public bool Installed { get; private set; } + + /// + /// Gets the number of packages to detect. + /// + public int PackageCount { get; private set; } + } + + /// + /// Additional arguments used when detected a forward compatible bundle. + /// + [Serializable] + public class DetectForwardCompatibleBundleEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The identity of the forward compatible bundle. + /// Relationship type for this forward compatible bundle. + /// The tag of the forward compatible bundle. + /// Whether the detected forward compatible bundle is per machine. + /// The version of the forward compatible bundle detected. + /// The cancel recommendation from the engine. + /// The ignore recommendation from the engine. + public DetectForwardCompatibleBundleEventArgs(string bundleId, RelationType relationType, string bundleTag, bool perMachine, long version, bool cancelRecommendation, bool ignoreBundleRecommendation) + : base(cancelRecommendation) + { + this.BundleId = bundleId; + this.RelationType = relationType; + this.BundleTag = bundleTag; + this.PerMachine = perMachine; + this.Version = Engine.LongToVersion(version); + this.IgnoreBundle = ignoreBundleRecommendation; + } + + /// + /// Gets the identity of the forward compatible bundle detected. + /// + public string BundleId { get; private set; } + + /// + /// Gets the relationship type of the forward compatible bundle. + /// + public RelationType RelationType { get; private set; } + + /// + /// Gets the tag of the forward compatible bundle. + /// + public string BundleTag { get; private set; } + + /// + /// Gets whether the detected forward compatible bundle is per machine. + /// + public bool PerMachine { get; private set; } + + /// + /// Gets the version of the forward compatible bundle detected. + /// + public Version Version { get; private set; } + + /// + /// Instructs the engine whether to use the forward compatible bundle. + /// + public bool IgnoreBundle { get; set; } + } + + /// + /// Additional arguments used when the detection for an update has begun. + /// + [Serializable] + public class DetectUpdateBeginEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The location to check for an updated bundle. + /// The cancel recommendation from the engine. + /// The skip recommendation from the engine. + public DetectUpdateBeginEventArgs(string updateLocation, bool cancelRecommendation, bool skipRecommendation) + : base(cancelRecommendation) + { + this.UpdateLocation = updateLocation; + } + + /// + /// Gets the identity of the bundle to detect. + /// + public string UpdateLocation { get; private set; } + + /// + /// Whether to skip checking for bundle updates. + /// + public bool Skip { get; set; } + } + + /// + /// Additional arguments used when the detection for an update has begun. + /// + [Serializable] + public class DetectUpdateEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The location to check for an updated bundle. + /// The expected size of the updated bundle. + /// The expected version of the updated bundle. + /// The title of the updated bundle. + /// The summary of the updated bundle. + /// The content type of the content of the updated bundle. + /// The content of the updated bundle. + /// The recommendation from the engine. + /// The recommendation from the engine. + public DetectUpdateEventArgs(string updateLocation, long size, long version, string title, string summary, string contentType, string content, bool cancelRecommendation, bool stopRecommendation) + : base(cancelRecommendation) + { + this.UpdateLocation = updateLocation; + this.Size = size; + this.Version = Engine.LongToVersion(version); + this.Title = title; + this.Summary = summary; + this.ContentType = contentType; + this.Content = content; + this.StopProcessingUpdates = stopRecommendation; + } + + /// + /// Gets the identity of the bundle to detect. + /// + public string UpdateLocation { get; private set; } + + /// + /// Gets the size of the updated bundle. + /// + public long Size { get; private set; } + + /// + /// Gets the version of the updated bundle. + /// + public Version Version { get; private set; } + + /// + /// Gets the title of the the updated bundle. + /// + public string Title { get; private set; } + + /// + /// Gets the summary of the updated bundle. + /// + public string Summary { get; private set; } + + /// + /// Gets the content type of the content of the updated bundle. + /// + public string ContentType { get; private set; } + + /// + /// Gets the content of the updated bundle. + /// + public string Content { get; private set; } + + /// + /// Tells the engine to stop giving the rest of the updates found in the feed. + /// + public bool StopProcessingUpdates { get; set; } + } + + /// + /// Additional arguments used when the detection for an update has completed. + /// + [Serializable] + public class DetectUpdateCompleteEventArgs : StatusEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The return code of the operation. + /// The recommendation from the engine. + public DetectUpdateCompleteEventArgs(int hrStatus, bool ignoreRecommendation) + : base(hrStatus) + { + this.IgnoreError = ignoreRecommendation; + } + + /// + /// If Status is an error, then set this to true to ignore it and continue detecting. + /// + public bool IgnoreError { get; set; } + } + + /// + /// Additional arguments used when a related bundle has been detected for a bundle. + /// + [Serializable] + public class DetectRelatedBundleEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The identity of the related package bundle. + /// Relationship type for this related bundle. + /// The tag of the related package bundle. + /// Whether the detected bundle is per machine. + /// The version of the related bundle detected. + /// The operation that will be taken on the detected bundle. + /// The recommendation from the engine. + public DetectRelatedBundleEventArgs(string productCode, RelationType relationType, string bundleTag, bool perMachine, long version, RelatedOperation operation, bool cancelRecommendation) + : base(cancelRecommendation) + { + this.ProductCode = productCode; + this.RelationType = relationType; + this.BundleTag = bundleTag; + this.PerMachine = perMachine; + this.Version = Engine.LongToVersion(version); + this.Operation = operation; + } + + /// + /// Gets the identity of the related bundle detected. + /// + public string ProductCode { get; private set; } + + /// + /// Gets the relationship type of the related bundle. + /// + public RelationType RelationType { get; private set; } + + /// + /// Gets the tag of the related package bundle. + /// + public string BundleTag { get; private set; } + + /// + /// Gets whether the detected bundle is per machine. + /// + public bool PerMachine { get; private set; } + + /// + /// Gets the version of the related bundle detected. + /// + public Version Version { get; private set; } + + /// + /// Gets the operation that will be taken on the detected bundle. + /// + public RelatedOperation Operation { get; private set; } + } + + /// + /// Additional arguments used when the detection for a specific package has begun. + /// + [Serializable] + public class DetectPackageBeginEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The identity of the package to detect. + /// The recommendation from the engine. + public DetectPackageBeginEventArgs(string packageId, bool cancelRecommendation) + : base(cancelRecommendation) + { + this.PackageId = packageId; + } + + /// + /// Gets the identity of the package to detect. + /// + public string PackageId { get; private set; } + } + + /// + /// Additional arguments used when a package was not found but a newer package using the same provider key was. + /// + [Serializable] + public class DetectCompatibleMsiPackageEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The identity of the package that was not detected. + /// The identity of the compatible package that was detected. + /// The version of the compatible package that was detected. + /// The recommendation from the engine. + public DetectCompatibleMsiPackageEventArgs(string packageId, string compatiblePackageId, long compatiblePackageVersion, bool cancelRecommendation) + : base(cancelRecommendation) + { + this.PackageId = packageId; + this.CompatiblePackageId = compatiblePackageId; + this.CompatiblePackageVersion = Engine.LongToVersion(compatiblePackageVersion); + } + + /// + /// Gets the identity of the package that was not detected. + /// + public string PackageId { get; private set; } + + /// + /// Gets the identity of the compatible package that was detected. + /// + public string CompatiblePackageId { get; private set; } + + /// + /// Gets the version of the compatible package that was detected. + /// + public Version CompatiblePackageVersion { get; private set; } + } + + /// + /// Additional arguments used when a related MSI package has been detected for a package. + /// + [Serializable] + public class DetectRelatedMsiPackageEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The identity of the package detecting. + /// The upgrade code of the related package detected. + /// The identity of the related package detected. + /// Whether the detected package is per machine. + /// The version of the related package detected. + /// The operation that will be taken on the detected package. + /// The recommendation from the engine. + public DetectRelatedMsiPackageEventArgs(string packageId, string upgradeCode, string productCode, bool perMachine, long version, RelatedOperation operation, bool cancelRecommendation) + : base(cancelRecommendation) + { + this.PackageId = packageId; + this.UpgradeCode = upgradeCode; + this.ProductCode = productCode; + this.PerMachine = perMachine; + this.Version = Engine.LongToVersion(version); + this.Operation = operation; + } + + /// + /// Gets the identity of the product's package detected. + /// + public string PackageId { get; private set; } + + /// + /// Gets the upgrade code of the related package detected. + /// + public string UpgradeCode { get; private set; } + + /// + /// Gets the identity of the related package detected. + /// + public string ProductCode { get; private set; } + + /// + /// Gets whether the detected package is per machine. + /// + public bool PerMachine { get; private set; } + + /// + /// Gets the version of the related package detected. + /// + public Version Version { get; private set; } + + /// + /// Gets the operation that will be taken on the detected package. + /// + public RelatedOperation Operation { get; private set; } + } + + /// + /// Additional arguments used when a target MSI package has been detected. + /// + public class DetectTargetMsiPackageEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// Detected package identifier. + /// Detected product code. + /// Package state detected. + /// The recommendation from the engine. + public DetectTargetMsiPackageEventArgs(string packageId, string productCode, PackageState state, bool cancelRecommendation) + : base(cancelRecommendation) + { + this.PackageId = packageId; + this.ProductCode = productCode; + this.State = state; + } + + /// + /// Gets the identity of the target's package detected. + /// + public string PackageId { get; private set; } + + /// + /// Gets the product code of the target MSI detected. + /// + public string ProductCode { get; private set; } + + /// + /// Gets the detected patch package state. + /// + public PackageState State { get; private set; } + } + + /// + /// Additional arguments used when a feature in an MSI package has been detected. + /// + public class DetectMsiFeatureEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// Detected package identifier. + /// Detected feature identifier. + /// Feature state detected. + /// The recommendation from the engine. + public DetectMsiFeatureEventArgs(string packageId, string featureId, FeatureState state, bool cancelRecommendation) + : base(cancelRecommendation) + { + this.PackageId = packageId; + this.FeatureId = featureId; + this.State = state; + } + + /// + /// Gets the identity of the feature's package detected. + /// + public string PackageId { get; private set; } + + /// + /// Gets the identity of the feature detected. + /// + public string FeatureId { get; private set; } + + /// + /// Gets the detected feature state. + /// + public FeatureState State { get; private set; } + } + + /// + /// Additional arguments used when the detection for a specific package has completed. + /// + [Serializable] + public class DetectPackageCompleteEventArgs : StatusEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The identity of the package detected. + /// The return code of the operation. + /// The state of the specified package. + public DetectPackageCompleteEventArgs(string packageId, int hrStatus, PackageState state) + : base(hrStatus) + { + this.PackageId = packageId; + this.State = state; + } + + /// + /// Gets the identity of the package detected. + /// + public string PackageId { get; private set; } + + /// + /// Gets the state of the specified package. + /// + public PackageState State { get; private set; } + } + + /// + /// Additional arguments used when the detection phase has completed. + /// + [Serializable] + public class DetectCompleteEventArgs : StatusEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The return code of the operation. + public DetectCompleteEventArgs(int hrStatus) + : base(hrStatus) + { + } + } + + /// + /// Additional arguments used when the engine has begun planning the installation. + /// + [Serializable] + public class PlanBeginEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The number of packages to plan for. + /// The recommendation from the engine. + public PlanBeginEventArgs(int packageCount, bool cancelRecommendation) + : base(cancelRecommendation) + { + this.PackageCount = packageCount; + } + + /// + /// Gets the number of packages to plan for. + /// + public int PackageCount { get; private set; } + } + + /// + /// Additional arguments used when the engine has begun planning for a related bundle. + /// + [Serializable] + public class PlanRelatedBundleEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The identity of the bundle to plan for. + /// The recommended requested state for the bundle. + /// The requested state for the bundle. + /// The recommendation from the engine. + public PlanRelatedBundleEventArgs(string bundleId, RequestState recommendedState, RequestState state, bool cancelRecommendation) + : base(cancelRecommendation) + { + this.BundleId = bundleId; + this.RecommendedState = recommendedState; + this.State = state; + } + + /// + /// Gets the identity of the bundle to plan for. + /// + public string BundleId { get; private set; } + + /// + /// Gets the recommended requested state for the bundle. + /// + public RequestState RecommendedState { get; private set; } + + /// + /// Gets or sets the requested state for the bundle. + /// + public RequestState State { get; set; } + } + + /// + /// Additional arguments used when the engine has begun planning the installation of a specific package. + /// + [Serializable] + public class PlanPackageBeginEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The identity of the package to plan for. + /// The recommended requested state for the package. + /// The requested state for the package. + /// The recommendation from the engine. + public PlanPackageBeginEventArgs(string packageId, RequestState recommendedState, RequestState state, bool cancelRecommendation) + : base(cancelRecommendation) + { + this.PackageId = packageId; + this.RecommendedState = recommendedState; + this.State = state; + } + + /// + /// Gets the identity of the package to plan for. + /// + public string PackageId { get; private set; } + + /// + /// Gets the recommended requested state for the package. + /// + public RequestState RecommendedState { get; private set; } + + /// + /// Gets or sets the requested state for the package. + /// + public RequestState State { get; set; } + } + + /// + /// Additional arguments used when the engine is about to plan a newer package using the same provider key. + /// + [Serializable] + public class PlanCompatibleMsiPackageBeginEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The identity of the package that was not detected. + /// The identity of the compatible package that was detected. + /// The version of the compatible package that was detected. + /// The recommended request state for the compatible package. + /// The requested state for the compatible package. + /// The recommendation from the engine. + public PlanCompatibleMsiPackageBeginEventArgs(string packageId, string compatiblePackageId, long compatiblePackageVersion, RequestState recommendedState, RequestState state, bool cancelRecommendation) + : base(cancelRecommendation) + { + this.PackageId = packageId; + this.CompatiblePackageId = compatiblePackageId; + this.CompatiblePackageVersion = Engine.LongToVersion(compatiblePackageVersion); + this.RecommendedState = recommendedState; + this.State = state; + } + + /// + /// Gets the identity of the package that was not detected. + /// + public string PackageId { get; private set; } + + /// + /// Gets the identity of the compatible package detected. + /// + public string CompatiblePackageId { get; private set; } + + /// + /// Gets the version of the compatible package detected. + /// + public Version CompatiblePackageVersion { get; private set; } + + /// + /// Gets the recommended state to use for the compatible package for planning. + /// + public RequestState RecommendedState { get; private set; } + + /// + /// Gets or sets the state to use for the compatible package for planning. + /// + public RequestState State { get; set; } + } + + /// + /// Additional arguments used when the engine has completed planning the installation of a specific package. + /// + [Serializable] + public class PlanCompatibleMsiPackageCompleteEventArgs : StatusEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The identity of the package planned for. + /// The identity of the compatible package that was detected. + /// The return code of the operation. + /// The current state of the package. + /// The requested state for the package + /// The execution action to take. + /// The rollback action to take. + public PlanCompatibleMsiPackageCompleteEventArgs(string packageId, string compatiblePackageId, int hrStatus, PackageState state, RequestState requested, ActionState execute, ActionState rollback) + : base(hrStatus) + { + this.PackageId = packageId; + this.CompatiblePackageId = compatiblePackageId; + this.State = state; + this.Requested = requested; + this.Execute = execute; + this.Rollback = rollback; + } + + /// + /// Gets the identity of the package planned for. + /// + public string PackageId { get; private set; } + + /// + /// Gets the identity of the compatible package detected. + /// + public string CompatiblePackageId { get; private set; } + + /// + /// Gets the current state of the package. + /// + public PackageState State { get; private set; } + + /// + /// Gets the requested state for the package. + /// + public RequestState Requested { get; private set; } + + /// + /// Gets the execution action to take. + /// + public ActionState Execute { get; private set; } + + /// + /// Gets the rollback action to take. + /// + public ActionState Rollback { get; private set; } + } + + /// + /// Additional arguments used when engine is about to plan a MSP applied to a target MSI package. + /// + [Serializable] + public class PlanTargetMsiPackageEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// Package identifier of the patch being planned. + /// Product code identifier being planned. + /// Recommended package state of the patch being planned. + /// Package state of the patch being planned. + /// The recommendation from the engine. + public PlanTargetMsiPackageEventArgs(string packageId, string productCode, RequestState recommendedState, RequestState state, bool cancelRecommendation) + : base(cancelRecommendation) + { + this.PackageId = packageId; + this.ProductCode = productCode; + this.RecommendedState = recommendedState; + this.State = state; + } + + /// + /// Gets the identity of the patch package to plan. + /// + public string PackageId { get; private set; } + + /// + /// Gets the identity of the patch's target MSI to plan. + /// + public string ProductCode { get; private set; } + + /// + /// Gets the recommended state of the patch to use by planning. + /// + public RequestState RecommendedState { get; private set; } + + /// + /// Gets or sets the state of the patch to use by planning. + /// + public RequestState State { get; set; } + } + + /// + /// Additional arguments used when engine is about to plan a feature in an MSI package. + /// + [Serializable] + public class PlanMsiFeatureEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// Package identifier being planned. + /// Feature identifier being planned. + /// Recommended feature state being planned. + /// Feature state being planned. + /// The recommendation from the engine. + public PlanMsiFeatureEventArgs(string packageId, string featureId, FeatureState recommendedState, FeatureState state, bool cancelRecommendation) + : base(cancelRecommendation) + { + this.PackageId = packageId; + this.FeatureId = featureId; + this.RecommendedState = recommendedState; + this.State = state; + } + + /// + /// Gets the identity of the feature's package to plan. + /// + public string PackageId { get; private set; } + + /// + /// Gets the identity of the feature to plan. + /// + public string FeatureId { get; private set; } + + /// + /// Gets the recommended feature state to use by planning. + /// + public FeatureState RecommendedState { get; private set; } + + /// + /// Gets or sets the feature state to use by planning. + /// + public FeatureState State { get; set; } + } + + /// + /// Additional arguments used when then engine has completed planning the installation of a specific package. + /// + [Serializable] + public class PlanPackageCompleteEventArgs : StatusEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The identity of the package planned for. + /// The return code of the operation. + /// The current state of the package. + /// The requested state for the package + /// The execution action to take. + /// The rollback action to take. + public PlanPackageCompleteEventArgs(string packageId, int hrStatus, PackageState state, RequestState requested, ActionState execute, ActionState rollback) + : base(hrStatus) + { + this.PackageId = packageId; + this.State = state; + this.Requested = requested; + this.Execute = execute; + this.Rollback = rollback; + } + + /// + /// Gets the identity of the package planned for. + /// + public string PackageId { get; private set; } + + /// + /// Gets the current state of the package. + /// + public PackageState State { get; private set; } + + /// + /// Gets the requested state for the package. + /// + public RequestState Requested { get; private set; } + + /// + /// Gets the execution action to take. + /// + public ActionState Execute { get; private set; } + + /// + /// Gets the rollback action to take. + /// + public ActionState Rollback { get; private set; } + } + + /// + /// Additional arguments used when the engine has completed planning the installation. + /// + [Serializable] + public class PlanCompleteEventArgs : StatusEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The return code of the operation. + public PlanCompleteEventArgs(int hrStatus) + : base(hrStatus) + { + } + } + + /// + /// Additional arguments used when the engine has begun installing the bundle. + /// + [Serializable] + public class ApplyBeginEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The number of phases during apply. + /// The recommendation from the engine. + public ApplyBeginEventArgs(int phaseCount, bool cancelRecommendation) + : base(cancelRecommendation) + { + this.PhaseCount = phaseCount; + } + + /// + /// Gets the number of phases that the engine will go through in apply. + /// There are currently two possible phases: cache and execute. + /// + public int PhaseCount { get; private set; } + } + + /// + /// Additional arguments used when the engine is about to start the elevated process. + /// + [Serializable] + public class ElevateBeginEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The recommendation from the engine. + public ElevateBeginEventArgs(bool cancelRecommendation) + : base(cancelRecommendation) + { + } + } + + /// + /// Additional arguments used when the engine has completed starting the elevated process. + /// + [Serializable] + public class ElevateCompleteEventArgs : StatusEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The return code of the operation. + public ElevateCompleteEventArgs(int hrStatus) + : base(hrStatus) + { + } + } + + /// + /// Additional arguments used when the engine has changed progress for the bundle installation. + /// + [Serializable] + public class ProgressEventArgs : CancellableHResultEventArgs + { + /// + /// Creates an new instance of the class. + /// + /// The percentage from 0 to 100 completed for a package. + /// The percentage from 0 to 100 completed for the bundle. + /// The recommendation from the engine. + public ProgressEventArgs(int progressPercentage, int overallPercentage, bool cancelRecommendation) + : base(cancelRecommendation) + { + this.ProgressPercentage = progressPercentage; + this.OverallPercentage = overallPercentage; + } + + /// + /// Gets the percentage from 0 to 100 completed for a package. + /// + public int ProgressPercentage { get; private set; } + + /// + /// Gets the percentage from 0 to 100 completed for the bundle. + /// + public int OverallPercentage { get; private set; } + } + + /// + /// Additional arguments used when the engine has encountered an error. + /// + [Serializable] + public class ErrorEventArgs : ResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The error type. + /// The identity of the package that yielded the error. + /// The error code. + /// The error message. + /// Recommended display flags for an error dialog. + /// The exteded data for the error. + /// Recommended result from engine. + /// The result to return to the engine. + public ErrorEventArgs(ErrorType errorType, string packageId, int errorCode, string errorMessage, int dwUIHint, string[] data, Result recommendation, Result result) + : base(recommendation, result) + { + this.ErrorType = errorType; + this.PackageId = packageId; + this.ErrorCode = errorCode; + this.ErrorMessage = errorMessage; + this.UIHint = dwUIHint; + this.Data = new ReadOnlyCollection(data ?? new string[] { }); + } + + /// + /// Gets the type of error that occurred. + /// + public ErrorType ErrorType { get; private set; } + + /// + /// Gets the identity of the package that yielded the error. + /// + public string PackageId { get; private set; } + + /// + /// Gets the error code. + /// + public int ErrorCode { get; private set; } + + /// + /// Gets the error message. + /// + public string ErrorMessage { get; private set; } + + /// + /// Gets the recommended display flags for an error dialog. + /// + public int UIHint { get; private set; } + + /// + /// Gets the extended data for the error. + /// + public IList Data { get; private set; } + } + + /// + /// Additional arguments used when the engine has begun registering the location and visibility of the bundle. + /// + [Serializable] + public class RegisterBeginEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The recommendation from the engine. + public RegisterBeginEventArgs(bool cancelRecommendation) + : base(cancelRecommendation) + { + } + } + + /// + /// Additional arguments used when the engine has completed registering the location and visilibity of the bundle. + /// + [Serializable] + public class RegisterCompleteEventArgs : StatusEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The return code of the operation. + public RegisterCompleteEventArgs(int hrStatus) + : base(hrStatus) + { + } + } + + /// + /// Additional arguments used when the engine has begun removing the registration for the location and visibility of the bundle. + /// + [Serializable] + public class UnregisterBeginEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The recommendation from the engine. + public UnregisterBeginEventArgs(bool cancelRecommendation) + : base(cancelRecommendation) + { + } + } + + /// + /// Additional arguments used when the engine has completed removing the registration for the location and visibility of the bundle. + /// + [Serializable] + public class UnregisterCompleteEventArgs : StatusEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The return code of the operation. + public UnregisterCompleteEventArgs(int hrStatus) + : base(hrStatus) + { + } + } + + /// + /// Additional arguments used when the engine has begun caching the installation sources. + /// + [Serializable] + public class CacheBeginEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The recommendation from the engine. + public CacheBeginEventArgs(bool cancelRecommendation) + : base(cancelRecommendation) + { + } + } + + /// + /// Additional arguments used when the engine begins to acquire containers or payloads. + /// + [Serializable] + public class CacheAcquireBeginEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + public CacheAcquireBeginEventArgs(string packageOrContainerId, string payloadId, CacheOperation operation, string source, bool cancelRecommendation) + : base(cancelRecommendation) + { + this.PackageOrContainerId = packageOrContainerId; + this.PayloadId = payloadId; + this.Operation = operation; + this.Source = source; + } + + /// + /// Gets the identifier of the container or package. + /// + public string PackageOrContainerId { get; private set; } + + /// + /// Gets the identifier of the payload (if acquiring a payload). + /// + public string PayloadId { get; private set; } + + /// + /// Gets the cache acquire operation. + /// + public CacheOperation Operation { get; private set; } + + /// + /// Gets the source of the container or payload. + /// + public string Source { get; private set; } + } + + /// + /// Additional arguments used when the engine acquires some part of a container or payload. + /// + [Serializable] + public class CacheAcquireProgressEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + public CacheAcquireProgressEventArgs(string packageOrContainerId, string payloadId, long progress, long total, int overallPercentage, bool cancelRecommendation) + : base(cancelRecommendation) + { + this.PackageOrContainerId = packageOrContainerId; + this.PayloadId = payloadId; + this.Progress = progress; + this.Total = total; + this.OverallPercentage = overallPercentage; + } + + /// + /// Gets the identifier of the container or package. + /// + public string PackageOrContainerId { get; private set; } + + /// + /// Gets the identifier of the payload (if acquiring a payload). + /// + public string PayloadId { get; private set; } + + /// + /// Gets the number of bytes cached thus far. + /// + public long Progress { get; private set; } + + /// + /// Gets the total bytes to cache. + /// + public long Total { get; private set; } + + /// + /// Gets the overall percentage of progress of caching. + /// + public int OverallPercentage { get; private set; } + } + + /// + /// Additional arguments used when the engine completes the acquisition of a container or payload. + /// + [Serializable] + public class CacheAcquireCompleteEventArgs : ActionEventArgs + { + /// + /// Creates a new instance of the class. + /// + public CacheAcquireCompleteEventArgs(string packageOrContainerId, string payloadId, int hrStatus, BOOTSTRAPPER_CACHEACQUIRECOMPLETE_ACTION recommendation, BOOTSTRAPPER_CACHEACQUIRECOMPLETE_ACTION action) + : base(hrStatus, recommendation, action) + { + this.PackageOrContainerId = packageOrContainerId; + this.PayloadId = payloadId; + } + + /// + /// Gets the identifier of the container or package. + /// + public string PackageOrContainerId { get; private set; } + + /// + /// Gets the identifier of the payload (if acquiring a payload). + /// + public string PayloadId { get; private set; } + } + + /// + /// Additional arguments used when the engine starts the verification of a payload. + /// + [Serializable] + public class CacheVerifyBeginEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + public CacheVerifyBeginEventArgs(string packageId, string payloadId, bool cancelRecommendation) + : base(cancelRecommendation) + { + this.PackageId = packageId; + this.PayloadId = payloadId; + } + + /// + /// Gets the identifier of the package. + /// + public string PackageId { get; private set; } + + /// + /// Gets the identifier of the payload. + /// + public string PayloadId { get; private set; } + } + + /// + /// Additional arguments used when the engine completes the verification of a payload. + /// + [Serializable] + public class CacheVerifyCompleteEventArgs : ActionEventArgs + { + /// + /// Creates a new instance of the class. + /// + public CacheVerifyCompleteEventArgs(string packageId, string payloadId, int hrStatus, BOOTSTRAPPER_CACHEVERIFYCOMPLETE_ACTION recommendation, BOOTSTRAPPER_CACHEVERIFYCOMPLETE_ACTION action) + : base(hrStatus, recommendation, action) + { + this.PackageId = packageId; + this.PayloadId = payloadId; + } + + /// + /// Gets the identifier of the package. + /// + public string PackageId { get; private set; } + + /// + /// Gets the identifier of the payload. + /// + public string PayloadId { get; private set; } + } + + /// + /// Additional arguments used after the engine has cached the installation sources. + /// + [Serializable] + public class CacheCompleteEventArgs : StatusEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The return code of the operation. + public CacheCompleteEventArgs(int hrStatus) + : base(hrStatus) + { + } + } + + /// + /// Additional arguments used when the engine has begun installing packages. + /// + [Serializable] + public class ExecuteBeginEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The number of packages to act on. + /// The recommendation from the engine. + public ExecuteBeginEventArgs(int packageCount, bool cancelRecommendation) + : base(cancelRecommendation) + { + this.PackageCount = packageCount; + } + + /// + /// Gets the number of packages to act on. + /// + public int PackageCount { get; private set; } + } + + /// + /// Additional arguments used when the engine has begun installing a specific package. + /// + [Serializable] + public class ExecutePackageBeginEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The identity of the package to act on. + /// Whether the package should really be acted on. + /// The recommendation from the engine. + public ExecutePackageBeginEventArgs(string packageId, bool shouldExecute, bool cancelRecommendation) + : base(cancelRecommendation) + { + this.PackageId = packageId; + this.ShouldExecute = shouldExecute; + } + + /// + /// Gets the identity of the package to act on. + /// + public string PackageId { get; private set; } + + /// + /// Gets whether the package should really be acted on. + /// + public bool ShouldExecute { get; private set; } + } + + /// + /// Additional arguments used when the engine executes one or more patches targeting a product. + /// + [Serializable] + public class ExecutePatchTargetEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The identity of the package to act on. + /// The product code of the target of the patch. + /// The recommendation from the engine. + public ExecutePatchTargetEventArgs(string packageId, string targetProductCode, bool cancelRecommendation) + : base(cancelRecommendation) + { + this.PackageId = packageId; + this.TargetProductCode = targetProductCode; + } + + /// + /// Gets the identity of the package to act on. + /// + public string PackageId { get; private set; } + + /// + /// Gets the product code being targeted. + /// + public string TargetProductCode { get; private set; } + } + + /// + /// Additional arguments used when Windows Installer sends an installation message. + /// + [Serializable] + public class ExecuteMsiMessageEventArgs : ResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The identity of the package that yielded this message. + /// The type of this message. + /// Recommended display flags for this message. + /// The message. + /// The extended data for the message. + /// Recommended result from engine. + /// The result to return to the engine. + public ExecuteMsiMessageEventArgs(string packageId, InstallMessage messageType, int dwUIHint, string message, string[] data, Result recommendation, Result result) + : base(recommendation, result) + { + this.PackageId = packageId; + this.MessageType = messageType; + this.UIHint = dwUIHint; + this.Message = message; + this.Data = new ReadOnlyCollection(data ?? new string[] { }); + } + + /// + /// Gets the identity of the package that yielded this message. + /// + public string PackageId { get; private set; } + + /// + /// Gets the type of this message. + /// + public InstallMessage MessageType { get; private set; } + + /// + /// Gets the recommended display flags for this message. + /// + public int UIHint { get; private set; } + + /// + /// Gets the message. + /// + public string Message { get; private set; } + + /// + /// Gets the extended data for the message. + /// + public IList Data { get; private set; } + } + + /// + /// Additional arugments used for file in use installation messages. + /// + [Serializable] + public class ExecuteFilesInUseEventArgs : ResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The identity of the package that yielded the files in use message. + /// The list of files in use. + /// Recommended result from engine. + /// The result to return to the engine. + public ExecuteFilesInUseEventArgs(string packageId, string[] files, Result recommendation, Result result) + : base(recommendation, result) + { + this.PackageId = packageId; + this.Files = new ReadOnlyCollection(files ?? new string[] { }); + } + + /// + /// Gets the identity of the package that yielded the files in use message. + /// + public string PackageId { get; private set; } + + /// + /// Gets the list of files in use. + /// + public IList Files { get; private set; } + } + + /// + /// Additional arguments used when the engine has completed installing a specific package. + /// + [Serializable] + public class ExecutePackageCompleteEventArgs : ActionEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The identity of the package that was acted on. + /// The return code of the operation. + /// Whether a restart is required. + /// Recommended action from engine. + /// The action to perform. + public ExecutePackageCompleteEventArgs(string packageId, int hrStatus, ApplyRestart restart, BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION recommendation, BOOTSTRAPPER_EXECUTEPACKAGECOMPLETE_ACTION action) + : base(hrStatus, recommendation, action) + { + this.PackageId = packageId; + this.Restart = restart; + } + + /// + /// Gets the identity of the package that was acted on. + /// + public string PackageId { get; private set; } + + /// + /// Gets the package restart state after being applied. + /// + public ApplyRestart Restart { get; private set; } + } + + /// + /// Additional arguments used when the engine has completed installing packages. + /// + [Serializable] + public class ExecuteCompleteEventArgs : StatusEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The return code of the operation. + public ExecuteCompleteEventArgs(int hrStatus) + : base(hrStatus) + { + } + } + + /// + /// Additional arguments used when the engine has completed installing the bundle. + /// + [Serializable] + public class ApplyCompleteEventArgs : ActionEventArgs + { + /// + /// Creates a new instance of the clas. + /// + /// The return code of the operation. + /// Whether a restart is required. + /// Recommended action from engine. + /// The action to perform. + public ApplyCompleteEventArgs(int hrStatus, ApplyRestart restart, BOOTSTRAPPER_APPLYCOMPLETE_ACTION recommendation, BOOTSTRAPPER_APPLYCOMPLETE_ACTION action) + : base(hrStatus, recommendation, action) + { + this.Restart = restart; + } + + /// + /// Gets the apply restart state when complete. + /// + public ApplyRestart Restart { get; private set; } + } + + /// + /// Additional arguments used by the engine to allow the BA to change the source + /// using or . + /// + [Serializable] + public class ResolveSourceEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The identity of the package or container that requires source. + /// The identity of the payload that requires source. + /// The current path used for source resolution. + /// Optional URL to download container or payload. + /// The recommended action from the engine. + /// The action to perform. + /// The recommendation from the engine. + public ResolveSourceEventArgs(string packageOrContainerId, string payloadId, string localSource, string downloadSource, BOOTSTRAPPER_RESOLVESOURCE_ACTION recommendation, BOOTSTRAPPER_RESOLVESOURCE_ACTION action, bool cancelRecommendation) + : base(cancelRecommendation) + { + this.PackageOrContainerId = packageOrContainerId; + this.PayloadId = payloadId; + this.LocalSource = localSource; + this.DownloadSource = downloadSource; + this.Recommendation = recommendation; + this.Action = action; + } + + /// + /// Gets the identity of the package or container that requires source. + /// + public string PackageOrContainerId { get; private set; } + + /// + /// Gets the identity of the payload that requires source. + /// + public string PayloadId { get; private set; } + + /// + /// Gets the current path used for source resolution. + /// + public string LocalSource { get; private set; } + + /// + /// Gets the optional URL to download container or payload. + /// + public string DownloadSource { get; private set; } + + /// + /// Gets the recommended action from the engine. + /// + public BOOTSTRAPPER_RESOLVESOURCE_ACTION Recommendation { get; private set; } + + /// + /// Gets or sets the action to perform. + /// + public BOOTSTRAPPER_RESOLVESOURCE_ACTION Action { get; set; } + } + + /// + /// Additional arguments used by the engine when it has begun caching a specific package. + /// + [Serializable] + public class CachePackageBeginEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The identity of the package that is being cached. + /// Number of payloads to be cached. + /// The size on disk required by the specific package. + /// The recommendation from the engine. + public CachePackageBeginEventArgs(string packageId, int cachePayloads, long packageCacheSize, bool cancelRecommendation) + : base(cancelRecommendation) + { + this.PackageId = packageId; + this.CachePayloads = cachePayloads; + this.PackageCacheSize = packageCacheSize; + } + + /// + /// Gets the identity of the package that is being cached. + /// + public string PackageId { get; private set; } + + /// + /// Gets number of payloads to be cached. + /// + public long CachePayloads { get; private set; } + + /// + /// Gets the size on disk required by the specific package. + /// + public long PackageCacheSize { get; private set; } + } + + /// + /// Additional arguments passed by the engine when it has completed caching a specific package. + /// + [Serializable] + public class CachePackageCompleteEventArgs : ActionEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The identity of the package that was cached. + /// The return code of the operation. + /// Recommended action from engine. + /// The action to perform. + public CachePackageCompleteEventArgs(string packageId, int hrStatus, BOOTSTRAPPER_CACHEPACKAGECOMPLETE_ACTION recommendation, BOOTSTRAPPER_CACHEPACKAGECOMPLETE_ACTION action) + : base(hrStatus, recommendation, action) + { + this.PackageId = packageId; + } + + /// + /// Gets the identity of the package that was cached. + /// + public string PackageId { get; private set; } + } + + /// + /// Additional arguments passed by the engine while executing on payload. + /// + [Serializable] + public class ExecuteProgressEventArgs : CancellableHResultEventArgs + { + /// + /// Creates a new instance of the class. + /// + /// The identifier of the package being executed. + /// The percentage from 0 to 100 of the execution progress for a single payload. + /// The percentage from 0 to 100 of the execution progress for all payload. + /// The recommendation from the engine. + public ExecuteProgressEventArgs(string packageId, int progressPercentage, int overallPercentage, bool cancelRecommendation) + : base(cancelRecommendation) + { + this.PackageId = packageId; + this.ProgressPercentage = progressPercentage; + this.OverallPercentage = overallPercentage; + } + + /// + /// Gets the identity of the package that was executed. + /// + public string PackageId { get; private set; } + + /// + /// Gets the percentage from 0 to 100 of the execution progress for a single payload. + /// + public int ProgressPercentage { get; private set; } + + /// + /// Gets the percentage from 0 to 100 of the execution progress for all payloads. + /// + public int OverallPercentage { get; private set; } + } + + /// + /// Additional arguments passed by the engine before it tries to launch the preapproved executable. + /// + [Serializable] + public class LaunchApprovedExeBeginArgs : CancellableHResultEventArgs + { + public LaunchApprovedExeBeginArgs(bool cancelRecommendation) + : base(cancelRecommendation) + { + } + } + + /// + /// Additional arguments passed by the engine after it finished trying to launch the preapproved executable. + /// + [Serializable] + public class LaunchApprovedExeCompleteArgs : StatusEventArgs + { + private int processId; + + public LaunchApprovedExeCompleteArgs(int hrStatus, int processId) + : base(hrStatus) + { + this.processId = processId; + } + + /// + /// Gets the ProcessId of the process that was launched. + /// This is only valid if the status reports success. + /// + public int ProcessId + { + get { return this.processId; } + } + } +} diff --git a/src/WixToolset.Mba.Core/Exceptions.cs b/src/WixToolset.Mba.Core/Exceptions.cs new file mode 100644 index 00000000..360b360d --- /dev/null +++ b/src/WixToolset.Mba.Core/Exceptions.cs @@ -0,0 +1,145 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.BootstrapperCore +{ + using System; + using System.Runtime.Serialization; + + /// + /// Base class for exception returned to the bootstrapper application host. + /// + [Serializable] + public abstract class BootstrapperException : Exception + { + /// + /// Creates an instance of the base class with the given HRESULT. + /// + /// The HRESULT for the exception that is used by the bootstrapper application host. + public BootstrapperException(int hr) + { + this.HResult = hr; + } + + /// + /// Initializes a new instance of the class. + /// + /// Exception message. + public BootstrapperException(string message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Exception message + /// Inner exception associated with this one + public BootstrapperException(string message, Exception innerException) + : base(message, innerException) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Serialization information for this exception + /// Streaming context to serialize to + protected BootstrapperException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } + + /// + /// The bootstrapper application assembly loaded by the host does not contain exactly one instance of the + /// class. + /// + /// + [Serializable] + public class MissingAttributeException : BootstrapperException + { + /// + /// Creates a new instance of the class. + /// + public MissingAttributeException() + : base(NativeMethods.E_NOTFOUND) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Exception message. + public MissingAttributeException(string message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Exception message + /// Inner exception associated with this one + public MissingAttributeException(string message, Exception innerException) + : base(message, innerException) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Serialization information for this exception + /// Streaming context to serialize to + protected MissingAttributeException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } + + /// + /// The bootstrapper application factory specified by the + /// does not extend the base class. + /// + /// + /// + [Serializable] + public class InvalidBootstrapperApplicationFactoryException : BootstrapperException + { + /// + /// Creates a new instance of the class. + /// + public InvalidBootstrapperApplicationFactoryException() + : base(NativeMethods.E_UNEXPECTED) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Exception message. + public InvalidBootstrapperApplicationFactoryException(string message) + : base(message) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Exception message + /// Inner exception associated with this one + public InvalidBootstrapperApplicationFactoryException(string message, Exception innerException) + : base(message, innerException) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// Serialization information for this exception + /// Streaming context to serialize to + protected InvalidBootstrapperApplicationFactoryException(SerializationInfo info, StreamingContext context) + : base(info, context) + { + } + } +} diff --git a/src/WixToolset.Mba.Core/HostSection.cs b/src/WixToolset.Mba.Core/HostSection.cs new file mode 100644 index 00000000..e5b7ea64 --- /dev/null +++ b/src/WixToolset.Mba.Core/HostSection.cs @@ -0,0 +1,47 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.BootstrapperCore +{ + using System; + using System.Configuration; + + /// + /// Handler for the Host configuration section. + /// + public sealed class HostSection : ConfigurationSection + { + private static readonly ConfigurationProperty assemblyNameProperty = new ConfigurationProperty("assemblyName", typeof(string), null, ConfigurationPropertyOptions.IsRequired); + private static readonly ConfigurationProperty supportedFrameworksProperty = new ConfigurationProperty("", typeof(SupportedFrameworkElementCollection), null, ConfigurationPropertyOptions.IsDefaultCollection); + + /// + /// Creates a new instance of the class. + /// + public HostSection() + { + } + + /// + /// Gets the name of the assembly that contians the child class. + /// + /// + /// The assembly specified by this name must contain the to identify + /// the type of the child class. + /// + [ConfigurationProperty("assemblyName", IsRequired = true)] + public string AssemblyName + { + get { return (string)base[assemblyNameProperty]; } + set { base[assemblyNameProperty] = value; } + } + + /// + /// Gets the of supported frameworks for the host configuration. + /// + [ConfigurationProperty("", IsDefaultCollection = true)] + [ConfigurationCollection(typeof(SupportedFrameworkElement))] + public SupportedFrameworkElementCollection SupportedFrameworks + { + get { return (SupportedFrameworkElementCollection)base[supportedFrameworksProperty]; } + } + } +} diff --git a/src/WixToolset.Mba.Core/IBootstrapperApplicationData.cs b/src/WixToolset.Mba.Core/IBootstrapperApplicationData.cs new file mode 100644 index 00000000..c8c6e6e3 --- /dev/null +++ b/src/WixToolset.Mba.Core/IBootstrapperApplicationData.cs @@ -0,0 +1,12 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.BootstrapperCore +{ + using System.IO; + + public interface IBootstrapperApplicationData + { + FileInfo BADataFile { get; } + IBundleInfo Bundle { get; } + } +} \ No newline at end of file diff --git a/src/WixToolset.Mba.Core/IBootstrapperApplicationFactory.cs b/src/WixToolset.Mba.Core/IBootstrapperApplicationFactory.cs new file mode 100644 index 00000000..414d28ed --- /dev/null +++ b/src/WixToolset.Mba.Core/IBootstrapperApplicationFactory.cs @@ -0,0 +1,52 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.BootstrapperCore +{ + using System; + using System.CodeDom.Compiler; + using System.Runtime.InteropServices; + + [ComVisible(true)] + [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)] + [Guid("2965A12F-AC7B-43A0-85DF-E4B2168478A4")] + [GeneratedCodeAttribute("WixToolset.Bootstrapper.InteropCodeGenerator", "1.0.0.0")] + public interface IBootstrapperApplicationFactory + { + IBootstrapperApplication Create( + [MarshalAs(UnmanagedType.Interface)] IBootstrapperEngine pEngine, + ref Command command + ); + } + + [Serializable] + [StructLayout(LayoutKind.Sequential)] + [GeneratedCodeAttribute("WixToolset.Bootstrapper.InteropCodeGenerator", "1.0.0.0")] + public struct Command + { + [MarshalAs(UnmanagedType.U4)] private readonly LaunchAction action; + [MarshalAs(UnmanagedType.U4)] private readonly Display display; + [MarshalAs(UnmanagedType.U4)] private readonly Restart restart; + [MarshalAs(UnmanagedType.LPWStr)] private readonly string wzCommandLine; + [MarshalAs(UnmanagedType.I4)] private readonly int nCmdShow; + [MarshalAs(UnmanagedType.U4)] private readonly ResumeType resume; + private readonly IntPtr hwndSplashScreen; + [MarshalAs(UnmanagedType.I4)] private readonly RelationType relation; + [MarshalAs(UnmanagedType.Bool)] private readonly bool passthrough; + [MarshalAs(UnmanagedType.LPWStr)] private readonly string wzLayoutDirectory; + + public IBootstrapperCommand GetBootstrapperCommand() + { + return new BootstrapperCommand( + this.action, + this.display, + this.restart, + this.wzCommandLine, + this.nCmdShow, + this.resume, + this.hwndSplashScreen, + this.relation, + this.passthrough, + this.wzLayoutDirectory); + } + } +} diff --git a/src/WixToolset.Mba.Core/IBootstrapperCommand.cs b/src/WixToolset.Mba.Core/IBootstrapperCommand.cs new file mode 100644 index 00000000..332b4c3b --- /dev/null +++ b/src/WixToolset.Mba.Core/IBootstrapperCommand.cs @@ -0,0 +1,63 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.BootstrapperCore +{ + using System; + + /// + /// Command information passed from the engine for the BA to perform. + /// + public interface IBootstrapperCommand + { + /// + /// Gets the action for the BA to perform. + /// + LaunchAction Action { get; } + + /// + /// Gets the display level for the BA. + /// + Display Display { get; } + + /// + /// Gets the action to perform if a reboot is required. + /// + Restart Restart { get; } + + /// + /// Gets the command line arguments as a string array. + /// + /// + /// Array of command line arguments not handled by the engine. + /// + /// The command line could not be parsed into an array. + string[] CommandLineArgs { get; } + + int CmdShow { get; } + + /// + /// Gets the method of how the engine was resumed from a previous installation step. + /// + ResumeType Resume { get; } + + /// + /// Gets the handle to the splash screen window. If no splash screen was displayed this value will be IntPtr.Zero. + /// + IntPtr SplashScreen { get; } + + /// + /// If this was run from a related bundle, specifies the relation type. + /// + RelationType Relation { get; } + + /// + /// If this was run from a backward compatible bundle. + /// + bool Passthrough { get; } + + /// + /// Gets layout directory. + /// + string LayoutDirectory { get; } + } +} diff --git a/src/WixToolset.Mba.Core/IBundleInfo.cs b/src/WixToolset.Mba.Core/IBundleInfo.cs new file mode 100644 index 00000000..a5f4b9c7 --- /dev/null +++ b/src/WixToolset.Mba.Core/IBundleInfo.cs @@ -0,0 +1,16 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.BootstrapperCore +{ + using System.Collections.Generic; + + public interface IBundleInfo + { + string LogVariable { get; } + string Name { get; } + IDictionary Packages { get; } + bool PerMachine { get; } + + void AddRelatedBundleAsPackage(DetectRelatedBundleEventArgs e); + } +} \ No newline at end of file diff --git a/src/WixToolset.Mba.Core/IDefaultBootstrapperApplication.cs b/src/WixToolset.Mba.Core/IDefaultBootstrapperApplication.cs new file mode 100644 index 00000000..ccbe84db --- /dev/null +++ b/src/WixToolset.Mba.Core/IDefaultBootstrapperApplication.cs @@ -0,0 +1,65 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.BootstrapperCore +{ + using System; + + public interface IDefaultBootstrapperApplication : IBootstrapperApplication + { + event EventHandler ApplyBegin; + event EventHandler ApplyComplete; + event EventHandler CacheAcquireBegin; + event EventHandler CacheAcquireComplete; + event EventHandler CacheAcquireProgress; + event EventHandler CacheBegin; + event EventHandler CacheComplete; + event EventHandler CachePackageBegin; + event EventHandler CachePackageComplete; + event EventHandler CacheVerifyBegin; + event EventHandler CacheVerifyComplete; + event EventHandler DetectBegin; + event EventHandler DetectCompatibleMsiPackage; + event EventHandler DetectComplete; + event EventHandler DetectForwardCompatibleBundle; + event EventHandler DetectMsiFeature; + event EventHandler DetectPackageBegin; + event EventHandler DetectPackageComplete; + event EventHandler DetectRelatedBundle; + event EventHandler DetectRelatedMsiPackage; + event EventHandler DetectTargetMsiPackage; + event EventHandler DetectUpdate; + event EventHandler DetectUpdateBegin; + event EventHandler DetectUpdateComplete; + event EventHandler ElevateBegin; + event EventHandler ElevateComplete; + event EventHandler Error; + event EventHandler ExecuteBegin; + event EventHandler ExecuteComplete; + event EventHandler ExecuteFilesInUse; + event EventHandler ExecuteMsiMessage; + event EventHandler ExecutePackageBegin; + event EventHandler ExecutePackageComplete; + event EventHandler ExecutePatchTarget; + event EventHandler ExecuteProgress; + event EventHandler LaunchApprovedExeBegin; + event EventHandler LaunchApprovedExeComplete; + event EventHandler PlanBegin; + event EventHandler PlanCompatibleMsiPackageBegin; + event EventHandler PlanCompatibleMsiPackageComplete; + event EventHandler PlanComplete; + event EventHandler PlanMsiFeature; + event EventHandler PlanPackageBegin; + event EventHandler PlanPackageComplete; + event EventHandler PlanRelatedBundle; + event EventHandler PlanTargetMsiPackage; + event EventHandler Progress; + event EventHandler RegisterBegin; + event EventHandler RegisterComplete; + event EventHandler ResolveSource; + event EventHandler Shutdown; + event EventHandler Startup; + event EventHandler SystemShutdown; + event EventHandler UnregisterBegin; + event EventHandler UnregisterComplete; + } +} \ No newline at end of file diff --git a/src/WixToolset.Mba.Core/IEngine.cs b/src/WixToolset.Mba.Core/IEngine.cs new file mode 100644 index 00000000..46b8158a --- /dev/null +++ b/src/WixToolset.Mba.Core/IEngine.cs @@ -0,0 +1,176 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.BootstrapperCore +{ + using System; + using System.ComponentModel; + using System.Security; + + public interface IEngine + { + /// + /// Gets or sets numeric variables for the engine. + /// + IVariables NumericVariables { get; } + + /// + /// Gets the number of packages in the bundle. + /// + int PackageCount { get; } + + /// + /// Gets or sets string variables for the engine using SecureStrings. + /// + IVariables SecureStringVariables { get; } + + /// + /// Gets or sets string variables for the engine. + /// + IVariables StringVariables { get; } + + /// + /// Gets or sets variables for the engine. + /// + /// The class can keep track of when the build and revision fields are undefined, but the engine can't. + /// Therefore, the build and revision fields must be defined when setting a variable. + /// Use the NormalizeVersion method to make sure the engine can accept the Version. + /// + /// To keep track of versions without build or revision fields, use StringVariables instead. + /// + /// The given was invalid. + IVariables VersionVariables { get; } + + /// + /// Install the packages. + /// + /// The parent window for the installation user interface. + void Apply(IntPtr hwndParent); + + /// + /// Close the splash screen if it is still open. Does nothing if the splash screen is not or + /// never was opened. + /// + void CloseSplashScreen(); + + /// + /// Determine if all installation conditions are fulfilled. + /// + void Detect(); + + /// + /// Determine if all installation conditions are fulfilled. + /// + /// The parent window for the installation user interface. + void Detect(IntPtr hwndParent); + + /// + /// Elevate the install. + /// + /// The parent window of the elevation dialog. + /// true if elevation succeeded; otherwise, false if the user cancelled. + /// A Win32 error occurred. + bool Elevate(IntPtr hwndParent); + + /// + /// Escapes the input string. + /// + /// The string to escape. + /// The escaped string. + /// A Win32 error occurred. + string EscapeString(string input); + + /// + /// Evaluates the string. + /// + /// The string representing the condition to evaluate. + /// Whether the condition evaluated to true or false. + bool EvaluateCondition(string condition); + + /// + /// Formats the input string. + /// + /// The string to format. + /// The formatted string. + /// A Win32 error occurred. + string FormatString(string format); + + /// + /// Launches a preapproved executable elevated. As long as the engine already elevated, there will be no UAC prompt. + /// + /// The parent window of the elevation dialog (if the engine hasn't elevated yet). + /// Id of the ApprovedExeForElevation element specified when the bundle was authored. + /// Optional arguments. + void LaunchApprovedExe(IntPtr hwndParent, string approvedExeForElevationId, string arguments); + + /// + /// Launches a preapproved executable elevated. As long as the engine already elevated, there will be no UAC prompt. + /// + /// The parent window of the elevation dialog (if the engine hasn't elevated yet). + /// Id of the ApprovedExeForElevation element specified when the bundle was authored. + /// Optional arguments. + /// Timeout in milliseconds. When set to something other than zero, the engine will call WaitForInputIdle for the new process with this timeout before calling OnLaunchApprovedExeComplete. + void LaunchApprovedExe(IntPtr hwndParent, string approvedExeForElevationId, string arguments, int waitForInputIdleTimeout); + + /// + /// Logs the . + /// + /// The logging level. + /// The message to log. + void Log(LogLevel level, string message); + + /// + /// Determine the installation sequencing and costing. + /// + /// The action to perform when planning. + void Plan(LaunchAction action); + + /// + /// Set the update information for a bundle. + /// + /// Optional local source path for the update. Default is "update\[OriginalNameOfBundle].exe". + /// Optional download source for the update. + /// Size of the expected update. + /// Type of the hash expected on the update. + /// Optional hash expected for the update. + void SetUpdate(string localSource, string downloadSource, long size, UpdateHashType hashType, byte[] hash); + + /// + /// Set the local source for a package or container. + /// + /// The id that uniquely identifies the package or container. + /// The id that uniquely identifies the payload. + /// The new source path. + void SetLocalSource(string packageOrContainerId, string payloadId, string path); + + /// + /// Set the new download URL for a package or container. + /// + /// The id that uniquely identifies the package or container. + /// The id that uniquely identifies the payload. + /// The new url. + /// The user name for proxy authentication. + /// The password for proxy authentication. + void SetDownloadSource(string packageOrContainerId, string payloadId, string url, string user, string password); + + /// + /// Sends error message when embedded. + /// + /// Error code. + /// Error message. + /// UI buttons to show on error dialog. + int SendEmbeddedError(int errorCode, string message, int uiHint); + + /// + /// Sends progress percentages when embedded. + /// + /// Percentage completed thus far. + /// Overall percentage completed. + int SendEmbeddedProgress(int progressPercentage, int overallPercentage); + + /// + /// Shuts down the engine. + /// + /// Exit code indicating reason for shut down. + void Quit(int exitCode); + } +} diff --git a/src/WixToolset.Mba.Core/IPackageInfo.cs b/src/WixToolset.Mba.Core/IPackageInfo.cs new file mode 100644 index 00000000..f4c7c558 --- /dev/null +++ b/src/WixToolset.Mba.Core/IPackageInfo.cs @@ -0,0 +1,20 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.BootstrapperCore +{ + public interface IPackageInfo + { + CacheType CacheType { get; } + string Description { get; } + bool DisplayInternalUI { get; } + string DisplayName { get; } + string Id { get; } + string InstallCondition { get; } + bool Permanent { get; } + string ProductCode { get; } + PackageType Type { get; } + string UpgradeCode { get; } + string Version { get; } + bool Vital { get; } + } +} \ No newline at end of file diff --git a/src/WixToolset.Mba.Core/IVariables.cs b/src/WixToolset.Mba.Core/IVariables.cs new file mode 100644 index 00000000..15da4c84 --- /dev/null +++ b/src/WixToolset.Mba.Core/IVariables.cs @@ -0,0 +1,27 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.BootstrapperCore +{ + using System; + + /// + /// An accessor for numeric, string, and version variables for the engine. + /// + public interface IVariables + { + /// + /// Gets or sets the variable given by . + /// + /// The name of the variable to get/set. + /// The value of the given variable. + /// An error occurred getting the variable. + T this[string name] { get; set; } + + /// + /// Gets whether the variable given by exists. + /// + /// The name of the variable to check. + /// True if the variable given by exists; otherwise, false. + bool Contains(string name); + } +} diff --git a/src/WixToolset.Mba.Core/NativeMethods.cs b/src/WixToolset.Mba.Core/NativeMethods.cs new file mode 100644 index 00000000..1964cb45 --- /dev/null +++ b/src/WixToolset.Mba.Core/NativeMethods.cs @@ -0,0 +1,37 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.BootstrapperCore +{ + using System; + using System.Runtime.InteropServices; + + /// + /// Contains native constants, functions, and structures for this assembly. + /// + internal static class NativeMethods + { + #region Error Constants + internal const int S_OK = 0; + internal const int E_MOREDATA = unchecked((int)0x800700ea); + internal const int E_INSUFFICIENT_BUFFER = unchecked((int)0x8007007a); + internal const int E_CANCELLED = unchecked((int)0x800704c7); + internal const int E_ALREADYINITIALIZED = unchecked((int)0x800704df); + internal const int E_NOTFOUND = unchecked((int)0x80070490); + internal const int E_NOTIMPL = unchecked((int)0x80004001); + internal const int E_UNEXPECTED = unchecked((int)0x8000ffff); + #endregion + + #region Functions + [DllImport("shell32.dll", ExactSpelling = true, SetLastError = true)] + internal static extern IntPtr CommandLineToArgvW( + [MarshalAs(UnmanagedType.LPWStr)] string lpCmdLine, + out int pNumArgs + ); + + [DllImport("kernel32.dll", ExactSpelling = true, SetLastError = true)] + internal static extern IntPtr LocalFree( + IntPtr hMem + ); + #endregion + } +} diff --git a/src/WixToolset.Mba.Core/PackageInfo.cs b/src/WixToolset.Mba.Core/PackageInfo.cs new file mode 100644 index 00000000..99ebb33a --- /dev/null +++ b/src/WixToolset.Mba.Core/PackageInfo.cs @@ -0,0 +1,181 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.BootstrapperCore +{ + using System; + using System.Collections.Generic; + using System.Xml; + using System.Xml.XPath; + + public enum CacheType + { + No, + Yes, + Always, + } + + public enum PackageType + { + Unknown, + Exe, + Msi, + Msp, + Msu, + UpgradeBundle, + AddonBundle, + PatchBundle, + } + + public class PackageInfo : IPackageInfo + { + public string Id { get; internal set; } + public string DisplayName { get; internal set; } + public string Description { get; internal set; } + public PackageType Type { get; internal set; } + public bool Permanent { get; internal set; } + public bool Vital { get; internal set; } + public bool DisplayInternalUI { get; internal set; } + public string ProductCode { get; internal set; } + public string UpgradeCode { get; internal set; } + public string Version { get; internal set; } + public string InstallCondition { get; internal set; } + public CacheType CacheType { get; internal set; } + + internal PackageInfo() { } + + public static IEnumerable ParsePackagesFromXml(XPathNavigator root) + { + XmlNamespaceManager namespaceManager = new XmlNamespaceManager(root.NameTable); + namespaceManager.AddNamespace("p", BootstrapperApplicationData.XMLNamespace); + XPathNodeIterator nodes = root.Select("/p:BootstrapperApplicationData/p:WixPackageProperties", namespaceManager); + + foreach (XPathNavigator node in nodes) + { + var package = new PackageInfo(); + + string id = BootstrapperApplicationData.GetAttribute(node, "Package"); + if (id == null) + { + throw new Exception("Failed to get package identifier for package."); + } + package.Id = id; + + package.DisplayName = BootstrapperApplicationData.GetAttribute(node, "DisplayName"); + + package.Description = BootstrapperApplicationData.GetAttribute(node, "Description"); + + PackageType? packageType = GetPackageTypeAttribute(node, "PackageType"); + if (!packageType.HasValue) + { + throw new Exception("Failed to get package type for package."); + } + package.Type = packageType.Value; + + bool? permanent = BootstrapperApplicationData.GetYesNoAttribute(node, "Permanent"); + if (!permanent.HasValue) + { + throw new Exception("Failed to get permanent settings for package."); + } + package.Permanent = permanent.Value; + + bool? vital = BootstrapperApplicationData.GetYesNoAttribute(node, "Vital"); + if (!vital.HasValue) + { + throw new Exception("Failed to get vital setting for package."); + } + package.Vital = vital.Value; + + bool? displayInternalUI = BootstrapperApplicationData.GetYesNoAttribute(node, "DisplayInternalUI"); + package.DisplayInternalUI = displayInternalUI.HasValue && displayInternalUI.Value; + + package.ProductCode = BootstrapperApplicationData.GetAttribute(node, "ProductCode"); + + package.UpgradeCode = BootstrapperApplicationData.GetAttribute(node, "UpgradeCode"); + + package.Version = BootstrapperApplicationData.GetAttribute(node, "Version"); + + package.InstallCondition = BootstrapperApplicationData.GetAttribute(node, "InstallCondition"); + + yield return package; + } + } + + public static CacheType? GetCacheTypeAttribute(XPathNavigator node, string attributeName) + { + string attributeValue = BootstrapperApplicationData.GetAttribute(node, attributeName); + + if (attributeValue == null) + { + return null; + } + + if (attributeValue.Equals("yes", StringComparison.InvariantCulture)) + { + return CacheType.Yes; + } + else if (attributeValue.Equals("always", StringComparison.InvariantCulture)) + { + return CacheType.Always; + } + else + { + return CacheType.No; + } + } + + public static PackageType? GetPackageTypeAttribute(XPathNavigator node, string attributeName) + { + string attributeValue = BootstrapperApplicationData.GetAttribute(node, attributeName); + + if (attributeValue == null) + { + return null; + } + + if (attributeValue.Equals("Exe", StringComparison.InvariantCulture)) + { + return PackageType.Exe; + } + else if (attributeValue.Equals("Msi", StringComparison.InvariantCulture)) + { + return PackageType.Msi; + } + else if (attributeValue.Equals("Msp", StringComparison.InvariantCulture)) + { + return PackageType.Msp; + } + else if (attributeValue.Equals("Msu", StringComparison.InvariantCulture)) + { + return PackageType.Msu; + } + else + { + return PackageType.Unknown; + } + } + + public static PackageInfo GetRelatedBundleAsPackage(string id, RelationType relationType, bool perMachine, Version version) + { + PackageInfo package = new PackageInfo(); + package.Id = id; + package.Version = version.ToString(); + + switch (relationType) + { + case RelationType.Addon: + package.Type = PackageType.AddonBundle; + break; + case RelationType.Patch: + package.Type = PackageType.PatchBundle; + break; + case RelationType.Upgrade: + package.Type = PackageType.UpgradeBundle; + break; + default: + throw new Exception(string.Format("Unknown related bundle type: {0}", relationType)); + } + + return package; + } + } +} diff --git a/src/WixToolset.Mba.Core/SupportedFrameworkElement.cs b/src/WixToolset.Mba.Core/SupportedFrameworkElement.cs new file mode 100644 index 00000000..37a31b69 --- /dev/null +++ b/src/WixToolset.Mba.Core/SupportedFrameworkElement.cs @@ -0,0 +1,47 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.BootstrapperCore +{ + using System; + using System.Configuration; + + /// + /// Handler for the supportedFramework configuration section. + /// + public sealed class SupportedFrameworkElement : ConfigurationElement + { + private static readonly ConfigurationProperty versionProperty = new ConfigurationProperty("version", typeof(string), null, ConfigurationPropertyOptions.IsRequired); + private static readonly ConfigurationProperty runtimeVersionProperty = new ConfigurationProperty("runtimeVersion", typeof(string)); + + /// + /// Creates a new instance of the class. + /// + public SupportedFrameworkElement() + { + } + + /// + /// Gets the version of the supported framework. + /// + /// + /// The assembly specified by this name must contain a value matching the NETFX version registry key under + /// "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\NET Framework Setup\NDP". + /// + [ConfigurationProperty("version", IsRequired = true)] + public string Version + { + get { return (string)base[versionProperty]; } + set { base[versionProperty] = value; } + } + + /// + /// Gets the runtime version required by this supported framework. + /// + [ConfigurationProperty("runtimeVersion", IsRequired = false)] + public string RuntimeVersion + { + get { return (string)base[runtimeVersionProperty]; } + set { base[runtimeVersionProperty] = value; } + } + } +} diff --git a/src/WixToolset.Mba.Core/SupportedFrameworkElementCollection.cs b/src/WixToolset.Mba.Core/SupportedFrameworkElementCollection.cs new file mode 100644 index 00000000..1a5aa2de --- /dev/null +++ b/src/WixToolset.Mba.Core/SupportedFrameworkElementCollection.cs @@ -0,0 +1,36 @@ +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + +namespace WixToolset.BootstrapperCore +{ + using System; + using System.Configuration; + using System.Diagnostics.CodeAnalysis; + + /// + /// Handler for the supportedFramework collection. + /// + [SuppressMessage("Microsoft.Design", "CA1010:CollectionsShouldImplementGenericInterface")] + [ConfigurationCollection(typeof(SupportedFrameworkElement), AddItemName = "supportedFramework", CollectionType = ConfigurationElementCollectionType.BasicMap)] + public sealed class SupportedFrameworkElementCollection : ConfigurationElementCollection + { + public override ConfigurationElementCollectionType CollectionType + { + get { return ConfigurationElementCollectionType.BasicMap; } + } + + protected override string ElementName + { + get { return "supportedFramework"; } + } + + protected override ConfigurationElement CreateNewElement() + { + return new SupportedFrameworkElement(); + } + + protected override object GetElementKey(ConfigurationElement element) + { + return (element as SupportedFrameworkElement).Version; + } + } +} diff --git a/src/WixToolset.Mba.Core/WixToolset.BootstrapperCore.config b/src/WixToolset.Mba.Core/WixToolset.BootstrapperCore.config new file mode 100644 index 00000000..1e284001 --- /dev/null +++ b/src/WixToolset.Mba.Core/WixToolset.BootstrapperCore.config @@ -0,0 +1,26 @@ + + + + + + + +
+ + + + + + + + + + + + + + diff --git a/src/balutil/inc/IBootstrapperApplicationFactory.h b/src/balutil/inc/IBootstrapperApplicationFactory.h new file mode 100644 index 00000000..e29c23bc --- /dev/null +++ b/src/balutil/inc/IBootstrapperApplicationFactory.h @@ -0,0 +1,14 @@ +#pragma once +// Copyright (c) .NET Foundation and contributors. All rights reserved. Licensed under the Microsoft Reciprocal License. See LICENSE.TXT file in the project root for full license information. + + +#include "precomp.h" + +DECLARE_INTERFACE_IID_(IBootstrapperApplicationFactory, IUnknown, "2965A12F-AC7B-43A0-85DF-E4B2168478A4") +{ + STDMETHOD(Create)( + __in IBootstrapperEngine* pEngine, + __in const BOOTSTRAPPER_COMMAND *pCommand, + __out IBootstrapperApplication **ppApplication + ); +}; -- cgit v1.2.3-55-g6feb