Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Dec 4, 2025

The ComClassGenerator fails when processing generic COM classes because hint names contain angle brackets <>, which are invalid characters for Roslyn source generators. This causes the generator to throw ArgumentException and produce no output.

[GeneratedComClass]
internal partial class ClassFactory<T> : IClassFactory where T : class, new()
{
    // Previously failed with CS8785 warning:
    // "The hintName 'ClassFactory<T>' contains an invalid character '<' at position 12."
}

Changes:

  • Replace < and > with { and } in hint names when calling context.AddSource() in ComClassGenerator
  • Add test coverage for generic COM class generation in ComClassGeneratorOutputShape
Original prompt

This section details on the original issue you should resolve

<issue_title>COM class source generator fails awkwardly with type generics</issue_title>
<issue_description>When generating a COM class with the COM source generator, the following behavior results. The warneing does indicate some issue, but it is odd it fails for both the generic and non-generic version.

The build has a warning that does indicate the problem, but the run-time behavior is rather confusing.

CSC : warning CS8785: Generator 'ComClassGenerator' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type 'ArgumentException' with message 'The hintName 'ClassFactory<T>' contains an invalid character '<' at position 12. (Parameter 'hintName')'.

Repro:

// > dotnet run
// CSC : warning CS8785: Generator 'ComClassGenerator' failed to generate source. It will not contribute to the output and compilation errors may occur as a result. Exception was of type 'ArgumentException' with message 'The hintName 'ClassFactory<T>' contains an invalid character '<' at position 12. (Parameter 'hintName')'.
// Failed to query for IClassFactory: -2147467262
// Failed to query for IClassFactory: -2147467262

using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;

QueryForClassFactory(new ClassFactory());
QueryForClassFactory(new ClassFactory<object>());

static unsafe void QueryForClassFactory<T>(T t) where T : class, new()
{
    T factory = new();
    nint factoryPtr = (nint)ComInterfaceMarshaller<T>.ConvertToUnmanaged(factory);
    Guid IID_IClassFactory = typeof(IClassFactory).GUID;
    var hr = Marshal.QueryInterface(factoryPtr, in IID_IClassFactory, out nint ppvObject);
    Marshal.Release(factoryPtr);
    if (hr != 0)
    {
        Console.WriteLine($"Failed to query for IClassFactory: {hr}");
        return;
    }

    Console.WriteLine("Successfully queried for IClassFactory.");
    Marshal.Release(ppvObject);
}

[GeneratedComInterface]
[Guid("00000001-0000-0000-C000-000000000046")]
[InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
internal partial interface IClassFactory
{
    void CreateInstance(
        [MarshalAs(UnmanagedType.Interface)] object? pUnkOuter,
        ref Guid riid,
        out IntPtr ppvObject);

    void LockServer([MarshalAs(UnmanagedType.Bool)] bool fLock);
}

[GeneratedComClass]
internal partial class ClassFactory : IClassFactory
{
   public unsafe void CreateInstance([MarshalAs(UnmanagedType.Interface)] object? pUnkOuter, ref Guid riid, out nint ppvObject)
    => throw new NotImplementedException();

   public void LockServer([MarshalAs(UnmanagedType.Bool)] bool fLock)
    => throw new NotImplementedException();
}

[GeneratedComClass]
internal partial class ClassFactory<T> : IClassFactory where T : class, new()
{
   public unsafe void CreateInstance([MarshalAs(UnmanagedType.Interface)] object? pUnkOuter, ref Guid riid, out nint ppvObject)
    => throw new NotImplementedException();

   public void LockServer([MarshalAs(UnmanagedType.Bool)] bool fLock)
    => throw new NotImplementedException();
}
```</issue_description>

<agent_instructions>To fix this issue, update the `ComClassGenerator` to replace `<` and `>` with `{` and `}` when producing hint names for the generated source files.

Also, add a test case to validate that we don't regress the behavior in the future.</agent_instructions>

## Comments on the Issue (you are @copilot in this section)

<comments>
<comment_new><author>@AaronRobinsonMSFT</author><body>
/cc @jkoritzinsky @jtschuster </body></comment_new>
</comments>

💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

Replace < and > with { and } in hint names to avoid ArgumentException when generating source for generic COM classes. Add test case to validate the fix.

Co-authored-by: jkoritzinsky <1571408+jkoritzinsky@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix COM class source generator failure with type generics Fix ComClassGenerator failure with generic types Dec 4, 2025
Copilot AI requested a review from jkoritzinsky December 4, 2025 20:43
Copilot finished work on behalf of jkoritzinsky December 4, 2025 20:43
@dotnet-policy-service
Copy link
Contributor

Tagging subscribers to this area: @dotnet/interop-contrib
See info in area-owners.md if you want to be subscribed.

Copy link
Member

@AaronRobinsonMSFT AaronRobinsonMSFT left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:shipit:

Copilot finished reviewing on behalf of jkoritzinsky December 4, 2025 23:20
@jkoritzinsky jkoritzinsky enabled auto-merge (squash) December 4, 2025 23:23
@jkoritzinsky jkoritzinsky disabled auto-merge December 4, 2025 23:23
@jkoritzinsky jkoritzinsky enabled auto-merge (squash) December 4, 2025 23:23
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR fixes a bug where the ComClassGenerator source generator fails when processing generic COM classes. The issue occurs because Roslyn's AddSource() method rejects hint names containing angle brackets (<, >), which are present in generic type names like ClassFactory<T>. The fix replaces these characters with curly braces ({, }) to create valid hint names while preserving uniqueness.

Key Changes

  • Modified hint name generation in ComClassGenerator to replace invalid angle bracket characters
  • Added test coverage for generic COM class generation

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.

File Description
ComClassGenerator.cs Replaces < and > with { and } in hint names before calling AddSource()
ComClassGeneratorOutputShape.cs Adds test case to verify generic COM class generation works correctly

@jkoritzinsky
Copy link
Member

/ba-g failures tracked by #122228

@jkoritzinsky jkoritzinsky merged commit ea1ac5f into main Dec 5, 2025
97 of 107 checks passed
@jkoritzinsky jkoritzinsky deleted the copilot/fix-com-class-generator-issue branch December 5, 2025 16:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

COM class source generator fails awkwardly with type generics

4 participants