/// <summary> /// Creates a binder. /// </summary> public WixBinder() { this.extensions = new List <BinderExtension>(); this.inspectorExtensions = new List <InspectorExtension>(); this.fileManager = new BinderFileManager(); this.fileManager.TempFilesLocation = this.TempFilesLocation; }
/// <summary> /// Saves an output to a path on disk. /// </summary> /// <param name="path">Path to save output file to on disk.</param> /// <param name="binderFileManager">If provided, the binder file manager is used to bind files into the output.</param> /// <param name="wixVariableResolver">The Wix variable resolver.</param> /// <param name="tempFilesLocation">Location for temporary files.</param> public void Save(string path, BinderFileManager binderFileManager, WixVariableResolver wixVariableResolver, string tempFilesLocation) { FileMode fileMode = FileMode.Create; // Assure the location to output the xml exists Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(path))); // Check if there was a cab on the output when it was created if (SaveCab(path, binderFileManager, wixVariableResolver, tempFilesLocation)) { fileMode = FileMode.Append; } // save the xml using (FileStream fs = new FileStream(path, fileMode)) { XmlWriter writer = null; try { writer = new XmlTextWriter(fs, System.Text.Encoding.UTF8); writer.WriteStartDocument(); this.Persist(writer); writer.WriteEndDocument(); } finally { if (null != writer) { writer.Close(); } } } }
/// <summary> /// Creates a binder. /// </summary> public WixBinder() { this.extensions = new List<BinderExtension>(); this.inspectorExtensions = new List<InspectorExtension>(); this.fileManager = new BinderFileManager(); this.fileManager.TempFilesLocation = this.TempFilesLocation; }
/// <summary> /// Instantiate a new CabinetWorkItem. /// </summary> /// <param name="fileRows">The collection of files in this cabinet.</param> /// <param name="cabinetFile">The cabinet file.</param> /// <param name="maxThreshold">Maximum threshold for each cabinet.</param> /// <param name="compressionLevel">The compression level of the cabinet.</param> /// <param name="binderFileManager">The binder file manager.</param> public CabinetWorkItem(FileRowCollection fileRows, string cabinetFile, int maxThreshold, Cab.CompressionLevel compressionLevel, BinderFileManager binderFileManager) { this.cabinetFile = cabinetFile; this.compressionLevel = compressionLevel; this.fileRows = fileRows; this.binderFileManager = binderFileManager; this.maxThreshold = maxThreshold; }
public ContainerInfo(string id, string name, string type, string downloadUrl, BinderFileManager fileManager) { this.Id = id; this.Name = name; this.Type = type; this.DownloadUrl = downloadUrl; this.FileManager = fileManager; this.TempPath = Path.Combine(fileManager.TempFilesLocation, name); this.FileInfo = new FileInfo(this.TempPath); }
/// <summary> /// Initializes package state from the MSI contents. /// </summary> private void ResolveMsiPackage(BinderFileManager fileManager, Dictionary<string, PayloadInfoRow> allPayloads, Dictionary<string, ContainerInfo> containers, YesNoType suppressLooseFilePayloadGeneration, YesNoType enableFeatureSelection, YesNoType forcePerMachine, Output bundle) { string sourcePath = this.PackagePayload.FullFileName; bool longNamesInImage = false; bool compressed = false; try { // Read data out of the msi database... using (Microsoft.Deployment.WindowsInstaller.SummaryInfo sumInfo = new Microsoft.Deployment.WindowsInstaller.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. this.PerMachine = (0 == (sumInfo.WordCount & 8)) ? YesNoDefaultType.Yes : YesNoDefaultType.No; } using (Microsoft.Deployment.WindowsInstaller.Database db = new Microsoft.Deployment.WindowsInstaller.Database(sourcePath)) { this.ProductCode = ChainPackageInfo.GetProperty(db, "ProductCode"); this.Language = ChainPackageInfo.GetProperty(db, "ProductLanguage"); this.Version = ChainPackageInfo.GetProperty(db, "ProductVersion"); if (!Common.IsValidModuleOrBundleVersion(this.Version)) { // not a proper .NET version (i.e., five fields); can we get a valid version number up to four fields? string version = null; string[] versionParts = this.Version.Split('.'); int count = versionParts.Length; if (0 < count) { version = versionParts[0]; for (int i = 1; i < 4 && i < count; ++i) { version = String.Concat(version, ".", versionParts[i]); } } if (!String.IsNullOrEmpty(version) && Common.IsValidModuleOrBundleVersion(version)) { this.core.OnMessage(WixWarnings.VersionTruncated(this.PackagePayload.SourceLineNumbers, this.Version, sourcePath, version)); this.Version = version; } else { this.core.OnMessage(WixErrors.InvalidProductVersion(this.PackagePayload.SourceLineNumbers, this.Version, sourcePath)); } } if (String.IsNullOrEmpty(this.CacheId)) { this.CacheId = String.Format("{0}v{1}", this.ProductCode, this.Version); } if (String.IsNullOrEmpty(this.DisplayName)) { this.DisplayName = ChainPackageInfo.GetProperty(db, "ProductName"); } this.Manufacturer = ChainPackageInfo.GetProperty(db, "Manufacturer"); this.VerifyMsiProperties(); if (YesNoType.Yes == forcePerMachine) { if (YesNoDefaultType.No == this.PerMachine) { this.core.OnMessage(WixWarnings.PerUserButForcingPerMachine(this.PackagePayload.SourceLineNumbers, sourcePath)); this.PerMachine = YesNoDefaultType.Yes; // ensure that we think the MSI is per-machine. } this.MsiProperties.Add(new MsiPropertyInfo(this.Id, "ALLUSERS", "1")); // force ALLUSERS=1 via the MSI command-line. } else if (ChainPackageInfo.HasProperty(db, "ALLUSERS")) { string allusers = ChainPackageInfo.GetProperty(db, "ALLUSERS"); if (allusers.Equals("1", StringComparison.Ordinal)) { if (YesNoDefaultType.No == this.PerMachine) { this.core.OnMessage(WixErrors.PerUserButAllUsersEquals1(this.PackagePayload.SourceLineNumbers, sourcePath)); } } else if (allusers.Equals("2", StringComparison.Ordinal)) { this.core.OnMessage(WixWarnings.DiscouragedAllUsersValue(this.PackagePayload.SourceLineNumbers, sourcePath, (YesNoDefaultType.Yes == this.PerMachine) ? "machine" : "user")); } else { this.core.OnMessage(WixErrors.UnsupportedAllUsersValue(this.PackagePayload.SourceLineNumbers, sourcePath, allusers)); } } else if (YesNoDefaultType.Yes == this.PerMachine) // not forced per-machine and no ALLUSERS property, flip back to per-user { this.core.OnMessage(WixWarnings.ImplicitlyPerUser(this.PackagePayload.SourceLineNumbers, sourcePath)); this.PerMachine = YesNoDefaultType.No; } if (String.IsNullOrEmpty(this.Description) && ChainPackageInfo.HasProperty(db, "ARPCOMMENTS")) { this.Description = ChainPackageInfo.GetProperty(db, "ARPCOMMENTS"); } // Ensure the MSI package is appropriately marked visible or not. bool alreadyVisible = !ChainPackageInfo.HasProperty(db, "ARPSYSTEMCOMPONENT"); if (alreadyVisible != this.Visible) // if not already set to the correct visibility. { // If the authoring specifically added "ARPSYSTEMCOMPONENT", don't do it again. bool sysComponentSet = false; foreach (MsiPropertyInfo propertyInfo in this.MsiProperties) { if ("ARPSYSTEMCOMPONENT".Equals(propertyInfo.Name, StringComparison.Ordinal)) { sysComponentSet = true; break; } } if (!sysComponentSet) { this.MsiProperties.Add(new MsiPropertyInfo(this.Id, "ARPSYSTEMCOMPONENT", this.Visible ? "" : "1")); } } // Unless the MSI or setup code overrides the default, set MSIFASTINSTALL for best performance. if (!ChainPackageInfo.HasProperty(db, "MSIFASTINSTALL")) { bool fastInstallSet = false; foreach (MsiPropertyInfo propertyInfo in this.MsiProperties) { if ("MSIFASTINSTALL".Equals(propertyInfo.Name, StringComparison.Ordinal)) { fastInstallSet = true; break; } } if (!fastInstallSet) { this.MsiProperties.Add(new MsiPropertyInfo(this.Id, "MSIFASTINSTALL", "7")); } } this.UpgradeCode = ChainPackageInfo.GetProperty(db, "UpgradeCode"); // Represent the Upgrade table as related packages. if (db.Tables.Contains("Upgrade") && !String.IsNullOrEmpty(this.UpgradeCode)) { using (Microsoft.Deployment.WindowsInstaller.View view = db.OpenView("SELECT `UpgradeCode`, `VersionMin`, `VersionMax`, `Language`, `Attributes` FROM `Upgrade`")) { view.Execute(); while (true) { using (Microsoft.Deployment.WindowsInstaller.Record record = view.Fetch()) { if (null == record) { break; } RelatedPackage related = new RelatedPackage(); related.Id = record.GetString(1); related.MinVersion = record.GetString(2); related.MaxVersion = record.GetString(3); string languages = record.GetString(4); if (!String.IsNullOrEmpty(languages)) { string[] splitLanguages = languages.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries); related.Languages.AddRange(splitLanguages); } int attributes = record.GetInteger(5); // when an Upgrade row has an upgrade code different than this package's upgrade code, don't count it as a possible downgrade to this package related.OnlyDetect = ((attributes & MsiInterop.MsidbUpgradeAttributesOnlyDetect) == MsiInterop.MsidbUpgradeAttributesOnlyDetect) && this.UpgradeCode.Equals(related.Id, StringComparison.OrdinalIgnoreCase); related.MinInclusive = (attributes & MsiInterop.MsidbUpgradeAttributesVersionMinInclusive) == MsiInterop.MsidbUpgradeAttributesVersionMinInclusive; related.MaxInclusive = (attributes & MsiInterop.MsidbUpgradeAttributesVersionMaxInclusive) == MsiInterop.MsidbUpgradeAttributesVersionMaxInclusive; related.LangInclusive = (attributes & MsiInterop.MsidbUpgradeAttributesLanguagesExclusive) == 0; this.RelatedPackages.Add(related); } } } } // If feature selection is enabled, represent the Feature table in the manifest. if (YesNoType.Yes == enableFeatureSelection && db.Tables.Contains("Feature")) { using (Microsoft.Deployment.WindowsInstaller.View featureView = db.OpenView("SELECT `Component_` FROM `FeatureComponents` WHERE `Feature_` = ?"), componentView = db.OpenView("SELECT `FileSize` FROM `File` WHERE `Component_` = ?")) { using (Microsoft.Deployment.WindowsInstaller.Record featureRecord = new Microsoft.Deployment.WindowsInstaller.Record(1), componentRecord = new Microsoft.Deployment.WindowsInstaller.Record(1)) { using (Microsoft.Deployment.WindowsInstaller.View allFeaturesView = db.OpenView("SELECT * FROM `Feature`")) { allFeaturesView.Execute(); while (true) { using (Microsoft.Deployment.WindowsInstaller.Record allFeaturesResultRecord = allFeaturesView.Fetch()) { if (null == allFeaturesResultRecord) { break; } MsiFeature feature = new MsiFeature(); string featureName = allFeaturesResultRecord.GetString(1); feature.Name = featureName; feature.Size = 0; feature.Parent = allFeaturesResultRecord.GetString(2); feature.Title = allFeaturesResultRecord.GetString(3); feature.Description = allFeaturesResultRecord.GetString(4); feature.Display = allFeaturesResultRecord.GetInteger(5); feature.Level = allFeaturesResultRecord.GetInteger(6); feature.Directory = allFeaturesResultRecord.GetString(7); feature.Attributes = allFeaturesResultRecord.GetInteger(8); this.MsiFeatures.Add(feature); // Determine Feature Size featureRecord.SetString(1, featureName); featureView.Execute(featureRecord); // Loop over all the components while (true) { using (Microsoft.Deployment.WindowsInstaller.Record componentResultRecord = featureView.Fetch()) { if (null == componentResultRecord) { break; } string component = componentResultRecord.GetString(1); componentRecord.SetString(1, component); componentView.Execute(componentRecord); // Loop over all the files while (true) { using (Microsoft.Deployment.WindowsInstaller.Record fileResultRecord = componentView.Fetch()) { if (null == fileResultRecord) { break; } string fileSize = fileResultRecord.GetString(1); feature.Size += Convert.ToInt32(fileSize, CultureInfo.InvariantCulture.NumberFormat); } } } } } } } } } } // Add all external cabinets as package payloads. if (db.Tables.Contains("Media")) { foreach (string cabinet in db.ExecuteStringQuery("SELECT `Cabinet` FROM `Media`")) { if (!String.IsNullOrEmpty(cabinet) && !cabinet.StartsWith("#", StringComparison.Ordinal)) { // If we didn't find the Payload as an existing child of the package, we need to // add it. We expect the file to exist on-disk in the same relative location as // the MSI expects to find it... string cabinetName = Path.Combine(Path.GetDirectoryName(this.PackagePayload.Name), cabinet); if (!this.IsExistingPayload(cabinetName)) { string generatedId = Common.GenerateIdentifier("cab", true, this.PackagePayload.Id, cabinet); string payloadSourceFile = fileManager.ResolveRelatedFile(this.PackagePayload.UnresolvedSourceFile, cabinet, "Cabinet", this.PackagePayload.SourceLineNumbers, BindStage.Normal); PayloadInfoRow payloadNew = PayloadInfoRow.Create(this.SourceLineNumbers, bundle, generatedId, cabinetName, payloadSourceFile, true, this.PackagePayload.SuppressSignatureValidation, null, this.PackagePayload.Container, this.PackagePayload.Packaging); payloadNew.ParentPackagePayload = this.PackagePayload.Id; if (!String.IsNullOrEmpty(payloadNew.Container)) { containers[payloadNew.Container].Payloads.Add(payloadNew); } this.Payloads.Add(payloadNew); allPayloads.Add(payloadNew.Id, payloadNew); this.Size += payloadNew.FileSize; // add the newly added payload to the package size. } } } } // Add all external files as package payloads and calculate the total install size as the rollup of // File table's sizes. this.InstallSize = 0; if (db.Tables.Contains("Component") && db.Tables.Contains("Directory") && db.Tables.Contains("File")) { Hashtable directories = new Hashtable(); // Load up the directory hash table so we will be able to resolve source paths // for files in the MSI database. using (Microsoft.Deployment.WindowsInstaller.View view = db.OpenView("SELECT `Directory`, `Directory_Parent`, `DefaultDir` FROM `Directory`")) { view.Execute(); while (true) { using (Microsoft.Deployment.WindowsInstaller.Record record = view.Fetch()) { if (null == record) { break; } string sourceName = Installer.GetName(record.GetString(3), true, longNamesInImage); directories.Add(record.GetString(1), new ResolvedDirectory(record.GetString(2), sourceName)); } } } // Resolve the source paths to external files and add each file size to the total // install size of the package. using (Microsoft.Deployment.WindowsInstaller.View view = db.OpenView("SELECT `Directory_`, `File`, `FileName`, `File`.`Attributes`, `FileSize` FROM `Component`, `File` WHERE `Component`.`Component`=`File`.`Component_`")) { view.Execute(); while (true) { using (Microsoft.Deployment.WindowsInstaller.Record record = view.Fetch()) { if (null == record) { break; } // Skip adding the loose files as payloads if it was suppressed. if (suppressLooseFilePayloadGeneration != YesNoType.Yes) { // If the file is explicitly uncompressed or the MSI is uncompressed and the file is not // explicitly marked compressed then this is an external file. if (MsiInterop.MsidbFileAttributesNoncompressed == (record.GetInteger(4) & MsiInterop.MsidbFileAttributesNoncompressed) || (!compressed && 0 == (record.GetInteger(4) & MsiInterop.MsidbFileAttributesCompressed))) { string generatedId = Common.GenerateIdentifier("f", true, this.PackagePayload.Id, record.GetString(2)); string fileSourcePath = Binder.GetFileSourcePath(directories, record.GetString(1), record.GetString(3), compressed, longNamesInImage); string payloadSourceFile = fileManager.ResolveRelatedFile(this.PackagePayload.UnresolvedSourceFile, fileSourcePath, "File", this.PackagePayload.SourceLineNumbers, BindStage.Normal); string name = Path.Combine(Path.GetDirectoryName(this.PackagePayload.Name), fileSourcePath); if (!this.IsExistingPayload(name)) { PayloadInfoRow payloadNew = PayloadInfoRow.Create(this.SourceLineNumbers, bundle, generatedId, name, payloadSourceFile, true, this.PackagePayload.SuppressSignatureValidation, null, this.PackagePayload.Container, this.PackagePayload.Packaging); payloadNew.ParentPackagePayload = this.PackagePayload.Id; if (!String.IsNullOrEmpty(payloadNew.Container)) { containers[payloadNew.Container].Payloads.Add(payloadNew); } this.Payloads.Add(payloadNew); allPayloads.Add(payloadNew.Id, payloadNew); this.Size += payloadNew.FileSize; // add the newly added payload to the package size. } } } this.InstallSize += record.GetInteger(5); } } } } // Import any dependency providers from the MSI. if (db.Tables.Contains("WixDependencyProvider")) { // Use the old schema (v1) if the Version column does not exist. bool hasVersion = db.Tables["WixDependencyProvider"].Columns.Contains("Version"); string query = "SELECT `ProviderKey`, `Version`, `DisplayName`, `Attributes` FROM `WixDependencyProvider`"; if (!hasVersion) { query = "SELECT `ProviderKey`, `Attributes` FROM `WixDependencyProvider`"; } using (Microsoft.Deployment.WindowsInstaller.View view = db.OpenView(query)) { view.Execute(); while (true) { using (Microsoft.Deployment.WindowsInstaller.Record record = view.Fetch()) { if (null == record) { break; } // Import the provider key and attributes. ProvidesDependency dependency = null; string providerKey = record.GetString(1); if (hasVersion) { string version = record.GetString(2) ?? this.Version; string displayName = record.GetString(3) ?? this.DisplayName; int attributes = record.GetInteger(4); dependency = new ProvidesDependency(providerKey, version, displayName, attributes); } else { int attributes = record.GetInteger(2); dependency = new ProvidesDependency(providerKey, this.Version, this.DisplayName, attributes); } dependency.Imported = true; this.Provides.Add(dependency); } } } } } } catch (Microsoft.Deployment.WindowsInstaller.InstallerException e) { this.core.OnMessage(WixErrors.UnableToReadPackageInformation(this.PackagePayload.SourceLineNumbers, sourcePath, e.Message)); } }
public ChainPackageInfo(Row chainPackageRow, Table wixGroupTable, Dictionary<string, PayloadInfoRow> allPayloads, Dictionary<string, ContainerInfo> containers, BinderFileManager fileManager, BinderCore core, Output bundle) : base(chainPackageRow.SourceLineNumbers, bundle.Tables["ChainPackageInfo"]) { string id = (string)chainPackageRow[0]; string packageType = (string)chainPackageRow[1]; string payloadId = (string)chainPackageRow[2]; string installCondition = (string)chainPackageRow[3]; string installCommand = (string)chainPackageRow[4]; string repairCommand = (string)chainPackageRow[5]; string uninstallCommand = (string)chainPackageRow[6]; object cacheData = chainPackageRow[7]; string cacheId = (string)chainPackageRow[8]; object attributesData = chainPackageRow[9]; object vitalData = chainPackageRow[10]; object perMachineData = chainPackageRow[11]; string detectCondition = (string)chainPackageRow[12]; string msuKB = (string)chainPackageRow[13]; object repairableData = chainPackageRow[14]; string logPathVariable = (string)chainPackageRow[15]; string rollbackPathVariable = (string)chainPackageRow[16]; string protocol = (string)chainPackageRow[17]; long installSize = (int)chainPackageRow[18]; object suppressLooseFilePayloadGenerationData = chainPackageRow[19]; object enableFeatureSelectionData = chainPackageRow[20]; object forcePerMachineData = chainPackageRow[21]; object displayInternalUIData = chainPackageRow[22]; BundlePackageAttributes attributes = (null == attributesData) ? 0 : (BundlePackageAttributes)attributesData; YesNoAlwaysType cache = YesNoAlwaysType.NotSet; if (null != cacheData) { switch ((int)cacheData) { case 0: cache = YesNoAlwaysType.No; break; case 1: cache = YesNoAlwaysType.Yes; break; case 2: cache = YesNoAlwaysType.Always; break; } } YesNoType vital = (null == vitalData || 1 == (int)vitalData) ? YesNoType.Yes : YesNoType.No; YesNoDefaultType perMachine = YesNoDefaultType.NotSet; if (null != perMachineData) { switch ((int)perMachineData) { case 0: perMachine = YesNoDefaultType.No; break; case 1: perMachine = YesNoDefaultType.Yes; break; case 2: perMachine = YesNoDefaultType.Default; break; } } YesNoType repairable = YesNoType.NotSet; if (null != repairableData) { repairable = (1 == (int)repairableData) ? YesNoType.Yes : YesNoType.No; } YesNoType suppressLooseFilePayloadGeneration = YesNoType.NotSet; if (null != suppressLooseFilePayloadGenerationData) { suppressLooseFilePayloadGeneration = (1 == (int)suppressLooseFilePayloadGenerationData) ? YesNoType.Yes : YesNoType.No; } YesNoType enableFeatureSelection = YesNoType.NotSet; if (null != enableFeatureSelectionData) { enableFeatureSelection = (1 == (int)enableFeatureSelectionData) ? YesNoType.Yes : YesNoType.No; } YesNoType forcePerMachine = YesNoType.NotSet; if (null != forcePerMachineData) { forcePerMachine = (1 == (int)forcePerMachineData) ? YesNoType.Yes : YesNoType.No; } YesNoType displayInternalUI = YesNoType.NotSet; if (null != displayInternalUIData) { displayInternalUI = (1 == (int)displayInternalUIData) ? YesNoType.Yes : YesNoType.No; } this.core = core; this.Id = id; this.ChainPackageType = (Compiler.ChainPackageType)Enum.Parse(typeof(Compiler.ChainPackageType), packageType, true); PayloadInfoRow packagePayload; if (!allPayloads.TryGetValue(payloadId, out packagePayload)) { this.core.OnMessage(WixErrors.IdentifierNotFound("Payload", payloadId)); return; } this.PackagePayload = packagePayload; this.InstallCondition = installCondition; this.InstallCommand = installCommand; this.RepairCommand = repairCommand; this.UninstallCommand = uninstallCommand; this.PerMachine = perMachine; this.ProductCode = null; this.Cache = YesNoAlwaysType.NotSet == cache ? YesNoAlwaysType.Yes : cache; // The default is yes. this.CacheId = cacheId; this.Permanent = (BundlePackageAttributes.Permanent == (attributes & BundlePackageAttributes.Permanent)); this.Visible = (BundlePackageAttributes.Visible == (attributes & BundlePackageAttributes.Visible)); this.Slipstream = (BundlePackageAttributes.Slipstream == (attributes & BundlePackageAttributes.Slipstream)); this.Vital = (YesNoType.Yes == vital); // true only when specifically requested. this.DetectCondition = detectCondition; this.MsuKB = msuKB; this.Protocol = protocol; this.Repairable = (YesNoType.Yes == repairable); // true only when specifically requested. this.LogPathVariable = logPathVariable; this.RollbackLogPathVariable = rollbackPathVariable; this.DisplayInternalUI = (YesNoType.Yes == displayInternalUI); this.Payloads = new List<PayloadInfoRow>(); this.RelatedPackages = new List<RelatedPackage>(); this.MsiFeatures = new List<MsiFeature>(); this.MsiProperties = new List<MsiPropertyInfo>(); this.SlipstreamMsps = new List<string>(); this.ExitCodes = new List<ExitCodeInfo>(); this.Provides = new ProvidesDependencyCollection(); this.TargetCodes = new RowDictionary<WixBundlePatchTargetCodeRow>(); // Default the display name and description to the package payload. this.DisplayName = this.PackagePayload.ProductName; this.Description = this.PackagePayload.Description; // Start the package size with the package's payload size. this.Size = this.PackagePayload.FileSize; // get all contained payloads... foreach (Row row in wixGroupTable.Rows) { string rowParentName = (string)row[0]; string rowParentType = (string)row[1]; string rowChildName = (string)row[2]; string rowChildType = (string)row[3]; if ("Package" == rowParentType && this.Id == rowParentName && "Payload" == rowChildType && this.PackagePayload.Id != rowChildName) { PayloadInfoRow payload = allPayloads[rowChildName]; this.Payloads.Add(payload); this.Size += payload.FileSize; // add each payload to the total size of the package. } } // Default the install size to the calculated package size. this.InstallSize = this.Size; switch (this.ChainPackageType) { case Compiler.ChainPackageType.Msi: this.ResolveMsiPackage(fileManager, allPayloads, containers, suppressLooseFilePayloadGeneration, enableFeatureSelection, forcePerMachine, bundle); break; case Compiler.ChainPackageType.Msp: this.ResolveMspPackage(bundle); break; case Compiler.ChainPackageType.Msu: this.ResolveMsuPackage(); break; case Compiler.ChainPackageType.Exe: this.ResolveExePackage(); break; } if (CompilerCore.IntegerNotSet != installSize) { this.InstallSize = installSize; } }
public ContainerInfo(Row row, BinderFileManager fileManager) : this((string)row[0], (string)row[1], (string)row[2], (string)row[3], fileManager) { this.SourceLineNumbers = row.SourceLineNumbers; }
private void WriteBurnManifestPayloadAttributes(XmlTextWriter writer, PayloadInfoRow payload, bool embeddedOnly, BinderFileManager fileManager, Dictionary<string, PayloadInfoRow> allPayloads) { Debug.Assert(!embeddedOnly || PackagingType.Embedded == payload.Packaging); writer.WriteAttributeString("Id", payload.Id); writer.WriteAttributeString("FilePath", payload.Name); writer.WriteAttributeString("FileSize", payload.FileSize.ToString(CultureInfo.InvariantCulture)); writer.WriteAttributeString("Hash", payload.Hash); if (payload.LayoutOnly) { writer.WriteAttributeString("LayoutOnly", "yes"); } if (!String.IsNullOrEmpty(payload.PublicKey)) { writer.WriteAttributeString("CertificateRootPublicKeyIdentifier", payload.PublicKey); } if (!String.IsNullOrEmpty(payload.Thumbprint)) { writer.WriteAttributeString("CertificateRootThumbprint", payload.Thumbprint); } switch (payload.Packaging) { case PackagingType.Embedded: // this means it's in a container. if (!String.IsNullOrEmpty(payload.DownloadUrl)) { this.core.OnMessage(WixWarnings.DownloadUrlNotSupportedForEmbeddedPayloads(payload.SourceLineNumbers, payload.Id)); } writer.WriteAttributeString("Packaging", "embedded"); writer.WriteAttributeString("SourcePath", payload.EmbeddedId); if (Compiler.BurnUXContainerId != payload.Container) { writer.WriteAttributeString("Container", payload.Container); } break; case PackagingType.External: string packageId = payload.ParentPackagePayload; string parentUrl = payload.ParentPackagePayload == null ? null : allPayloads[payload.ParentPackagePayload].DownloadUrl; string resolvedUrl = fileManager.ResolveUrl(payload.DownloadUrl, parentUrl, packageId, payload.Id, payload.Name); if (!String.IsNullOrEmpty(resolvedUrl)) { writer.WriteAttributeString("DownloadUrl", resolvedUrl); } else if (!String.IsNullOrEmpty(payload.DownloadUrl)) { writer.WriteAttributeString("DownloadUrl", payload.DownloadUrl); } writer.WriteAttributeString("Packaging", "external"); writer.WriteAttributeString("SourcePath", payload.Name); break; } if (!String.IsNullOrEmpty(payload.CatalogId)) { writer.WriteAttributeString("Catalog", payload.CatalogId); } }
/// <summary> /// Resolves the source path of a file. /// </summary> /// <param name="source">Original source value.</param> /// <param name="type">Optional type of source file being resolved.</param> /// <param name="sourceLineNumbers">Optional source line of source file being resolved.</param> /// <param name="bindStage">The binding stage used to determine what collection of bind paths will be used</param> /// <returns>Should return a valid path for the stream to be imported.</returns> public virtual string ResolveFile(string source, string type, SourceLineNumberCollection sourceLineNumbers, BindStage bindStage) { // the following new local variables are used for bind path and protect the changes to object field. StringCollection currentBindPaths = null; NameValueCollection currentNamedBindPaths = null; StringCollection currentSourcePaths = null; if (String.IsNullOrEmpty(source)) { throw new ArgumentNullException("source"); } // Call the original override function first. If it returns an answer then return that, // otherwise using the default resolving logic string filePath = this.ResolveFile(source, type, sourceLineNumbers); if (!String.IsNullOrEmpty(filePath)) { return(filePath); } // Assign the correct bind path to file manager currentSourcePaths = this.sourcePaths[bindStage]; currentNamedBindPaths = this.namedBindPaths[bindStage]; if (BindStage.Target != bindStage && BindStage.Updated != bindStage) { currentBindPaths = this.bindPaths[bindStage]; } else { currentBindPaths = this.sourcePaths[bindStage]; } // If the path is rooted, it better exist or we're not going to find it. if (Path.IsPathRooted(source)) { if (BinderFileManager.CheckFileExists(source)) { return(source); } } else // not a rooted path so let's try applying all the different source resolution options. { const string bindPathOpenString = "!(bindpath."; if (source.StartsWith(bindPathOpenString, StringComparison.Ordinal) && source.IndexOf(')') != -1) { int bindpathSignatureLength = bindPathOpenString.Length; string name = source.Substring(bindpathSignatureLength, source.IndexOf(')') - bindpathSignatureLength); string[] values = currentNamedBindPaths.GetValues(name); if (null != values) { foreach (string bindPath in values) { // Parse out '\\' chars that separate the "bindpath" variable and the next part of the path, // because Path.Combine() thinks that rooted second paths don't need the first path. string nameSection = string.Empty; int nameStart = bindpathSignatureLength + 1 + name.Length; // +1 for the closing bracket. nameSection = source.Substring(nameStart).TrimStart('\\'); filePath = Path.Combine(bindPath, nameSection); if (BinderFileManager.CheckFileExists(filePath)) { return(filePath); } } } } else if (source.StartsWith("SourceDir\\", StringComparison.Ordinal) || source.StartsWith("SourceDir/", StringComparison.Ordinal)) { foreach (string bindPath in currentBindPaths) { filePath = Path.Combine(bindPath, source.Substring(10)); if (BinderFileManager.CheckFileExists(filePath)) { return(filePath); } } } else if (BinderFileManager.CheckFileExists(source)) { return(source); } foreach (string path in currentSourcePaths) { filePath = Path.Combine(path, source); if (BinderFileManager.CheckFileExists(filePath)) { return(filePath); } if (source.StartsWith("SourceDir\\", StringComparison.Ordinal) || source.StartsWith("SourceDir/", StringComparison.Ordinal)) { filePath = Path.Combine(path, source.Substring(10)); if (BinderFileManager.CheckFileExists(filePath)) { return(filePath); } } } } // Didn't find the file. throw new WixFileNotFoundException(sourceLineNumbers, source, type); }
/// <summary> /// Saves a library to a path on disk. /// </summary> /// <param name="path">Path to save library file to on disk.</param> /// <param name="binderFileManager">If provided, the binder file manager is used to bind files into the library.</param> /// <param name="wixVariableResolver">The Wix variable resolver.</param> public void Save(string path, BinderFileManager binderFileManager, WixVariableResolver wixVariableResolver) { FileMode fileMode = FileMode.Create; StringCollection fileIds = new StringCollection(); StringCollection files = new StringCollection(); int index = 0; // resolve paths to files and create the library cabinet file foreach (Section section in this.sections) { foreach (Table table in section.Tables) { foreach (Row row in table.Rows) { foreach (Field field in row.Fields) { ObjectField objectField = field as ObjectField; if (null != objectField) { if (null != binderFileManager && null != objectField.Data) { string cabinetFileId = (index++).ToString(CultureInfo.InvariantCulture); // resolve wix variables string resolvedValue = wixVariableResolver.ResolveVariables(row.SourceLineNumbers, (string)objectField.Data, false); files.Add(binderFileManager.ResolveFile(resolvedValue, table.Name, row.SourceLineNumbers, BindStage.Normal)); // File was successfully resolved so track this cabient file id. objectField.CabinetFileId = cabinetFileId; fileIds.Add(cabinetFileId); } else // clear out a previous cabinet file id value { objectField.CabinetFileId = null; } } } } } } // do not save the library if errors were found while resolving object paths if (wixVariableResolver.EncounteredError) { return; } // create the cabinet file if (0 < fileIds.Count) { using (WixCreateCab cab = new WixCreateCab(Path.GetFileName(path), Path.GetDirectoryName(path), fileIds.Count, 0, 0, CompressionLevel.Mszip)) { for (int i = 0; i < fileIds.Count; i++) { cab.AddFile(files[i], fileIds[i]); } cab.Complete(); } // append the library xml to the end of the newly created cabinet file fileMode = FileMode.Append; } // Assure the location to output the lib exists Directory.CreateDirectory(Path.GetDirectoryName(Path.GetFullPath(path))); // save the xml using (FileStream fs = new FileStream(path, fileMode)) { XmlWriter writer = null; try { writer = new XmlTextWriter(fs, System.Text.Encoding.UTF8); writer.WriteStartDocument(); this.Persist(writer); writer.WriteEndDocument(); } finally { if (null != writer) { writer.Close(); } } } }
/// <summary> /// Resolves paths to files. /// </summary> /// <param name="sectionTables">TableCollection of tables to process</param> /// <param name="binderFileManager">If provided, the binder file manager is used to bind files into the output.</param> /// <param name="wixVariableResolver">The Wix variable resolver.</param> /// <param name="tempFilesLocation">Location for temporary files.</param> /// <param name="cabinets">Hash of source cabinets.</param> /// <param name="fileIds">Collection of CabinetFileIds.</param> /// <param name="files">Collection of file paths from compressed files.</param> /// <param name="index">CabinetFileId generator.</param> public static void ResolveSectionFiles(TableCollection sectionTables, BinderFileManager binderFileManager, WixVariableResolver wixVariableResolver, string tempFilesLocation, Hashtable cabinets, StringCollection fileIds, StringCollection files, ref int index) { foreach (Table table in sectionTables) { foreach (Row row in table.Rows) { foreach (Field field in row.Fields) { ObjectField objectField = field as ObjectField; if (null != objectField && null != objectField.Data) { string file = null; string previousFile = null; bool isDefault = true; bool isPreviousDefault = true; // resolve localization and wix variables if there is a file manager that would use the value // if it was different, otherwise we just don't care so skip the whole variable resolution thing. if (null != wixVariableResolver && null != binderFileManager) { objectField.Data = wixVariableResolver.ResolveVariables(row.SourceLineNumbers, (string)objectField.Data, false, ref isDefault); if (null != objectField.PreviousData) { objectField.PreviousData = wixVariableResolver.ResolveVariables(row.SourceLineNumbers, objectField.PreviousData, false, ref isPreviousDefault); } // do not save the output if errors were found while resolving object paths if (wixVariableResolver.EncounteredError) { return; } } // file is compressed in a cabinet (and not modified above) if (null != objectField.CabinetFileId && isDefault) { // index cabinets that have not been previously encountered if (!cabinets.ContainsKey(objectField.BaseUri)) { Uri baseUri = new Uri(objectField.BaseUri); string localFileNameWithoutExtension = Path.GetFileNameWithoutExtension(baseUri.LocalPath); string extractedDirectoryName = String.Format(CultureInfo.InvariantCulture, "cab_{0}_{1}", cabinets.Count, localFileNameWithoutExtension); // index the cabinet file's base URI (source location) and extracted directory cabinets.Add(objectField.BaseUri, Path.Combine(tempFilesLocation, extractedDirectoryName)); } // set the path to the file once its extracted from the cabinet file = Path.Combine((string)cabinets[objectField.BaseUri], objectField.CabinetFileId); } else if (null != binderFileManager) { file = binderFileManager.ResolveFile((string)objectField.Data, table.Name, row.SourceLineNumbers, BindStage.Normal); } // add the file to the list of files to go in the cabinet if (null != file) { string cabinetFileId = (index++).ToString(CultureInfo.InvariantCulture); objectField.CabinetFileId = cabinetFileId; fileIds.Add(cabinetFileId); files.Add(file); } // previous file is compressed in a cabinet (and not modified above) if (null != objectField.PreviousCabinetFileId && isPreviousDefault) { // index cabinets that have not been previously encountered if (!cabinets.ContainsKey(objectField.PreviousBaseUri)) { Uri baseUri = new Uri(objectField.PreviousBaseUri); string localFileNameWithoutExtension = Path.GetFileNameWithoutExtension(baseUri.LocalPath); string extractedDirectoryName = String.Format(CultureInfo.InvariantCulture, "cab_{0}_{1}", cabinets.Count, localFileNameWithoutExtension); // index the cabinet file's base URI (source location) and extracted directory cabinets.Add(objectField.PreviousBaseUri, Path.Combine(tempFilesLocation, extractedDirectoryName)); } // set the path to the file once its extracted from the cabinet previousFile = Path.Combine((string)cabinets[objectField.PreviousBaseUri], objectField.PreviousCabinetFileId); } else if (null != objectField.PreviousData && null != binderFileManager) { previousFile = binderFileManager.ResolveFile((string)objectField.PreviousData, table.Name, row.SourceLineNumbers, BindStage.Normal); } // add the file to the list of files to go in the cabinet if (null != previousFile) { string cabinetFileId = (index++).ToString(CultureInfo.InvariantCulture); objectField.PreviousCabinetFileId = cabinetFileId; fileIds.Add(cabinetFileId); files.Add(previousFile); } } } } } }
public virtual CabinetBuildOption ResolveCabinet(FileRowCollection fileRows, ref string cabinetPath) { if (fileRows == null) { throw new ArgumentNullException("fileRows"); } // no special behavior specified, use the default if (null == this.cabCachePath && !this.reuseCabinets) { return(CabinetBuildOption.BuildAndMove); } // if a cabinet cache path was provided, change the location for the cabinet // to be built to if (null != this.cabCachePath) { string cabinetName = Path.GetFileName(cabinetPath); cabinetPath = Path.Combine(this.cabCachePath, cabinetName); } // if we still think we're going to reuse the cabinet check to see if the cabinet exists first if (this.reuseCabinets) { bool cabinetValid = false; if (BinderFileManager.CheckFileExists(cabinetPath)) { // check to see if // 1. any files are added or removed // 2. order of files changed or names changed // 3. modified time changed cabinetValid = true; // Need to force garbage collection of WixEnumerateCab to ensure the handle // associated with it is closed before it is reused. using (Cab.WixEnumerateCab wixEnumerateCab = new Cab.WixEnumerateCab()) { ArrayList fileList = wixEnumerateCab.Enumerate(cabinetPath); if (fileRows.Count != fileList.Count) { cabinetValid = false; } else { int i = 0; foreach (FileRow fileRow in fileRows) { // First check that the file identifiers match because that is quick and easy. CabinetFileInfo cabFileInfo = fileList[i] as CabinetFileInfo; cabinetValid = (cabFileInfo.FileId == fileRow.File); if (cabinetValid) { // Still valid so ensure the source time stamp hasn't changed. Thus we need // to convert the source file time stamp into a cabinet compatible data/time. DateTime sourceFileTime = File.GetLastWriteTime(fileRow.Source); ushort sourceCabDate; ushort sourceCabTime; Cab.Interop.CabInterop.DateTimeToCabDateAndTime(sourceFileTime, out sourceCabDate, out sourceCabTime); cabinetValid = (cabFileInfo.Date == sourceCabDate && cabFileInfo.Time == sourceCabTime); } if (!cabinetValid) { break; } i++; } } } } return(cabinetValid ? CabinetBuildOption.Copy : CabinetBuildOption.BuildAndCopy); } else // by default move the built cabinet { return(CabinetBuildOption.BuildAndMove); } }
/// <summary> /// Saves an outputs cab to a path on disk. /// </summary> /// <param name="path">Path to save outputs cab to on disk.</param> /// <param name="binderFileManager">If provided, the binder file manager is used to bind files into the outputs cab.</param> /// <param name="wixVariableResolver">The Wix variable resolver.</param> /// <param name="tempFilesLocation">Location for temporary files.</param> /// <returns>Returns true if a cabinet existed or was created, false otherwise.</returns> public bool SaveCab(string path, BinderFileManager binderFileManager, WixVariableResolver wixVariableResolver, string tempFilesLocation) { bool hasCab = false; // Check if there was a cab on the wixout when it was created if (null != this.cabPath) { // There was already a cab on the wixout when it was loaded. Reuse that one. File.Copy(this.cabPath, path, true); if (null != this.tempFileCollection) { this.tempFileCollection.Delete(); } hasCab = true; } else { int index = 0; Hashtable cabinets = new Hashtable(); StringCollection fileIds = new StringCollection(); StringCollection files = new StringCollection(); if (null != tempFilesLocation) { // resolve paths to files and create the output cabinet file if (0 == this.sections.Count) { Output.ResolveSectionFiles(this.tables, binderFileManager, wixVariableResolver, tempFilesLocation, cabinets, fileIds, files, ref index); } else { foreach (Section section in this.sections) { Output.ResolveSectionFiles(section.Tables, binderFileManager, wixVariableResolver, tempFilesLocation, cabinets, fileIds, files, ref index); } } } // extract files that come from cabinet files if (0 < cabinets.Count) { // ensure the temporary directory exists Directory.CreateDirectory(tempFilesLocation); foreach (DictionaryEntry cabinet in cabinets) { Uri baseUri = new Uri((string)cabinet.Key); string localPath; if ("embeddedresource" == baseUri.Scheme) { int bytesRead; byte[] buffer = new byte[512]; string originalLocalPath = Path.GetFullPath(baseUri.LocalPath.Substring(1)); string resourceName = baseUri.Fragment.Substring(1); Assembly assembly = Assembly.LoadFile(originalLocalPath); localPath = String.Concat(cabinet.Value, ".cab"); using (FileStream fs = File.OpenWrite(localPath)) { using (Stream resourceStream = assembly.GetManifestResourceStream(resourceName)) { while (0 < (bytesRead = resourceStream.Read(buffer, 0, buffer.Length))) { fs.Write(buffer, 0, bytesRead); } } } } else // normal file { localPath = baseUri.LocalPath; } // extract the cabinet's files into a temporary directory Directory.CreateDirectory((string)cabinet.Value); using (WixExtractCab extractCab = new WixExtractCab()) { extractCab.Extract(localPath, (string)cabinet.Value); } } } // create the cabinet file if (0 < fileIds.Count) { using (WixCreateCab cab = new WixCreateCab(Path.GetFileName(path), Path.GetDirectoryName(path), fileIds.Count, 0, 0, CompressionLevel.Mszip)) { for (int i = 0; i < fileIds.Count; i++) { cab.AddFile(files[i], fileIds[i]); } cab.Complete(); } // append the output xml to the end of the newly created cabinet file hasCab = true; } } return(hasCab); }
/// <summary> /// Saves an outputs cab to a path on disk. /// </summary> /// <param name="path">Path to save outputs cab to on disk.</param> /// <param name="binderFileManager">If provided, the binder file manager is used to bind files into the outputs cab.</param> /// <param name="wixVariableResolver">The Wix variable resolver.</param> /// <param name="tempFilesLocation">Location for temporary files.</param> /// <returns>Returns true if a cabinet existed or was created, false otherwise.</returns> public bool SaveCab(string path, BinderFileManager binderFileManager, WixVariableResolver wixVariableResolver, string tempFilesLocation) { bool hasCab = false; // Check if there was a cab on the wixout when it was created if (null != this.cabPath) { // There was already a cab on the wixout when it was loaded. Reuse that one. File.Copy(this.cabPath, path, true); if (null != this.tempFileCollection) { this.tempFileCollection.Delete(); } hasCab = true; } else { int index = 0; Hashtable cabinets = new Hashtable(); StringCollection fileIds = new StringCollection(); StringCollection files = new StringCollection(); if (null != tempFilesLocation) { // resolve paths to files and create the output cabinet file if (0 == this.sections.Count) { Output.ResolveSectionFiles(this.tables, binderFileManager, wixVariableResolver, tempFilesLocation, cabinets, fileIds, files, ref index); } else { foreach (Section section in this.sections) { Output.ResolveSectionFiles(section.Tables, binderFileManager, wixVariableResolver, tempFilesLocation, cabinets, fileIds, files, ref index); } } } // extract files that come from cabinet files if (0 < cabinets.Count) { // ensure the temporary directory exists Directory.CreateDirectory(tempFilesLocation); foreach (DictionaryEntry cabinet in cabinets) { Uri baseUri = new Uri((string)cabinet.Key); string localPath; if ("embeddedresource" == baseUri.Scheme) { int bytesRead; byte[] buffer = new byte[512]; string originalLocalPath = Path.GetFullPath(baseUri.LocalPath.Substring(1)); string resourceName = baseUri.Fragment.Substring(1); Assembly assembly = Assembly.LoadFile(originalLocalPath); localPath = String.Concat(cabinet.Value, ".cab"); using (FileStream fs = File.OpenWrite(localPath)) { using (Stream resourceStream = assembly.GetManifestResourceStream(resourceName)) { while (0 < (bytesRead = resourceStream.Read(buffer, 0, buffer.Length))) { fs.Write(buffer, 0, bytesRead); } } } } else // normal file { localPath = baseUri.LocalPath; } // extract the cabinet's files into a temporary directory Directory.CreateDirectory((string)cabinet.Value); using (WixExtractCab extractCab = new WixExtractCab()) { extractCab.Extract(localPath, (string)cabinet.Value); } } } // create the cabinet file if (0 < fileIds.Count) { using (WixCreateCab cab = new WixCreateCab(Path.GetFileName(path), Path.GetDirectoryName(path), fileIds.Count, 0, 0, CompressionLevel.Mszip)) { for (int i = 0; i < fileIds.Count; i++) { cab.AddFile(files[i], fileIds[i]); } cab.Complete(); } // append the output xml to the end of the newly created cabinet file hasCab = true; } } return hasCab; }
private void WriteBurnManifestContainerAttributes(XmlTextWriter writer, string executableName, ContainerInfo container, int containerIndex, BinderFileManager fileManager) { writer.WriteAttributeString("Id", container.Id); writer.WriteAttributeString("FileSize", container.FileInfo.Length.ToString(CultureInfo.InvariantCulture)); writer.WriteAttributeString("Hash", Common.GetFileHash(container.FileInfo)); if (container.Type == "detached") { string resolvedUrl = fileManager.ResolveUrl(container.DownloadUrl, null, null, container.Id, container.Name); if (!String.IsNullOrEmpty(resolvedUrl)) { writer.WriteAttributeString("DownloadUrl", resolvedUrl); } else if (!String.IsNullOrEmpty(container.DownloadUrl)) { writer.WriteAttributeString("DownloadUrl", container.DownloadUrl); } writer.WriteAttributeString("FilePath", container.Name); } else if (container.Type == "attached") { if (!String.IsNullOrEmpty(container.DownloadUrl)) { this.core.OnMessage(WixWarnings.DownloadUrlNotSupportedForAttachedContainers(container.SourceLineNumbers, container.Id)); } writer.WriteAttributeString("FilePath", executableName); // attached containers use the name of the bundle since they are attached to the executable. writer.WriteAttributeString("AttachedIndex", containerIndex.ToString(CultureInfo.InvariantCulture)); writer.WriteAttributeString("Attached", "yes"); writer.WriteAttributeString("Primary", "yes"); } }