// 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.Mba.Core { using System; using System.ComponentModel; using System.Runtime.InteropServices; using System.Security; using System.Text; /// /// Default implementation of . /// public sealed class Engine : IEngine { private static readonly string normalizeVersionFormatString = "{0} must be less than or equal to " + UInt16.MaxValue; private IBootstrapperEngine engine; /// /// Creates a new instance of the container class. /// /// The to contain. internal Engine(IBootstrapperEngine engine) { this.engine = engine; } /// public int PackageCount { get { int count; this.engine.GetPackageCount(out count); return count; } } /// public void Apply(IntPtr hwndParent) { this.engine.Apply(hwndParent); } /// public void CloseSplashScreen() { this.engine.CloseSplashScreen(); } /// public int CompareVersions(string version1, string version2) { this.engine.CompareVersions(version1, version2, out var result); return result; } /// public bool ContainsVariable(string name) { return BalUtil.BalVariableExistsFromEngine(this.engine, name); } /// 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) { StrUtil.StrHandle handle = new StrUtil.StrHandle(); try { int ret = BalUtil.BalEscapeStringFromEngine(this.engine, input, ref handle); if (ret != NativeMethods.S_OK) { throw new Win32Exception(ret); } return handle.ToUniString(); } finally { handle.Dispose(); } } /// public bool EvaluateCondition(string condition) { bool value; this.engine.EvaluateCondition(condition, out value); return value; } /// public string FormatString(string format) { StrUtil.StrHandle handle = new StrUtil.StrHandle(); try { int ret = BalUtil.BalFormatStringFromEngine(this.engine, format, ref handle); if (ret != NativeMethods.S_OK) { throw new Win32Exception(ret); } return handle.ToUniString(); } finally { handle.Dispose(); } } /// public long GetVariableNumeric(string name) { int ret = this.engine.GetVariableNumeric(name, out long value); if (NativeMethods.S_OK != ret) { throw new Win32Exception(ret); } return value; } /// public SecureString GetVariableSecureString(string name) { StrUtil.StrHandle handle = new StrUtil.StrHandle(); try { int ret = BalUtil.BalGetStringVariableFromEngine(this.engine, name, ref handle); if (ret != NativeMethods.S_OK) { throw new Win32Exception(ret); } return handle.ToSecureString(); } finally { handle.Dispose(); } } /// public string GetVariableString(string name) { StrUtil.StrHandle handle = new StrUtil.StrHandle(); try { int ret = BalUtil.BalGetStringVariableFromEngine(this.engine, name, ref handle); if (ret != NativeMethods.S_OK) { throw new Win32Exception(ret); } return handle.ToUniString(); } finally { handle.Dispose(); } } /// public string GetVariableVersion(string name) { StrUtil.StrHandle handle = new StrUtil.StrHandle(); try { int ret = BalUtil.BalGetVersionVariableFromEngine(this.engine, name, ref handle); if (ret != NativeMethods.S_OK) { throw new Win32Exception(ret); } return handle.ToUniString(); } finally { handle.Dispose(); } } /// public string GetRelatedBundleVariable(string bundleId, string name) { StrUtil.StrHandle handle = new StrUtil.StrHandle(); try { int ret = BalUtil.BalGetRelatedBundleVariableFromEngine(this.engine, bundleId, name, ref handle); if (ret != NativeMethods.S_OK) { throw new Win32Exception(ret); } return handle.ToUniString(); } finally { handle.Dispose(); } } /// 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, string hash) { this.engine.SetUpdate(localSource, downloadSource, size, hashType, hash); } /// public void SetUpdateSource(string url) { this.engine.SetUpdateSource(url); } /// 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 void SetVariableNumeric(string name, long value) { this.engine.SetVariableNumeric(name, value); } /// public void SetVariableString(string name, SecureString value, bool formatted) { IntPtr pValue = Marshal.SecureStringToCoTaskMemUnicode(value); try { this.engine.SetVariableString(name, pValue, formatted); } finally { Marshal.FreeCoTaskMem(pValue); } } /// public void SetVariableString(string name, string value, bool formatted) { IntPtr pValue = Marshal.StringToCoTaskMemUni(value); try { this.engine.SetVariableString(name, pValue, formatted); } finally { Marshal.FreeCoTaskMem(pValue); } } /// public void SetVariableVersion(string name, string value) { IntPtr pValue = Marshal.StringToCoTaskMemUni(value); try { this.engine.SetVariableVersion(name, pValue); } finally { Marshal.FreeCoTaskMem(pValue); } } /// 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); } /// /// Utility method for converting a into a . /// /// /// 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; } /// /// Utility method for converting a into a . /// /// /// 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 Version can be represented in a . /// 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); } } }