Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ComInterfaceGenerator generates code with pointer type in generic #82504

Closed
jtschuster opened this issue Feb 23, 2023 · 5 comments · Fixed by #82740
Closed

ComInterfaceGenerator generates code with pointer type in generic #82504

jtschuster opened this issue Feb 23, 2023 · 5 comments · Fixed by #82740
Assignees
Labels
area-System.Runtime.InteropServices in-pr There is an active PR which will close this issue when it is merged source-generator Indicates an issue with a source generator feature
Milestone

Comments

@jtschuster
Copy link
Member

In custom collections generated code, the code generated for the following snippet contains byte* as a generic argument, causing a compiler error.

Input Code:

using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
[assembly:DisableRuntimeMarshalling]

[global::System.Runtime.InteropServices.Marshalling.GeneratedComInterfaceAttribute]
partial interface INativeAPI : IUnmanagedInterfaceType
{
    
    [return:MarshalUsing(ConstantElementCount=10)]
    System.Byte[] Method(
        System.Byte[] p,
        in System.Byte[] pIn,
        int pRefSize,
        [MarshalUsing(CountElementName = "pRefSize")] ref System.Byte[] pRef,
        [MarshalUsing(CountElementName = "pOutSize")] out System.Byte[] pOut,
        out int pOutSize);
}
// Try using the generated native interface
sealed class NativeAPI : IUnmanagedVirtualMethodTableProvider, INativeAPI.Native
{
    public VirtualMethodTableInfo GetVirtualMethodTableInfoForKey(System.Type type) => throw null;
}
partial interface INativeAPI
{
        static unsafe void* IUnmanagedInterfaceType.VirtualMethodTableManagedImplementation => null;
}

Generated Code:

// <auto-generated/>
unsafe partial interface INativeAPI
{
    internal unsafe partial interface Native
    {
        [System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute]
        internal static ABI_Method(void* __this_native, byte* __p_native, byte** __pIn_native__param, int pRefSize, byte** __pRef_native__param, byte** __pOut_native__param, int* __pOutSize_native__param)
        {
            ...
            try
            {
                ...
            }
            catch (System.Exception __exception)
            {
                // error CS0306: The type 'byte*' may not be used as a type argument
                __retVal_native = System.Runtime.InteropServices.Marshalling.ExceptionDefaultMarshaller<byte*>.ConvertToUnmanaged(__exception);
            }
            finally
            {
                // Cleanup - Perform required cleanup.
               ...
            }

            return __retVal_native;
        }
    }
}
@jtschuster jtschuster self-assigned this Feb 23, 2023
@ghost ghost added the untriaged New issue has not been triaged by the area owner label Feb 23, 2023
@ghost
Copy link

ghost commented Feb 23, 2023

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

Issue Details

In custom collections generated code, the code generated for the following snippet contains byte* as a generic argument, causing a compiler error.

Input Code:

using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;
[assembly:DisableRuntimeMarshalling]

[global::System.Runtime.InteropServices.Marshalling.GeneratedComInterfaceAttribute]
partial interface INativeAPI : IUnmanagedInterfaceType
{
    
    [return:MarshalUsing(ConstantElementCount=10)]
    System.Byte[] Method(
        System.Byte[] p,
        in System.Byte[] pIn,
        int pRefSize,
        [MarshalUsing(CountElementName = "pRefSize")] ref System.Byte[] pRef,
        [MarshalUsing(CountElementName = "pOutSize")] out System.Byte[] pOut,
        out int pOutSize);
}
// Try using the generated native interface
sealed class NativeAPI : IUnmanagedVirtualMethodTableProvider, INativeAPI.Native
{
    public VirtualMethodTableInfo GetVirtualMethodTableInfoForKey(System.Type type) => throw null;
}
partial interface INativeAPI
{
        static unsafe void* IUnmanagedInterfaceType.VirtualMethodTableManagedImplementation => null;
}

Generated Code:

// <auto-generated/>
unsafe partial interface INativeAPI
{
    internal unsafe partial interface Native
    {
        [System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute]
        internal static ABI_Method(void* __this_native, byte* __p_native, byte** __pIn_native__param, int pRefSize, byte** __pRef_native__param, byte** __pOut_native__param, int* __pOutSize_native__param)
        {
            ...
            try
            {
                ...
            }
            catch (System.Exception __exception)
            {
                // error CS0306: The type 'byte*' may not be used as a type argument
                __retVal_native = System.Runtime.InteropServices.Marshalling.ExceptionDefaultMarshaller<byte*>.ConvertToUnmanaged(__exception);
            }
            finally
            {
                // Cleanup - Perform required cleanup.
               ...
            }

            return __retVal_native;
        }
    }
}
Author: jtschuster
Assignees: jtschuster
Labels:

area-System.Runtime.InteropServices

Milestone: -

@elinor-fung
Copy link
Member

We created a helper for handling this when we were doing LibraryImportGenerator:

public static TypeSyntax GetCompatibleGenericTypeParameterSyntax(this TypeSyntax type)
{
TypeSyntax spanElementTypeSyntax = type;
if (spanElementTypeSyntax is PointerTypeSyntax)
{
// Pointers cannot be passed to generics, so use IntPtr for this case.
spanElementTypeSyntax = SystemIntPtrType;
}
return spanElementTypeSyntax;
}

@jkoritzinsky
Copy link
Member

It looks like I missed/forgot to use this for the COM exception marshalling logic. Should be pretty easy to fix.

@AaronRobinsonMSFT AaronRobinsonMSFT added source-generator Indicates an issue with a source generator feature and removed untriaged New issue has not been triaged by the area owner labels Feb 24, 2023
@AaronRobinsonMSFT AaronRobinsonMSFT added this to the 8.0.0 milestone Feb 24, 2023
@jtschuster
Copy link
Member Author

fixed in #82582

@jtschuster
Copy link
Member Author

Not quite fixed, the value returned by the generic methods needs to be cast as the variable type.

byte* __retVal_native;
catch (System.Exception __exception)
{
    // Cannot implicity convert nint to byte*
    __retVal_native = System.Runtime.InteropServices.Marshalling.ExceptionDefaultMarshaller<System.IntPtr>.ConvertToUnmanaged(__exception);
}

@jtschuster jtschuster reopened this Feb 27, 2023
@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Feb 27, 2023
@ghost ghost locked as resolved and limited conversation to collaborators Mar 30, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-System.Runtime.InteropServices in-pr There is an active PR which will close this issue when it is merged source-generator Indicates an issue with a source generator feature
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants