private async Task AdjustManifest(XDocument template, AppxManifestCreatorOptions config, DirectoryInfo baseDirectory, string[] entryPoints) { XNamespace nsUap = "http://schemas.microsoft.com/appx/manifest/uap/windows10"; XNamespace nsUap4 = "http://schemas.microsoft.com/appx/manifest/uap/windows10/4"; XNamespace nsUap6 = "http://schemas.microsoft.com/appx/manifest/uap/windows10/6"; XNamespace defaultNamespace = "http://schemas.microsoft.com/appx/manifest/foundation/windows10"; var root = template.Root; if (root == null) { root = new XElement(defaultNamespace + "Package"); template.Add(root); } else { defaultNamespace = root.GetDefaultNamespace(); } // Add capability var addCapability = new AddCapability("runFullTrust"); var capabilityExecutor = new AddCapabilityExecutor(template); await capabilityExecutor.Execute(addCapability).ConfigureAwait(false); // Set identity var setIdentity = new SetPackageIdentity { Name = config.PackageName, Publisher = config.PublisherName, ProcessorArchitecture = config.PackageArchitecture.ToString("G").ToLowerInvariant() }; var major = config.Version.Major; var minor = config.Version.Minor; var build = config.Version.Build; var revision = config.Version.Revision; if (major < 0) { throw new FormatException("Invalid version format, major version is required."); } if (minor < 0) { throw new FormatException("Invalid version format, major version is required."); } if (revision < 0) { revision = 0; } if (build < 0) { build = 0; } setIdentity.Version = new Version(major, minor, build, revision).ToString(); var executor = new SetPackageIdentityExecutor(template); await executor.Execute(setIdentity).ConfigureAwait(false); // Add namespaces (legacy) if (root.GetPrefixOfNamespace(nsUap) == null) { root.Add(new XAttribute(XNamespace.Xmlns + "uap", nsUap.NamespaceName)); } if (root.GetPrefixOfNamespace(nsUap4) == null) { root.Add(new XAttribute(XNamespace.Xmlns + "uap4", nsUap6.NamespaceName)); } if (root.GetPrefixOfNamespace(nsUap6) == null) { root.Add(new XAttribute(XNamespace.Xmlns + "uap6", nsUap6.NamespaceName)); } var package = GetOrCreateNode(template, "Package", defaultNamespace); var properties = GetOrCreateNode(package, "Properties", defaultNamespace); GetOrCreateNode(properties, "DisplayName", defaultNamespace).Value = config.PackageDisplayName ?? config.PackageName ?? "DisplayName"; GetOrCreateNode(properties, "Description", defaultNamespace).Value = config.PackageDisplayName ?? config.PackageName ?? "Description"; GetOrCreateNode(properties, "PublisherDisplayName", defaultNamespace).Value = config.PublisherDisplayName ?? config.PublisherName ?? "Publisher"; GetOrCreateNode(properties, "Logo", defaultNamespace).Value = "Assets\\Logo.png"; var applicationsNode = GetOrCreateNode(package, "Applications", defaultNamespace); var usedNames = new HashSet<string>(); foreach (var item in entryPoints) { var applicationNode = this.CreateApplicationNodeFromExe(baseDirectory, item); applicationsNode.Add(applicationNode); var idCandidate = Regex.Replace(Path.GetFileNameWithoutExtension(item), "[^a-zA-z0-9_]+", string.Empty); if (!usedNames.Add(idCandidate)) { var index = 1; var baseIdCandidate = idCandidate; while (!usedNames.Add(baseIdCandidate + "_" + index)) { index++; } idCandidate = baseIdCandidate + "_" + index; } applicationNode.SetAttributeValue("Id", idCandidate); } var branding = new MsixHeroBrandingInjector(); await branding.Inject(template, MsixHeroBrandingInjector.BrandingInjectorOverrideOption.PreferIncoming).ConfigureAwait(false); }
public async IAsyncEnumerable<CreatedItem> CreateManifestForDirectory( DirectoryInfo sourceDirectory, AppxManifestCreatorOptions options = default, [EnumeratorCancellation] CancellationToken cancellationToken = default, IProgress<Progress> progress = null) { options ??= AppxManifestCreatorOptions.Default; // Add logo to assets if there is nothing if (options.CreateLogo) { CreatedItem logo = default; foreach (var entryPoint in options.EntryPoints ?? Enumerable.Empty<string>()) { cancellationToken.ThrowIfCancellationRequested(); try { var entryPointPath = new FileInfo(Path.Combine(sourceDirectory.FullName, entryPoint)); if (entryPointPath.Exists) { logo = await this.CreateLogo(entryPointPath).ConfigureAwait(false); } } // ReSharper disable once EmptyGeneralCatchClause catch { } if (!default(CreatedItem).Equals(logo)) { break; } } if (default(CreatedItem).Equals(logo)) { logo = await this.CreateDefaultLogo(cancellationToken).ConfigureAwait(false); } yield return logo; } if (options.RegistryFile?.Exists == true) { await foreach (var registryItem in this.CreateRegistryEntries(options.RegistryFile).ConfigureAwait(false)) { cancellationToken.ThrowIfCancellationRequested(); if (!registryItem.Equals(default(CreatedItem))) { yield return registryItem; } } } // The actual part - create the manifest var modPackageTemplate = GetBundledResourcePath("ModificationPackage.AppxManifest.xml"); await using var openTemplate = File.OpenRead(modPackageTemplate); var xml = await XDocument.LoadAsync(openTemplate, LoadOptions.None, cancellationToken).ConfigureAwait(false); var entryPoints = options.EntryPoints; if (entryPoints?.Any() != true) { var getExeFiles = await this.GetEntryPointCandidates(sourceDirectory, cancellationToken).ConfigureAwait(false); entryPoints = getExeFiles.ToArray(); } if (options.EntryPoints?.Any() == true) { foreach (var entryPoint in options.EntryPoints) { cancellationToken.ThrowIfCancellationRequested(); ExceptionGuard.Guard(() => { var fvi = FileVersionInfo.GetVersionInfo(Path.Combine(sourceDirectory.FullName, entryPoint)); if (options.Version == null) { options.Version = Version.TryParse(fvi.ProductVersion ?? fvi.FileVersion ?? "#", out var v) ? v : null; } if (string.IsNullOrEmpty(options.PackageName) && !string.IsNullOrEmpty(Sanitize(fvi.ProductName))) { options.PackageName = Sanitize(fvi.ProductName, "ProductName")?.Trim(); } if (string.IsNullOrEmpty(options.PackageDisplayName) && !string.IsNullOrEmpty(fvi.ProductName)) { options.PackageDisplayName = fvi.ProductName?.Trim(); } if (string.IsNullOrEmpty(options.PublisherName) && !string.IsNullOrEmpty(Sanitize(fvi.CompanyName))) { options.PublisherName = "CN=" + Sanitize(fvi.CompanyName, "CompanyName"); } if (string.IsNullOrEmpty(options.PublisherDisplayName) && !string.IsNullOrEmpty(Sanitize(fvi.CompanyName))) { options.PublisherDisplayName = fvi.CompanyName?.Trim(); } }); if (options.Version != null && !string.IsNullOrEmpty(options.PublisherName) && !string.IsNullOrEmpty(options.PublisherDisplayName) && !string.IsNullOrEmpty(options.PackageName) && !string.IsNullOrEmpty(options.PackageDisplayName)) { break; } } } if (string.IsNullOrEmpty(options.PackageDisplayName)) { options.PackageDisplayName = "MyPackage"; } if (string.IsNullOrEmpty(options.PackageName)) { options.PackageName = "MyPackage"; } if (string.IsNullOrEmpty(options.PublisherName)) { options.PublisherName = "CN=Publisher"; } if (string.IsNullOrEmpty(options.PublisherDisplayName)) { options.PublisherDisplayName = "Publisher"; } if (options.Version == null) { options.Version = new Version(1, 0, 0); } await this.AdjustManifest(xml, options, sourceDirectory, entryPoints).ConfigureAwait(false); var manifestContent = xml.ToString(SaveOptions.OmitDuplicateNamespaces); var manifestFilePath = Path.Combine(Path.GetTempPath(), Path.GetFileName(FileConstants.AppxManifestFile) + "-" + Guid.NewGuid().ToString("N").Substring(0, 10) + ".xml"); await File.WriteAllTextAsync(manifestFilePath, manifestContent, Encoding.UTF8, cancellationToken); yield return CreatedItem.CreateManifest(manifestFilePath); }