private void UpdatePayloadPackagingType(WixBundlePayloadRow payload) { if (PackagingType.Unknown == payload.Packaging) { if (YesNoDefaultType.Yes == payload.Compressed) { payload.Packaging = PackagingType.Embedded; } else if (YesNoDefaultType.No == payload.Compressed) { payload.Packaging = PackagingType.External; } else { payload.Packaging = this.DefaultPackaging; } } // Embedded payloads that are not assigned a container already are placed in the default attached // container. if (PackagingType.Embedded == payload.Packaging && String.IsNullOrEmpty(payload.Container)) { payload.Container = Compiler.BurnDefaultAttachedContainerId; } }
private void ImportExternalCabinetAsPayloads(Dtf.Database db, WixBundlePayloadRow packagePayload, ISet <string> payloadNames) { 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(packagePayload.Name), cabinet); if (!payloadNames.Contains(cabinetName)) { string generatedId = Common.GenerateIdentifier("cab", packagePayload.Id, cabinet); string payloadSourceFile = FileManager.ResolveRelatedFile(packagePayload.UnresolvedSourceFile, cabinet, "Cabinet", this.Facade.Package.SourceLineNumbers, BindStage.Normal); WixBundlePayloadRow payload = (WixBundlePayloadRow)this.PayloadTable.CreateRow(this.Facade.Package.SourceLineNumbers); payload.Id = generatedId; payload.Name = cabinetName; payload.SourceFile = payloadSourceFile; payload.Compressed = packagePayload.Compressed; payload.UnresolvedSourceFile = cabinetName; payload.Package = packagePayload.Package; payload.Container = packagePayload.Container; payload.ContentFile = true; payload.EnableSignatureValidation = packagePayload.EnableSignatureValidation; payload.Packaging = packagePayload.Packaging; payload.ParentPackagePayload = packagePayload.Id; } } } } }
/// <summary> /// Processes the Exe packages to add properties and payloads from the Exe packages. /// </summary> public void Execute() { WixBundlePayloadRow packagePayload = this.AuthoredPayloads.Get(this.Facade.Package.PackagePayload); if (String.IsNullOrEmpty(this.Facade.Package.CacheId)) { this.Facade.Package.CacheId = packagePayload.Hash; } this.Facade.Package.Version = packagePayload.Version; }
public void Execute() { WixBundlePayloadRow packagePayload = this.AuthoredPayloads.Get(this.Facade.Package.PackagePayload); if (String.IsNullOrEmpty(this.Facade.Package.CacheId)) { this.Facade.Package.CacheId = packagePayload.Hash; } this.Facade.Package.PerMachine = YesNoDefaultType.Yes; // MSUs are always per-machine. }
private static IList <SoftwareTag> CollectPackageTags(Output bundle) { List <SoftwareTag> tags = new List <SoftwareTag>(); Table packageTable = bundle.Tables["WixBundlePackage"]; if (null != packageTable) { Table payloadTable = bundle.Tables["WixBundlePayload"]; RowDictionary <WixBundlePayloadRow> payloads = new RowDictionary <WixBundlePayloadRow>(payloadTable); foreach (WixBundlePackageRow row in packageTable.RowsAs <WixBundlePackageRow>()) { if (WixBundlePackageType.Msi == row.Type) { string packagePayloadId = row.PackagePayload; WixBundlePayloadRow payload = payloads.Get(packagePayloadId); using (Database db = new Database(payload.FullFileName)) { if (db.Tables.Contains("SoftwareIdentificationTag")) { using (View view = db.OpenView("SELECT `Regid`, `UniqueId`, `Type` FROM `SoftwareIdentificationTag`")) { view.Execute(); while (true) { using (Record record = view.Fetch()) { if (null == record) { break; } TagType type = String.IsNullOrEmpty(record.GetString(3)) ? TagType.Unknown : (TagType)Enum.Parse(typeof(TagType), record.GetString(3)); tags.Add(new SoftwareTag() { Regid = record.GetString(1), Id = record.GetString(2), Type = type }); } } } } } } } } return(tags); }
public void Execute() { this.GenerateBAManifestBundleTables(); this.GenerateBAManifestMsiFeatureTables(); this.GenerateBAManifestPackageTables(); this.GenerateBAManifestPayloadTables(); string baManifestPath = Path.Combine(this.TempFilesLocation, "wix-badata.xml"); this.CreateBootstrapperApplicationManifest(baManifestPath); this.BootstrapperApplicationManifestPayloadRow = this.CreateBootstrapperApplicationManifestPayloadRow(baManifestPath); }
private void UpdatePayloadVersionInformation(WixBundlePayloadRow payload) { FileVersionInfo versionInfo = FileVersionInfo.GetVersionInfo(payload.SourceFile); if (null != versionInfo) { // Use the fixed version info block for the file since the resource text may not be a dotted quad. Version version = new Version(versionInfo.ProductMajorPart, versionInfo.ProductMinorPart, versionInfo.ProductBuildPart, versionInfo.ProductPrivatePart); if (ProcessPayloadsCommand.EmptyVersion != version) { payload.Version = version.ToString(); } payload.Description = versionInfo.FileDescription; payload.DisplayName = versionInfo.ProductName; } }
/// <summary> /// Processes the Msp packages to add properties and payloads from the Msp packages. /// </summary> public void Execute() { WixBundlePayloadRow packagePayload = this.AuthoredPayloads.Get(this.Facade.Package.PackagePayload); string sourcePath = packagePayload.FullFileName; try { // Read data out of the msp database... using (Dtf.SummaryInfo sumInfo = new Dtf.SummaryInfo(sourcePath, false)) { this.Facade.MspPackage.PatchCode = sumInfo.RevisionNumber.Substring(0, 38); } using (Dtf.Database db = new Dtf.Database(sourcePath)) { if (String.IsNullOrEmpty(this.Facade.Package.DisplayName)) { this.Facade.Package.DisplayName = ProcessMspPackageCommand.GetPatchMetadataProperty(db, "DisplayName"); } if (String.IsNullOrEmpty(this.Facade.Package.Description)) { this.Facade.Package.Description = ProcessMspPackageCommand.GetPatchMetadataProperty(db, "Description"); } this.Facade.MspPackage.Manufacturer = ProcessMspPackageCommand.GetPatchMetadataProperty(db, "ManufacturerName"); } this.ProcessPatchXml(packagePayload, sourcePath); } catch (Dtf.InstallerException e) { Messaging.Instance.OnMessage(WixErrors.UnableToReadPackageInformation(packagePayload.SourceLineNumbers, sourcePath, e.Message)); return; } if (String.IsNullOrEmpty(this.Facade.Package.CacheId)) { this.Facade.Package.CacheId = this.Facade.MspPackage.PatchCode; } }
private void UpdatePayloadFileInformation(WixBundlePayloadRow payload) { FileInfo fileInfo = new FileInfo(payload.SourceFile); if (null != fileInfo) { payload.FileSize = (int)fileInfo.Length; payload.Hash = Common.GetFileHash(fileInfo.FullName); // Try to get the certificate if the payload is a signed file and we're not suppressing signature validation. if (payload.EnableSignatureValidation) { X509Certificate2 certificate = null; try { certificate = new X509Certificate2(fileInfo.FullName); } catch (CryptographicException) // we don't care about non-signed files. { } // If there is a certificate, remember its hashed public key identifier and thumbprint. if (null != certificate) { byte[] publicKeyIdentifierHash = new byte[128]; uint publicKeyIdentifierHashSize = (uint)publicKeyIdentifierHash.Length; WixToolset.Core.Native.NativeMethods.HashPublicKeyInfo(certificate.Handle, publicKeyIdentifierHash, ref publicKeyIdentifierHashSize); StringBuilder sb = new StringBuilder(((int)publicKeyIdentifierHashSize + 1) * 2); for (int i = 0; i < publicKeyIdentifierHashSize; ++i) { sb.AppendFormat("{0:X2}", publicKeyIdentifierHash[i]); } payload.PublicKey = sb.ToString(); payload.Thumbprint = certificate.Thumbprint; } } } }
private WixBundlePayloadRow CreateBootstrapperApplicationManifestPayloadRow(string baManifestPath) { Table payloadTable = this.Output.EnsureTable(this.TableDefinitions["WixBundlePayload"]); WixBundlePayloadRow row = (WixBundlePayloadRow)payloadTable.CreateRow(this.BundleRow.SourceLineNumbers); row.Id = Common.GenerateIdentifier("ux", "BootstrapperApplicationData.xml"); row.Name = "BootstrapperApplicationData.xml"; row.SourceFile = baManifestPath; row.Compressed = YesNoDefaultType.Yes; row.UnresolvedSourceFile = baManifestPath; row.Container = Compiler.BurnUXContainerId; row.EmbeddedId = String.Format(CultureInfo.InvariantCulture, BurnCommon.BurnUXContainerEmbeddedIdFormat, this.LastUXPayloadIndex); row.Packaging = PackagingType.Embedded; FileInfo fileInfo = new FileInfo(row.SourceFile); row.FileSize = (int)fileInfo.Length; row.Hash = Common.GetFileHash(fileInfo.FullName); return(row); }
/// <summary> /// Creates a new row in the table. /// </summary> /// <param name="sourceLineNumbers">Original source lines for this row.</param> /// <param name="add">Specifies whether to only create the row or add it to the table automatically.</param> /// <returns>Row created in table.</returns> public Row CreateRow(SourceLineNumber sourceLineNumbers, bool add = true) { Row row; switch (this.Name) { case "BBControl": row = new BBControlRow(sourceLineNumbers, this); break; case "WixBundlePackage": row = new WixBundlePackageRow(sourceLineNumbers, this); break; case "WixBundleExePackage": row = new WixBundleExePackageRow(sourceLineNumbers, this); break; case "WixBundleMsiPackage": row = new WixBundleMsiPackageRow(sourceLineNumbers, this); break; case "WixBundleMspPackage": row = new WixBundleMspPackageRow(sourceLineNumbers, this); break; case "WixBundleMsuPackage": row = new WixBundleMsuPackageRow(sourceLineNumbers, this); break; case "Component": row = new ComponentRow(sourceLineNumbers, this); break; case "WixBundleContainer": row = new WixBundleContainerRow(sourceLineNumbers, this); break; case "Control": row = new ControlRow(sourceLineNumbers, this); break; case "File": row = new FileRow(sourceLineNumbers, this); break; case "WixBundleMsiFeature": row = new WixBundleMsiFeatureRow(sourceLineNumbers, this); break; case "WixBundleMsiProperty": row = new WixBundleMsiPropertyRow(sourceLineNumbers, this); break; case "Media": row = new MediaRow(sourceLineNumbers, this); break; case "WixBundlePayload": row = new WixBundlePayloadRow(sourceLineNumbers, this); break; case "Property": row = new PropertyRow(sourceLineNumbers, this); break; case "WixRelatedBundle": row = new WixRelatedBundleRow(sourceLineNumbers, this); break; case "WixBundleRelatedPackage": row = new WixBundleRelatedPackageRow(sourceLineNumbers, this); break; case "WixBundleRollbackBoundary": row = new WixBundleRollbackBoundaryRow(sourceLineNumbers, this); break; case "Upgrade": row = new UpgradeRow(sourceLineNumbers, this); break; case "WixBundleVariable": row = new WixBundleVariableRow(sourceLineNumbers, this); break; case "WixAction": row = new WixActionRow(sourceLineNumbers, this); break; case "WixApprovedExeForElevation": row = new WixApprovedExeForElevationRow(sourceLineNumbers, this); break; case "WixBundle": row = new WixBundleRow(sourceLineNumbers, this); break; case "WixBundlePackageExitCode": row = new WixBundlePackageExitCodeRow(sourceLineNumbers, this); break; case "WixBundlePatchTargetCode": row = new WixBundlePatchTargetCodeRow(sourceLineNumbers, this); break; case "WixBundleSlipstreamMsp": row = new WixBundleSlipstreamMspRow(sourceLineNumbers, this); break; case "WixBundleUpdate": row = new WixBundleUpdateRow(sourceLineNumbers, this); break; case "WixBundleCatalog": row = new WixBundleCatalogRow(sourceLineNumbers, this); break; case "WixChain": row = new WixChainRow(sourceLineNumbers, this); break; case "WixChainItem": row = new WixChainItemRow(sourceLineNumbers, this); break; case "WixBundlePackageCommandLine": row = new WixBundlePackageCommandLineRow(sourceLineNumbers, this); break; case "WixComplexReference": row = new WixComplexReferenceRow(sourceLineNumbers, this); break; case "WixDeltaPatchFile": row = new WixDeltaPatchFileRow(sourceLineNumbers, this); break; case "WixDeltaPatchSymbolPaths": row = new WixDeltaPatchSymbolPathsRow(sourceLineNumbers, this); break; case "WixFile": row = new WixFileRow(sourceLineNumbers, this); break; case "WixGroup": row = new WixGroupRow(sourceLineNumbers, this); break; case "WixMedia": row = new WixMediaRow(sourceLineNumbers, this); break; case "WixMediaTemplate": row = new WixMediaTemplateRow(sourceLineNumbers, this); break; case "WixMerge": row = new WixMergeRow(sourceLineNumbers, this); break; case "WixPayloadProperties": row = new WixPayloadPropertiesRow(sourceLineNumbers, this); break; case "WixProperty": row = new WixPropertyRow(sourceLineNumbers, this); break; case "WixSimpleReference": row = new WixSimpleReferenceRow(sourceLineNumbers, this); break; case "WixUpdateRegistration": row = new WixUpdateRegistrationRow(sourceLineNumbers, this); break; case "WixVariable": row = new WixVariableRow(sourceLineNumbers, this); break; default: row = new Row(sourceLineNumbers, this); break; } if (add) { this.Rows.Add(row); } return(row); }
private void WriteBurnManifestPayloadAttributes(XmlTextWriter writer, WixBundlePayloadRow payload, bool embeddedOnly, Dictionary <string, WixBundlePayloadRow> 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)) { Messaging.Instance.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 = this.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.Catalog)) { writer.WriteAttributeString("Catalog", payload.Catalog); } }
private void ProcessPatchXml(WixBundlePayloadRow packagePayload, string sourcePath) { HashSet <string> uniqueTargetCodes = new HashSet <string>(); string patchXml = Dtf.Installer.ExtractPatchXmlData(sourcePath); XmlDocument doc = new XmlDocument(); doc.LoadXml(patchXml); XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable); nsmgr.AddNamespace("p", "http://www.microsoft.com/msi/patch_applicability.xsd"); // Determine target ProductCodes and/or UpgradeCodes. foreach (XmlNode node in doc.SelectNodes("/p:MsiPatch/p:TargetProduct", nsmgr)) { // If this patch targets a product code, this is the best case. XmlNode targetCodeElement = node.SelectSingleNode("p:TargetProductCode", nsmgr); WixBundlePatchTargetCodeAttributes attributes = WixBundlePatchTargetCodeAttributes.None; if (ProcessMspPackageCommand.TargetsCode(targetCodeElement)) { attributes = WixBundlePatchTargetCodeAttributes.TargetsProductCode; } else // maybe targets an upgrade code? { targetCodeElement = node.SelectSingleNode("p:UpgradeCode", nsmgr); if (ProcessMspPackageCommand.TargetsCode(targetCodeElement)) { attributes = WixBundlePatchTargetCodeAttributes.TargetsUpgradeCode; } else // this patch targets an unknown number of products { this.Facade.MspPackage.Attributes |= WixBundleMspPackageAttributes.TargetUnspecified; } } string targetCode = targetCodeElement.InnerText; if (uniqueTargetCodes.Add(targetCode)) { WixBundlePatchTargetCodeRow row = (WixBundlePatchTargetCodeRow)this.WixBundlePatchTargetCodeTable.CreateRow(packagePayload.SourceLineNumbers); row.MspPackageId = packagePayload.Id; row.TargetCode = targetCode; row.Attributes = attributes; } } // Suppress patch sequence data for improved performance. XmlNode root = doc.DocumentElement; foreach (XmlNode node in root.SelectNodes("p:SequenceData", nsmgr)) { root.RemoveChild(node); } // Save the XML as compact as possible. using (StringWriter writer = new StringWriter()) { XmlWriterSettings settings = new XmlWriterSettings() { Encoding = ProcessMspPackageCommand.XmlOutputEncoding, Indent = false, NewLineChars = string.Empty, NewLineHandling = NewLineHandling.Replace, }; using (XmlWriter xmlWriter = XmlWriter.Create(writer, settings)) { doc.WriteTo(xmlWriter); } this.Facade.MspPackage.PatchXml = writer.ToString(); } }
public void Execute() { throw new NotImplementedException(); #if TODO this.FileTransfers = Enumerable.Empty <FileTransfer>(); this.ContentFilePaths = Enumerable.Empty <string>(); // First look for data we expect to find... Chain, WixGroups, etc. // We shouldn't really get past the linker phase if there are // no group items... that means that there's no UX, no Chain, // *and* no Containers! Table chainPackageTable = this.GetRequiredTable("WixBundlePackage"); Table wixGroupTable = this.GetRequiredTable("WixGroup"); // Ensure there is one and only one row in the WixBundle table. // The compiler and linker behavior should have colluded to get // this behavior. WixBundleRow bundleRow = (WixBundleRow)this.GetSingleRowTable("WixBundle"); bundleRow.PerMachine = true; // default to per-machine but the first-per user package wil flip the bundle per-user. // Ensure there is one and only one row in the WixBootstrapperApplication table. // The compiler and linker behavior should have colluded to get // this behavior. Row baRow = this.GetSingleRowTable("WixBootstrapperApplication"); // Ensure there is one and only one row in the WixChain table. // The compiler and linker behavior should have colluded to get // this behavior. WixChainRow chainRow = (WixChainRow)this.GetSingleRowTable("WixChain"); if (Messaging.Instance.EncounteredError) { return; } // If there are any fields to resolve later, create the cache to populate during bind. IDictionary <string, string> variableCache = null; if (this.DelayedFields.Any()) { variableCache = new Dictionary <string, string>(StringComparer.InvariantCultureIgnoreCase); } // TODO: Although the WixSearch tables are defined in the Util extension, // the Bundle Binder has to know all about them. We hope to revisit all // of this in the 4.0 timeframe. IEnumerable <WixSearchInfo> orderedSearches = this.OrderSearches(); // Extract files that come from cabinet files (this does not extract files from merge modules). { var extractEmbeddedFilesCommand = new ExtractEmbeddedFilesCommand(); extractEmbeddedFilesCommand.FilesWithEmbeddedFiles = ExpectedEmbeddedFiles; extractEmbeddedFilesCommand.Execute(); } // Get the explicit payloads. RowDictionary <WixBundlePayloadRow> payloads = new RowDictionary <WixBundlePayloadRow>(this.Output.Tables["WixBundlePayload"]); // Update explicitly authored payloads with their parent package and container (as appropriate) // to make it easier to gather the payloads later. foreach (WixGroupRow row in wixGroupTable.RowsAs <WixGroupRow>()) { if (ComplexReferenceChildType.Payload == row.ChildType) { WixBundlePayloadRow payload = payloads.Get(row.ChildId); if (ComplexReferenceParentType.Package == row.ParentType) { Debug.Assert(String.IsNullOrEmpty(payload.Package)); payload.Package = row.ParentId; } else if (ComplexReferenceParentType.Container == row.ParentType) { Debug.Assert(String.IsNullOrEmpty(payload.Container)); payload.Container = row.ParentId; } else if (ComplexReferenceParentType.Layout == row.ParentType) { payload.LayoutOnly = true; } } } List <FileTransfer> fileTransfers = new List <FileTransfer>(); string layoutDirectory = Path.GetDirectoryName(this.OutputPath); // Process the explicitly authored payloads. ISet <string> processedPayloads; { ProcessPayloadsCommand command = new ProcessPayloadsCommand(); command.Payloads = payloads.Values; command.DefaultPackaging = bundleRow.DefaultPackagingType; command.LayoutDirectory = layoutDirectory; command.Execute(); fileTransfers.AddRange(command.FileTransfers); processedPayloads = new HashSet <string>(payloads.Keys); } IDictionary <string, PackageFacade> facades; { GetPackageFacadesCommand command = new GetPackageFacadesCommand(); command.PackageTable = chainPackageTable; command.ExePackageTable = this.Output.Tables["WixBundleExePackage"]; command.MsiPackageTable = this.Output.Tables["WixBundleMsiPackage"]; command.MspPackageTable = this.Output.Tables["WixBundleMspPackage"]; command.MsuPackageTable = this.Output.Tables["WixBundleMsuPackage"]; command.Execute(); facades = command.PackageFacades; } // Process each package facade. Note this is likely to add payloads and other rows to tables so // note that any indexes created above may be out of date now. foreach (PackageFacade facade in facades.Values) { switch (facade.Package.Type) { case WixBundlePackageType.Exe: { ProcessExePackageCommand command = new ProcessExePackageCommand(); command.AuthoredPayloads = payloads; command.Facade = facade; command.Execute(); // ? variableCache.Add(String.Concat("packageManufacturer.", facade.Package.WixChainItemId), facade.ExePackage.Manufacturer); } break; case WixBundlePackageType.Msi: { var command = new ProcessMsiPackageCommand(); command.AuthoredPayloads = payloads; command.Facade = facade; command.BackendExtensions = this.BackendExtensions; command.MsiFeatureTable = this.Output.EnsureTable(this.TableDefinitions["WixBundleMsiFeature"]); command.MsiPropertyTable = this.Output.EnsureTable(this.TableDefinitions["WixBundleMsiProperty"]); command.PayloadTable = this.Output.Tables["WixBundlePayload"]; command.RelatedPackageTable = this.Output.EnsureTable(this.TableDefinitions["WixBundleRelatedPackage"]); command.Execute(); if (null != variableCache) { variableCache.Add(String.Concat("packageLanguage.", facade.Package.WixChainItemId), facade.MsiPackage.ProductLanguage.ToString()); if (null != facade.MsiPackage.Manufacturer) { variableCache.Add(String.Concat("packageManufacturer.", facade.Package.WixChainItemId), facade.MsiPackage.Manufacturer); } } } break; case WixBundlePackageType.Msp: { ProcessMspPackageCommand command = new ProcessMspPackageCommand(); command.AuthoredPayloads = payloads; command.Facade = facade; command.WixBundlePatchTargetCodeTable = this.Output.EnsureTable(this.TableDefinitions["WixBundlePatchTargetCode"]); command.Execute(); } break; case WixBundlePackageType.Msu: { ProcessMsuPackageCommand command = new ProcessMsuPackageCommand(); command.Facade = facade; command.Execute(); } break; } if (null != variableCache) { BindBundleCommand.PopulatePackageVariableCache(facade.Package, variableCache); } } // Reindex the payloads now that all the payloads (minus the manifest payloads that will be created later) // are present. payloads = new RowDictionary <WixBundlePayloadRow>(this.Output.Tables["WixBundlePayload"]); // Process the payloads that were added by processing the packages. { ProcessPayloadsCommand command = new ProcessPayloadsCommand(); command.Payloads = payloads.Values.Where(r => !processedPayloads.Contains(r.Id)).ToList(); command.DefaultPackaging = bundleRow.DefaultPackagingType; command.LayoutDirectory = layoutDirectory; command.Execute(); fileTransfers.AddRange(command.FileTransfers); processedPayloads = null; } // Set the package metadata from the payloads now that we have the complete payload information. ILookup <string, WixBundlePayloadRow> payloadsByPackage = payloads.Values.ToLookup(p => p.Package); { foreach (PackageFacade facade in facades.Values) { facade.Package.Size = 0; IEnumerable <WixBundlePayloadRow> packagePayloads = payloadsByPackage[facade.Package.WixChainItemId]; foreach (WixBundlePayloadRow payload in packagePayloads) { facade.Package.Size += payload.FileSize; } if (!facade.Package.InstallSize.HasValue) { facade.Package.InstallSize = facade.Package.Size; } WixBundlePayloadRow packagePayload = payloads[facade.Package.PackagePayload]; if (String.IsNullOrEmpty(facade.Package.Description)) { facade.Package.Description = packagePayload.Description; } if (String.IsNullOrEmpty(facade.Package.DisplayName)) { facade.Package.DisplayName = packagePayload.DisplayName; } } } // Give the UX payloads their embedded IDs... int uxPayloadIndex = 0; { foreach (WixBundlePayloadRow payload in payloads.Values.Where(p => Compiler.BurnUXContainerId == p.Container)) { // In theory, UX payloads could be embedded in the UX CAB, external to the bundle EXE, or even // downloaded. The current engine requires the UX to be fully present before any downloading starts, // so that rules out downloading. Also, the burn engine does not currently copy external UX payloads // into the temporary UX directory correctly, so we don't allow external either. if (PackagingType.Embedded != payload.Packaging) { Messaging.Instance.OnMessage(WixWarnings.UxPayloadsOnlySupportEmbedding(payload.SourceLineNumbers, payload.FullFileName)); payload.Packaging = PackagingType.Embedded; } payload.EmbeddedId = String.Format(CultureInfo.InvariantCulture, BurnCommon.BurnUXContainerEmbeddedIdFormat, uxPayloadIndex); ++uxPayloadIndex; } if (0 == uxPayloadIndex) { // If we didn't get any UX payloads, it's an error! throw new WixException(WixErrors.MissingBundleInformation("BootstrapperApplication")); } // Give the embedded payloads without an embedded id yet an embedded id. int payloadIndex = 0; foreach (WixBundlePayloadRow payload in payloads.Values) { Debug.Assert(PackagingType.Unknown != payload.Packaging); if (PackagingType.Embedded == payload.Packaging && String.IsNullOrEmpty(payload.EmbeddedId)) { payload.EmbeddedId = String.Format(CultureInfo.InvariantCulture, BurnCommon.BurnAttachedContainerEmbeddedIdFormat, payloadIndex); ++payloadIndex; } } } // Determine patches to automatically slipstream. { AutomaticallySlipstreamPatchesCommand command = new AutomaticallySlipstreamPatchesCommand(); command.PackageFacades = facades.Values; command.SlipstreamMspTable = this.Output.EnsureTable(this.TableDefinitions["WixBundleSlipstreamMsp"]); command.WixBundlePatchTargetCodeTable = this.Output.EnsureTable(this.TableDefinitions["WixBundlePatchTargetCode"]); command.Execute(); } // If catalog files exist, non-embedded payloads should validate with the catalogs. IEnumerable <WixBundleCatalogRow> catalogs = this.Output.Tables["WixBundleCatalog"].RowsAs <WixBundleCatalogRow>(); if (catalogs.Any()) { VerifyPayloadsWithCatalogCommand command = new VerifyPayloadsWithCatalogCommand(); command.Catalogs = catalogs; command.Payloads = payloads.Values; command.Execute(); } if (Messaging.Instance.EncounteredError) { return; } IEnumerable <PackageFacade> orderedFacades; IEnumerable <WixBundleRollbackBoundaryRow> boundaries; { OrderPackagesAndRollbackBoundariesCommand command = new OrderPackagesAndRollbackBoundariesCommand(); command.Boundaries = new RowDictionary <WixBundleRollbackBoundaryRow>(this.Output.Tables["WixBundleRollbackBoundary"]); command.PackageFacades = facades; command.WixGroupTable = wixGroupTable; command.Execute(); orderedFacades = command.OrderedPackageFacades; boundaries = command.UsedRollbackBoundaries; } // Resolve any delayed fields before generating the manifest. if (this.DelayedFields.Any()) { var resolveDelayedFieldsCommand = new ResolveDelayedFieldsCommand(); resolveDelayedFieldsCommand.OutputType = this.Output.Type; resolveDelayedFieldsCommand.DelayedFields = this.DelayedFields; resolveDelayedFieldsCommand.ModularizationGuid = null; resolveDelayedFieldsCommand.VariableCache = variableCache; resolveDelayedFieldsCommand.Execute(); } // Set the overridable bundle provider key. this.SetBundleProviderKey(this.Output, bundleRow); // Import or generate dependency providers for packages in the manifest. this.ProcessDependencyProviders(this.Output, facades); // Update the bundle per-machine/per-user scope based on the chained packages. this.ResolveBundleInstallScope(bundleRow, orderedFacades); // Generate the core-defined BA manifest tables... { CreateBootstrapperApplicationManifestCommand command = new CreateBootstrapperApplicationManifestCommand(); command.BundleRow = bundleRow; command.ChainPackages = orderedFacades; command.LastUXPayloadIndex = uxPayloadIndex; command.MsiFeatures = this.Output.Tables["WixBundleMsiFeature"].RowsAs <WixBundleMsiFeatureRow>(); command.Output = this.Output; command.Payloads = payloads; command.TableDefinitions = this.TableDefinitions; command.TempFilesLocation = this.IntermediateFolder; command.Execute(); WixBundlePayloadRow baManifestPayload = command.BootstrapperApplicationManifestPayloadRow; payloads.Add(baManifestPayload); } //foreach (BinderExtension extension in this.Extensions) //{ // extension.PostBind(this.Context); //} // Create all the containers except the UX container first so the manifest (that goes in the UX container) // can contain all size and hash information about the non-UX containers. RowDictionary <WixBundleContainerRow> containers = new RowDictionary <WixBundleContainerRow>(this.Output.Tables["WixBundleContainer"]); ILookup <string, WixBundlePayloadRow> payloadsByContainer = payloads.Values.ToLookup(p => p.Container); int attachedContainerIndex = 1; // count starts at one because UX container is "0". IEnumerable <WixBundlePayloadRow> uxContainerPayloads = Enumerable.Empty <WixBundlePayloadRow>(); foreach (WixBundleContainerRow container in containers.Values) { IEnumerable <WixBundlePayloadRow> containerPayloads = payloadsByContainer[container.Id]; if (!containerPayloads.Any()) { if (container.Id != Compiler.BurnDefaultAttachedContainerId) { // TODO: display warning that we're ignoring container that ended up with no paylods in it. } } else if (Compiler.BurnUXContainerId == container.Id) { container.WorkingPath = Path.Combine(this.IntermediateFolder, container.Name); container.AttachedContainerIndex = 0; // Gather the list of UX payloads but ensure the BootstrapperApplication Payload is the first // in the list since that is the Payload that Burn attempts to load. List <WixBundlePayloadRow> uxPayloads = new List <WixBundlePayloadRow>(); string baPayloadId = baRow.FieldAsString(0); foreach (WixBundlePayloadRow uxPayload in containerPayloads) { if (uxPayload.Id == baPayloadId) { uxPayloads.Insert(0, uxPayload); } else { uxPayloads.Add(uxPayload); } } uxContainerPayloads = uxPayloads; } else { container.WorkingPath = Path.Combine(this.IntermediateFolder, container.Name); // Add detached containers to the list of file transfers. if (ContainerType.Detached == container.Type) { FileTransfer transfer; if (FileTransfer.TryCreate(container.WorkingPath, Path.Combine(layoutDirectory, container.Name), true, "Container", container.SourceLineNumbers, out transfer)) { transfer.Built = true; fileTransfers.Add(transfer); } } else // update the attached container index. { Debug.Assert(ContainerType.Attached == container.Type); container.AttachedContainerIndex = attachedContainerIndex; ++attachedContainerIndex; } this.CreateContainer(container, containerPayloads, null); } } // Create the bundle manifest then UX container. string manifestPath = Path.Combine(this.IntermediateFolder, "bundle-manifest.xml"); { var command = new CreateBurnManifestCommand(); command.BackendExtensions = this.BackendExtensions; command.Output = this.Output; command.BundleInfo = bundleRow; command.Chain = chainRow; command.Containers = containers; command.Catalogs = catalogs; command.ExecutableName = Path.GetFileName(this.OutputPath); command.OrderedPackages = orderedFacades; command.OutputPath = manifestPath; command.RollbackBoundaries = boundaries; command.OrderedSearches = orderedSearches; command.Payloads = payloads; command.UXContainerPayloads = uxContainerPayloads; command.Execute(); } WixBundleContainerRow uxContainer = containers[Compiler.BurnUXContainerId]; this.CreateContainer(uxContainer, uxContainerPayloads, manifestPath); // Copy the burn.exe to a writable location then mark it to be moved to its final build location. Note // that today, the x64 Burn uses the x86 stub. string stubPlatform = (Platform.X64 == bundleRow.Platform) ? "x86" : bundleRow.Platform.ToString(); string stubFile = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), stubPlatform, "burn.exe"); string bundleTempPath = Path.Combine(this.IntermediateFolder, Path.GetFileName(this.OutputPath)); Messaging.Instance.OnMessage(WixVerboses.GeneratingBundle(bundleTempPath, stubFile)); string bundleFilename = Path.GetFileName(this.OutputPath); if ("setup.exe".Equals(bundleFilename, StringComparison.OrdinalIgnoreCase)) { Messaging.Instance.OnMessage(WixErrors.InsecureBundleFilename(bundleFilename)); } FileTransfer bundleTransfer; if (FileTransfer.TryCreate(bundleTempPath, this.OutputPath, true, "Bundle", bundleRow.SourceLineNumbers, out bundleTransfer)) { bundleTransfer.Built = true; fileTransfers.Add(bundleTransfer); } File.Copy(stubFile, bundleTempPath, true); File.SetAttributes(bundleTempPath, FileAttributes.Normal); this.UpdateBurnResources(bundleTempPath, this.OutputPath, bundleRow); // Update the .wixburn section to point to at the UX and attached container(s) then attach the containers // if they should be attached. using (BurnWriter writer = BurnWriter.Open(bundleTempPath)) { FileInfo burnStubFile = new FileInfo(bundleTempPath); writer.InitializeBundleSectionData(burnStubFile.Length, bundleRow.BundleId); // Always attach the UX container first writer.AppendContainer(uxContainer.WorkingPath, BurnWriter.Container.UX); // Now append all other attached containers foreach (WixBundleContainerRow container in containers.Values) { if (ContainerType.Attached == container.Type) { // The container was only created if it had payloads. if (!String.IsNullOrEmpty(container.WorkingPath) && Compiler.BurnUXContainerId != container.Id) { writer.AppendContainer(container.WorkingPath, BurnWriter.Container.Attached); } } } } if (null != this.PdbFile) { Pdb pdb = new Pdb(); pdb.Output = Output; pdb.Save(this.PdbFile); } this.FileTransfers = fileTransfers; this.ContentFilePaths = payloads.Values.Where(p => p.ContentFile).Select(p => p.FullFileName).ToList(); }
private long ImportExternalFileAsPayloadsAndReturnInstallSize(Dtf.Database db, WixBundlePayloadRow packagePayload, bool longNamesInImage, bool compressed, ISet <string> payloadNames) { long size = 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 (Dtf.View view = db.OpenView("SELECT `Directory`, `Directory_Parent`, `DefaultDir` FROM `Directory`")) { view.Execute(); while (true) { using (Dtf.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 (Dtf.View view = db.OpenView("SELECT `Directory_`, `File`, `FileName`, `File`.`Attributes`, `FileSize` FROM `Component`, `File` WHERE `Component`.`Component`=`File`.`Component_`")) { view.Execute(); while (true) { using (Dtf.Record record = view.Fetch()) { if (null == record) { break; } // Skip adding the loose files as payloads if it was suppressed. if (!this.Facade.MsiPackage.SuppressLooseFilePayloadGeneration) { // 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 fileSourcePath = Binder.GetFileSourcePath(directories, record.GetString(1), record.GetString(3), compressed, longNamesInImage); string name = Path.Combine(Path.GetDirectoryName(packagePayload.Name), fileSourcePath); if (!payloadNames.Contains(name)) { string generatedId = Common.GenerateIdentifier("f", packagePayload.Id, record.GetString(2)); string payloadSourceFile = FileManager.ResolveRelatedFile(packagePayload.UnresolvedSourceFile, fileSourcePath, "File", this.Facade.Package.SourceLineNumbers, BindStage.Normal); WixBundlePayloadRow payload = (WixBundlePayloadRow)this.PayloadTable.CreateRow(this.Facade.Package.SourceLineNumbers); payload.Id = generatedId; payload.Name = name; payload.SourceFile = payloadSourceFile; payload.Compressed = packagePayload.Compressed; payload.UnresolvedSourceFile = name; payload.Package = packagePayload.Package; payload.Container = packagePayload.Container; payload.ContentFile = true; payload.EnableSignatureValidation = packagePayload.EnableSignatureValidation; payload.Packaging = packagePayload.Packaging; payload.ParentPackagePayload = packagePayload.Id; } } } size += record.GetInteger(5); } } } } return(size); }
/// <summary> /// Processes the MSI packages to add properties and payloads from the MSI packages. /// </summary> public void Execute() { WixBundlePayloadRow packagePayload = this.AuthoredPayloads.Get(this.Facade.Package.PackagePayload); string sourcePath = packagePayload.FullFileName; bool longNamesInImage = false; bool compressed = false; bool x64 = false; try { // Read data out of the msi database... using (Dtf.SummaryInfo 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); x64 = (sumInfo.Template.Contains("x64") || sumInfo.Template.Contains("Intel64")); // 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.Facade.Package.PerMachine = (0 == (sumInfo.WordCount & 8)) ? YesNoDefaultType.Yes : YesNoDefaultType.No; this.Facade.Package.x64 = x64 ? YesNoType.Yes : YesNoType.No; } using (Dtf.Database db = new Dtf.Database(sourcePath)) { this.Facade.MsiPackage.ProductCode = ProcessMsiPackageCommand.GetProperty(db, "ProductCode"); this.Facade.MsiPackage.UpgradeCode = ProcessMsiPackageCommand.GetProperty(db, "UpgradeCode"); this.Facade.MsiPackage.Manufacturer = ProcessMsiPackageCommand.GetProperty(db, "Manufacturer"); this.Facade.MsiPackage.ProductLanguage = Convert.ToInt32(ProcessMsiPackageCommand.GetProperty(db, "ProductLanguage"), CultureInfo.InvariantCulture); this.Facade.MsiPackage.ProductVersion = ProcessMsiPackageCommand.GetProperty(db, "ProductVersion"); if (!Common.IsValidModuleOrBundleVersion(this.Facade.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 = this.Facade.MsiPackage.ProductVersion.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)) { Messaging.Instance.OnMessage(WixWarnings.VersionTruncated(this.Facade.Package.SourceLineNumbers, this.Facade.MsiPackage.ProductVersion, sourcePath, version)); this.Facade.MsiPackage.ProductVersion = version; } else { Messaging.Instance.OnMessage(WixErrors.InvalidProductVersion(this.Facade.Package.SourceLineNumbers, this.Facade.MsiPackage.ProductVersion, sourcePath)); } } if (String.IsNullOrEmpty(this.Facade.Package.CacheId)) { this.Facade.Package.CacheId = String.Format("{0}v{1}", this.Facade.MsiPackage.ProductCode, this.Facade.MsiPackage.ProductVersion); } if (String.IsNullOrEmpty(this.Facade.Package.DisplayName)) { this.Facade.Package.DisplayName = ProcessMsiPackageCommand.GetProperty(db, "ProductName"); } if (String.IsNullOrEmpty(this.Facade.Package.Description)) { this.Facade.Package.Description = ProcessMsiPackageCommand.GetProperty(db, "ARPCOMMENTS"); } ISet <string> payloadNames = this.GetPayloadTargetNames(); ISet <string> msiPropertyNames = this.GetMsiPropertyNames(); this.SetPerMachineAppropriately(db, sourcePath); // Ensure the MSI package is appropriately marked visible or not. this.SetPackageVisibility(db, 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("MSIFASTINSTALL", "7"); } this.CreateRelatedPackages(db); // If feature selection is enabled, represent the Feature table in the manifest. if (this.Facade.MsiPackage.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.Package.InstallSize = this.ImportExternalFileAsPayloadsAndReturnInstallSize(db, packagePayload, longNamesInImage, compressed, payloadNames); // Add all dependency providers from the MSI. this.ImportDependencyProviders(db); } } catch (Dtf.InstallerException e) { Messaging.Instance.OnMessage(WixErrors.UnableToReadPackageInformation(this.Facade.Package.SourceLineNumbers, sourcePath, e.Message)); } }
private void GenerateBAManifestPackageTables() { Table wixPackagePropertiesTable = this.Output.EnsureTable(this.TableDefinitions["WixPackageProperties"]); foreach (PackageFacade package in this.ChainPackages) { WixBundlePayloadRow packagePayload = this.Payloads[package.Package.PackagePayload]; Row row = wixPackagePropertiesTable.CreateRow(package.Package.SourceLineNumbers); row[0] = package.Package.WixChainItemId; row[1] = (YesNoType.Yes == package.Package.Vital) ? "yes" : "no"; row[2] = package.Package.DisplayName; row[3] = package.Package.Description; row[4] = package.Package.Size.ToString(CultureInfo.InvariantCulture); // TODO: DownloadSize (compressed) (what does this mean when it's embedded?) row[5] = package.Package.Size.ToString(CultureInfo.InvariantCulture); // Package.Size (uncompressed) row[6] = package.Package.InstallSize.Value.ToString(CultureInfo.InvariantCulture); // InstallSize (required disk space) row[7] = package.Package.Type.ToString(CultureInfo.InvariantCulture); row[8] = package.Package.Permanent ? "yes" : "no"; row[9] = package.Package.LogPathVariable; row[10] = package.Package.RollbackLogPathVariable; row[11] = (PackagingType.Embedded == packagePayload.Packaging) ? "yes" : "no"; if (WixBundlePackageType.Msi == package.Package.Type) { row[12] = package.MsiPackage.DisplayInternalUI ? "yes" : "no"; if (!String.IsNullOrEmpty(package.MsiPackage.ProductCode)) { row[13] = package.MsiPackage.ProductCode; } if (!String.IsNullOrEmpty(package.MsiPackage.UpgradeCode)) { row[14] = package.MsiPackage.UpgradeCode; } } else if (WixBundlePackageType.Msp == package.Package.Type) { row[12] = package.MspPackage.DisplayInternalUI ? "yes" : "no"; if (!String.IsNullOrEmpty(package.MspPackage.PatchCode)) { row[13] = package.MspPackage.PatchCode; } } if (!String.IsNullOrEmpty(package.Package.Version)) { row[15] = package.Package.Version; } if (!String.IsNullOrEmpty(package.Package.InstallCondition)) { row[16] = package.Package.InstallCondition; } switch (package.Package.Cache) { case YesNoAlwaysType.No: row[17] = "no"; break; case YesNoAlwaysType.Yes: row[17] = "yes"; break; case YesNoAlwaysType.Always: row[17] = "always"; break; } } }