diff --git a/src/WinRT.Generator.Core/DebugRepro/DebugReproPacker.cs b/src/WinRT.Generator.Core/DebugRepro/DebugReproPacker.cs
index db68eaef15..ba0da678e9 100644
--- a/src/WinRT.Generator.Core/DebugRepro/DebugReproPacker.cs
+++ b/src/WinRT.Generator.Core/DebugRepro/DebugReproPacker.cs
@@ -10,6 +10,7 @@
using System.Text;
using System.Text.Json;
using System.Threading;
+using WindowsRuntime.Generator.Errors;
using WindowsRuntime.Generator.Helpers;
namespace WindowsRuntime.Generator.DebugRepro;
@@ -18,14 +19,8 @@ namespace WindowsRuntime.Generator.DebugRepro;
/// Leaf helpers shared across the CsWinRT CLI generators for packaging and unpacking debug repros.
///
///
-/// Each generator's SaveDebugRepro/UnpackDebugRepro still owns the high-level orchestration
-/// (which input categories exist, which subfolders are used, how the response file is re-stitched). This
-/// type only owns the small, identical-across-tools building blocks:
-///
-/// - Hashing the original file path into a stable, collision-free file name.
-/// - Copying files (or a single file) into a destination directory using the hashed names.
-/// - Serializing / deserializing the "hashed name → original path" mapping as JSON inside the repro archive.
-///
+/// Each generator still owns the high-level orchestration (which input categories exist, which subfolders are
+/// used, how the response file is re-stitched). This type only owns identical helpers that can be reused.
///
internal static class DebugReproPacker
{
@@ -148,4 +143,76 @@ public static Dictionary ExtractPathMap(ZipArchiveEntry pathMapE
// Load the mapping with all the original file paths for the included files
return JsonSerializer.Deserialize(stream, GeneratorJsonSerializerContext.Default.DictionaryStringString)!;
}
+
+ ///
+ /// Prepares the staging directory and target archive path for a debug repro save operation.
+ ///
+ /// The per-tool error factory used to throw if does not exist.
+ /// The user-provided directory where the resulting .zip archive will be written. Must already exist.
+ /// The CLI tool name (e.g. "cswinrtimplgen"), used as the prefix of the staging directory.
+ /// The file name of the resulting .zip archive (e.g. "impl-debug-repro.zip").
+ /// A pair containing the freshly-created staging directory and the absolute path of the target archive.
+ /// Thrown via if does not exist.
+ public static (string TempDirectory, string ZipPath) BeginSave(
+ string debugReproDirectory,
+ string toolName,
+ string archiveFileName)
+ where TError : IGeneratorErrorFactory
+ {
+ // The target folder must exist
+ if (!Directory.Exists(debugReproDirectory))
+ {
+ throw TError.DebugReproDirectoryDoesNotExist(debugReproDirectory);
+ }
+
+ // Path for the ZIP archive
+ string zipPath = Path.Combine(debugReproDirectory, archiveFileName);
+
+ // Create a temporary directory to stage files for the ZIP
+ string tempFolderName = $"{toolName}-debug-repro-{Guid.NewGuid().ToString().ToUpperInvariant()}";
+ string tempDirectory = Path.Combine(Path.GetTempPath(), tempFolderName);
+
+ _ = Directory.CreateDirectory(tempDirectory);
+
+ return (tempDirectory, zipPath);
+ }
+
+ ///
+ /// Finalizes a debug repro save by zipping the staging directory into the target archive and deleting the staging directory.
+ ///
+ /// The staging directory previously returned by .
+ /// The absolute path of the target .zip archive, previously returned by .
+ ///
+ /// If a file already exists at , it is deleted before the new archive is created.
+ ///
+ public static void FinalizeSave(string tempDirectory, string zipPath)
+ {
+ // Delete the previous file, if it exists
+ if (File.Exists(zipPath))
+ {
+ File.Delete(zipPath);
+ }
+
+ // Create the actual .zip file in the target directory
+ ZipFile.CreateFromDirectory(tempDirectory, zipPath);
+
+ // Clean up the temporary directory
+ Directory.Delete(tempDirectory, recursive: true);
+ }
+
+ ///
+ /// Creates a freshly-named temporary directory for unpacking a debug repro .zip archive.
+ ///
+ /// The CLI tool name (e.g. "cswinrtimplgen"), used as the prefix of the directory.
+ /// The absolute path of the created directory.
+ public static string CreateUnpackTempDirectory(string toolName)
+ {
+ // Create a temporary directory to extract the files from the debug repro
+ string tempFolderName = $"{toolName}-debug-repro-unpack-{Guid.NewGuid().ToString().ToUpperInvariant()}";
+ string tempDirectory = Path.Combine(Path.GetTempPath(), tempFolderName);
+
+ _ = Directory.CreateDirectory(tempDirectory);
+
+ return tempDirectory;
+ }
}
diff --git a/src/WinRT.Generator.Core/Errors/IGeneratorErrorFactory.cs b/src/WinRT.Generator.Core/Errors/IGeneratorErrorFactory.cs
index 21f31ef861..8906ab8c63 100644
--- a/src/WinRT.Generator.Core/Errors/IGeneratorErrorFactory.cs
+++ b/src/WinRT.Generator.Core/Errors/IGeneratorErrorFactory.cs
@@ -9,18 +9,10 @@ namespace WindowsRuntime.Generator.Errors;
/// Routes shared logical errors through the per-tool well-known exception factory.
///
///
-///
/// Shared infrastructure (response-file parsing, debug-repro packing, etc.) is generic over an
-/// implementation of this interface and reaches the per-tool factory through its static abstract
-/// members. This preserves per-tool exception identity exactly: each factory continues to assign its
-/// own numeric error IDs, format its own messages (including embedded tool names), and construct
-/// its own concrete subtype.
-///
-///
-/// Implementations must be sealed (not static) so they can participate in the
-/// static abstract interface contract. The implementing type is not meant to be instantiated;
-/// it is used as a type parameter to dispatch the factory call.
-///
+/// implementation of this interface to preserve per-tool exception identity exactly: each factory
+/// continues to assign its own numeric error IDs, format its own messages (including embedded tool names),
+/// and construct its own concrete subtype.
///
internal interface IGeneratorErrorFactory
{
diff --git a/src/WinRT.Generator.Core/Errors/UnhandledGeneratorException.cs b/src/WinRT.Generator.Core/Errors/UnhandledGeneratorException.cs
index 929afaccc9..3b51d8ad6b 100644
--- a/src/WinRT.Generator.Core/Errors/UnhandledGeneratorException.cs
+++ b/src/WinRT.Generator.Core/Errors/UnhandledGeneratorException.cs
@@ -10,7 +10,7 @@ namespace WindowsRuntime.Generator.Errors;
///
///
/// Each per-tool unhandled exception inherits from this type and provides its
-/// and so that the standardized
+/// and so that the standardized
/// message remains tool-specific.
///
/// The phase that failed.
@@ -24,16 +24,15 @@ internal abstract class UnhandledGeneratorException(string phase, Exception exce
protected abstract string ErrorPrefix { get; }
///
- /// Gets the description of the generator used in the standard message
- /// (e.g. "impl generator", "interop generator", "WinMD generator").
+ /// Gets the name of the generator used in the standard message.
///
- protected abstract string GeneratorDescription { get; }
+ protected abstract string GeneratorName { get; }
///
public override string ToString()
{
return
- $"""error {ErrorPrefix}9999: The CsWinRT {GeneratorDescription} failed with an unhandled exception """ +
+ $"""error {ErrorPrefix}9999: The CsWinRT {GeneratorName} generator failed with an unhandled exception """ +
$"""('{InnerException!.GetType().Name}': '{InnerException!.Message}') during the '{phase}' phase. This might be due to an invalid """ +
$"""configuration in the current project, but the generator should still correctly identify that and fail gracefully. Please open an """ +
$"""issue at https://github.com/microsoft/CsWinRT and provide a minimal repro, if possible.""";
diff --git a/src/WinRT.Generator.Core/Errors/WellKnownGeneratorMessages.cs b/src/WinRT.Generator.Core/Errors/WellKnownGeneratorMessages.cs
new file mode 100644
index 0000000000..03e5bee363
--- /dev/null
+++ b/src/WinRT.Generator.Core/Errors/WellKnownGeneratorMessages.cs
@@ -0,0 +1,50 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace WindowsRuntime.Generator.Errors;
+
+///
+/// Shared message templates for the well-known logical errors defined by .
+///
+///
+/// Each per-tool WellKnown*Exceptions factory uses these helpers to format its own
+/// instance of every method, ensuring that the message
+/// text stays identical across all generators while the per-tool error ID prefix (e.g.
+/// CSWINRTIMPLGEN) and concrete exception type are still chosen per-tool.
+///
+internal static class WellKnownGeneratorMessages
+{
+ ///
+ public const string ResponseFileReadError = "Failed to read the response file (e.g. it may be missing or not accessible).";
+
+ ///
+ /// The name of the response-file argument that failed to parse.
+ public static string ResponseFileArgumentParsingError(string argumentName)
+ {
+ return $"Failed to parse argument '{argumentName}' from response file.";
+ }
+
+ ///
+ public const string MalformedResponseFile = "The response file is malformed and contains invalid content.";
+
+ ///
+ /// The directory path that does not exist.
+ public static string DebugReproDirectoryDoesNotExist(string path)
+ {
+ return $"The debug repro directory '{path}' does not exist.";
+ }
+
+ ///
+ /// The debug-repro file entry path that has no mapping.
+ public static string DebugReproMissingFileEntryMapping(string path)
+ {
+ return $"The debug repro file entry with path '{path}' is missing its assembly path mapping.";
+ }
+
+ ///
+ /// The debug-repro file entry path that was not recognized.
+ public static string DebugReproUnrecognizedFileEntry(string path)
+ {
+ return $"The debug repro file entry with path '{path}' was not recognized.";
+ }
+}
diff --git a/src/WinRT.Interop.Generator/Extensions/IncrementalHashExtensions.cs b/src/WinRT.Generator.Core/Extensions/IncrementalHashExtensions.cs
similarity index 95%
rename from src/WinRT.Interop.Generator/Extensions/IncrementalHashExtensions.cs
rename to src/WinRT.Generator.Core/Extensions/IncrementalHashExtensions.cs
index ed75d20673..1db570f31a 100644
--- a/src/WinRT.Interop.Generator/Extensions/IncrementalHashExtensions.cs
+++ b/src/WinRT.Generator.Core/Extensions/IncrementalHashExtensions.cs
@@ -5,7 +5,7 @@
using System.IO;
using System.Security.Cryptography;
-namespace WindowsRuntime.InteropGenerator;
+namespace WindowsRuntime.Generator.Extensions;
///
/// Extensions for the type.
@@ -34,4 +34,4 @@ public void AppendData(Stream stream)
ArrayPool.Shared.Return(buffer);
}
}
-}
\ No newline at end of file
+}
diff --git a/src/WinRT.Generator.Core/Extensions/PathExtensions.cs b/src/WinRT.Generator.Core/Extensions/PathExtensions.cs
index b4afd3b725..fcb37d6130 100644
--- a/src/WinRT.Generator.Core/Extensions/PathExtensions.cs
+++ b/src/WinRT.Generator.Core/Extensions/PathExtensions.cs
@@ -36,21 +36,6 @@ internal static class PathExtensions
return path?.Replace('\\', '/');
}
- ///
- public static ReadOnlySpan Normalize(ReadOnlySpan path)
- {
- if (OperatingSystem.IsWindows())
- {
- return path;
- }
-
- char[] buffer = new char[path.Length];
-
- path.Replace(buffer, '\\', '/');
-
- return buffer;
- }
-
///
/// Checks whether a given path represents a file or folder contained within a folder with a given name.
///
diff --git a/src/WinRT.WinMD.Generator/Extensions/RuntimeContextExtensions.cs b/src/WinRT.Generator.Core/Extensions/RuntimeContextExtensions.cs
similarity index 98%
rename from src/WinRT.WinMD.Generator/Extensions/RuntimeContextExtensions.cs
rename to src/WinRT.Generator.Core/Extensions/RuntimeContextExtensions.cs
index 8794f0c543..7123d56211 100644
--- a/src/WinRT.WinMD.Generator/Extensions/RuntimeContextExtensions.cs
+++ b/src/WinRT.Generator.Core/Extensions/RuntimeContextExtensions.cs
@@ -7,7 +7,7 @@
#pragma warning disable IDE0046
-namespace WindowsRuntime.WinMDGenerator;
+namespace WindowsRuntime.Generator.Extensions;
///
/// Extensions for the type.
diff --git a/src/WinRT.Generator.Core/GeneratorHost.cs b/src/WinRT.Generator.Core/GeneratorHost.cs
index ba60c250f7..27df49e2d1 100644
--- a/src/WinRT.Generator.Core/GeneratorHost.cs
+++ b/src/WinRT.Generator.Core/GeneratorHost.cs
@@ -11,21 +11,11 @@ namespace WindowsRuntime.Generator;
///
/// Shared Run entry-point scaffold for the CsWinRT CLI generators.
///
-///
-/// Each generator's Run method historically opened with an identical preamble:
-///
-/// - If the input file path looks like a .zip, unpack a debug repro and re-route to the extracted .rsp.
-/// - Parse the response file into a per-tool args record.
-/// - If DebugReproDirectory is set and we are not already replaying, save a debug repro of the current invocation.
-///
-/// encapsulates that preamble. Each generator's Run now starts with a
-/// single call to it; the per-tool unpack / save / parse logic is supplied via delegates so behavior
-/// stays identical (same log messages, same exception phases, same per-tool unhandled exception type).
-///
internal static class GeneratorHost
{
///
- /// Runs the shared unpack → parse → save preamble for a CsWinRT CLI generator.
+ /// Runs the shared unpack, parse, save preamble for a CsWinRT CLI generator and returns a
+ /// ready to drive the remaining per-tool phases.
///
/// The per-tool args record (must implement ).
/// The input file path (response file or debug-repro .zip).
@@ -36,8 +26,11 @@ internal static class GeneratorHost
/// Wraps an unexpected exception into the per-tool Unhandled*Exception with the given phase name.
/// Logs a progress message to the user (typically ConsoleApp.Log from ConsoleAppFramework).
/// The token for the operation.
- /// The parsed instance.
- public static TArgs Prepare(
+ ///
+ /// A pre-bound to the parsed args,
+ /// and for use by subsequent phases.
+ ///
+ public static GeneratorPhaseRunner CreateRunner(
string inputFilePath,
string toolName,
Func unpackDebugRepro,
@@ -109,7 +102,6 @@ public static TArgs Prepare(
args.Token.ThrowIfCancellationRequested();
- return args;
+ return new(args, wrapUnhandled, log);
}
}
-
diff --git a/src/WinRT.Generator.Core/GeneratorPhaseRunner{TArgs}.cs b/src/WinRT.Generator.Core/GeneratorPhaseRunner{TArgs}.cs
new file mode 100644
index 0000000000..58b3cf1299
--- /dev/null
+++ b/src/WinRT.Generator.Core/GeneratorPhaseRunner{TArgs}.cs
@@ -0,0 +1,111 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+using System;
+using WindowsRuntime.Generator.Errors;
+
+#pragma warning disable CS1573
+
+namespace WindowsRuntime.Generator;
+
+///
+/// Runs the body of a single generator phase, wrapping unexpected exceptions in the per-tool
+/// Unhandled*Exception and optionally logging a progress message before the body runs.
+///
+/// The per-tool args record (must implement ).
+/// The parsed per-tool args, forwarded to every body.
+/// Wraps an unexpected exception into the per-tool Unhandled*Exception with the given phase name.
+/// Logs a progress message to the user (typically ConsoleApp.Log from ConsoleAppFramework).
+internal readonly struct GeneratorPhaseRunner(
+ TArgs args,
+ Func wrapUnhandled,
+ Action log)
+ where TArgs : IGeneratorArgs
+{
+ ///
+ /// Gets the parsed per-tool args, forwarded to every body.
+ ///
+ public TArgs Args => args;
+
+ ///
+ /// Runs , wrapping any unexpected exception in the per-tool
+ /// Unhandled*Exception with as the phase tag.
+ ///
+ /// The phase name used by the per-tool Unhandled*Exception.
+ /// The body of the phase to run. The captured is forwarded as its argument.
+ public void RunPhase(string phaseName, Action body)
+ {
+ try
+ {
+ body(Args);
+ }
+ catch (Exception e) when (!e.IsWellKnown)
+ {
+ throw wrapUnhandled(phaseName, e);
+ }
+
+ args.Token.ThrowIfCancellationRequested();
+ }
+
+ ///
+ /// The progress message to log before the body runs.
+ public void RunPhase(string phaseName, string logMessage, Action body)
+ {
+ try
+ {
+ log(logMessage);
+
+ body(Args);
+ }
+ catch (Exception e) when (!e.IsWellKnown)
+ {
+ throw wrapUnhandled(phaseName, e);
+ }
+
+ args.Token.ThrowIfCancellationRequested();
+ }
+
+ ///
+ /// The value returned by .
+ public T RunPhase(string phaseName, Func body)
+ {
+ T result;
+
+ try
+ {
+ result = body(Args);
+ }
+ catch (Exception e) when (!e.IsWellKnown)
+ {
+ throw wrapUnhandled(phaseName, e);
+ }
+
+ args.Token.ThrowIfCancellationRequested();
+
+ return result;
+ }
+
+ ///
+ /// The progress message to log before the body runs.
+ /// The value returned by .
+ public T RunPhase(string phaseName, string logMessage, Func body)
+ {
+ T result;
+
+ try
+ {
+ log(logMessage);
+
+ result = body(Args);
+ }
+ catch (Exception e) when (!e.IsWellKnown)
+ {
+ throw wrapUnhandled(phaseName, e);
+ }
+
+ args.Token.ThrowIfCancellationRequested();
+
+ return result;
+ }
+}
+
diff --git a/src/WinRT.Interop.Generator/Helpers/MvidGenerator.cs b/src/WinRT.Generator.Core/Helpers/MvidGenerator.cs
similarity index 57%
rename from src/WinRT.Interop.Generator/Helpers/MvidGenerator.cs
rename to src/WinRT.Generator.Core/Helpers/MvidGenerator.cs
index d738973660..200483f064 100644
--- a/src/WinRT.Interop.Generator/Helpers/MvidGenerator.cs
+++ b/src/WinRT.Generator.Core/Helpers/MvidGenerator.cs
@@ -6,14 +6,38 @@
using System.IO;
using System.Linq;
using System.Security.Cryptography;
+using WindowsRuntime.Generator.Extensions;
-namespace WindowsRuntime.InteropGenerator.Helpers;
+namespace WindowsRuntime.Generator.Helpers;
///
/// A generator for MVIDs for .NET modules.
///
internal static class MvidGenerator
{
+ ///
+ /// Generates a deterministic MVID based on two input IIDs.
+ ///
+ /// The first IID to combine.
+ /// The second IID to combine.
+ /// The resulting MVID.
+ public static Guid CreateMvid(Guid left, Guid right)
+ {
+ Span input = stackalloc byte[32];
+
+ // Write the two IIDs in sequence
+ _ = left.TryWriteBytes(input, bigEndian: true, out _);
+ _ = right.TryWriteBytes(input[16..], bigEndian: true, out _);
+
+ Span hash = stackalloc byte[SHA1.HashSizeInBytes];
+
+ // Hash the two IIDs together (the order matters)
+ _ = SHA1.HashData(input, hash);
+
+ // Create the final MVID from the first 16 bytes of the hash
+ return new(hash[..16]);
+ }
+
///
/// Generates a deterministic MVID based on a set of input assemblies.
///
diff --git a/src/WinRT.Generator.Core/IGeneratorArgs.cs b/src/WinRT.Generator.Core/IGeneratorArgs.cs
index 34c2a1be87..f6bf0ed5c8 100644
--- a/src/WinRT.Generator.Core/IGeneratorArgs.cs
+++ b/src/WinRT.Generator.Core/IGeneratorArgs.cs
@@ -6,14 +6,12 @@
namespace WindowsRuntime.Generator;
///
-/// Common surface implemented by every per-tool args record (e.g. ImplGeneratorArgs,
-/// InteropGeneratorArgs) so the shared entry-point scaffold
-/// can dispatch through a couple of well-known properties.
+/// Common surface implemented by every per-tool arguments record.
///
internal interface IGeneratorArgs
{
///
- /// Gets the token for the operation.
+ /// Gets the cancellation token for the generator invocation.
///
CancellationToken Token { get; }
diff --git a/src/WinRT.Generator.Core/Parsing/ResponseFileBuilder.cs b/src/WinRT.Generator.Core/Parsing/ResponseFileBuilder.cs
index 00e2699e39..fa90f69710 100644
--- a/src/WinRT.Generator.Core/Parsing/ResponseFileBuilder.cs
+++ b/src/WinRT.Generator.Core/Parsing/ResponseFileBuilder.cs
@@ -8,51 +8,22 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
-using System.Threading;
using WindowsRuntime.Generator.Attributes;
namespace WindowsRuntime.Generator.Parsing;
///
-/// Formats an args record into a response file by reflecting over its
-/// []-annotated public properties.
+/// Helper to format argument objects into response files.
///
-///
-///
-/// Properties are emitted in declaration order (the order returned by ),
-/// one name]]>value per line. The output round-trips cleanly through
-/// .
-///
-///
-/// Per-property handling:
-///
-/// - -typed properties are skipped (they have no CLI surface).
-/// - Properties without are skipped.
-/// - values are skipped (they round-trip as "missing").
-/// - Empty [] values are skipped (they round-trip as "missing"
-/// to the optional-array default, matching the previous per-tool emit behavior).
-/// - values that are on properties without
-/// are skipped (they
-/// round-trip to the optional-bool default, matching the previous per-tool emit behavior).
-/// - All other values are formatted using :
-/// strings emit as-is, arrays emit as comma-joined, primitives use .
-///
-///
-///
internal static class ResponseFileBuilder
{
- /// The required dynamic-access annotation for the TArgs type parameter.
- private const DynamicallyAccessedMemberTypes ArgsAccessKinds =
- DynamicallyAccessedMemberTypes.PublicProperties;
-
///
- /// Formats as a response file string suitable for
- /// .
+ /// Formats as a response file string.
///
/// The strongly-typed args record.
/// The args instance to format.
/// The formatted response file text.
- public static string Format<[DynamicallyAccessedMembers(ArgsAccessKinds)] TArgs>(TArgs args)
+ public static string Format<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.PublicProperties)] TArgs>(TArgs args)
where TArgs : class
{
StringBuilder builder = new();
@@ -83,8 +54,8 @@ internal static class ResponseFileBuilder
}
// Optional booleans default to 'false' on parse, so emitting "name false" would be
- // redundant. Required booleans always emit (both 'true' and 'false') so the parser sees
- // them and doesn't reject them as missing-required.
+ // redundant. Required booleans always emit (both 'true' and 'false') so the parser
+ // sees them and doesn't reject them as missing-required.
bool isRequired = property.GetCustomAttribute() is not null;
if (value is false && !isRequired)
@@ -112,13 +83,14 @@ private static string FormatValue(object value)
return s;
}
+ // String values are formatted as comma-separated lists, without brackets or spaces
if (value is string[] array)
{
return string.Join(',', array);
}
- // All other primitive values use invariant culture, matching the parser's invariant
- // 'Convert.ChangeType' so the round-trip is deterministic.
+ // All other primitive values use invariant culture, matching the parser's
+ // invariant 'Convert.ChangeType' so the round-trip is deterministic.
return Convert.ToString(value, CultureInfo.InvariantCulture) ?? string.Empty;
}
}
diff --git a/src/WinRT.Generator.Core/Parsing/ResponseFileParser.cs b/src/WinRT.Generator.Core/Parsing/ResponseFileParser.cs
index f635d005de..25a2bc7a6b 100644
--- a/src/WinRT.Generator.Core/Parsing/ResponseFileParser.cs
+++ b/src/WinRT.Generator.Core/Parsing/ResponseFileParser.cs
@@ -16,52 +16,25 @@
namespace WindowsRuntime.Generator.Parsing;
///
-/// Parses a response file into a strongly-typed args record by reflecting over its
-/// []-annotated public properties.
+/// Helper to parse response files into argument objects.
///
-///
-///
-/// The shape of the response file is one name]]>value per line, with optional
-/// blank lines (the MSBuild ToolTask may emit them). The first token of each non-blank line
-/// is the CLI flag name; everything after the first space (right-trimmed) is the value.
-///
-///
-/// Per-property handling:
-///
-/// - -typed properties are set from the parser's token
-/// parameter (they have no ).
-/// - Properties without are skipped.
-/// - Required properties (those with ) throw
-///
-/// if the value is missing or fails to parse.
-/// - Optional properties default to the if
-/// is present, otherwise to default(T) (with
-/// [] defaulting to an empty array).
-/// - Value coercion is handled by
-/// for primitives, with ; arrays use
-/// with comma separator.
-///
-///
-///
internal static class ResponseFileParser
{
- /// The required dynamic-access annotation for the TArgs type parameter.
- private const DynamicallyAccessedMemberTypes ArgsAccessKinds =
- DynamicallyAccessedMemberTypes.PublicProperties;
-
///
/// Parses an instance of from a response file at the given path.
///
///
- /// The path may be prefixed with @ (matching MSBuild's default escaping for ToolTask
- /// response files), which is stripped before reading the file.
+ /// The path may be prefixed with @ (matching MSBuild's default escaping
+ /// for ToolTask response files), which is stripped before reading the file.
///
/// The strongly-typed args record. Must have a public parameterless constructor surface (only public properties are inspected via reflection).
/// The per-tool well-known exception factory used to route parsing errors.
/// The path to the response file (optionally prefixed with @).
/// The cancellation token for the operation.
/// The populated instance.
- public static TArgs Parse<[DynamicallyAccessedMembers(ArgsAccessKinds)] TArgs, TErr>(string path, CancellationToken token)
+ public static TArgs Parse<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.AllConstructors | DynamicallyAccessedMemberTypes.PublicProperties)] TArgs, TErr>(
+ string path,
+ CancellationToken token)
where TArgs : class
where TErr : IGeneratorErrorFactory
{
@@ -84,7 +57,9 @@ internal static class ResponseFileParser
throw TErr.ResponseFileReadError(e);
}
- return ParseLines(lines, token);
+ Dictionary argsMap = BuildArgsMap(lines);
+
+ return Populate(argsMap, token);
}
///
@@ -95,25 +70,14 @@ internal static class ResponseFileParser
/// The stream containing the response file content.
/// The cancellation token for the operation.
/// The populated instance.
- public static TArgs Parse<[DynamicallyAccessedMembers(ArgsAccessKinds)] TArgs, TErr>(Stream stream, CancellationToken token)
+ public static TArgs Parse<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.AllConstructors | DynamicallyAccessedMemberTypes.PublicProperties)] TArgs, TErr>(
+ Stream stream,
+ CancellationToken token)
where TArgs : class
where TErr : IGeneratorErrorFactory
{
- return ParseLines(File.ReadAllLines(stream), token);
- }
+ string[] lines = File.ReadAllLines(stream);
- ///
- /// Parses an instance of from the pre-split lines of a response file.
- ///
- /// The strongly-typed args record.
- /// The per-tool well-known exception factory used to route parsing errors.
- /// The lines read from the response file.
- /// The cancellation token for the operation.
- /// The populated instance.
- public static TArgs ParseLines<[DynamicallyAccessedMembers(ArgsAccessKinds)] TArgs, TErr>(string[] lines, CancellationToken token)
- where TArgs : class
- where TErr : IGeneratorErrorFactory
- {
Dictionary argsMap = BuildArgsMap(lines);
return Populate(argsMap, token);
@@ -164,20 +128,16 @@ private static Dictionary BuildArgsMap(string[] lines)
}
///
- /// Constructs via
- /// (to bypass enforcement at construction time) and then
- /// populates each public property by reflecting on its CLI attribute, nullability, default value, and type.
+ /// Populates an arguments object with the provided parsed values.
///
/// The strongly-typed args record.
/// The per-tool well-known exception factory used to route parsing errors.
/// The pre-built name-to-value map.
/// The cancellation token, assigned to any -typed property on .
/// The populated instance.
- [UnconditionalSuppressMessage(
- "Trimming",
- "IL2087:'type' argument does not satisfy 'DynamicallyAccessedMembersAttribute' in call to target method.",
- Justification = "GetUninitializedObject does not invoke any constructor; it allocates an instance of TArgs without running any user code, so the PublicConstructors/NonPublicConstructors annotation is not required.")]
- private static TArgs Populate<[DynamicallyAccessedMembers(ArgsAccessKinds)] TArgs, TErr>(Dictionary argsMap, CancellationToken token)
+ private static TArgs Populate<[DynamicallyAccessedMembers(DynamicallyAccessedMemberTypes.AllConstructors | DynamicallyAccessedMemberTypes.PublicProperties)] TArgs, TErr>(
+ Dictionary argsMap,
+ CancellationToken token)
where TArgs : class
where TErr : IGeneratorErrorFactory
{
@@ -186,8 +146,6 @@ private static Dictionary BuildArgsMap(string[] lines)
// response file values, with explicit defaults applied for non-required properties.
TArgs instance = (TArgs)RuntimeHelpers.GetUninitializedObject(typeof(TArgs));
- NullabilityInfoContext nullabilityContext = new();
-
foreach (PropertyInfo property in typeof(TArgs).GetProperties(BindingFlags.Public | BindingFlags.Instance))
{
Type propertyType = property.PropertyType;
@@ -214,7 +172,7 @@ private static Dictionary BuildArgsMap(string[] lines)
if (!hasValue)
{
- ApplyDefault(instance, property, propertyType, isRequired, nullabilityContext);
+ ApplyDefault(instance, property, propertyType, isRequired);
continue;
}
@@ -233,7 +191,7 @@ private static Dictionary BuildArgsMap(string[] lines)
}
else
{
- ApplyDefault(instance, property, propertyType, isRequired: false, nullabilityContext);
+ ApplyDefault(instance, property, propertyType, isRequired: false);
}
}
@@ -248,13 +206,11 @@ private static Dictionary BuildArgsMap(string[] lines)
/// The property being set.
/// The property's type.
/// Whether the property has .
- /// The shared for nullable-reference inspection.
private static void ApplyDefault(
object instance,
PropertyInfo property,
Type propertyType,
- bool isRequired,
- NullabilityInfoContext nullabilityContext)
+ bool isRequired)
where TErr : IGeneratorErrorFactory
{
if (isRequired)
@@ -263,7 +219,7 @@ private static void ApplyDefault(
}
// '[DefaultValue("…")]' takes precedence: it lets per-tool args express initializer-style
- // defaults that 'GetUninitializedObject' would otherwise skip.
+ // defaults that 'GetUninitializedObject' would otherwise skip (initializers aren't needed).
DefaultValueAttribute? defaultValueAttribute = property.GetCustomAttribute();
if (defaultValueAttribute is not null)
@@ -280,18 +236,6 @@ private static void ApplyDefault(
return;
}
-
- // Nullable reference types default to null (matching 'GetNullableStringArgument'). For value
- // types and non-nullable reference types we leave 'default(T)' from 'GetUninitializedObject'.
- if (!propertyType.IsValueType)
- {
- NullabilityInfo nullability = nullabilityContext.Create(property);
-
- if (nullability.ReadState == NullabilityState.Nullable)
- {
- property.SetValue(instance, null);
- }
- }
}
///
diff --git a/src/WinRT.Generator.Core/Properties/AssemblyInfo.cs b/src/WinRT.Generator.Core/Properties/AssemblyInfo.cs
deleted file mode 100644
index 41f427dd1d..0000000000
--- a/src/WinRT.Generator.Core/Properties/AssemblyInfo.cs
+++ /dev/null
@@ -1,10 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-using System.Runtime.CompilerServices;
-
-[assembly: InternalsVisibleTo("cswinrtimplgen")]
-[assembly: InternalsVisibleTo("cswinrtinteropgen")]
-[assembly: InternalsVisibleTo("cswinrtprojectiongen")]
-[assembly: InternalsVisibleTo("cswinrtprojectionrefgen")]
-[assembly: InternalsVisibleTo("cswinrtwinmdgen")]
diff --git a/src/WinRT.Interop.Generator/References/WellKnownPublicKeyTokens.cs b/src/WinRT.Generator.Core/References/WellKnownPublicKeyTokens.cs
similarity index 62%
rename from src/WinRT.Interop.Generator/References/WellKnownPublicKeyTokens.cs
rename to src/WinRT.Generator.Core/References/WellKnownPublicKeyTokens.cs
index a9f34cc3da..0942d8ec00 100644
--- a/src/WinRT.Interop.Generator/References/WellKnownPublicKeyTokens.cs
+++ b/src/WinRT.Generator.Core/References/WellKnownPublicKeyTokens.cs
@@ -1,35 +1,40 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
-namespace WindowsRuntime.InteropGenerator.References;
+namespace WindowsRuntime.Generator.References;
///
-/// Well known public key tokens.
+/// Well-known public key tokens for assemblies used by the CsWinRT generators.
///
internal static class WellKnownPublicKeyTokens
{
///
- /// The public key data for System.Memory.dll.
+ /// The public key token for mscorlib.
+ ///
+ public static readonly byte[] MSCorLib = [0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89];
+
+ ///
+ /// The public key token for System.Memory.dll.
///
public static readonly byte[] SystemMemory = [0xCC, 0x7B, 0x13, 0xFF, 0xCD, 0x2D, 0xDD, 0x51];
///
- /// The public key data for System.ObjectModel.dll.
+ /// The public key token for System.ObjectModel.dll.
///
public static readonly byte[] SystemObjectModel = [0xB0, 0x3F, 0x5F, 0x7F, 0x11, 0xD5, 0x0A, 0x3A];
///
- /// The public key data for System.Runtime.InteropServices.dll.
+ /// The public key token for System.Runtime.InteropServices.dll.
///
public static readonly byte[] SystemRuntimeInteropServices = [0xB0, 0x3F, 0x5F, 0x7F, 0x11, 0xD5, 0x0A, 0x3A];
///
- /// The public key data for System.Numerics.Vectors.dll.
+ /// The public key token for System.Numerics.Vectors.dll.
///
public static readonly byte[] SystemNumericsVectors = [0xB0, 0x3F, 0x5F, 0x7F, 0x11, 0xD5, 0x0A, 0x3A];
///
- /// The public key data for System.Threading.dll.
+ /// The public key token for System.Threading.dll.
///
public static readonly byte[] SystemThreading = [0xB0, 0x3F, 0x5F, 0x7F, 0x11, 0xD5, 0x0A, 0x3A];
@@ -37,4 +42,4 @@ internal static class WellKnownPublicKeyTokens
/// The public key token for CsWinRT assemblies (31bf3856ad364e35).
///
public static readonly byte[] CsWinRT = [0x31, 0xBF, 0x38, 0x56, 0xAD, 0x36, 0x4E, 0x35];
-}
\ No newline at end of file
+}
diff --git a/src/WinRT.Generator.Core/References/WellKnownPublicKeys.cs b/src/WinRT.Generator.Core/References/WellKnownPublicKeys.cs
new file mode 100644
index 0000000000..1c755b9d73
--- /dev/null
+++ b/src/WinRT.Generator.Core/References/WellKnownPublicKeys.cs
@@ -0,0 +1,22 @@
+// Copyright (c) Microsoft Corporation.
+// Licensed under the MIT License.
+
+namespace WindowsRuntime.Generator.References;
+
+///
+/// Well-known public keys for assemblies used by the CsWinRT generators.
+///
+internal static class WellKnownPublicKeys
+{
+ ///
+ /// The public key used by the precompiled Windows SDK projection assemblies (WinRT.Sdk.Projection.dll,
+ /// WinRT.Sdk.Xaml.Projection.dll) and the merged projection assembly (WinRT.Projection.dll) that
+ /// the projection generator produces at app build time.
+ ///
+ public static readonly byte[] WindowsSdkProjection = [0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x06, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x52, 0x53, 0x41, 0x31, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xB5, 0xFC, 0x90, 0xE7, 0x02, 0x7F, 0x67, 0x87, 0x1E, 0x77, 0x3A, 0x8F, 0xDE, 0x89, 0x38, 0xC8, 0x1D, 0xD4, 0x02, 0xBA, 0x65, 0xB9, 0x20, 0x1D, 0x60, 0x59, 0x3E, 0x96, 0xC4, 0x92, 0x65, 0x1E, 0x88, 0x9C, 0xC1, 0x3F, 0x14, 0x15, 0xEB, 0xB5, 0x3F, 0xAC, 0x11, 0x31, 0xAE, 0x0B, 0xD3, 0x33, 0xC5, 0xEE, 0x60, 0x21, 0x67, 0x2D, 0x97, 0x18, 0xEA, 0x31, 0xA8, 0xAE, 0xBD, 0x0D, 0xA0, 0x07, 0x2F, 0x25, 0xD8, 0x7D, 0xBA, 0x6F, 0xC9, 0x0F, 0xFD, 0x59, 0x8E, 0xD4, 0xDA, 0x35, 0xE4, 0x4C, 0x39, 0x8C, 0x45, 0x43, 0x07, 0xE8, 0xE3, 0x3B, 0x84, 0x26, 0x14, 0x3D, 0xAE, 0xC9, 0xF5, 0x96, 0x83, 0x6F, 0x97, 0xC8, 0xF7, 0x47, 0x50, 0xE5, 0x97, 0x5C, 0x64, 0xE2, 0x18, 0x9F, 0x45, 0xDE, 0xF4, 0x6B, 0x2A, 0x2B, 0x12, 0x47, 0xAD, 0xC3, 0x65, 0x2B, 0xF5, 0xC3, 0x08, 0x05, 0x5D, 0xA9];
+
+ ///
+ /// The public key for the real CsWinRT 3.0 runtime release assemblies (e.g. WinRT.Runtime.dll).
+ ///
+ public static readonly byte[] CsWinRT = [0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x06, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x52, 0x53, 0x41, 0x31, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x65, 0x32, 0x43, 0xC2, 0xEC, 0x7B, 0x83, 0x00, 0x92, 0x93, 0xB0, 0xE7, 0x98, 0x19, 0x3A, 0x8B, 0xB1, 0x03, 0x90, 0xB5, 0xA1, 0x2A, 0x3F, 0x2D, 0x5C, 0x58, 0x28, 0x2D, 0x71, 0x29, 0xDA, 0xD2, 0xD0, 0xC0, 0x12, 0x75, 0x53, 0x29, 0xC1, 0xA4, 0x51, 0x73, 0xE1, 0xAC, 0x9B, 0x8B, 0x4C, 0x0A, 0x4E, 0x07, 0x82, 0x30, 0xBD, 0xD5, 0xE8, 0xCE, 0x39, 0x32, 0x08, 0x3B, 0x09, 0x89, 0x2D, 0x82, 0x8E, 0x4B, 0x18, 0xAF, 0x00, 0xCE, 0x74, 0x6B, 0xCC, 0x99, 0x4D, 0xAD, 0x06, 0xAC, 0xEC, 0x3E, 0x69, 0x79, 0x3E, 0x75, 0xF8, 0xD2, 0xCC, 0x8E, 0x77, 0xF4, 0x46, 0x68, 0x55, 0x0C, 0xA9, 0xB8, 0x3D, 0xD6, 0x48, 0x2D, 0xA9, 0xAA, 0x4D, 0x2E, 0x8B, 0xCF, 0x2E, 0x17, 0x93, 0xCF, 0x84, 0xC4, 0x95, 0x34, 0x6B, 0x1B, 0x99, 0xEB, 0x99, 0x76, 0x7F, 0xB4, 0x12, 0x46, 0x67, 0x2E, 0x7C, 0xF0];
+}
diff --git a/src/WinRT.Generator.Core/WinRT.Generator.Core.csproj b/src/WinRT.Generator.Core/WinRT.Generator.Core.csproj
index 55ac42ef9a..5e0d083a0e 100644
--- a/src/WinRT.Generator.Core/WinRT.Generator.Core.csproj
+++ b/src/WinRT.Generator.Core/WinRT.Generator.Core.csproj
@@ -29,4 +29,16 @@
strict
true
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/src/WinRT.Generator.Tasks/RunCsWinRTWinMDGenerator.cs b/src/WinRT.Generator.Tasks/RunCsWinRTWinMDGenerator.cs
index a5c3aa5ded..64817c827c 100644
--- a/src/WinRT.Generator.Tasks/RunCsWinRTWinMDGenerator.cs
+++ b/src/WinRT.Generator.Tasks/RunCsWinRTWinMDGenerator.cs
@@ -126,7 +126,7 @@ protected override string GenerateFullPathToTool()
string? effectiveArchitecture = CsWinRTToolsArchitecture;
// Special case for when 'AnyCPU' is specified (mostly for testing scenarios).
- if (effectiveArchitecture?.Equals("AnyCPU", System.StringComparison.OrdinalIgnoreCase) is true)
+ if (effectiveArchitecture?.Equals("AnyCPU", StringComparison.OrdinalIgnoreCase) is true)
{
return Path.Combine(CsWinRTToolsDirectory!, ToolName);
}
diff --git a/src/WinRT.Impl.Generator/Errors/UnhandledImplException.cs b/src/WinRT.Impl.Generator/Errors/UnhandledImplException.cs
index 4d1f987fba..af5926b763 100644
--- a/src/WinRT.Impl.Generator/Errors/UnhandledImplException.cs
+++ b/src/WinRT.Impl.Generator/Errors/UnhandledImplException.cs
@@ -17,5 +17,5 @@ internal sealed class UnhandledImplException(string phase, Exception exception)
protected override string ErrorPrefix => WellKnownImplExceptions.ErrorPrefix;
///
- protected override string GeneratorDescription => "impl generator";
+ protected override string GeneratorName => "impl";
}
diff --git a/src/WinRT.Impl.Generator/Errors/WellKnownImplExceptions.cs b/src/WinRT.Impl.Generator/Errors/WellKnownImplExceptions.cs
index 960ee08993..ab965be045 100644
--- a/src/WinRT.Impl.Generator/Errors/WellKnownImplExceptions.cs
+++ b/src/WinRT.Impl.Generator/Errors/WellKnownImplExceptions.cs
@@ -23,28 +23,22 @@ private WellKnownImplExceptions()
{
}
- ///
- /// Some exception was thrown when trying to read the response file.
- ///
+ ///
public static Exception ResponseFileReadError(Exception exception)
{
- return Exception(1, "Failed to read the response file to run 'cswinrtimplgen'.", exception);
+ return Exception(1, WellKnownGeneratorMessages.ResponseFileReadError, exception);
}
- ///
- /// Failed to parse an argument from the response file.
- ///
+ ///
public static Exception ResponseFileArgumentParsingError(string argumentName, Exception? exception = null)
{
- return Exception(2, $"Failed to parse argument '{argumentName}' from response file.", exception);
+ return Exception(2, WellKnownGeneratorMessages.ResponseFileArgumentParsingError(argumentName), exception);
}
- ///
- /// The input response file is malformed.
- ///
+ ///
public static Exception MalformedResponseFile()
{
- return Exception(3, "The response file is malformed and contains invalid content.");
+ return Exception(3, WellKnownGeneratorMessages.MalformedResponseFile);
}
///
@@ -103,28 +97,22 @@ public static Exception SignDllError(Exception exception)
return Exception(10, "Failed to sign the impl .dll on disk.", exception);
}
- ///
- /// The debug repro directory does not exist.
- ///
+ ///
public static Exception DebugReproDirectoryDoesNotExist(string path)
{
- return Exception(11, $"The debug repro directory '{path}' does not exist.");
+ return Exception(11, WellKnownGeneratorMessages.DebugReproDirectoryDoesNotExist(path));
}
- ///
- /// The debug repro contains a file entry that has no mapping.
- ///
+ ///
public static Exception DebugReproMissingFileEntryMapping(string path)
{
- return Exception(12, $"The debug repro file entry with path '{path}' is missing its assembly path mapping.");
+ return Exception(12, WellKnownGeneratorMessages.DebugReproMissingFileEntryMapping(path));
}
- ///
- /// The debug repro contains a file entry that was not recognized.
- ///
+ ///
public static Exception DebugReproUnrecognizedFileEntry(string path)
{
- return Exception(13, $"The debug repro file entry with path '{path}' was not recognized.");
+ return Exception(13, WellKnownGeneratorMessages.DebugReproUnrecognizedFileEntry(path));
}
///
diff --git a/src/WinRT.Impl.Generator/Extensions/RuntimeContextExtensions.cs b/src/WinRT.Impl.Generator/Extensions/RuntimeContextExtensions.cs
deleted file mode 100644
index 55b50ba06f..0000000000
--- a/src/WinRT.Impl.Generator/Extensions/RuntimeContextExtensions.cs
+++ /dev/null
@@ -1,40 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-using System;
-using AsmResolver.DotNet;
-using AsmResolver.PE;
-
-#pragma warning disable IDE0046
-
-namespace WindowsRuntime.ImplGenerator;
-
-///
-/// Extensions for the type.
-///
-internal static class RuntimeContextExtensions
-{
- extension(RuntimeContext signature)
- {
- ///
- /// Loads a .NET module into the context from the provided input image.
- ///
- /// The image containing the .NET metadata.
- /// The module.
- /// Occurs when the image does not contain a valid .NET metadata directory.
- public ModuleDefinition LoadModule(PEImage peImage)
- {
- AssemblyDefinition assemblyDefinition = signature.LoadAssembly(peImage);
-
- // Every valid .NET assembly will always have exactly one module. In practice, we should
- // never encounter an assembly with zero or more than one module, but we can still check
- // and ensure that this is the case, just to guard against malformed .NET assemblies too.
- if (assemblyDefinition.Modules is not [ModuleDefinition moduleDefinition])
- {
- throw new BadImageFormatException();
- }
-
- return moduleDefinition;
- }
- }
-}
\ No newline at end of file
diff --git a/src/WinRT.Impl.Generator/Extensions/SignatureComparerExtensions.cs b/src/WinRT.Impl.Generator/Extensions/SignatureComparerExtensions.cs
deleted file mode 100644
index c1aa401f6a..0000000000
--- a/src/WinRT.Impl.Generator/Extensions/SignatureComparerExtensions.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-using System;
-using System.Collections.Generic;
-using AsmResolver.DotNet.Signatures;
-
-namespace WindowsRuntime.ImplGenerator;
-
-///
-/// Extensions for .
-///
-internal static class SignatureComparerExtensions
-{
-#pragma warning disable IDE0052 // TODO: remove this once Roslyn bug is fixed
- ///
- /// Backing field for .
- ///
- private static readonly SignatureComparer IgnoreVersion = new(SignatureComparisonFlags.VersionAgnostic);
-#pragma warning restore IDE0052
-
- extension(SignatureComparer comparer)
- {
- ///
- /// An immutable default instance of , with .
- ///
- public static SignatureComparer IgnoreVersion => IgnoreVersion;
-
- ///
- /// Creates an instance for a pair of values.
- ///
- /// The resulting instance.
- public IEqualityComparer<(TypeSignature, TypeSignature)> MakeValueTupleComparer()
- {
- return new SignatureValueTupleComparer(comparer);
- }
- }
-}
-
-///
-/// An for a pair of values.
-///
-file sealed class SignatureValueTupleComparer : IEqualityComparer<(TypeSignature, TypeSignature)>
-{
- ///
- /// The wrapped instance used for comparison.
- ///
- private readonly SignatureComparer _comparer;
-
- ///
- /// Creates a new instance with the specified parameters.
- ///
- /// The instance to wrap.
- public SignatureValueTupleComparer(SignatureComparer comparer)
- {
- _comparer = comparer;
- }
-
- ///
- public bool Equals((TypeSignature, TypeSignature) x, (TypeSignature, TypeSignature) y)
- {
- return _comparer.Equals(x.Item1, y.Item1) && _comparer.Equals(x.Item2, y.Item2);
- }
-
- ///
- public int GetHashCode((TypeSignature, TypeSignature) obj)
- {
- return HashCode.Combine(_comparer.GetHashCode(obj.Item1), _comparer.GetHashCode(obj.Item2));
- }
-}
\ No newline at end of file
diff --git a/src/WinRT.Impl.Generator/Generation/ImplGenerator.DebugRepro.cs b/src/WinRT.Impl.Generator/Generation/ImplGenerator.DebugRepro.cs
index 7027c9802d..dea139fcf1 100644
--- a/src/WinRT.Impl.Generator/Generation/ImplGenerator.DebugRepro.cs
+++ b/src/WinRT.Impl.Generator/Generation/ImplGenerator.DebugRepro.cs
@@ -33,11 +33,7 @@ internal static partial class ImplGenerator
/// The path to the resulting response file to use.
private static string UnpackDebugRepro(string path, CancellationToken token)
{
- // Create a temporary directory to extract the files from the debug repro
- string tempFolderName = $"cswinrtimplgen-debug-repro-unpack-{Guid.NewGuid().ToString().ToUpperInvariant()}";
- string tempDirectory = Path.Combine(Path.GetTempPath(), tempFolderName);
-
- _ = Directory.CreateDirectory(tempDirectory);
+ string tempDirectory = DebugReproPacker.CreateUnpackTempDirectory("cswinrtimplgen");
token.ThrowIfCancellationRequested();
@@ -148,21 +144,13 @@ private static void SaveDebugRepro(ImplGeneratorArgs args)
return;
}
- // The target folder must exist
- if (!Directory.Exists(args.DebugReproDirectory))
- {
- throw WellKnownImplExceptions.DebugReproDirectoryDoesNotExist(args.DebugReproDirectory);
- }
-
- // Path for the ZIP archive
- string zipPath = Path.Combine(args.DebugReproDirectory, "impl-debug-repro.zip");
+ (string tempDirectory, string zipPath) = DebugReproPacker.BeginSave(
+ args.DebugReproDirectory,
+ toolName: "cswinrtimplgen",
+ archiveFileName: "impl-debug-repro.zip");
- // Create a temporary directory to stage files for the ZIP
- string tempFolderName = $"cswinrtimplgen-debug-repro-{Guid.NewGuid().ToString().ToUpperInvariant()}";
- string tempDirectory = Path.Combine(Path.GetTempPath(), tempFolderName);
string referenceDirectory = Path.Combine(tempDirectory, "reference");
- _ = Directory.CreateDirectory(tempDirectory);
_ = Directory.CreateDirectory(referenceDirectory);
// Map with all the original paths
@@ -203,16 +191,6 @@ private static void SaveDebugRepro(ImplGeneratorArgs args)
args.Token.ThrowIfCancellationRequested();
- // Delete the previous file, if it exists
- if (File.Exists(zipPath))
- {
- File.Delete(zipPath);
- }
-
- // Create the actual .zip file in the target directory
- ZipFile.CreateFromDirectory(tempDirectory, zipPath);
-
- // Clean up the temporary directory
- Directory.Delete(tempDirectory, recursive: true);
+ DebugReproPacker.FinalizeSave(tempDirectory, zipPath);
}
}
diff --git a/src/WinRT.Impl.Generator/Generation/ImplGenerator.cs b/src/WinRT.Impl.Generator/Generation/ImplGenerator.cs
index a6e2e389a7..331c19a05d 100644
--- a/src/WinRT.Impl.Generator/Generation/ImplGenerator.cs
+++ b/src/WinRT.Impl.Generator/Generation/ImplGenerator.cs
@@ -19,9 +19,11 @@
using ConsoleAppFramework;
using WindowsRuntime.Generator;
using WindowsRuntime.Generator.Errors;
+using WindowsRuntime.Generator.Extensions;
+using WindowsRuntime.Generator.Helpers;
using WindowsRuntime.Generator.Parsing;
+using WindowsRuntime.Generator.References;
using WindowsRuntime.ImplGenerator.Errors;
-using WindowsRuntime.ImplGenerator.References;
namespace WindowsRuntime.ImplGenerator.Generation;
@@ -68,7 +70,7 @@ internal static partial class ImplGenerator
/// The token for the operation.
public static void Run([Argument] string inputFilePath, CancellationToken token)
{
- ImplGeneratorArgs args = GeneratorHost.Prepare(
+ GeneratorPhaseRunner runner = GeneratorHost.CreateRunner(
inputFilePath: inputFilePath,
toolName: "cswinrtimplgen",
unpackDebugRepro: UnpackDebugRepro,
@@ -78,82 +80,43 @@ public static void Run([Argument] string inputFilePath, CancellationToken token)
log: ConsoleApp.Log,
token: token);
- RuntimeContext runtimeContext;
- ModuleDefinition outputModule;
-
// Initialize the assembly resolver and load the output module
- try
- {
- LoadOutputModule(args, out runtimeContext, out outputModule);
- }
- catch (Exception e) when (!e.IsWellKnown)
- {
- throw new UnhandledImplException("loading", e);
- }
-
- args.Token.ThrowIfCancellationRequested();
-
- ModuleDefinition implModule;
+ (RuntimeContext runtimeContext, ModuleDefinition outputModule) = runner.RunPhase(
+ phaseName: "loading",
+ body: LoadOutputModule);
// Define the impl module to emit
- try
- {
- implModule = DefineImplModule(runtimeContext, outputModule);
- }
- catch (Exception e) when (!e.IsWellKnown)
- {
- throw new UnhandledImplException("loading", e);
- }
-
- args.Token.ThrowIfCancellationRequested();
+ ModuleDefinition implModule = runner.RunPhase(
+ phaseName: "loading",
+ body: _ => DefineImplModule(runtimeContext, outputModule));
// Emit all necessary IL code in the impl module
- try
+ runner.RunPhase(phaseName: "generation", body: _ =>
{
EmitAssemblyAttributes(outputModule, implModule);
EmitTypeForwards(outputModule, implModule);
- }
- catch (Exception e) when (!e.IsWellKnown)
- {
- throw new UnhandledImplException("generation", e);
- }
-
- args.Token.ThrowIfCancellationRequested();
+ });
// Write the module to disk with all the generated contents
- try
- {
- WriteImplModuleToDisk(args, outputModule, implModule);
- }
- catch (Exception e) when (!e.IsWellKnown)
- {
- throw new UnhandledImplException("emit", e);
- }
+ runner.RunPhase(
+ phaseName: "emit",
+ body: args => WriteImplModuleToDisk(args, outputModule, implModule));
// Signs the module on disk, if needed
- try
- {
- SignImplModuleOnDisk(args, outputModule);
- }
- catch (Exception e) when (!e.IsWellKnown)
- {
- throw new UnhandledImplException("sign", e);
- }
+ runner.RunPhase(
+ phaseName: "sign",
+ body: args => SignImplModuleOnDisk(args, outputModule));
// Notify the user that generation was successful
- ConsoleApp.Log($"Impl code generated -> {Path.Combine(args.GeneratedAssemblyDirectory, implModule.Name!)}");
+ ConsoleApp.Log($"Impl code generated -> {Path.Combine(runner.Args.GeneratedAssemblyDirectory, implModule.Name!)}");
}
///
/// Loads the output assembly being produced.
///
/// The arguments for this invocation.
- /// The instance in use.
- /// The loaded for the output assembly.
- private static void LoadOutputModule(
- ImplGeneratorArgs args,
- out RuntimeContext runtimeContext,
- out ModuleDefinition outputModule)
+ /// The instance in use and the loaded for the output assembly.
+ private static (RuntimeContext RuntimeContext, ModuleDefinition OutputModule) LoadOutputModule(ImplGeneratorArgs args)
{
PEImage outputAssemblyImage;
@@ -178,12 +141,12 @@ private static void LoadOutputModule(
PathAssemblyResolver assemblyResolver = new(args.ReferenceAssemblyPaths);
// Initialize the runtime context (this will be reused to allow caching)
- runtimeContext = new RuntimeContext(targetRuntime, assemblyResolver);
+ RuntimeContext runtimeContext = new(targetRuntime, assemblyResolver);
// Try to load the .dll at the current path
try
{
- outputModule = runtimeContext.LoadModule(outputAssemblyImage);
+ return (runtimeContext, runtimeContext.LoadModule(outputAssemblyImage));
}
catch (Exception e)
{
@@ -276,7 +239,7 @@ private static void EmitTypeForwards(ModuleDefinition inputModule, ModuleDefinit
// will always have a version number equal or higher than this, so it will load correctly.
AssemblyReference sdkProjectionAssembly = new("WinRT.Sdk.Projection"u8, new Version(0, 0, 0, 0))
{
- PublicKeyOrToken = ImplValues.PublicKeyData,
+ PublicKeyOrToken = WellKnownPublicKeys.WindowsSdkProjection,
HasPublicKey = true
};
@@ -284,7 +247,7 @@ private static void EmitTypeForwards(ModuleDefinition inputModule, ModuleDefinit
// This is only used when the option to use Windows UI Xaml projections is enabled.
AssemblyReference sdkXamlProjectionAssembly = new("WinRT.Sdk.Xaml.Projection"u8, new Version(0, 0, 0, 0))
{
- PublicKeyOrToken = ImplValues.PublicKeyData,
+ PublicKeyOrToken = WellKnownPublicKeys.WindowsSdkProjection,
HasPublicKey = true
};
@@ -292,7 +255,7 @@ private static void EmitTypeForwards(ModuleDefinition inputModule, ModuleDefinit
// Unlike the implementation .dll for the Windows SDK however, this .dll is created on the fly.
AssemblyReference projectionAssembly = new("WinRT.Projection"u8, new Version(0, 0, 0, 0))
{
- PublicKeyOrToken = ImplValues.PublicKeyData,
+ PublicKeyOrToken = WellKnownPublicKeys.WindowsSdkProjection,
HasPublicKey = true
};
diff --git a/src/WinRT.Impl.Generator/Helpers/MvidGenerator.cs b/src/WinRT.Impl.Generator/Helpers/MvidGenerator.cs
deleted file mode 100644
index 4a87706e0c..0000000000
--- a/src/WinRT.Impl.Generator/Helpers/MvidGenerator.cs
+++ /dev/null
@@ -1,36 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-using System;
-using System.Security.Cryptography;
-
-namespace WindowsRuntime.ImplGenerator;
-
-///
-/// A generator for MVIDs for .NET modules.
-///
-internal static class MvidGenerator
-{
- ///
- /// Generates a deterministic MVID based on two input IIDs.
- ///
- /// The first IID to combine.
- /// The second IID to combine.
- /// The resulting MVID.
- public static Guid CreateMvid(Guid left, Guid right)
- {
- Span input = stackalloc byte[32];
-
- // Write the two IIDs in sequence
- _ = left.TryWriteBytes(input, bigEndian: true, out _);
- _ = right.TryWriteBytes(input[16..], bigEndian: true, out _);
-
- Span hash = stackalloc byte[SHA1.HashSizeInBytes];
-
- // Hash the two IIDs together (the order matters)
- _ = SHA1.HashData(input, hash);
-
- // Create the final MVID from the first 16 bytes of the hash
- return new(hash[..16]);
- }
-}
diff --git a/src/WinRT.Impl.Generator/References/ImplValues.cs b/src/WinRT.Impl.Generator/References/ImplValues.cs
deleted file mode 100644
index e29b8828de..0000000000
--- a/src/WinRT.Impl.Generator/References/ImplValues.cs
+++ /dev/null
@@ -1,20 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-namespace WindowsRuntime.ImplGenerator.References;
-
-///
-/// Well known impl values (constants).
-///
-internal static class ImplValues
-{
- ///
- /// The public key for CsWinRT assemblies.
- ///
- public const string PublicKey = "0024000004800000940000000602000000240000525341310004000001000100B5FC90E7027F67871E773A8FDE8938C81DD402BA65B9201D60593E96C492651E889CC13F1415EBB53FAC1131AE0BD333C5EE6021672D9718EA31A8AEBD0DA0072F25D87DBA6FC90FFD598ED4DA35E44C398C454307E8E33B8426143DAEC9F596836F97C8F74750E5975C64E2189F45DEF46B2A2B1247ADC3652BF5C308055DA9";
-
- ///
- /// The public key data for CsWinRT assemblies.
- ///
- public static readonly byte[] PublicKeyData = [0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x06, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x52, 0x53, 0x41, 0x31, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xB5, 0xFC, 0x90, 0xE7, 0x02, 0x7F, 0x67, 0x87, 0x1E, 0x77, 0x3A, 0x8F, 0xDE, 0x89, 0x38, 0xC8, 0x1D, 0xD4, 0x02, 0xBA, 0x65, 0xB9, 0x20, 0x1D, 0x60, 0x59, 0x3E, 0x96, 0xC4, 0x92, 0x65, 0x1E, 0x88, 0x9C, 0xC1, 0x3F, 0x14, 0x15, 0xEB, 0xB5, 0x3F, 0xAC, 0x11, 0x31, 0xAE, 0x0B, 0xD3, 0x33, 0xC5, 0xEE, 0x60, 0x21, 0x67, 0x2D, 0x97, 0x18, 0xEA, 0x31, 0xA8, 0xAE, 0xBD, 0x0D, 0xA0, 0x07, 0x2F, 0x25, 0xD8, 0x7D, 0xBA, 0x6F, 0xC9, 0x0F, 0xFD, 0x59, 0x8E, 0xD4, 0xDA, 0x35, 0xE4, 0x4C, 0x39, 0x8C, 0x45, 0x43, 0x07, 0xE8, 0xE3, 0x3B, 0x84, 0x26, 0x14, 0x3D, 0xAE, 0xC9, 0xF5, 0x96, 0x83, 0x6F, 0x97, 0xC8, 0xF7, 0x47, 0x50, 0xE5, 0x97, 0x5C, 0x64, 0xE2, 0x18, 0x9F, 0x45, 0xDE, 0xF4, 0x6B, 0x2A, 0x2B, 0x12, 0x47, 0xAD, 0xC3, 0x65, 0x2B, 0xF5, 0xC3, 0x08, 0x05, 0x5D, 0xA9];
-}
\ No newline at end of file
diff --git a/src/WinRT.Interop.Generator/Errors/UnhandledInteropException.cs b/src/WinRT.Interop.Generator/Errors/UnhandledInteropException.cs
index c4b0ee30bf..972d473b14 100644
--- a/src/WinRT.Interop.Generator/Errors/UnhandledInteropException.cs
+++ b/src/WinRT.Interop.Generator/Errors/UnhandledInteropException.cs
@@ -17,5 +17,5 @@ internal sealed class UnhandledInteropException(string phase, Exception exceptio
protected override string ErrorPrefix => WellKnownInteropExceptions.ErrorPrefix;
///
- protected override string GeneratorDescription => "interop generator";
+ protected override string GeneratorName => "interop";
}
diff --git a/src/WinRT.Interop.Generator/Errors/WellKnownInteropExceptions.cs b/src/WinRT.Interop.Generator/Errors/WellKnownInteropExceptions.cs
index 3f9e6c721f..6df46e720a 100644
--- a/src/WinRT.Interop.Generator/Errors/WellKnownInteropExceptions.cs
+++ b/src/WinRT.Interop.Generator/Errors/WellKnownInteropExceptions.cs
@@ -284,36 +284,28 @@ public static WellKnownInteropException IDictionary2TypeCodeGenerationError(Type
return Exception(27, $"Failed to generate marshalling code for 'IDictionary' type '{dictionaryType}'.", exception);
}
- ///
- /// Some exception was thrown when trying to read the response file.
- ///
+ ///
public static WellKnownInteropException ResponseFileReadError(Exception exception)
{
- return Exception(28, "Failed to read the response file to run 'cswinrtinteropgen'.", exception);
+ return Exception(28, WellKnownGeneratorMessages.ResponseFileReadError, exception);
}
- ///
- /// Failed to parse an argument from the response file.
- ///
+ ///
public static WellKnownInteropException ResponseFileArgumentParsingError(string argumentName, Exception? exception = null)
{
- return Exception(29, $"Failed to parse argument '{argumentName}' from response file.", exception);
+ return Exception(29, WellKnownGeneratorMessages.ResponseFileArgumentParsingError(argumentName), exception);
}
- ///
- /// The input response file is malformed.
- ///
+ ///
public static WellKnownInteropException MalformedResponseFile()
{
- return Exception(30, "The response file is malformed and contains invalid content.");
+ return Exception(30, WellKnownGeneratorMessages.MalformedResponseFile);
}
- ///
- /// The debug repro directory does not exist.
- ///
+ ///
public static WellKnownInteropException DebugReproDirectoryDoesNotExist(string path)
{
- return Exception(31, $"The debug repro directory '{path}' does not exist.");
+ return Exception(31, WellKnownGeneratorMessages.DebugReproDirectoryDoesNotExist(path));
}
///
@@ -788,20 +780,16 @@ public static WellKnownInteropException ReservedDllOriginalPathMismatchFromDebug
return Exception(88, $"The reserved '{dllName}' assembly has a mismatching path with the item supplied via '$(ReferencePath)': the debug repro cannot be generated.");
}
- ///
- /// The debug repro contains a file entry that has no mapping.
- ///
+ ///
public static WellKnownInteropException DebugReproMissingFileEntryMapping(string path)
{
- return Exception(89, $"The debug repro file entry with path '{path}' is missing its assembly path mapping.");
+ return Exception(89, WellKnownGeneratorMessages.DebugReproMissingFileEntryMapping(path));
}
- ///
- /// The debug repro contains a file entry that was not recognized.
- ///
+ ///
public static WellKnownInteropException DebugReproUnrecognizedFileEntry(string path)
{
- return Exception(90, $"The debug repro file entry with path '{path}' was not recognized.");
+ return Exception(90, WellKnownGeneratorMessages.DebugReproUnrecognizedFileEntry(path));
}
///
diff --git a/src/WinRT.Interop.Generator/Extensions/RuntimeContextExtensions.cs b/src/WinRT.Interop.Generator/Extensions/RuntimeContextExtensions.cs
deleted file mode 100644
index 05b9c3833f..0000000000
--- a/src/WinRT.Interop.Generator/Extensions/RuntimeContextExtensions.cs
+++ /dev/null
@@ -1,39 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-using System;
-using AsmResolver.DotNet;
-
-#pragma warning disable IDE0046
-
-namespace WindowsRuntime.InteropGenerator;
-
-///
-/// Extensions for the type.
-///
-internal static class RuntimeContextExtensions
-{
- extension(RuntimeContext signature)
- {
- ///
- /// Loads a .NET module into the context from the provided input file.
- ///
- /// The file path to the input executable to load.
- /// The module.
- /// Occurs when the image does not contain a valid .NET metadata directory.
- public ModuleDefinition LoadModule(string filePath)
- {
- AssemblyDefinition assemblyDefinition = signature.LoadAssembly(filePath);
-
- // Every valid .NET assembly will always have exactly one module. In practice, we should
- // never encounter an assembly with zero or more than one module, but we can still check
- // and ensure that this is the case, just to guard against malformed .NET assemblies too.
- if (assemblyDefinition.Modules is not [ModuleDefinition moduleDefinition])
- {
- throw new BadImageFormatException();
- }
-
- return moduleDefinition;
- }
- }
-}
\ No newline at end of file
diff --git a/src/WinRT.Interop.Generator/Generation/InteropGenerator.DebugRepro.cs b/src/WinRT.Interop.Generator/Generation/InteropGenerator.DebugRepro.cs
index e5309cf44c..f39a75b95b 100644
--- a/src/WinRT.Interop.Generator/Generation/InteropGenerator.DebugRepro.cs
+++ b/src/WinRT.Interop.Generator/Generation/InteropGenerator.DebugRepro.cs
@@ -38,11 +38,7 @@ internal partial class InteropGenerator
/// The path to the resulting response file to use.
private static string UnpackDebugRepro(string path, CancellationToken token)
{
- // Create a temporary directory to extract the files from the debug repro
- string tempFolderName = $"cswinrtinteropgen-debug-repro-unpack-{Guid.NewGuid().ToString().ToUpperInvariant()}";
- string tempDirectory = Path.Combine(Path.GetTempPath(), tempFolderName);
-
- _ = Directory.CreateDirectory(tempDirectory);
+ string tempDirectory = DebugReproPacker.CreateUnpackTempDirectory("cswinrtinteropgen");
token.ThrowIfCancellationRequested();
@@ -205,22 +201,14 @@ private static void SaveDebugRepro(InteropGeneratorArgs args)
return;
}
- // The target folder must exist
- if (!Directory.Exists(args.DebugReproDirectory))
- {
- throw WellKnownInteropExceptions.DebugReproDirectoryDoesNotExist(args.DebugReproDirectory);
- }
-
- // Path for the ZIP archive
- string zipPath = Path.Combine(args.DebugReproDirectory, "interop-debug-repro.zip");
+ (string tempDirectory, string zipPath) = DebugReproPacker.BeginSave(
+ args.DebugReproDirectory,
+ toolName: "cswinrtinteropgen",
+ archiveFileName: "interop-debug-repro.zip");
- // Create a temporary directory to stage files for the ZIP
- string tempFolderName = $"cswinrtinteropgen-debug-repro-{Guid.NewGuid().ToString().ToUpperInvariant()}";
- string tempDirectory = Path.Combine(Path.GetTempPath(), tempFolderName);
string referenceDirectory = Path.Combine(tempDirectory, "reference");
string implementationDirectory = Path.Combine(tempDirectory, "implementation");
- _ = Directory.CreateDirectory(tempDirectory);
_ = Directory.CreateDirectory(referenceDirectory);
_ = Directory.CreateDirectory(implementationDirectory);
@@ -282,17 +270,7 @@ private static void SaveDebugRepro(InteropGeneratorArgs args)
args.Token.ThrowIfCancellationRequested();
- // Delete the previous file, if it exists
- if (File.Exists(zipPath))
- {
- File.Delete(zipPath);
- }
-
- // Create the actual .zip file in the target directory
- ZipFile.CreateFromDirectory(tempDirectory, zipPath);
-
- // Clean up the temporary directory
- Directory.Delete(tempDirectory, recursive: true);
+ DebugReproPacker.FinalizeSave(tempDirectory, zipPath);
}
///
diff --git a/src/WinRT.Interop.Generator/Generation/InteropGenerator.Discover.cs b/src/WinRT.Interop.Generator/Generation/InteropGenerator.Discover.cs
index 1608a1ed40..42760ba3c2 100644
--- a/src/WinRT.Interop.Generator/Generation/InteropGenerator.Discover.cs
+++ b/src/WinRT.Interop.Generator/Generation/InteropGenerator.Discover.cs
@@ -11,6 +11,8 @@
using AsmResolver.DotNet.Signatures;
using AsmResolver.PE;
using WindowsRuntime.Generator.Errors;
+using WindowsRuntime.Generator.Extensions;
+using WindowsRuntime.Generator.References;
using WindowsRuntime.InteropGenerator.Discovery;
using WindowsRuntime.InteropGenerator.Errors;
using WindowsRuntime.InteropGenerator.Models;
@@ -556,7 +558,7 @@ private static InteropReferences CreateDiscoveryInteropReferences(ModuleDefiniti
AssemblyReference windowsRuntimeAssembly = new("WinRT.Runtime"u8, windowsRuntimeVersion)
{
// Set the public keys, as it's needed to ensure references compare as equals as expected
- PublicKeyOrToken = InteropValues.CsWinRTPublicKeyData,
+ PublicKeyOrToken = WellKnownPublicKeys.CsWinRT,
HasPublicKey = true
};
diff --git a/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs b/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs
index 24da3772da..012efd323f 100644
--- a/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs
+++ b/src/WinRT.Interop.Generator/Generation/InteropGenerator.Emit.cs
@@ -10,10 +10,10 @@
using AsmResolver.DotNet.Signatures;
using WindowsRuntime.Generator;
using WindowsRuntime.Generator.Errors;
+using WindowsRuntime.Generator.Helpers;
using WindowsRuntime.InteropGenerator.Builders;
using WindowsRuntime.InteropGenerator.Errors;
using WindowsRuntime.InteropGenerator.Fixups;
-using WindowsRuntime.InteropGenerator.Helpers;
using WindowsRuntime.InteropGenerator.Models;
using WindowsRuntime.InteropGenerator.References;
using WindowsRuntime.InteropGenerator.Rewriters;
diff --git a/src/WinRT.Interop.Generator/Generation/InteropGenerator.cs b/src/WinRT.Interop.Generator/Generation/InteropGenerator.cs
index 44693e753d..7ec2f9c60c 100644
--- a/src/WinRT.Interop.Generator/Generation/InteropGenerator.cs
+++ b/src/WinRT.Interop.Generator/Generation/InteropGenerator.cs
@@ -1,12 +1,10 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
-using System;
using System.IO;
using System.Threading;
using ConsoleAppFramework;
using WindowsRuntime.Generator;
-using WindowsRuntime.Generator.Errors;
using WindowsRuntime.Generator.Parsing;
using WindowsRuntime.InteropGenerator.Errors;
using WindowsRuntime.InteropGenerator.References;
@@ -25,7 +23,7 @@ internal static partial class InteropGenerator
/// The token for the operation.
public static void Run([Argument] string inputFilePath, CancellationToken token)
{
- InteropGeneratorArgs args = GeneratorHost.Prepare(
+ GeneratorPhaseRunner runner = GeneratorHost.CreateRunner(
inputFilePath: inputFilePath,
toolName: "cswinrtinteropgen",
unpackDebugRepro: UnpackDebugRepro,
@@ -35,38 +33,19 @@ public static void Run([Argument] string inputFilePath, CancellationToken token)
log: ConsoleApp.Log,
token: token);
- InteropGeneratorDiscoveryState discoveryState;
+ // Discover the types to process
+ InteropGeneratorDiscoveryState discoveryState = runner.RunPhase(
+ phaseName: "discovery",
+ logMessage: $"Processing {runner.Args.ReferenceAssemblyPaths.Length + runner.Args.ImplementationAssemblyPaths.Length + 1} module(s)",
+ body: Discover);
- // Wrap the actual logic, to ensure that we're only ever throwing an exception that will result
- // in either graceful cancellation, or a well formatted error message. The 'ConsoleApp' code is
- // taking care of passing the exception 'ToString()' result to the output buffer, so we want all
- // exceptions that can reach that path to have our custom formatting implementation there.
- try
- {
- ConsoleApp.Log($"Processing {args.ReferenceAssemblyPaths.Length + args.ImplementationAssemblyPaths.Length + 1} module(s)");
-
- discoveryState = Discover(args);
- }
- catch (Exception e) when (!e.IsWellKnown)
- {
- throw new UnhandledInteropException("discovery", e);
- }
-
- args.Token.ThrowIfCancellationRequested();
-
- // Same thing for the emit phase
- try
- {
- ConsoleApp.Log("Generating interop code");
-
- Emit(args, discoveryState);
- }
- catch (Exception e) when (!e.IsWellKnown)
- {
- throw new UnhandledInteropException("emit", e);
- }
+ // Emit the resulting interop assembly
+ runner.RunPhase(
+ phaseName: "emit",
+ logMessage: "Generating interop code",
+ body: args => Emit(args, discoveryState));
// Notify the user that generation was successful
- ConsoleApp.Log($"Interop code generated -> {Path.Combine(args.GeneratedAssemblyDirectory, InteropNames.WindowsRuntimeInteropDllName)}");
+ ConsoleApp.Log($"Interop code generated -> {Path.Combine(runner.Args.GeneratedAssemblyDirectory, InteropNames.WindowsRuntimeInteropDllName)}");
}
}
\ No newline at end of file
diff --git a/src/WinRT.Interop.Generator/References/InteropReferences.cs b/src/WinRT.Interop.Generator/References/InteropReferences.cs
index fb8e570927..77c1e2ed9d 100644
--- a/src/WinRT.Interop.Generator/References/InteropReferences.cs
+++ b/src/WinRT.Interop.Generator/References/InteropReferences.cs
@@ -4,6 +4,7 @@
using System;
using AsmResolver.DotNet;
using AsmResolver.DotNet.Signatures;
+using WindowsRuntime.Generator.References;
using WindowsRuntime.InteropGenerator.Factories;
#pragma warning disable IDE0032
diff --git a/src/WinRT.Interop.Generator/References/InteropValues.cs b/src/WinRT.Interop.Generator/References/InteropValues.cs
deleted file mode 100644
index a74b9748d5..0000000000
--- a/src/WinRT.Interop.Generator/References/InteropValues.cs
+++ /dev/null
@@ -1,30 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-namespace WindowsRuntime.InteropGenerator.References;
-
-///
-/// Well known interop values (constants).
-///
-internal static class InteropValues
-{
- ///
- /// The public key for CsWinRT assemblies.
- ///
- public const string CsWinRTPublicKey = "0024000004800000940000000602000000240000525341310004000001000100653243C2EC7B83009293B0E798193A8BB10390B5A12A3F2D5C58282D7129DAD2D0C012755329C1A45173E1AC9B8B4C0A4E078230BDD5E8CE3932083B09892D828E4B18AF00CE746BCC994DAD06ACEC3E69793E75F8D2CC8E77F44668550CA9B83DD6482DA9AA4D2E8BCF2E1793CF84C495346B1B99EB99767FB41246672E7CF0";
-
- ///
- /// The public key for Windows SDK projection assemblies.
- ///
- public const string WindowsSdkProjectionPublicKey = "0024000004800000940000000602000000240000525341310004000001000100B5FC90E7027F67871E773A8FDE8938C81DD402BA65B9201D60593E96C492651E889CC13F1415EBB53FAC1131AE0BD333C5EE6021672D9718EA31A8AEBD0DA0072F25D87DBA6FC90FFD598ED4DA35E44C398C454307E8E33B8426143DAEC9F596836F97C8F74750E5975C64E2189F45DEF46B2A2B1247ADC3652BF5C308055DA9";
-
- ///
- /// The public key data for CsWinRT assemblies.
- ///
- public static readonly byte[] CsWinRTPublicKeyData = [0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x06, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x52, 0x53, 0x41, 0x31, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x65, 0x32, 0x43, 0xC2, 0xEC, 0x7B, 0x83, 0x00, 0x92, 0x93, 0xB0, 0xE7, 0x98, 0x19, 0x3A, 0x8B, 0xB1, 0x03, 0x90, 0xB5, 0xA1, 0x2A, 0x3F, 0x2D, 0x5C, 0x58, 0x28, 0x2D, 0x71, 0x29, 0xDA, 0xD2, 0xD0, 0xC0, 0x12, 0x75, 0x53, 0x29, 0xC1, 0xA4, 0x51, 0x73, 0xE1, 0xAC, 0x9B, 0x8B, 0x4C, 0x0A, 0x4E, 0x07, 0x82, 0x30, 0xBD, 0xD5, 0xE8, 0xCE, 0x39, 0x32, 0x08, 0x3B, 0x09, 0x89, 0x2D, 0x82, 0x8E, 0x4B, 0x18, 0xAF, 0x00, 0xCE, 0x74, 0x6B, 0xCC, 0x99, 0x4D, 0xAD, 0x06, 0xAC, 0xEC, 0x3E, 0x69, 0x79, 0x3E, 0x75, 0xF8, 0xD2, 0xCC, 0x8E, 0x77, 0xF4, 0x46, 0x68, 0x55, 0x0C, 0xA9, 0xB8, 0x3D, 0xD6, 0x48, 0x2D, 0xA9, 0xAA, 0x4D, 0x2E, 0x8B, 0xCF, 0x2E, 0x17, 0x93, 0xCF, 0x84, 0xC4, 0x95, 0x34, 0x6B, 0x1B, 0x99, 0xEB, 0x99, 0x76, 0x7F, 0xB4, 0x12, 0x46, 0x67, 0x2E, 0x7C, 0xF0];
-
- ///
- /// The public key data for Windows SDK projection assemblies.
- ///
- public static readonly byte[] WindowsSdkProjectionPublicKeyData = [0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x06, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x52, 0x53, 0x41, 0x31, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xB5, 0xFC, 0x90, 0xE7, 0x02, 0x7F, 0x67, 0x87, 0x1E, 0x77, 0x3A, 0x8F, 0xDE, 0x89, 0x38, 0xC8, 0x1D, 0xD4, 0x02, 0xBA, 0x65, 0xB9, 0x20, 0x1D, 0x60, 0x59, 0x3E, 0x96, 0xC4, 0x92, 0x65, 0x1E, 0x88, 0x9C, 0xC1, 0x3F, 0x14, 0x15, 0xEB, 0xB5, 0x3F, 0xAC, 0x11, 0x31, 0xAE, 0x0B, 0xD3, 0x33, 0xC5, 0xEE, 0x60, 0x21, 0x67, 0x2D, 0x97, 0x18, 0xEA, 0x31, 0xA8, 0xAE, 0xBD, 0x0D, 0xA0, 0x07, 0x2F, 0x25, 0xD8, 0x7D, 0xBA, 0x6F, 0xC9, 0x0F, 0xFD, 0x59, 0x8E, 0xD4, 0xDA, 0x35, 0xE4, 0x4C, 0x39, 0x8C, 0x45, 0x43, 0x07, 0xE8, 0xE3, 0x3B, 0x84, 0x26, 0x14, 0x3D, 0xAE, 0xC9, 0xF5, 0x96, 0x83, 0x6F, 0x97, 0xC8, 0xF7, 0x47, 0x50, 0xE5, 0x97, 0x5C, 0x64, 0xE2, 0x18, 0x9F, 0x45, 0xDE, 0xF4, 0x6B, 0x2A, 0x2B, 0x12, 0x47, 0xAD, 0xC3, 0x65, 0x2B, 0xF5, 0xC3, 0x08, 0x05, 0x5D, 0xA9];
-}
\ No newline at end of file
diff --git a/src/WinRT.Interop.Generator/References/WellKnownInterfaceIIDs.cs b/src/WinRT.Interop.Generator/References/WellKnownInterfaceIIDs.cs
index 4d56b5bdfd..fafda0e0fb 100644
--- a/src/WinRT.Interop.Generator/References/WellKnownInterfaceIIDs.cs
+++ b/src/WinRT.Interop.Generator/References/WellKnownInterfaceIIDs.cs
@@ -65,7 +65,7 @@ internal static class WellKnownInterfaceIIDs
/// Whether to use Windows.UI.Xaml projections.
/// The instance to use.
/// The for the get_IID_... method for .
- ///
+ ///
///
/// The types handled by this method should be kept in sync with
/// and
diff --git a/src/WinRT.Projection.Generator/Errors/UnhandledProjectionGeneratorException.cs b/src/WinRT.Projection.Generator/Errors/UnhandledProjectionGeneratorException.cs
index 75bff109be..da7ea08ff4 100644
--- a/src/WinRT.Projection.Generator/Errors/UnhandledProjectionGeneratorException.cs
+++ b/src/WinRT.Projection.Generator/Errors/UnhandledProjectionGeneratorException.cs
@@ -17,6 +17,6 @@ internal sealed class UnhandledProjectionGeneratorException(string phase, Except
protected override string ErrorPrefix => WellKnownProjectionGeneratorExceptions.ErrorPrefix;
///
- protected override string GeneratorDescription => "projection generator";
+ protected override string GeneratorName => "projection";
}
diff --git a/src/WinRT.Projection.Generator/Errors/WellKnownProjectionGeneratorExceptions.cs b/src/WinRT.Projection.Generator/Errors/WellKnownProjectionGeneratorExceptions.cs
index 5a6c98cc04..4ac475f319 100644
--- a/src/WinRT.Projection.Generator/Errors/WellKnownProjectionGeneratorExceptions.cs
+++ b/src/WinRT.Projection.Generator/Errors/WellKnownProjectionGeneratorExceptions.cs
@@ -26,28 +26,22 @@ private WellKnownProjectionGeneratorExceptions()
{
}
- ///
- /// Some exception was thrown when trying to read the response file.
- ///
+ ///
public static Exception ResponseFileReadError(Exception exception)
{
- return Exception(1, "Failed to read the response file to run 'cswinrtprojectiongen'.", exception);
+ return Exception(1, WellKnownGeneratorMessages.ResponseFileReadError, exception);
}
- ///
- /// Failed to parse an argument from the response file.
- ///
+ ///
public static Exception ResponseFileArgumentParsingError(string argumentName, Exception? exception = null)
{
- return Exception(2, $"Failed to parse argument '{argumentName}' from response file.", exception);
+ return Exception(2, WellKnownGeneratorMessages.ResponseFileArgumentParsingError(argumentName), exception);
}
- ///
- /// The input response file is malformed.
- ///
+ ///
public static Exception MalformedResponseFile()
{
- return Exception(3, "The response file is malformed and contains invalid content.");
+ return Exception(3, WellKnownGeneratorMessages.MalformedResponseFile);
}
///
@@ -100,28 +94,22 @@ public static Exception CsWinRTProcessError(int exitCode, Exception exception)
return Exception(8, $"The projection writer failed during source generation (exit code {exitCode}).", exception);
}
- ///
- /// The debug repro directory does not exist.
- ///
+ ///
public static Exception DebugReproDirectoryDoesNotExist(string path)
{
- return Exception(9, $"The debug repro directory '{path}' does not exist.");
+ return Exception(9, WellKnownGeneratorMessages.DebugReproDirectoryDoesNotExist(path));
}
- ///
- /// The debug repro contains a file entry that has no mapping.
- ///
+ ///
public static Exception DebugReproMissingFileEntryMapping(string path)
{
- return Exception(10, $"The debug repro file entry with path '{path}' is missing its assembly path mapping.");
+ return Exception(10, WellKnownGeneratorMessages.DebugReproMissingFileEntryMapping(path));
}
- ///
- /// The debug repro contains a file entry that was not recognized.
- ///
+ ///
public static Exception DebugReproUnrecognizedFileEntry(string path)
{
- return Exception(11, $"The debug repro file entry with path '{path}' was not recognized.");
+ return Exception(11, WellKnownGeneratorMessages.DebugReproUnrecognizedFileEntry(path));
}
///
diff --git a/src/WinRT.Projection.Generator/Extensions/SignatureComparerExtensions.cs b/src/WinRT.Projection.Generator/Extensions/SignatureComparerExtensions.cs
deleted file mode 100644
index 82670098d4..0000000000
--- a/src/WinRT.Projection.Generator/Extensions/SignatureComparerExtensions.cs
+++ /dev/null
@@ -1,70 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-using System;
-using System.Collections.Generic;
-using AsmResolver.DotNet.Signatures;
-
-namespace WindowsRuntime.ProjectionGenerator;
-
-///
-/// Extensions for .
-///
-internal static class SignatureComparerExtensions
-{
-#pragma warning disable IDE0052 // TODO: remove this once Roslyn bug is fixed
- ///
- /// Backing field for .
- ///
- private static readonly SignatureComparer IgnoreVersion = new(SignatureComparisonFlags.VersionAgnostic);
-#pragma warning restore IDE0052
-
- extension(SignatureComparer comparer)
- {
- ///
- /// An immutable default instance of , with .
- ///
- public static SignatureComparer IgnoreVersion => IgnoreVersion;
-
- ///
- /// Creates an instance for a pair of values.
- ///
- /// The resulting instance.
- public IEqualityComparer<(TypeSignature, TypeSignature)> MakeValueTupleComparer()
- {
- return new SignatureValueTupleComparer(comparer);
- }
- }
-}
-
-///
-/// An for a pair of values.
-///
-file sealed class SignatureValueTupleComparer : IEqualityComparer<(TypeSignature, TypeSignature)>
-{
- ///
- /// The wrapped instance used for comparison.
- ///
- private readonly SignatureComparer _comparer;
-
- ///
- /// Creates a new instance with the specified parameters.
- ///
- /// The instance to wrap.
- public SignatureValueTupleComparer(SignatureComparer comparer)
- {
- _comparer = comparer;
- }
-
- ///
- public bool Equals((TypeSignature, TypeSignature) x, (TypeSignature, TypeSignature) y)
- {
- return _comparer.Equals(x.Item1, y.Item1) && _comparer.Equals(x.Item2, y.Item2);
- }
-
- ///
- public int GetHashCode((TypeSignature, TypeSignature) obj)
- {
- return HashCode.Combine(_comparer.GetHashCode(obj.Item1), _comparer.GetHashCode(obj.Item2));
- }
-}
diff --git a/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.DebugRepro.cs b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.DebugRepro.cs
index 22d3816e1a..1e784160d3 100644
--- a/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.DebugRepro.cs
+++ b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.DebugRepro.cs
@@ -60,11 +60,7 @@ internal static partial class ProjectionGenerator
/// The path to the resulting response file to use.
private static string UnpackDebugRepro(string path, CancellationToken token)
{
- // Create a temporary directory to extract the files from the debug repro
- string tempFolderName = $"cswinrtprojectiongen-debug-repro-unpack-{Guid.NewGuid().ToString().ToUpperInvariant()}";
- string tempDirectory = Path.Combine(Path.GetTempPath(), tempFolderName);
-
- _ = Directory.CreateDirectory(tempDirectory);
+ string tempDirectory = DebugReproPacker.CreateUnpackTempDirectory("cswinrtprojectiongen");
token.ThrowIfCancellationRequested();
@@ -209,23 +205,15 @@ private static void SaveDebugRepro(ProjectionGeneratorArgs args)
return;
}
- // The target folder must exist
- if (!Directory.Exists(args.DebugReproDirectory))
- {
- throw WellKnownProjectionGeneratorExceptions.DebugReproDirectoryDoesNotExist(args.DebugReproDirectory);
- }
-
- // Path for the ZIP archive
- string zipPath = Path.Combine(args.DebugReproDirectory, "projection-debug-repro.zip");
+ (string tempDirectory, string zipPath) = DebugReproPacker.BeginSave(
+ args.DebugReproDirectory,
+ toolName: "cswinrtprojectiongen",
+ archiveFileName: "projection-debug-repro.zip");
- // Create a temporary directory to stage files for the ZIP
- string tempFolderName = $"cswinrtprojectiongen-debug-repro-{Guid.NewGuid().ToString().ToUpperInvariant()}";
- string tempDirectory = Path.Combine(Path.GetTempPath(), tempFolderName);
string referenceDirectory = Path.Combine(tempDirectory, ReferenceSubfolder);
string winmdDirectory = Path.Combine(tempDirectory, WinMDSubfolder);
string windowsMetadataDirectory = Path.Combine(tempDirectory, WindowsMetadataSubfolder);
- _ = Directory.CreateDirectory(tempDirectory);
_ = Directory.CreateDirectory(referenceDirectory);
_ = Directory.CreateDirectory(winmdDirectory);
_ = Directory.CreateDirectory(windowsMetadataDirectory);
@@ -301,16 +289,6 @@ private static void SaveDebugRepro(ProjectionGeneratorArgs args)
args.Token.ThrowIfCancellationRequested();
- // Delete the previous file, if it exists
- if (File.Exists(zipPath))
- {
- File.Delete(zipPath);
- }
-
- // Create the actual .zip file in the target directory
- ZipFile.CreateFromDirectory(tempDirectory, zipPath);
-
- // Clean up the temporary directory
- Directory.Delete(tempDirectory, recursive: true);
+ DebugReproPacker.FinalizeSave(tempDirectory, zipPath);
}
}
diff --git a/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.Emit.cs b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.Emit.cs
index 71ad974fbe..506a93f8f8 100644
--- a/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.Emit.cs
+++ b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.Emit.cs
@@ -3,13 +3,14 @@
using System;
using System.Collections.Generic;
-using System.Collections.Immutable;
using System.IO;
+using System.Runtime.InteropServices;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.Text;
using WindowsRuntime.Generator.Errors;
+using WindowsRuntime.Generator.References;
using WindowsRuntime.ProjectionGenerator.Errors;
namespace WindowsRuntime.ProjectionGenerator.Generation;
@@ -17,11 +18,6 @@ namespace WindowsRuntime.ProjectionGenerator.Generation;
///
internal partial class ProjectionGenerator
{
- ///
- /// The public key for CsWinRT assemblies, used for delay signing projection DLLs.
- ///
- private static readonly ImmutableArray CsWinRTPublicKey = [0x00, 0x24, 0x00, 0x00, 0x04, 0x80, 0x00, 0x00, 0x94, 0x00, 0x00, 0x00, 0x06, 0x02, 0x00, 0x00, 0x00, 0x24, 0x00, 0x00, 0x52, 0x53, 0x41, 0x31, 0x00, 0x04, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0xB5, 0xFC, 0x90, 0xE7, 0x02, 0x7F, 0x67, 0x87, 0x1E, 0x77, 0x3A, 0x8F, 0xDE, 0x89, 0x38, 0xC8, 0x1D, 0xD4, 0x02, 0xBA, 0x65, 0xB9, 0x20, 0x1D, 0x60, 0x59, 0x3E, 0x96, 0xC4, 0x92, 0x65, 0x1E, 0x88, 0x9C, 0xC1, 0x3F, 0x14, 0x15, 0xEB, 0xB5, 0x3F, 0xAC, 0x11, 0x31, 0xAE, 0x0B, 0xD3, 0x33, 0xC5, 0xEE, 0x60, 0x21, 0x67, 0x2D, 0x97, 0x18, 0xEA, 0x31, 0xA8, 0xAE, 0xBD, 0x0D, 0xA0, 0x07, 0x2F, 0x25, 0xD8, 0x7D, 0xBA, 0x6F, 0xC9, 0x0F, 0xFD, 0x59, 0x8E, 0xD4, 0xDA, 0x35, 0xE4, 0x4C, 0x39, 0x8C, 0x45, 0x43, 0x07, 0xE8, 0xE3, 0x3B, 0x84, 0x26, 0x14, 0x3D, 0xAE, 0xC9, 0xF5, 0x96, 0x83, 0x6F, 0x97, 0xC8, 0xF7, 0x47, 0x50, 0xE5, 0x97, 0x5C, 0x64, 0xE2, 0x18, 0x9F, 0x45, 0xDE, 0xF4, 0x6B, 0x2A, 0x2B, 0x12, 0x47, 0xAD, 0xC3, 0x65, 0x2B, 0xF5, 0xC3, 0x08, 0x05, 0x5D, 0xA9];
-
///
/// Runs the emit logic for the generator.
///
@@ -68,7 +64,7 @@ private static void Emit(ProjectionGeneratorArgs args, ProjectionGeneratorProces
allowUnsafe: true,
optimizationLevel: OptimizationLevel.Release,
deterministic: true,
- cryptoPublicKey: CsWinRTPublicKey,
+ cryptoPublicKey: ImmutableCollectionsMarshal.AsImmutableArray(WellKnownPublicKeys.WindowsSdkProjection),
delaySign: true,
generalDiagnosticOption: ReportDiagnostic.Info));
}
diff --git a/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.Generate.cs b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.Generate.cs
index 3b2e71e2f5..58e6fba9ee 100644
--- a/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.Generate.cs
+++ b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.Generate.cs
@@ -67,7 +67,7 @@ private static void GenerateSources(ProjectionGeneratorProcessingState processin
// Invoke the projection writer in-process via its public C# API.
try
{
- global::WindowsRuntime.ProjectionWriter.ProjectionWriter.Run(processingState.WriterOptions);
+ ProjectionWriter.ProjectionWriter.Run(processingState.WriterOptions);
}
catch (Exception e) when (!e.IsWellKnown)
{
diff --git a/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.cs b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.cs
index 4844f07463..7bb3a9ffb1 100644
--- a/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.cs
+++ b/src/WinRT.Projection.Generator/Generation/ProjectionGenerator.cs
@@ -1,12 +1,10 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
-using System;
using System.IO;
using System.Threading;
using ConsoleAppFramework;
using WindowsRuntime.Generator;
-using WindowsRuntime.Generator.Errors;
using WindowsRuntime.Generator.Parsing;
using WindowsRuntime.ProjectionGenerator.Errors;
@@ -24,7 +22,7 @@ internal static partial class ProjectionGenerator
/// The token for the operation.
public static void Run([Argument] string inputFilePath, CancellationToken token)
{
- ProjectionGeneratorArgs args = GeneratorHost.Prepare(
+ GeneratorPhaseRunner runner = GeneratorHost.CreateRunner(
inputFilePath: inputFilePath,
toolName: "cswinrtprojectiongen",
unpackDebugRepro: UnpackDebugRepro,
@@ -34,29 +32,18 @@ public static void Run([Argument] string inputFilePath, CancellationToken token)
log: ConsoleApp.Log,
token: token);
- ProjectionGeneratorProcessingState processingState;
-
- // Process all .winmd references
- try
- {
- // Show the appropriate message to inform users of what this generator is doing,
- // based on the input arguments. If we don't have precompiled projections, this
- // tool might run up to 3 times during builds, so this helps make things clearer.
- ConsoleApp.Log(args switch
+ // Process all .winmd references. Show the appropriate message to inform users of what this
+ // generator is doing, based on the input arguments. If we don't have precompiled projections,
+ // this tool might run up to 3 times during builds, so this helps make things clearer.
+ ProjectionGeneratorProcessingState processingState = runner.RunPhase(
+ phaseName: "processing",
+ logMessage: runner.Args switch
{
{ WindowsSdkOnly: true, WindowsUIXamlProjection: false } => "Processing Windows SDK .winmd references",
{ WindowsSdkOnly: true, WindowsUIXamlProjection: true } => "Processing 'Windows.UI.Xaml' .winmd references",
- _ => $"Processing {args.WinMDPaths.Length} .winmd reference(s)"
- });
-
- processingState = ProcessReferences(args);
- }
- catch (Exception e) when (!e.IsWellKnown)
- {
- throw new UnhandledProjectionGeneratorException("processing", e);
- }
-
- args.Token.ThrowIfCancellationRequested();
+ _ => $"Processing {runner.Args.WinMDPaths.Length} .winmd reference(s)"
+ },
+ body: ProcessReferences);
// If no types were found to project (e.g., component mode with no component references),
// skip the source generation and emit phases entirely (no .dll will be produced at all).
@@ -66,32 +53,18 @@ public static void Run([Argument] string inputFilePath, CancellationToken token)
}
// Invoke the projection writer (in-process) to generate the projection sources
- try
- {
- ConsoleApp.Log("Generating projection code");
-
- GenerateSources(processingState);
- }
- catch (Exception e) when (!e.IsWellKnown)
- {
- throw new UnhandledProjectionGeneratorException("source-generation", e);
- }
-
- args.Token.ThrowIfCancellationRequested();
+ runner.RunPhase(
+ phaseName: "source-generation",
+ logMessage: "Generating projection code",
+ body: _ => GenerateSources(processingState));
// Invoke Roslyn to compile the generated sources into 'WinRT.Projection.dll'
- try
- {
- ConsoleApp.Log("Compiling projection code");
-
- Emit(args, processingState);
- }
- catch (Exception e) when (!e.IsWellKnown)
- {
- throw new UnhandledProjectionGeneratorException("emit", e);
- }
+ runner.RunPhase(
+ phaseName: "emit",
+ logMessage: "Compiling projection code",
+ body: args => Emit(args, processingState));
// Notify the user that generation was successful
- ConsoleApp.Log($"Projection code generated -> {Path.Combine(args.GeneratedAssemblyDirectory, args.AssemblyName)}.dll");
+ ConsoleApp.Log($"Projection code generated -> {Path.Combine(runner.Args.GeneratedAssemblyDirectory, runner.Args.AssemblyName)}.dll");
}
}
\ No newline at end of file
diff --git a/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorProcessingState.cs b/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorProcessingState.cs
index fd1ede400c..b4c09a58bb 100644
--- a/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorProcessingState.cs
+++ b/src/WinRT.Projection.Generator/Generation/ProjectionGeneratorProcessingState.cs
@@ -10,7 +10,7 @@ namespace WindowsRuntime.ProjectionGenerator.Generation;
///
/// The path to the folder where sources will be generated.
/// The reference assembly paths excluding projection assemblies.
-/// The options to pass to .
+/// The options to pass to .
/// Whether any types were found to project.
internal sealed class ProjectionGeneratorProcessingState(
string sourcesFolder,
@@ -29,7 +29,7 @@ internal sealed class ProjectionGeneratorProcessingState(
public string[] ReferencesWithoutProjections { get; } = referencesWithoutProjections;
///
- /// Gets the options used to invoke .
+ /// Gets the options used to invoke .
///
public ProjectionWriterOptions WriterOptions { get; } = writerOptions;
diff --git a/src/WinRT.Projection.Ref.Generator/Errors/UnhandledReferenceProjectionGeneratorException.cs b/src/WinRT.Projection.Ref.Generator/Errors/UnhandledReferenceProjectionGeneratorException.cs
index 7c46c60ce8..1bf7f1f132 100644
--- a/src/WinRT.Projection.Ref.Generator/Errors/UnhandledReferenceProjectionGeneratorException.cs
+++ b/src/WinRT.Projection.Ref.Generator/Errors/UnhandledReferenceProjectionGeneratorException.cs
@@ -17,6 +17,6 @@ internal sealed class UnhandledReferenceProjectionGeneratorException(string phas
protected override string ErrorPrefix => WellKnownReferenceProjectionGeneratorExceptions.ErrorPrefix;
///
- protected override string GeneratorDescription => "reference projection generator";
+ protected override string GeneratorName => "reference projection";
}
diff --git a/src/WinRT.Projection.Ref.Generator/Errors/WellKnownReferenceProjectionGeneratorExceptions.cs b/src/WinRT.Projection.Ref.Generator/Errors/WellKnownReferenceProjectionGeneratorExceptions.cs
index b5ae41ee1b..aa3d8014d6 100644
--- a/src/WinRT.Projection.Ref.Generator/Errors/WellKnownReferenceProjectionGeneratorExceptions.cs
+++ b/src/WinRT.Projection.Ref.Generator/Errors/WellKnownReferenceProjectionGeneratorExceptions.cs
@@ -23,28 +23,22 @@ private WellKnownReferenceProjectionGeneratorExceptions()
{
}
- ///
- /// Some exception was thrown when trying to read the response file.
- ///
+ ///
public static Exception ResponseFileReadError(Exception exception)
{
- return Exception(1, "Failed to read the response file to run 'cswinrtprojectionrefgen'.", exception);
+ return Exception(1, WellKnownGeneratorMessages.ResponseFileReadError, exception);
}
- ///
- /// Failed to parse an argument from the response file.
- ///
+ ///
public static Exception ResponseFileArgumentParsingError(string argumentName, Exception? exception = null)
{
- return Exception(2, $"Failed to parse argument '{argumentName}' from response file.", exception);
+ return Exception(2, WellKnownGeneratorMessages.ResponseFileArgumentParsingError(argumentName), exception);
}
- ///
- /// The input response file is malformed.
- ///
+ ///
public static Exception MalformedResponseFile()
{
- return Exception(3, "The response file is malformed and contains invalid content.");
+ return Exception(3, WellKnownGeneratorMessages.MalformedResponseFile);
}
///
@@ -63,28 +57,22 @@ public static Exception CsWinRTProcessError(Exception exception)
return Exception(5, "The projection writer failed during source generation.", exception);
}
- ///
- /// The debug repro directory does not exist.
- ///
+ ///
public static Exception DebugReproDirectoryDoesNotExist(string path)
{
- return Exception(6, $"The debug repro directory '{path}' does not exist.");
+ return Exception(6, WellKnownGeneratorMessages.DebugReproDirectoryDoesNotExist(path));
}
- ///
- /// The debug repro contains a file entry that has no mapping.
- ///
+ ///
public static Exception DebugReproMissingFileEntryMapping(string path)
{
- return Exception(7, $"The debug repro file entry with path '{path}' is missing its assembly path mapping.");
+ return Exception(7, WellKnownGeneratorMessages.DebugReproMissingFileEntryMapping(path));
}
- ///
- /// The debug repro contains a file entry that was not recognized.
- ///
+ ///
public static Exception DebugReproUnrecognizedFileEntry(string path)
{
- return Exception(8, $"The debug repro file entry with path '{path}' was not recognized.");
+ return Exception(8, WellKnownGeneratorMessages.DebugReproUnrecognizedFileEntry(path));
}
///
diff --git a/src/WinRT.Projection.Ref.Generator/Generation/ReferenceProjectionGenerator.DebugRepro.cs b/src/WinRT.Projection.Ref.Generator/Generation/ReferenceProjectionGenerator.DebugRepro.cs
index 1358d044e9..1c08ac14e1 100644
--- a/src/WinRT.Projection.Ref.Generator/Generation/ReferenceProjectionGenerator.DebugRepro.cs
+++ b/src/WinRT.Projection.Ref.Generator/Generation/ReferenceProjectionGenerator.DebugRepro.cs
@@ -33,11 +33,7 @@ internal static partial class ReferenceProjectionGenerator
/// The path to the resulting response file to use.
private static string UnpackDebugRepro(string path, CancellationToken token)
{
- // Create a temporary directory to extract the files from the debug repro
- string tempFolderName = $"cswinrtprojectionrefgen-debug-repro-unpack-{Guid.NewGuid().ToString().ToUpperInvariant()}";
- string tempDirectory = Path.Combine(Path.GetTempPath(), tempFolderName);
-
- _ = Directory.CreateDirectory(tempDirectory);
+ string tempDirectory = DebugReproPacker.CreateUnpackTempDirectory("cswinrtprojectionrefgen");
token.ThrowIfCancellationRequested();
@@ -146,21 +142,13 @@ private static void SaveDebugRepro(ReferenceProjectionGeneratorArgs args)
return;
}
- // The target folder must exist
- if (!Directory.Exists(args.DebugReproDirectory))
- {
- throw WellKnownReferenceProjectionGeneratorExceptions.DebugReproDirectoryDoesNotExist(args.DebugReproDirectory);
- }
-
- // Path for the ZIP archive
- string zipPath = Path.Combine(args.DebugReproDirectory, "ref-projection-debug-repro.zip");
+ (string tempDirectory, string zipPath) = DebugReproPacker.BeginSave(
+ args.DebugReproDirectory,
+ toolName: "cswinrtprojectionrefgen",
+ archiveFileName: "ref-projection-debug-repro.zip");
- // Create a temporary directory to stage files for the ZIP
- string tempFolderName = $"cswinrtprojectionrefgen-debug-repro-{Guid.NewGuid().ToString().ToUpperInvariant()}";
- string tempDirectory = Path.Combine(Path.GetTempPath(), tempFolderName);
string inputDirectory = Path.Combine(tempDirectory, "input");
- _ = Directory.CreateDirectory(tempDirectory);
_ = Directory.CreateDirectory(inputDirectory);
// Expand all input paths (which may be file paths, directories to recursively scan, or
@@ -215,16 +203,6 @@ private static void SaveDebugRepro(ReferenceProjectionGeneratorArgs args)
args.Token.ThrowIfCancellationRequested();
- // Delete the previous file, if it exists
- if (File.Exists(zipPath))
- {
- File.Delete(zipPath);
- }
-
- // Create the actual .zip file in the target directory
- ZipFile.CreateFromDirectory(tempDirectory, zipPath);
-
- // Clean up the temporary directory
- Directory.Delete(tempDirectory, recursive: true);
+ DebugReproPacker.FinalizeSave(tempDirectory, zipPath);
}
}
diff --git a/src/WinRT.Projection.Ref.Generator/Generation/ReferenceProjectionGenerator.cs b/src/WinRT.Projection.Ref.Generator/Generation/ReferenceProjectionGenerator.cs
index 990f39a1ef..a242cbcd8e 100644
--- a/src/WinRT.Projection.Ref.Generator/Generation/ReferenceProjectionGenerator.cs
+++ b/src/WinRT.Projection.Ref.Generator/Generation/ReferenceProjectionGenerator.cs
@@ -29,7 +29,7 @@ internal static partial class ReferenceProjectionGenerator
/// The token for the operation.
public static void Run([Argument] string inputFilePath, CancellationToken token)
{
- ReferenceProjectionGeneratorArgs args = GeneratorHost.Prepare(
+ GeneratorPhaseRunner runner = GeneratorHost.CreateRunner(
inputFilePath: inputFilePath,
toolName: "cswinrtprojectionrefgen",
unpackDebugRepro: UnpackDebugRepro,
@@ -39,32 +39,25 @@ public static void Run([Argument] string inputFilePath, CancellationToken token)
log: ConsoleApp.Log,
token: token);
- // Validate the target framework. CsWinRT 3.0 requires .NET 10 or later.
- if (!string.IsNullOrEmpty(args.TargetFramework) && !args.TargetFramework.StartsWith("net10.0", StringComparison.Ordinal))
+ // Validate the target framework. CsWinRT 3.0 requires .NET 10 or later
+ if (!string.IsNullOrEmpty(runner.Args.TargetFramework) && !runner.Args.TargetFramework.StartsWith("net10.0", StringComparison.Ordinal))
{
- throw WellKnownReferenceProjectionGeneratorExceptions.UnsupportedTargetFramework(args.TargetFramework);
+ throw WellKnownReferenceProjectionGeneratorExceptions.UnsupportedTargetFramework(runner.Args.TargetFramework);
}
// Build the writer options from the parsed arguments
- ProjectionWriterOptions options;
+ ProjectionWriterOptions options = runner.RunPhase(
+ phaseName: "processing",
+ body: BuildWriterOptions);
- try
- {
- options = BuildWriterOptions(args);
- }
- catch (Exception e) when (!e.IsWellKnown)
- {
- throw new UnhandledReferenceProjectionGeneratorException("processing", e);
- }
-
- args.Token.ThrowIfCancellationRequested();
-
- // Invoke the projection writer (in-process) to generate the projection sources
+ // Invoke the projection writer (in-process) to generate the projection sources. We can't
+ // route this through the shared 'runner.RunPhase' helper because we wrap the exception
+ // into a well-known 'CsWinRTProcessError' rather than the per-tool 'Unhandled' factory.
try
{
ConsoleApp.Log($"Generating reference projection sources -> {options.OutputFolder}");
- global::WindowsRuntime.ProjectionWriter.ProjectionWriter.Run(options);
+ ProjectionWriter.ProjectionWriter.Run(options);
}
catch (Exception e) when (!e.IsWellKnown)
{
diff --git a/src/WinRT.Runtime2/Properties/WindowsRuntimeExceptionExtensions.cs b/src/WinRT.Runtime2/Properties/WindowsRuntimeExceptionExtensions.cs
index 06a163f49d..b86a3c1360 100644
--- a/src/WinRT.Runtime2/Properties/WindowsRuntimeExceptionExtensions.cs
+++ b/src/WinRT.Runtime2/Properties/WindowsRuntimeExceptionExtensions.cs
@@ -1106,7 +1106,7 @@ public static ArgumentException GetInvalidSeekOriginException(string? paramName)
extension(UnauthorizedAccessException)
{
///
- /// Throws an indicating that the internal buffer of a cannot be accessed.
+ /// Throws an indicating that the internal buffer of a cannot be accessed.
///
/// Always thrown.
[DoesNotReturn]
diff --git a/src/WinRT.WinMD.Generator/Errors/UnhandledWinMDException.cs b/src/WinRT.WinMD.Generator/Errors/UnhandledWinMDException.cs
index 7faae43b4c..9002ee8c21 100644
--- a/src/WinRT.WinMD.Generator/Errors/UnhandledWinMDException.cs
+++ b/src/WinRT.WinMD.Generator/Errors/UnhandledWinMDException.cs
@@ -17,5 +17,5 @@ internal sealed class UnhandledWinMDException(string phase, Exception exception)
protected override string ErrorPrefix => WellKnownWinMDExceptions.ErrorPrefix;
///
- protected override string GeneratorDescription => "WinMD generator";
+ protected override string GeneratorName => "WinMD";
}
diff --git a/src/WinRT.WinMD.Generator/Errors/WellKnownWinMDExceptions.cs b/src/WinRT.WinMD.Generator/Errors/WellKnownWinMDExceptions.cs
index 58a0678f00..d958c0c7a9 100644
--- a/src/WinRT.WinMD.Generator/Errors/WellKnownWinMDExceptions.cs
+++ b/src/WinRT.WinMD.Generator/Errors/WellKnownWinMDExceptions.cs
@@ -23,28 +23,22 @@ private WellKnownWinMDExceptions()
{
}
- ///
- /// Some exception was thrown when trying to read the response file.
- ///
+ ///
public static Exception ResponseFileReadError(Exception exception)
{
- return Exception(1, "Failed to read the response file to run 'cswinrtwinmdgen'.", exception);
+ return Exception(1, WellKnownGeneratorMessages.ResponseFileReadError, exception);
}
- ///
- /// The input response file is malformed.
- ///
+ ///
public static Exception MalformedResponseFile()
{
- return Exception(2, "The response file is malformed and contains invalid content.");
+ return Exception(2, WellKnownGeneratorMessages.MalformedResponseFile);
}
- ///
- /// Failed to parse an argument from the response file.
- ///
+ ///
public static Exception ResponseFileArgumentParsingError(string argumentName, Exception? exception = null)
{
- return Exception(3, $"Failed to parse argument '{argumentName}' from response file.", exception);
+ return Exception(3, WellKnownGeneratorMessages.ResponseFileArgumentParsingError(argumentName), exception);
}
///
@@ -79,28 +73,22 @@ public static Exception InputAssemblyRuntimeVersionNotFound(string path)
return Exception(7, $"Failed to probe the .NET runtime version from the input assembly '{path}'.");
}
- ///
- /// The debug repro directory does not exist.
- ///
+ ///
public static Exception DebugReproDirectoryDoesNotExist(string path)
{
- return Exception(8, $"The debug repro directory '{path}' does not exist.");
+ return Exception(8, WellKnownGeneratorMessages.DebugReproDirectoryDoesNotExist(path));
}
- ///
- /// The debug repro contains a file entry that has no mapping.
- ///
+ ///
public static Exception DebugReproMissingFileEntryMapping(string path)
{
- return Exception(9, $"The debug repro file entry with path '{path}' is missing its assembly path mapping.");
+ return Exception(9, WellKnownGeneratorMessages.DebugReproMissingFileEntryMapping(path));
}
- ///
- /// The debug repro contains a file entry that was not recognized.
- ///
+ ///
public static Exception DebugReproUnrecognizedFileEntry(string path)
{
- return Exception(10, $"The debug repro file entry with path '{path}' was not recognized.");
+ return Exception(10, WellKnownGeneratorMessages.DebugReproUnrecognizedFileEntry(path));
}
///
diff --git a/src/WinRT.WinMD.Generator/Generation/WinMDGenerator.DebugRepro.cs b/src/WinRT.WinMD.Generator/Generation/WinMDGenerator.DebugRepro.cs
index 49834c4124..4f2ea5783e 100644
--- a/src/WinRT.WinMD.Generator/Generation/WinMDGenerator.DebugRepro.cs
+++ b/src/WinRT.WinMD.Generator/Generation/WinMDGenerator.DebugRepro.cs
@@ -32,11 +32,7 @@ internal static partial class WinMDGenerator
/// The path to the resulting response file to use.
private static string UnpackDebugRepro(string path, CancellationToken token)
{
- // Create a temporary directory to extract the files from the debug repro
- string tempFolderName = $"cswinrtwinmdgen-debug-repro-unpack-{Guid.NewGuid().ToString().ToUpperInvariant()}";
- string tempDirectory = Path.Combine(Path.GetTempPath(), tempFolderName);
-
- _ = Directory.CreateDirectory(tempDirectory);
+ string tempDirectory = DebugReproPacker.CreateUnpackTempDirectory("cswinrtwinmdgen");
token.ThrowIfCancellationRequested();
@@ -159,21 +155,13 @@ private static void SaveDebugRepro(WinMDGeneratorArgs args)
return;
}
- // The target folder must exist
- if (!Directory.Exists(args.DebugReproDirectory))
- {
- throw WellKnownWinMDExceptions.DebugReproDirectoryDoesNotExist(args.DebugReproDirectory);
- }
-
- // Path for the ZIP archive
- string zipPath = Path.Combine(args.DebugReproDirectory, "winmd-debug-repro.zip");
+ (string tempDirectory, string zipPath) = DebugReproPacker.BeginSave(
+ args.DebugReproDirectory,
+ toolName: "cswinrtwinmdgen",
+ archiveFileName: "winmd-debug-repro.zip");
- // Create a temporary directory to stage files for the ZIP
- string tempFolderName = $"cswinrtwinmdgen-debug-repro-{Guid.NewGuid().ToString().ToUpperInvariant()}";
- string tempDirectory = Path.Combine(Path.GetTempPath(), tempFolderName);
string referenceDirectory = Path.Combine(tempDirectory, "reference");
- _ = Directory.CreateDirectory(tempDirectory);
_ = Directory.CreateDirectory(referenceDirectory);
// Map with all the original paths
@@ -214,16 +202,6 @@ private static void SaveDebugRepro(WinMDGeneratorArgs args)
args.Token.ThrowIfCancellationRequested();
- // Delete the previous file, if it exists
- if (File.Exists(zipPath))
- {
- File.Delete(zipPath);
- }
-
- // Create the actual .zip file in the target directory
- ZipFile.CreateFromDirectory(tempDirectory, zipPath);
-
- // Clean up the temporary directory
- Directory.Delete(tempDirectory, recursive: true);
+ DebugReproPacker.FinalizeSave(tempDirectory, zipPath);
}
}
diff --git a/src/WinRT.WinMD.Generator/Generation/WinMDGenerator.Discover.cs b/src/WinRT.WinMD.Generator/Generation/WinMDGenerator.Discover.cs
index ea927ce18b..86ab36b8ec 100644
--- a/src/WinRT.WinMD.Generator/Generation/WinMDGenerator.Discover.cs
+++ b/src/WinRT.WinMD.Generator/Generation/WinMDGenerator.Discover.cs
@@ -6,6 +6,7 @@
using System.Linq;
using AsmResolver.DotNet;
using AsmResolver.PE;
+using WindowsRuntime.Generator.Extensions;
using WindowsRuntime.WinMDGenerator.Discovery;
using WindowsRuntime.WinMDGenerator.Errors;
diff --git a/src/WinRT.WinMD.Generator/Generation/WinMDGenerator.cs b/src/WinRT.WinMD.Generator/Generation/WinMDGenerator.cs
index 8b850ce782..1f71951433 100644
--- a/src/WinRT.WinMD.Generator/Generation/WinMDGenerator.cs
+++ b/src/WinRT.WinMD.Generator/Generation/WinMDGenerator.cs
@@ -1,11 +1,9 @@
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
-using System;
using System.Threading;
using ConsoleAppFramework;
using WindowsRuntime.Generator;
-using WindowsRuntime.Generator.Errors;
using WindowsRuntime.Generator.Parsing;
using WindowsRuntime.WinMDGenerator.Errors;
@@ -39,7 +37,7 @@ internal static partial class WinMDGenerator
/// The token for the operation.
public static void Run([Argument] string inputFilePath, CancellationToken token)
{
- WinMDGeneratorArgs args = GeneratorHost.Prepare(
+ GeneratorPhaseRunner runner = GeneratorHost.CreateRunner(
inputFilePath: inputFilePath,
toolName: "cswinrtwinmdgen",
unpackDebugRepro: UnpackDebugRepro,
@@ -50,33 +48,17 @@ public static void Run([Argument] string inputFilePath, CancellationToken token)
token: token);
// Discover the types to process
- WinMDGeneratorDiscoveryState discoveryState;
-
- try
- {
- ConsoleApp.Log($"Processing assembly: '{System.IO.Path.GetFileName(args.InputAssemblyPath)}'");
-
- discoveryState = Discover(args);
- }
- catch (Exception e) when (!e.IsWellKnown)
- {
- throw new UnhandledWinMDException("discovery", e);
- }
-
- token.ThrowIfCancellationRequested();
+ WinMDGeneratorDiscoveryState discoveryState = runner.RunPhase(
+ phaseName: "discovery",
+ logMessage: $"Processing assembly: '{System.IO.Path.GetFileName(runner.Args.InputAssemblyPath)}'",
+ body: Discover);
// Generate and write the .winmd file
- try
- {
- ConsoleApp.Log($"Defining {discoveryState.PublicTypes.Count} authored type(s)");
-
- Generate(args, discoveryState);
- }
- catch (Exception e) when (!e.IsWellKnown)
- {
- throw new UnhandledWinMDException("generation", e);
- }
+ runner.RunPhase(
+ phaseName: "generation",
+ logMessage: $"Defining {discoveryState.PublicTypes.Count} authored type(s)",
+ body: args => Generate(args, discoveryState));
- ConsoleApp.Log($"Windows Runtime assembly (.winmd) generated -> {args.OutputWinmdPath}");
+ ConsoleApp.Log($"Windows Runtime assembly (.winmd) generated -> {runner.Args.OutputWinmdPath}");
}
}
\ No newline at end of file
diff --git a/src/WinRT.WinMD.Generator/References/WellKnownPublicKeyTokens.cs b/src/WinRT.WinMD.Generator/References/WellKnownPublicKeyTokens.cs
deleted file mode 100644
index 77897462dc..0000000000
--- a/src/WinRT.WinMD.Generator/References/WellKnownPublicKeyTokens.cs
+++ /dev/null
@@ -1,15 +0,0 @@
-// Copyright (c) Microsoft Corporation.
-// Licensed under the MIT License.
-
-namespace WindowsRuntime.WinMDGenerator.References;
-
-///
-/// Well known public key tokens.
-///
-internal static class WellKnownPublicKeyTokens
-{
- ///
- /// The public key data for mscorlib.
- ///
- public static readonly byte[] MSCorLib = [0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89];
-}
\ No newline at end of file
diff --git a/src/WinRT.WinMD.Generator/Writers/WinMDWriter.TypeMapping.cs b/src/WinRT.WinMD.Generator/Writers/WinMDWriter.TypeMapping.cs
index 4412429c39..07a492aa10 100644
--- a/src/WinRT.WinMD.Generator/Writers/WinMDWriter.TypeMapping.cs
+++ b/src/WinRT.WinMD.Generator/Writers/WinMDWriter.TypeMapping.cs
@@ -6,9 +6,9 @@
using AsmResolver.DotNet;
using AsmResolver.DotNet.Signatures;
using AsmResolver.PE.DotNet.Metadata.Tables;
+using WindowsRuntime.Generator.References;
using WindowsRuntime.InteropGenerator.References;
using WindowsRuntime.WinMDGenerator.Models;
-using WindowsRuntime.WinMDGenerator.References;
using AssemblyAttributes = AsmResolver.PE.DotNet.Metadata.Tables.AssemblyAttributes;
#pragma warning disable IDE0072
diff --git a/src/WinRT.WinMD.Generator/Writers/WinMDWriter.cs b/src/WinRT.WinMD.Generator/Writers/WinMDWriter.cs
index bd6ee8f52e..e7af3b363f 100644
--- a/src/WinRT.WinMD.Generator/Writers/WinMDWriter.cs
+++ b/src/WinRT.WinMD.Generator/Writers/WinMDWriter.cs
@@ -4,11 +4,11 @@
using System;
using System.Collections.Generic;
using AsmResolver.DotNet;
+using WindowsRuntime.Generator.References;
using WindowsRuntime.InteropGenerator.References;
using WindowsRuntime.WinMDGenerator.Errors;
using WindowsRuntime.WinMDGenerator.Helpers;
using WindowsRuntime.WinMDGenerator.Models;
-using WindowsRuntime.WinMDGenerator.References;
using AssemblyAttributes = AsmResolver.PE.DotNet.Metadata.Tables.AssemblyAttributes;
#pragma warning disable IDE0046