Exemplo n.º 1
0
        /// <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);
        }
Exemplo n.º 2
0
        public void Execute()
        {
            using (XmlTextWriter writer = new XmlTextWriter(this.OutputPath, Encoding.UTF8))
            {
                writer.WriteStartDocument();

                writer.WriteStartElement("BurnManifest", BurnCommon.BurnNamespace);

                // Write the condition, if there is one
                if (null != this.BundleInfo.Condition)
                {
                    writer.WriteElementString("Condition", this.BundleInfo.Condition);
                }

                // Write the log element if default logging wasn't disabled.
                if (!String.IsNullOrEmpty(this.BundleInfo.LogPrefix))
                {
                    writer.WriteStartElement("Log");
                    if (!String.IsNullOrEmpty(this.BundleInfo.LogPathVariable))
                    {
                        writer.WriteAttributeString("PathVariable", this.BundleInfo.LogPathVariable);
                    }
                    writer.WriteAttributeString("Prefix", this.BundleInfo.LogPrefix);
                    writer.WriteAttributeString("Extension", this.BundleInfo.LogExtension);
                    writer.WriteEndElement();
                }


                // Get update if specified.
                WixBundleUpdateRow updateRow = this.Output.Tables["WixBundleUpdate"].RowsAs <WixBundleUpdateRow>().FirstOrDefault();

                if (null != updateRow)
                {
                    writer.WriteStartElement("Update");
                    writer.WriteAttributeString("Location", updateRow.Location);
                    writer.WriteEndElement(); // </Update>
                }

                // Write the RelatedBundle elements

                // For the related bundles with duplicated identifiers the second instance is ignored (i.e. the Duplicates
                // enumeration in the index row list is not used).
                RowIndexedList <WixRelatedBundleRow> relatedBundles = new RowIndexedList <WixRelatedBundleRow>(this.Output.Tables["WixRelatedBundle"]);

                foreach (WixRelatedBundleRow relatedBundle in relatedBundles)
                {
                    writer.WriteStartElement("RelatedBundle");
                    writer.WriteAttributeString("Id", relatedBundle.Id);
                    writer.WriteAttributeString("Action", Convert.ToString(relatedBundle.Action, CultureInfo.InvariantCulture));
                    writer.WriteEndElement();
                }

                // Write the variables
                IEnumerable <WixBundleVariableRow> variables = this.Output.Tables["WixBundleVariable"].RowsAs <WixBundleVariableRow>();

                foreach (WixBundleVariableRow variable in variables)
                {
                    writer.WriteStartElement("Variable");
                    writer.WriteAttributeString("Id", variable.Id);
                    if (null != variable.Type)
                    {
                        writer.WriteAttributeString("Value", variable.Value);
                        writer.WriteAttributeString("Type", variable.Type);
                    }
                    writer.WriteAttributeString("Hidden", variable.Hidden ? "yes" : "no");
                    writer.WriteAttributeString("Persisted", variable.Persisted ? "yes" : "no");
                    writer.WriteEndElement();
                }

                // Write the searches
                foreach (WixSearchInfo searchinfo in this.OrderedSearches)
                {
                    searchinfo.WriteXml(writer);
                }

                // write the UX element
                writer.WriteStartElement("UX");
                if (!String.IsNullOrEmpty(this.BundleInfo.SplashScreenBitmapPath))
                {
                    writer.WriteAttributeString("SplashScreen", "yes");
                }

                // write the UX allPayloads...
                foreach (WixBundlePayloadRow payload in this.UXContainerPayloads)
                {
                    writer.WriteStartElement("Payload");
                    this.WriteBurnManifestPayloadAttributes(writer, payload, true, this.Payloads);
                    writer.WriteEndElement();
                }

                writer.WriteEndElement(); // </UX>

                // write the catalog elements
                if (this.Catalogs.Any())
                {
                    foreach (WixBundleCatalogRow catalog in this.Catalogs)
                    {
                        writer.WriteStartElement("Catalog");
                        writer.WriteAttributeString("Id", catalog.Id);
                        writer.WriteAttributeString("Payload", catalog.Payload);
                        writer.WriteEndElement();
                    }
                }

                foreach (WixBundleContainerRow container in this.Containers.Values)
                {
                    if (!String.IsNullOrEmpty(container.WorkingPath) && Compiler.BurnUXContainerId != container.Id)
                    {
                        writer.WriteStartElement("Container");
                        this.WriteBurnManifestContainerAttributes(writer, this.ExecutableName, container);
                        writer.WriteEndElement();
                    }
                }

                foreach (WixBundlePayloadRow payload in this.Payloads.Values)
                {
                    if (PackagingType.Embedded == payload.Packaging && Compiler.BurnUXContainerId != payload.Container)
                    {
                        writer.WriteStartElement("Payload");
                        this.WriteBurnManifestPayloadAttributes(writer, payload, true, this.Payloads);
                        writer.WriteEndElement();
                    }
                    else if (PackagingType.External == payload.Packaging)
                    {
                        writer.WriteStartElement("Payload");
                        this.WriteBurnManifestPayloadAttributes(writer, payload, false, this.Payloads);
                        writer.WriteEndElement();
                    }
                }

                foreach (WixBundleRollbackBoundaryRow rollbackBoundary in this.RollbackBoundaries)
                {
                    writer.WriteStartElement("RollbackBoundary");
                    writer.WriteAttributeString("Id", rollbackBoundary.ChainPackageId);
                    writer.WriteAttributeString("Vital", YesNoType.Yes == rollbackBoundary.Vital ? "yes" : "no");
                    writer.WriteAttributeString("Transaction", YesNoType.Yes == rollbackBoundary.Transaction ? "yes" : "no");
                    writer.WriteEndElement();
                }

                // Write the registration information...
                writer.WriteStartElement("Registration");

                writer.WriteAttributeString("Id", this.BundleInfo.BundleId.ToString("B"));
                writer.WriteAttributeString("ExecutableName", this.ExecutableName);
                writer.WriteAttributeString("PerMachine", this.BundleInfo.PerMachine ? "yes" : "no");
                writer.WriteAttributeString("Tag", this.BundleInfo.Tag);
                writer.WriteAttributeString("Version", this.BundleInfo.Version);
                writer.WriteAttributeString("ProviderKey", this.BundleInfo.ProviderKey);

                writer.WriteStartElement("Arp");
                writer.WriteAttributeString("Register", (0 < this.BundleInfo.DisableModify && this.BundleInfo.DisableRemove) ? "no" : "yes"); // do not register if disabled modify and remove.
                writer.WriteAttributeString("DisplayName", this.BundleInfo.Name);
                writer.WriteAttributeString("DisplayVersion", this.BundleInfo.Version);

                if (!String.IsNullOrEmpty(this.BundleInfo.Publisher))
                {
                    writer.WriteAttributeString("Publisher", this.BundleInfo.Publisher);
                }

                if (!String.IsNullOrEmpty(this.BundleInfo.HelpLink))
                {
                    writer.WriteAttributeString("HelpLink", this.BundleInfo.HelpLink);
                }

                if (!String.IsNullOrEmpty(this.BundleInfo.HelpTelephone))
                {
                    writer.WriteAttributeString("HelpTelephone", this.BundleInfo.HelpTelephone);
                }

                if (!String.IsNullOrEmpty(this.BundleInfo.AboutUrl))
                {
                    writer.WriteAttributeString("AboutUrl", this.BundleInfo.AboutUrl);
                }

                if (!String.IsNullOrEmpty(this.BundleInfo.UpdateUrl))
                {
                    writer.WriteAttributeString("UpdateUrl", this.BundleInfo.UpdateUrl);
                }

                if (!String.IsNullOrEmpty(this.BundleInfo.ParentName))
                {
                    writer.WriteAttributeString("ParentDisplayName", this.BundleInfo.ParentName);
                }

                if (1 == this.BundleInfo.DisableModify)
                {
                    writer.WriteAttributeString("DisableModify", "yes");
                }
                else if (2 == this.BundleInfo.DisableModify)
                {
                    writer.WriteAttributeString("DisableModify", "button");
                }

                if (this.BundleInfo.DisableRemove)
                {
                    writer.WriteAttributeString("DisableRemove", "yes");
                }
                writer.WriteEndElement(); // </Arp>

                // Get update registration if specified.
                WixUpdateRegistrationRow updateRegistrationInfo = this.Output.Tables["WixUpdateRegistration"].RowsAs <WixUpdateRegistrationRow>().FirstOrDefault();

                if (null != updateRegistrationInfo)
                {
                    writer.WriteStartElement("Update"); // <Update>
                    writer.WriteAttributeString("Manufacturer", updateRegistrationInfo.Manufacturer);

                    if (!String.IsNullOrEmpty(updateRegistrationInfo.Department))
                    {
                        writer.WriteAttributeString("Department", updateRegistrationInfo.Department);
                    }

                    if (!String.IsNullOrEmpty(updateRegistrationInfo.ProductFamily))
                    {
                        writer.WriteAttributeString("ProductFamily", updateRegistrationInfo.ProductFamily);
                    }

                    writer.WriteAttributeString("Name", updateRegistrationInfo.Name);
                    writer.WriteAttributeString("Classification", updateRegistrationInfo.Classification);
                    writer.WriteEndElement(); // </Update>
                }

                IEnumerable <Row> bundleTags = this.Output.Tables["WixBundleTag"].RowsAs <Row>();

                foreach (Row row in bundleTags)
                {
                    writer.WriteStartElement("SoftwareTag");
                    writer.WriteAttributeString("Filename", (string)row[0]);
                    writer.WriteAttributeString("Regid", (string)row[1]);
                    writer.WriteCData((string)row[4]);
                    writer.WriteEndElement();
                }

                writer.WriteEndElement(); // </Register>

                // write the Chain...
                writer.WriteStartElement("Chain");
                if (this.Chain.DisableRollback)
                {
                    writer.WriteAttributeString("DisableRollback", "yes");
                }

                if (this.Chain.DisableSystemRestore)
                {
                    writer.WriteAttributeString("DisableSystemRestore", "yes");
                }

                if (this.Chain.ParallelCache)
                {
                    writer.WriteAttributeString("ParallelCache", "yes");
                }

                // Index a few tables by package.
                ILookup <string, WixBundlePatchTargetCodeRow>    targetCodesByPatch       = this.Output.Tables["WixBundlePatchTargetCode"].RowsAs <WixBundlePatchTargetCodeRow>().ToLookup(r => r.MspPackageId);
                ILookup <string, WixBundleMsiFeatureRow>         msiFeaturesByPackage     = this.Output.Tables["WixBundleMsiFeature"].RowsAs <WixBundleMsiFeatureRow>().ToLookup(r => r.ChainPackageId);
                ILookup <string, WixBundleMsiPropertyRow>        msiPropertiesByPackage   = this.Output.Tables["WixBundleMsiProperty"].RowsAs <WixBundleMsiPropertyRow>().ToLookup(r => r.ChainPackageId);
                ILookup <string, WixBundlePayloadRow>            payloadsByPackage        = this.Payloads.Values.ToLookup(p => p.Package);
                ILookup <string, WixBundleRelatedPackageRow>     relatedPackagesByPackage = this.Output.Tables["WixBundleRelatedPackage"].RowsAs <WixBundleRelatedPackageRow>().ToLookup(r => r.ChainPackageId);
                ILookup <string, WixBundleSlipstreamMspRow>      slipstreamMspsByPackage  = this.Output.Tables["WixBundleSlipstreamMsp"].RowsAs <WixBundleSlipstreamMspRow>().ToLookup(r => r.ChainPackageId);
                ILookup <string, WixBundlePackageExitCodeRow>    exitCodesByPackage       = this.Output.Tables["WixBundlePackageExitCode"].RowsAs <WixBundlePackageExitCodeRow>().ToLookup(r => r.ChainPackageId);
                ILookup <string, WixBundlePackageCommandLineRow> commandLinesByPackage    = this.Output.Tables["WixBundlePackageCommandLine"].RowsAs <WixBundlePackageCommandLineRow>().ToLookup(r => r.ChainPackageId);

                // Build up the list of target codes from all the MSPs in the chain.
                List <WixBundlePatchTargetCodeRow> targetCodes = new List <WixBundlePatchTargetCodeRow>();

                foreach (PackageFacade package in this.OrderedPackages)
                {
                    writer.WriteStartElement(String.Format(CultureInfo.InvariantCulture, "{0}Package", package.Package.Type));

                    writer.WriteAttributeString("Id", package.Package.WixChainItemId);

                    switch (package.Package.Cache)
                    {
                    case YesNoAlwaysType.No:
                        writer.WriteAttributeString("Cache", "no");
                        break;

                    case YesNoAlwaysType.Yes:
                        writer.WriteAttributeString("Cache", "yes");
                        break;

                    case YesNoAlwaysType.Always:
                        writer.WriteAttributeString("Cache", "always");
                        break;
                    }

                    writer.WriteAttributeString("CacheId", package.Package.CacheId);
                    writer.WriteAttributeString("InstallSize", Convert.ToString(package.Package.InstallSize));
                    writer.WriteAttributeString("Size", Convert.ToString(package.Package.Size));
                    writer.WriteAttributeString("PerMachine", YesNoDefaultType.Yes == package.Package.PerMachine ? "yes" : "no");
                    writer.WriteAttributeString("Permanent", package.Package.Permanent ? "yes" : "no");
                    writer.WriteAttributeString("Vital", (YesNoType.Yes == package.Package.Vital) ? "yes" : "no");

                    if (null != package.Package.RollbackBoundary)
                    {
                        writer.WriteAttributeString("RollbackBoundaryForward", package.Package.RollbackBoundary);
                    }

                    if (!String.IsNullOrEmpty(package.Package.RollbackBoundaryBackward))
                    {
                        writer.WriteAttributeString("RollbackBoundaryBackward", package.Package.RollbackBoundaryBackward);
                    }

                    if (!String.IsNullOrEmpty(package.Package.LogPathVariable))
                    {
                        writer.WriteAttributeString("LogPathVariable", package.Package.LogPathVariable);
                    }

                    if (!String.IsNullOrEmpty(package.Package.RollbackLogPathVariable))
                    {
                        writer.WriteAttributeString("RollbackLogPathVariable", package.Package.RollbackLogPathVariable);
                    }

                    if (!String.IsNullOrEmpty(package.Package.InstallCondition))
                    {
                        writer.WriteAttributeString("InstallCondition", package.Package.InstallCondition);
                    }

                    if (WixBundlePackageType.Exe == package.Package.Type)
                    {
                        writer.WriteAttributeString("DetectCondition", package.ExePackage.DetectCondition);
                        writer.WriteAttributeString("InstallArguments", package.ExePackage.InstallCommand);
                        writer.WriteAttributeString("UninstallArguments", package.ExePackage.UninstallCommand);
                        writer.WriteAttributeString("RepairArguments", package.ExePackage.RepairCommand);
                        writer.WriteAttributeString("Repairable", package.ExePackage.Repairable ? "yes" : "no");
                        if (!String.IsNullOrEmpty(package.ExePackage.ExeProtocol))
                        {
                            writer.WriteAttributeString("Protocol", package.ExePackage.ExeProtocol);
                        }
                    }
                    else if (WixBundlePackageType.Msi == package.Package.Type)
                    {
                        writer.WriteAttributeString("ProductCode", package.MsiPackage.ProductCode);
                        writer.WriteAttributeString("Language", package.MsiPackage.ProductLanguage.ToString(CultureInfo.InvariantCulture));
                        writer.WriteAttributeString("Version", package.MsiPackage.ProductVersion);
                        writer.WriteAttributeString("DisplayInternalUI", package.MsiPackage.DisplayInternalUI ? "yes" : "no");
                        if (!String.IsNullOrEmpty(package.MsiPackage.UpgradeCode))
                        {
                            writer.WriteAttributeString("UpgradeCode", package.MsiPackage.UpgradeCode);
                        }
                    }
                    else if (WixBundlePackageType.Msp == package.Package.Type)
                    {
                        writer.WriteAttributeString("PatchCode", package.MspPackage.PatchCode);
                        writer.WriteAttributeString("PatchXml", package.MspPackage.PatchXml);
                        writer.WriteAttributeString("DisplayInternalUI", package.MspPackage.DisplayInternalUI ? "yes" : "no");

                        // If there is still a chance that all of our patches will target a narrow set of
                        // product codes, add the patch list to the overall list.
                        if (null != targetCodes)
                        {
                            if (!package.MspPackage.TargetUnspecified)
                            {
                                IEnumerable <WixBundlePatchTargetCodeRow> patchTargetCodes = targetCodesByPatch[package.MspPackage.ChainPackageId];

                                targetCodes.AddRange(patchTargetCodes);
                            }
                            else // we have a patch that targets the world, so throw the whole list away.
                            {
                                targetCodes = null;
                            }
                        }
                    }
                    else if (WixBundlePackageType.Msu == package.Package.Type)
                    {
                        writer.WriteAttributeString("DetectCondition", package.MsuPackage.DetectCondition);
                        writer.WriteAttributeString("KB", package.MsuPackage.MsuKB);
                    }

                    IEnumerable <WixBundleMsiFeatureRow> packageMsiFeatures = msiFeaturesByPackage[package.Package.WixChainItemId];

                    foreach (WixBundleMsiFeatureRow feature in packageMsiFeatures)
                    {
                        writer.WriteStartElement("MsiFeature");
                        writer.WriteAttributeString("Id", feature.Name);
                        writer.WriteEndElement();
                    }

                    IEnumerable <WixBundleMsiPropertyRow> packageMsiProperties = msiPropertiesByPackage[package.Package.WixChainItemId];

                    foreach (WixBundleMsiPropertyRow msiProperty in packageMsiProperties)
                    {
                        writer.WriteStartElement("MsiProperty");
                        writer.WriteAttributeString("Id", msiProperty.Name);
                        writer.WriteAttributeString("Value", msiProperty.Value);
                        if (!String.IsNullOrEmpty(msiProperty.Condition))
                        {
                            writer.WriteAttributeString("Condition", msiProperty.Condition);
                        }
                        writer.WriteEndElement();
                    }

                    IEnumerable <WixBundleSlipstreamMspRow> packageSlipstreamMsps = slipstreamMspsByPackage[package.Package.WixChainItemId];

                    foreach (WixBundleSlipstreamMspRow slipstreamMsp in packageSlipstreamMsps)
                    {
                        writer.WriteStartElement("SlipstreamMsp");
                        writer.WriteAttributeString("Id", slipstreamMsp.MspPackageId);
                        writer.WriteEndElement();
                    }

                    IEnumerable <WixBundlePackageExitCodeRow> packageExitCodes = exitCodesByPackage[package.Package.WixChainItemId];

                    foreach (WixBundlePackageExitCodeRow exitCode in packageExitCodes)
                    {
                        writer.WriteStartElement("ExitCode");

                        if (exitCode.Code.HasValue)
                        {
                            writer.WriteAttributeString("Code", unchecked ((uint)exitCode.Code).ToString(CultureInfo.InvariantCulture));
                        }
                        else
                        {
                            writer.WriteAttributeString("Code", "*");
                        }

                        writer.WriteAttributeString("Type", ((int)exitCode.Behavior).ToString(CultureInfo.InvariantCulture));
                        writer.WriteEndElement();
                    }

                    IEnumerable <WixBundlePackageCommandLineRow> packageCommandLines = commandLinesByPackage[package.Package.WixChainItemId];

                    foreach (WixBundlePackageCommandLineRow commandLine in packageCommandLines)
                    {
                        writer.WriteStartElement("CommandLine");
                        writer.WriteAttributeString("InstallArgument", commandLine.InstallArgument);
                        writer.WriteAttributeString("UninstallArgument", commandLine.UninstallArgument);
                        writer.WriteAttributeString("RepairArgument", commandLine.RepairArgument);
                        writer.WriteAttributeString("Condition", commandLine.Condition);
                        writer.WriteEndElement();
                    }

                    // Output the dependency information.
                    foreach (ProvidesDependency dependency in package.Provides)
                    {
                        // TODO: Add to wixpdb as an imported table, or link package wixpdbs to bundle wixpdbs.
                        dependency.WriteXml(writer);
                    }

                    IEnumerable <WixBundleRelatedPackageRow> packageRelatedPackages = relatedPackagesByPackage[package.Package.WixChainItemId];

                    foreach (WixBundleRelatedPackageRow related in packageRelatedPackages)
                    {
                        writer.WriteStartElement("RelatedPackage");
                        writer.WriteAttributeString("Id", related.Id);
                        if (!String.IsNullOrEmpty(related.MinVersion))
                        {
                            writer.WriteAttributeString("MinVersion", related.MinVersion);
                            writer.WriteAttributeString("MinInclusive", related.MinInclusive ? "yes" : "no");
                        }
                        if (!String.IsNullOrEmpty(related.MaxVersion))
                        {
                            writer.WriteAttributeString("MaxVersion", related.MaxVersion);
                            writer.WriteAttributeString("MaxInclusive", related.MaxInclusive ? "yes" : "no");
                        }
                        writer.WriteAttributeString("OnlyDetect", related.OnlyDetect ? "yes" : "no");

                        string[] relatedLanguages = related.Languages.Split(new[] { ',' }, StringSplitOptions.RemoveEmptyEntries);

                        if (0 < relatedLanguages.Length)
                        {
                            writer.WriteAttributeString("LangInclusive", related.LangInclusive ? "yes" : "no");
                            foreach (string language in relatedLanguages)
                            {
                                writer.WriteStartElement("Language");
                                writer.WriteAttributeString("Id", language);
                                writer.WriteEndElement();
                            }
                        }
                        writer.WriteEndElement();
                    }

                    // Write any contained Payloads with the PackagePayload being first
                    writer.WriteStartElement("PayloadRef");
                    writer.WriteAttributeString("Id", package.Package.PackagePayload);
                    writer.WriteEndElement();

                    IEnumerable <WixBundlePayloadRow> packagePayloads = payloadsByPackage[package.Package.WixChainItemId];

                    foreach (WixBundlePayloadRow payload in packagePayloads)
                    {
                        if (payload.Id != package.Package.PackagePayload)
                        {
                            writer.WriteStartElement("PayloadRef");
                            writer.WriteAttributeString("Id", payload.Id);
                            writer.WriteEndElement();
                        }
                    }

                    writer.WriteEndElement(); // </XxxPackage>
                }
                writer.WriteEndElement();     // </Chain>

                if (null != targetCodes)
                {
                    foreach (WixBundlePatchTargetCodeRow targetCode in targetCodes)
                    {
                        writer.WriteStartElement("PatchTargetCode");
                        writer.WriteAttributeString("TargetCode", targetCode.TargetCode);
                        writer.WriteAttributeString("Product", targetCode.TargetsProductCode ? "yes" : "no");
                        writer.WriteEndElement();
                    }
                }

                // Write the ApprovedExeForElevation elements.
                IEnumerable <WixApprovedExeForElevationRow> approvedExesForElevation = this.Output.Tables["WixApprovedExeForElevation"].RowsAs <WixApprovedExeForElevationRow>();

                foreach (WixApprovedExeForElevationRow approvedExeForElevation in approvedExesForElevation)
                {
                    writer.WriteStartElement("ApprovedExeForElevation");
                    writer.WriteAttributeString("Id", approvedExeForElevation.Id);
                    writer.WriteAttributeString("Key", approvedExeForElevation.Key);

                    if (!String.IsNullOrEmpty(approvedExeForElevation.ValueName))
                    {
                        writer.WriteAttributeString("ValueName", approvedExeForElevation.ValueName);
                    }

                    if (approvedExeForElevation.Win64)
                    {
                        writer.WriteAttributeString("Win64", "yes");
                    }

                    writer.WriteEndElement();
                }

                writer.WriteEndDocument(); // </BurnManifest>
            }
        }