private void SetPerMachineAppropriately(Dtf.Database db, WixBundleMsiPackageSymbol msiPackage, string sourcePath) { if (msiPackage.ForcePerMachine) { if (YesNoDefaultType.No == this.Facade.PackageSymbol.PerMachine) { this.Messaging.Write(WarningMessages.PerUserButForcingPerMachine(this.Facade.PackageSymbol.SourceLineNumbers, sourcePath)); this.Facade.PackageSymbol.PerMachine = YesNoDefaultType.Yes; // ensure that we think the package is per-machine. } // Force ALLUSERS=1 via the MSI command-line. this.AddMsiProperty(msiPackage, "ALLUSERS", "1"); } else { var allusers = ProcessMsiPackageCommand.GetProperty(db, "ALLUSERS"); if (String.IsNullOrEmpty(allusers)) { // Not forced per-machine and no ALLUSERS property, flip back to per-user. if (YesNoDefaultType.Yes == this.Facade.PackageSymbol.PerMachine) { this.Messaging.Write(WarningMessages.ImplicitlyPerUser(this.Facade.PackageSymbol.SourceLineNumbers, sourcePath)); this.Facade.PackageSymbol.PerMachine = YesNoDefaultType.No; } } else if (allusers.Equals("1", StringComparison.Ordinal)) { if (YesNoDefaultType.No == this.Facade.PackageSymbol.PerMachine) { this.Messaging.Write(ErrorMessages.PerUserButAllUsersEquals1(this.Facade.PackageSymbol.SourceLineNumbers, sourcePath)); } } else if (allusers.Equals("2", StringComparison.Ordinal)) { this.Messaging.Write(WarningMessages.DiscouragedAllUsersValue(this.Facade.PackageSymbol.SourceLineNumbers, sourcePath, (YesNoDefaultType.Yes == this.Facade.PackageSymbol.PerMachine) ? "machine" : "user")); } else { this.Messaging.Write(ErrorMessages.UnsupportedAllUsersValue(this.Facade.PackageSymbol.SourceLineNumbers, sourcePath, allusers)); } } }
/// <summary> /// Processes the MSI packages to add properties and payloads from the MSI packages. /// </summary> public void Execute() { var packagePayload = this.AuthoredPayloads[this.Facade.PackageSymbol.PayloadRef]; var msiPackage = (WixBundleMsiPackageSymbol)this.Facade.SpecificPackageSymbol; var sourcePath = packagePayload.SourceFile.Path; var longNamesInImage = false; var compressed = false; try { // Read data out of the msi database... using (var sumInfo = new Dtf.SummaryInfo(sourcePath, false)) { // 1 is the Word Count summary information stream bit that means // the MSI uses short file names when set. We care about long file // names so check when the bit is not set. longNamesInImage = 0 == (sumInfo.WordCount & 1); // 2 is the Word Count summary information stream bit that means // files are compressed in the MSI by default when the bit is set. compressed = 2 == (sumInfo.WordCount & 2); // 8 is the Word Count summary information stream bit that means // "Elevated privileges are not required to install this package." // in MSI 4.5 and below, if this bit is 0, elevation is required. var perMachine = (0 == (sumInfo.WordCount & 8)); var x64 = sumInfo.Template.Contains("x64"); this.Facade.PackageSymbol.PerMachine = perMachine ? YesNoDefaultType.Yes : YesNoDefaultType.No; this.Facade.PackageSymbol.Win64 = x64; } using (var db = new Dtf.Database(sourcePath)) { msiPackage.ProductCode = ProcessMsiPackageCommand.GetProperty(db, "ProductCode"); msiPackage.UpgradeCode = ProcessMsiPackageCommand.GetProperty(db, "UpgradeCode"); msiPackage.Manufacturer = ProcessMsiPackageCommand.GetProperty(db, "Manufacturer"); msiPackage.ProductLanguage = Convert.ToInt32(ProcessMsiPackageCommand.GetProperty(db, "ProductLanguage"), CultureInfo.InvariantCulture); msiPackage.ProductVersion = ProcessMsiPackageCommand.GetProperty(db, "ProductVersion"); if (!Common.IsValidModuleOrBundleVersion(msiPackage.ProductVersion)) { // not a proper .NET version (e.g., five fields); can we get a valid four-part version number? string version = null; string[] versionParts = msiPackage.ProductVersion.Split('.'); var count = versionParts.Length; if (0 < count) { version = versionParts[0]; for (var i = 1; i < 4 && i < count; ++i) { version = String.Concat(version, ".", versionParts[i]); } } if (!String.IsNullOrEmpty(version) && Common.IsValidModuleOrBundleVersion(version)) { this.Messaging.Write(WarningMessages.VersionTruncated(this.Facade.PackageSymbol.SourceLineNumbers, msiPackage.ProductVersion, sourcePath, version)); msiPackage.ProductVersion = version; } else { this.Messaging.Write(ErrorMessages.InvalidProductVersion(this.Facade.PackageSymbol.SourceLineNumbers, msiPackage.ProductVersion, sourcePath)); } } if (String.IsNullOrEmpty(this.Facade.PackageSymbol.CacheId)) { this.Facade.PackageSymbol.CacheId = String.Format("{0}v{1}", msiPackage.ProductCode, msiPackage.ProductVersion); } if (String.IsNullOrEmpty(this.Facade.PackageSymbol.DisplayName)) { this.Facade.PackageSymbol.DisplayName = ProcessMsiPackageCommand.GetProperty(db, "ProductName"); } if (String.IsNullOrEmpty(this.Facade.PackageSymbol.Description)) { this.Facade.PackageSymbol.Description = ProcessMsiPackageCommand.GetProperty(db, "ARPCOMMENTS"); } if (String.IsNullOrEmpty(this.Facade.PackageSymbol.Version)) { this.Facade.PackageSymbol.Version = msiPackage.ProductVersion; } var payloadNames = this.GetPayloadTargetNames(packagePayload.Id.Id); var msiPropertyNames = this.GetMsiPropertyNames(packagePayload.Id.Id); this.SetPerMachineAppropriately(db, msiPackage, sourcePath); // Ensure the MSI package is appropriately marked visible or not. this.SetPackageVisibility(db, msiPackage, msiPropertyNames); // Unless the MSI or setup code overrides the default, set MSIFASTINSTALL for best performance. if (!msiPropertyNames.Contains("MSIFASTINSTALL") && !ProcessMsiPackageCommand.HasProperty(db, "MSIFASTINSTALL")) { this.AddMsiProperty(msiPackage, "MSIFASTINSTALL", "7"); } this.CreateRelatedPackages(db); // If feature selection is enabled, represent the Feature table in the manifest. if ((msiPackage.Attributes & WixBundleMsiPackageAttributes.EnableFeatureSelection) == WixBundleMsiPackageAttributes.EnableFeatureSelection) { this.CreateMsiFeatures(db); } // Add all external cabinets as package payloads. this.ImportExternalCabinetAsPayloads(db, packagePayload, payloadNames); // Add all external files as package payloads and calculate the total install size as the rollup of // File table's sizes. this.Facade.PackageSymbol.InstallSize = this.ImportExternalFileAsPayloadsAndReturnInstallSize(db, packagePayload, longNamesInImage, compressed, payloadNames); // Add all dependency providers from the MSI. this.ImportDependencyProviders(msiPackage, db); } } catch (Dtf.InstallerException e) { this.Messaging.Write(ErrorMessages.UnableToReadPackageInformation(this.Facade.PackageSymbol.SourceLineNumbers, sourcePath, e.Message)); } }