| File: GenerateLauncher.cs | Web Access |
| Project: src\msbuild\src\Tasks\Microsoft.Build.Tasks.csproj (Microsoft.Build.Tasks.Core) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. using System; using System.IO; using System.Runtime.Versioning; using Microsoft.Build.Framework; using Microsoft.Build.Shared; using Microsoft.Build.Tasks.Deployment.Bootstrapper; using Microsoft.Build.Tasks.Deployment.ManifestUtilities; using Microsoft.Build.Utilities; using Constants = Microsoft.Build.Tasks.Deployment.ManifestUtilities.Constants; #nullable disable namespace Microsoft.Build.Tasks { /// <summary> /// Generates a bootstrapper for ClickOnce deployment projects. /// </summary> [MSBuildMultiThreadableTask] [SupportedOSPlatform("windows")] public sealed class GenerateLauncher : TaskExtension, IMultiThreadableTask { private const string LAUNCHER_EXE = "Launcher.exe"; private const string ENGINE_PATH = "Engine"; // relative to ClickOnce bootstrapper path #region Properties public TaskEnvironment TaskEnvironment { get; set; } = TaskEnvironment.Fallback; public ITaskItem EntryPoint { get; set; } public string LauncherPath { get; set; } public string OutputPath { get; set; } public string VisualStudioVersion { get; set; } public string AssemblyName { get; set; } [Output] public ITaskItem OutputEntryPoint { get; set; } #endregion // MSBuildTask0005 (transitive unsafe API) warnings are currently emitted here due to // an analyzer limitation around data-flow reachability. See https://github.com/dotnet/msbuild/issues/13867. public override bool Execute() { if (!NativeMethodsShared.IsWindows) { Log.LogErrorWithCodeFromResources("General.TaskRequiresWindows", nameof(GenerateLauncher)); return false; } if (LauncherPath == null) { // Launcher lives next to ClickOnce bootstrapper. // Use the TaskEnvironment overload of GetDefaultPath so the fallback is the // project directory rather than the process-wide current directory. LauncherPath = Path.Combine( Deployment.Bootstrapper.Util.GetDefaultPath(VisualStudioVersion, TaskEnvironment), ENGINE_PATH, LAUNCHER_EXE); } if (EntryPoint == null) { Log.LogErrorWithCodeFromResources("GenerateLauncher.InvalidInput"); return false; } AbsolutePath outputPath = string.IsNullOrEmpty(OutputPath) ? default : TaskEnvironment.GetAbsolutePath(OutputPath); var launcherBuilder = new LauncherBuilder(LauncherPath, TaskEnvironment); string entryPointFileName = Path.GetFileName(EntryPoint.ItemSpec); // If the EntryPoint specified is apphost.exe or singlefilehost.exe, we need to replace the EntryPoint // with the AssemblyName instead since apphost.exe/singlefilehost.exe is an intermediate file for // for final published {assemblyname}.exe. if ((entryPointFileName.Equals(Constants.AppHostExe, StringComparison.InvariantCultureIgnoreCase) || entryPointFileName.Equals(Constants.SingleFileHostExe, StringComparison.InvariantCultureIgnoreCase)) && !string.IsNullOrEmpty(AssemblyName)) { entryPointFileName = AssemblyName; } BuildResults results = launcherBuilder.Build(entryPointFileName, outputPath); BuildMessage[] messages = results.Messages; if (messages != null) { foreach (BuildMessage message in messages) { switch (message.Severity) { case BuildMessageSeverity.Error: Log.LogError(null, message.HelpCode, message.HelpKeyword, null, 0, 0, 0, 0, message.Message); break; case BuildMessageSeverity.Warning: Log.LogWarning(null, message.HelpCode, message.HelpKeyword, null, 0, 0, 0, 0, message.Message); break; case BuildMessageSeverity.Info: Log.LogMessage(null, message.HelpCode, message.HelpKeyword, null, 0, 0, 0, 0, message.Message); continue; } } } string outputEntryPoint = Path.Combine(Path.GetDirectoryName(EntryPoint.ItemSpec), results.KeyFile); OutputEntryPoint = new TaskItem(outputEntryPoint); OutputEntryPoint.SetMetadata(ItemMetadataNames.targetPath, results.KeyFile); return !Log.HasLoggedErrors; } } }