Add new proposed API to Ancillary.Interop (#81063)
authorJackson Schuster <36744439+jtschuster@users.noreply.github.com>
Fri, 17 Feb 2023 20:27:27 +0000 (12:27 -0800)
committerGitHub <noreply@github.com>
Fri, 17 Feb 2023 20:27:27 +0000 (12:27 -0800)
Updates the VTableStubGenerator to use the latest version of the proposed API.

Co-authored-by: Aaron Robinson <arobins@microsoft.com>
Co-authored-by: Jeremy Koritzinsky <jkoritzinsky@gmail.com>
53 files changed:
src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ComInterfaceGenerator.cs
src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/GeneratorDiagnostics.cs
src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/IncrementalMethodStubGenerationContext.cs
src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/InlinedTypes.cs [new file with mode: 0644]
src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/ManagedToNativeVTableMethodGenerator.cs
src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Marshallers/NativeToManagedThisMarshallerFactory.cs
src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/Strings.resx
src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.cs.xlf
src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.de.xlf
src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.es.xlf
src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.fr.xlf
src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.it.xlf
src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.ja.xlf
src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.ko.xlf
src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.pl.xlf
src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.pt-BR.xlf
src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.ru.xlf
src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.tr.xlf
src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.zh-Hans.xlf
src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/Resources/xlf/Strings.zh-Hant.xlf
src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/VtableIndexStubGenerator.cs
src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/NativeToManagedStubCodeContext.cs
src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeNames.cs
src/libraries/System.Runtime.InteropServices/gen/Microsoft.Interop.SourceGeneration/TypeSymbolExtensions.cs
src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ComObject.cs [new file with mode: 0644]
src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ComWrappersUnwrapper.cs [new file with mode: 0644]
src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/DefaultCaching.cs [new file with mode: 0644]
src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/DefaultIUnknownInterfaceDetailsStrategy.cs [new file with mode: 0644]
src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ExceptionHResultMarshaller.cs
src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/FreeThreadedStrategy.cs [new file with mode: 0644]
src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/GeneratedComInterfaceAttribute.cs
src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/GeneratedComWrappersBase.cs [new file with mode: 0644]
src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/IIUnknownCacheStrategy.cs [new file with mode: 0644]
src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/IIUnknownInterfaceDetailsStrategy.cs [new file with mode: 0644]
src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/IIUnknownInterfaceType.cs [new file with mode: 0644]
src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/IIUnknownStrategy.cs [new file with mode: 0644]
src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/IUnknownDerivedAttribute.cs [new file with mode: 0644]
src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/IUnknownDerivedDetails.cs [new file with mode: 0644]
src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/IUnmanagedInterfaceType.cs [new file with mode: 0644]
src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/IUnmanagedObjectUnwrapper.cs [new file with mode: 0644]
src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/IUnmanagedVirtualMethodTableProvider.cs
src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/UnmanagedObjectUnwrapper.cs [new file with mode: 0644]
src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/UnmanagedObjectUnwrapperAttribute.cs [new file with mode: 0644]
src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/VirtualMethodIndexAttribute.cs
src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/VirtualMethodTableInfo.cs [new file with mode: 0644]
src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/ImplicitThisTests.cs
src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/NoImplicitThisTests.cs
src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Tests/VTableGCHandlePair.cs
src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CallingConventionForwarding.cs
src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/CodeSnippets.cs
src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/GeneratedComInterfaceAnalyzerTests.cs
src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/IVirtualMethodIndexSignatureProvider.cs
src/libraries/System.Runtime.InteropServices/tests/ComInterfaceGenerator.Unit.Tests/NativeInterfaceShape.cs

index 9d5a973..a2c9391 100644 (file)
@@ -266,7 +266,8 @@ namespace Microsoft.Interop
                 ComInterfaceGeneratorHelpers.CreateGeneratorFactory(environment, MarshalDirection.ManagedToUnmanaged),
                 ComInterfaceGeneratorHelpers.CreateGeneratorFactory(environment, MarshalDirection.UnmanagedToManaged),
                 typeKeyOwner,
-                new SequenceEqualImmutableArray<Diagnostic>(generatorDiagnostics.Diagnostics.ToImmutableArray()));
+                new SequenceEqualImmutableArray<Diagnostic>(generatorDiagnostics.Diagnostics.ToImmutableArray()),
+                ParseTypeName(TypeNames.ComWrappersUnwrapper));
         }
 
         private static Diagnostic? GetDiagnosticIfInvalidTypeForGeneration(InterfaceDeclarationSyntax syntax, INamedTypeSymbol type)
index 0ba0e37..c8f55e8 100644 (file)
@@ -45,6 +45,16 @@ namespace Microsoft.Interop
             isEnabledByDefault: true,
             description: GetResourceString(nameof(SR.InvalidAttributedMethodDescription)));
 
+        public static readonly DiagnosticDescriptor InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttribute =
+            new DiagnosticDescriptor(
+            Ids.InvalidLibraryImportAttributeUsage,
+            GetResourceString(nameof(SR.InvalidVirtualMethodIndexAttributeUsage)),
+            GetResourceString(nameof(SR.InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttributeMessage)),
+            Category,
+            DiagnosticSeverity.Error,
+            isEnabledByDefault: true,
+            description: GetResourceString(nameof(SR.InvalidAttributedMethodDescription)));
+
         public static readonly DiagnosticDescriptor InvalidStringMarshallingConfiguration =
             new DiagnosticDescriptor(
             Ids.InvalidLibraryImportAttributeUsage,
index 0614a8d..e437df7 100644 (file)
@@ -18,5 +18,6 @@ namespace Microsoft.Interop
         MarshallingGeneratorFactoryKey<(TargetFramework TargetFramework, Version TargetFrameworkVersion)> ManagedToUnmanagedGeneratorFactory,
         MarshallingGeneratorFactoryKey<(TargetFramework TargetFramework, Version TargetFrameworkVersion)> UnmanagedToManagedGeneratorFactory,
         ManagedTypeInfo TypeKeyOwner,
-        SequenceEqualImmutableArray<Diagnostic> Diagnostics);
+        SequenceEqualImmutableArray<Diagnostic> Diagnostics,
+        TypeSyntax UnwrapperSyntax);
 }
diff --git a/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/InlinedTypes.cs b/src/libraries/System.Runtime.InteropServices/gen/ComInterfaceGenerator/InlinedTypes.cs
new file mode 100644 (file)
index 0000000..cb55e36
--- /dev/null
@@ -0,0 +1,124 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
+
+namespace Microsoft.Interop
+{
+    internal static class InlinedTypes
+    {
+        /// <summary>
+        /// Returns the ClassDeclarationSyntax for:
+        /// <code>
+        /// public sealed unsafe class ComWrappersUnwrapper : IUnmanagedObjectUnwrapper
+        /// {
+        ///     public static object GetObjectForUnmanagedWrapper(void* ptr)
+        ///     {
+        ///         return ComWrappers.ComInterfaceDispatch.GetInstance<object>((ComWrappers.ComInterfaceDispatch*)ptr);
+        ///     }
+        /// }
+        /// </code>
+        /// </summary>
+        public static ClassDeclarationSyntax ComWrappersUnwrapper { get; } = GetComWrappersUnwrapper();
+
+        public static ClassDeclarationSyntax GetComWrappersUnwrapper()
+        {
+            return ClassDeclaration("ComWrappersUnwrapper")
+                .AddModifiers(Token(SyntaxKind.SealedKeyword),
+                              Token(SyntaxKind.UnsafeKeyword),
+                              Token(SyntaxKind.StaticKeyword),
+                              Token(SyntaxKind.FileKeyword))
+                .AddMembers(
+                    MethodDeclaration(
+                        PredefinedType(Token(SyntaxKind.ObjectKeyword)),
+                        Identifier("GetComObjectForUnmanagedWrapper"))
+                    .AddModifiers(Token(SyntaxKind.PublicKeyword),
+                                  Token(SyntaxKind.StaticKeyword))
+                    .AddParameterListParameters(
+                        Parameter(Identifier("ptr"))
+                            .WithType(PointerType(PredefinedType(Token(SyntaxKind.VoidKeyword)))))
+                    .WithBody(body: Body()));
+
+            static BlockSyntax Body()
+            {
+                var invocation = InvocationExpression(
+                                    MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
+                                        MemberAccessExpression(
+                                            SyntaxKind.SimpleMemberAccessExpression,
+                                            IdentifierName("ComWrappers"),
+                                            IdentifierName("ComInterfaceDispatch")),
+                                        GenericName(
+                                            Identifier("GetInstance"),
+                                            TypeArgumentList(
+                                                SeparatedList<SyntaxNode>(
+                                                    new[] { PredefinedType(Token(SyntaxKind.ObjectKeyword)) })))))
+                                .AddArgumentListArguments(
+                                    Argument(
+                                        null,
+                                        Token(SyntaxKind.None),
+                                        CastExpression(
+                                            PointerType(
+                                                QualifiedName(
+                                                    IdentifierName("ComWrappers"),
+                                                    IdentifierName("ComInterfaceDispatch"))),
+                                            IdentifierName("ptr"))));
+
+                return Block(ReturnStatement(invocation));
+            }
+        }
+
+        /// <summary>
+        /// <code>
+        /// file static class UnmanagedObjectUnwrapper
+        /// {
+        ///     public static object GetObjectForUnmanagedWrapper<T>(void* ptr) where T : IUnmanagedObjectUnwrapper
+        ///     {
+        ///         return T.GetObjectForUnmanagedWrapper(ptr);
+        ///     }
+        /// }
+        /// </code>
+        /// </summary>
+        public static ClassDeclarationSyntax UnmanagedObjectUnwrapper { get; } = GetUnmanagedObjectUnwrapper();
+
+        private static ClassDeclarationSyntax GetUnmanagedObjectUnwrapper()
+        {
+            const string tUnwrapper = "TUnwrapper";
+            return ClassDeclaration("UnmanagedObjectUnwrapper")
+                  .AddModifiers(Token(SyntaxKind.FileKeyword),
+                                Token(SyntaxKind.StaticKeyword))
+                  .AddMembers(
+                      MethodDeclaration(
+                          PredefinedType(Token(SyntaxKind.ObjectKeyword)),
+                          Identifier("GetObjectForUnmanagedWrapper"))
+                      .AddModifiers(Token(SyntaxKind.PublicKeyword),
+                                    Token(SyntaxKind.StaticKeyword))
+                      .AddTypeParameterListParameters(
+                          TypeParameter(Identifier(tUnwrapper)))
+                      .AddParameterListParameters(
+                          Parameter(Identifier("ptr"))
+                              .WithType(PointerType(PredefinedType(Token(SyntaxKind.VoidKeyword)))))
+                      .AddConstraintClauses(TypeParameterConstraintClause(IdentifierName(tUnwrapper))
+                           .AddConstraints(TypeConstraint(ParseTypeName(TypeNames.IUnmanagedObjectUnwrapper))))
+                      .WithBody(body: Body()));
+
+            static BlockSyntax Body()
+            {
+                var invocation = InvocationExpression(
+                                    MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
+                                        IdentifierName("T"),
+                                        IdentifierName("GetObjectForUnmanagedWrapper")))
+                                .AddArgumentListArguments(
+                                    Argument(
+                                        null,
+                                        Token(SyntaxKind.None),
+                                        IdentifierName("ptr")));
+
+                return Block(ReturnStatement(invocation));
+            }
+
+        }
+    }
+}
index 9c615fc..482cc2b 100644 (file)
@@ -55,7 +55,7 @@ namespace Microsoft.Interop
             if (implicitThis)
             {
                 ImmutableArray<TypePositionInfo>.Builder newArgTypes = ImmutableArray.CreateBuilder<TypePositionInfo>(argTypes.Length + 1);
-                newArgTypes.Add(new TypePositionInfo(SpecialTypeInfo.IntPtr, NoMarshallingInfo.Instance)
+                newArgTypes.Add(new TypePositionInfo(new PointerTypeInfo("void*", "void*", false), NoMarshallingInfo.Instance)
                 {
                     InstanceIdentifier = NativeThisParameterIdentifier,
                     NativeIndex = 0
@@ -101,7 +101,7 @@ namespace Microsoft.Interop
         {
             var setupStatements = new List<StatementSyntax>
             {
-                // var (<thisParameter>, <virtualMethodTable>) = ((IUnmanagedVirtualMethodTableProvider)this).GetVirtualMethodTableInfoForKey<<containingTypeName>>();
+                // var (<thisParameter>, <virtualMethodTable>) = ((IUnmanagedVirtualMethodTableProvider)this).GetVirtualMethodTableInfoForKey(typeof(<containingTypeName>));
                 ExpressionStatement(
                     AssignmentExpression(
                         SyntaxKind.SimpleAssignmentExpression,
@@ -121,12 +121,9 @@ namespace Microsoft.Interop
                                     CastExpression(
                                         ParseTypeName(TypeNames.IUnmanagedVirtualMethodTableProvider),
                                         ThisExpression())),
-                                GenericName(
-                                    Identifier("GetVirtualMethodTableInfoForKey"),
-                                    TypeArgumentList(
-                                        SingletonSeparatedList(containingTypeName)))))
+                                IdentifierName("GetVirtualMethodTableInfoForKey") ))
                         .WithArgumentList(
-                            ArgumentList())))
+                            ArgumentList(SeparatedList(new[]{ Argument(TypeOfExpression(containingTypeName)) })))))
             };
 
             GeneratedStatements statements = GeneratedStatements.Create(
index 345986b..66e07ea 100644 (file)
@@ -3,16 +3,14 @@
 
 using System;
 using System.Collections.Generic;
+using System.Diagnostics;
 using Microsoft.CodeAnalysis.CSharp;
 using Microsoft.CodeAnalysis.CSharp.Syntax;
 using static Microsoft.CodeAnalysis.CSharp.SyntaxFactory;
 
 namespace Microsoft.Interop
 {
-    internal sealed record NativeThisInfo : MarshallingInfo
-    {
-        public static readonly NativeThisInfo Instance = new();
-    }
+    internal sealed record NativeThisInfo(TypeSyntax UnwrapperType) : MarshallingInfo;
 
     internal sealed class NativeToManagedThisMarshallerFactory : IMarshallingGeneratorFactory
     {
@@ -30,6 +28,8 @@ namespace Microsoft.Interop
             public ManagedTypeInfo AsNativeType(TypePositionInfo info) => new PointerTypeInfo("void*", "void*", false);
             public IEnumerable<StatementSyntax> Generate(TypePositionInfo info, StubCodeContext context)
             {
+                Debug.Assert(info.MarshallingAttributeInfo is NativeThisInfo);
+                TypeSyntax unwrapperType = ((NativeThisInfo)info.MarshallingAttributeInfo).UnwrapperType;
                 if (context.CurrentStage != StubCodeContext.Stage.Unmarshal)
                 {
                     yield break;
@@ -37,20 +37,25 @@ namespace Microsoft.Interop
 
                 (string managedIdentifier, string nativeIdentifier) = context.GetIdentifiers(info);
 
-                // <managed> = IUnmanagedVirtualMethodTableProvider.GetObjectForUnmanagedWrapper<<managedType>>(<native>);
+                // <managed> = (<managedType>)UnmanagedObjectUnwrapper.GetObjectFormUnmanagedWrapper<TUnmanagedUnwrapper>(<native>);
                 yield return ExpressionStatement(
-                    AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
-                    IdentifierName(managedIdentifier),
-                        InvocationExpression(
-                            MemberAccessExpression(SyntaxKind.SimpleMemberAccessExpression,
-                               ParseTypeName(TypeNames.IUnmanagedVirtualMethodTableProvider),
-                                GenericName(Identifier("GetObjectForUnmanagedWrapper"),
-                                    TypeArgumentList(
-                                        SingletonSeparatedList(
-                                            info.ManagedType.Syntax)))),
-                            ArgumentList(
-                                SingletonSeparatedList(
-                                    Argument(IdentifierName(nativeIdentifier)))))));
+                    AssignmentExpression(
+                        SyntaxKind.SimpleAssignmentExpression,
+                        IdentifierName(managedIdentifier),
+                        CastExpression(
+                            info.ManagedType.Syntax,
+                            InvocationExpression(
+                                MemberAccessExpression(
+                                    SyntaxKind.SimpleMemberAccessExpression,
+                                    ParseTypeName(TypeNames.UnmanagedObjectUnwrapper),
+                                    GenericName(Identifier("GetObjectForUnmanagedWrapper"))
+                                        .WithTypeArgumentList(
+                                            TypeArgumentList(
+                                                SingletonSeparatedList(
+                                                    unwrapperType)))),
+                                ArgumentList(
+                                    SingletonSeparatedList(
+                                        Argument(IdentifierName(nativeIdentifier))))))));
             }
 
             public SignatureBehavior GetNativeSignatureBehavior(TypePositionInfo info) => SignatureBehavior.NativeType;
index 82a2cc8..9748657 100644 (file)
   <data name="InterfaceTypeNotSupportedMessage" xml:space="preserve">
     <value>Using 'GeneratedComInterfaceAttribute' and 'InterfaceTypeAttribute' is not supported with 'ComInterfaceType' value '{0}'.</value>
   </data>
+  <data name="InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttributeMessage" xml:space="preserve">
+    <value>Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </value>
+  </data>
   <data name="MethodNotDeclaredInAttributedInterfaceDescription" xml:space="preserve">
     <value>All methods must be declared in the same partial definition of a 'GeneratedComInterface'-attributed interface type to ensure reliable calculation for virtual method table offsets.</value>
   </data>
   <data name="MethodNotDeclaredInAttributedInterfaceTitle" xml:space="preserve">
     <value>Method is declared in different partial declaration than the 'GeneratedComInterface' attribute.</value>
   </data>
-</root>
\ No newline at end of file
+</root>
index d76b502..71d862c 100644 (file)
         <target state="translated">Metoda {0} je obsažena v typu {1}, který není označen jako „partial“. Generování zdrojů volání P/Invoke bude metodu {0} ignorovat.</target>
         <note />
       </trans-unit>
+      <trans-unit id="InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttributeMessage">
+        <source>Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </source>
+        <target state="new">Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </target>
+        <note />
+      </trans-unit>
       <trans-unit id="InvalidAttributedMethodDescription">
         <source>Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic.</source>
         <target state="translated">Metody označené atributem LibraryImportAttribute by měly být typu „static“, „partial“ a non-generic. Generování zdrojů volání P/Invoke bude ignorovat metody typu non-„static“, non-„partial“ a generic.</target>
index ca522c0..257dd88 100644 (file)
         <target state="translated">Die Methode \"{0}\" ist in einem Typ \"{1}\" enthalten, der nicht als \"partiell\" gekennzeichnet ist. Die P/Invoke-Quellgenerierung ignoriert die Methode \"{0}\".</target>
         <note />
       </trans-unit>
+      <trans-unit id="InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttributeMessage">
+        <source>Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </source>
+        <target state="new">Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </target>
+        <note />
+      </trans-unit>
       <trans-unit id="InvalidAttributedMethodDescription">
         <source>Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic.</source>
         <target state="translated">Methoden, die mit \"LibraryImportAttribute\" gekennzeichnet sind, sollten \"statisch\", \"partiell\" und nicht generisch sein. Die P/Invoke-Quellgenerierung ignoriert Methoden, die nicht \"statisch\", nicht \"partiell\" oder generisch sind.</target>
index bc90cc7..7943139 100644 (file)
         <target state="translated">El método “{0}” está contenido en un tipo “{1}” que no está marcado como “partial”. La generación de código fuente P/Invoke omitirá el método “{0}”.</target>
         <note />
       </trans-unit>
+      <trans-unit id="InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttributeMessage">
+        <source>Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </source>
+        <target state="new">Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </target>
+        <note />
+      </trans-unit>
       <trans-unit id="InvalidAttributedMethodDescription">
         <source>Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic.</source>
         <target state="translated">Los métodos marcados con “LibraryImportAttribute” deben ser “static”, “partial” y no genéricos. La generación de código fuente P/Invoke omitirá los métodos que no sean “static”, “partial” ni genéricos.</target>
index 528f1ab..6c43431 100644 (file)
         <target state="translated">La méthode « {0} » est contenue dans un type « {1} » qui n’est pas marqué comme étant « partial ». La génération source P/Invoke ignore la méthode « {0} ».</target>
         <note />
       </trans-unit>
+      <trans-unit id="InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttributeMessage">
+        <source>Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </source>
+        <target state="new">Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </target>
+        <note />
+      </trans-unit>
       <trans-unit id="InvalidAttributedMethodDescription">
         <source>Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic.</source>
         <target state="translated">Les méthodes marquées avec « LibraryImportAttribute » doivent être « static », « partial » et non génériques. La génération de source P/Invoke ignore les méthodes qui ne sont pas statiques, non partielles ou génériques.</target>
index 2f90533..ce7c2e9 100644 (file)
         <target state="translated">Il metodo '{0}' è contenuto in un tipo '{1}' non contrassegnato come 'partial'. Durante la generazione dell'origine P/Invoke il metodo '{0}' verrà ignorato.</target>
         <note />
       </trans-unit>
+      <trans-unit id="InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttributeMessage">
+        <source>Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </source>
+        <target state="new">Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </target>
+        <note />
+      </trans-unit>
       <trans-unit id="InvalidAttributedMethodDescription">
         <source>Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic.</source>
         <target state="translated">I metodi contrassegnati con 'LibraryImportAttribute' devono essere 'static', 'partial' e non generici. Durante la generazione dell'origine P/Invoke i metodi non 'static', non 'partial' o generici verranno ignorati.</target>
index e3d4111..63722d9 100644 (file)
         <target state="translated">メソッド '{0}' は、'partial' とマークされていない型 '{1}' に含まれています。P/Invoke ソース生成はメソッド '{0}' を無視します。</target>
         <note />
       </trans-unit>
+      <trans-unit id="InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttributeMessage">
+        <source>Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </source>
+        <target state="new">Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </target>
+        <note />
+      </trans-unit>
       <trans-unit id="InvalidAttributedMethodDescription">
         <source>Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic.</source>
         <target state="translated">'LibraryImportAttribute' でマークされたメソッドは、'static'、'partial'、非ジェネリックである必要があります。P/Invoke ソース生成では、非 'static'、非 'partial'、ジェネリックであるメソッドは無視されます。</target>
index 9be2cb9..75f4f04 100644 (file)
         <target state="translated">메서드 '{0}'은(는) 'partial'로 표시되지 않은 '{1}' 형식에 포함되어 있습니다. P/Invoke 소스 생성은 '{0}' 메서드를 무시합니다.</target>
         <note />
       </trans-unit>
+      <trans-unit id="InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttributeMessage">
+        <source>Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </source>
+        <target state="new">Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </target>
+        <note />
+      </trans-unit>
       <trans-unit id="InvalidAttributedMethodDescription">
         <source>Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic.</source>
         <target state="translated">'LibraryImportAttribute'로 표시된 메소드는 'static', 'partial' 및 비제네릭이어야 합니다. P/Invoke 소스 생성은 'static'이 아니거나 'partial'이 아니거나 제네릭인 메서드를 무시합니다.</target>
index 3c87b15..40e1d34 100644 (file)
         <target state="translated">Metoda „{0}” jest zawarta w typie „{1}”, który nie jest oznaczony jako „częściowy”. Generowanie źródła funkcji P/Invoke zignoruje metodę „{0}”.</target>
         <note />
       </trans-unit>
+      <trans-unit id="InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttributeMessage">
+        <source>Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </source>
+        <target state="new">Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </target>
+        <note />
+      </trans-unit>
       <trans-unit id="InvalidAttributedMethodDescription">
         <source>Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic.</source>
         <target state="translated">Metody oznaczone jako atrybut „LibraryImportAttribute” powinny być „statyczne”, „częściowe” i nieogólne. Generowanie źródła funkcji P/Invoke zignoruje metody, które nie są „statyczne”, nie są „częściowe” lub ogólne.</target>
index aede0ec..d34e17d 100644 (file)
         <target state="translated">O '{0}' está contido em um tipo '{1}' que não está marcado como 'partial'. A geração de origem P/Invoke ignorará o método '{0}'.</target>
         <note />
       </trans-unit>
+      <trans-unit id="InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttributeMessage">
+        <source>Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </source>
+        <target state="new">Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </target>
+        <note />
+      </trans-unit>
       <trans-unit id="InvalidAttributedMethodDescription">
         <source>Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic.</source>
         <target state="translated">Os métodos marcados com 'LibraryImportAttribute' devem ser 'static', 'partial' e não genéricos. A geração de origem P/Invoke ignorará os métodos que não são 'static', não-'partial' ou genéricos.</target>
index 68eb144..cfc51db 100644 (file)
         <target state="translated">Метод \"{0}\" содержится в типе \"{1}\", который не помечен как \"partial\". Метод \"{0}\" будет игнорироваться при создании источника в P/Invoke.</target>
         <note />
       </trans-unit>
+      <trans-unit id="InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttributeMessage">
+        <source>Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </source>
+        <target state="new">Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </target>
+        <note />
+      </trans-unit>
       <trans-unit id="InvalidAttributedMethodDescription">
         <source>Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic.</source>
         <target state="translated">Методы, помеченные атрибутом \"LibraryImportAttribute\", должны быть \"static\", \"partial\" и неуниверсальными. При создании источника в P/Invoke будут игнорироваться методы, отличные от \"static\", \"partial\" или универсальные.</target>
index 25fdb1a..294324c 100644 (file)
         <target state="translated">'{0}'metodu, 'partial' olarak işaretlenmemiş olan bir '{1}' türünün içinde yer alıyor. P/Invoke kaynak oluşturma işlemi, '{0}' metodunu yok sayacak.</target>
         <note />
       </trans-unit>
+      <trans-unit id="InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttributeMessage">
+        <source>Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </source>
+        <target state="new">Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </target>
+        <note />
+      </trans-unit>
       <trans-unit id="InvalidAttributedMethodDescription">
         <source>Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic.</source>
         <target state="translated">'LibraryImportAttribute' ile işaretlenmiş metotlar 'static', 'partial' ve genel olmayan özellikte olmalıdır. P/Invoke kaynak oluşturma 'static', 'partial' ve genel olmayan özellikteki metotlar dışında kalan metotları yok sayar.</target>
index 24d4d07..ba7a01a 100644 (file)
         <target state="translated">方法“{0}”包含在未标记为 “partial” 的类型“{1}”中。P/Invoke 源生成将忽略方法“{0}”。</target>
         <note />
       </trans-unit>
+      <trans-unit id="InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttributeMessage">
+        <source>Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </source>
+        <target state="new">Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </target>
+        <note />
+      </trans-unit>
       <trans-unit id="InvalidAttributedMethodDescription">
         <source>Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic.</source>
         <target state="translated">标记为 “LibraryImportAttribute” 的方法应为 “static”、“partial” 和非泛型。P/Invoke 源生成将忽略非“static”、“non--partial” 或泛型的方法。</target>
index 2a320c3..e2a48f7 100644 (file)
         <target state="translated">方法 '{0}' 包含在未標示為 'partial' 的類型'{1}'中。產生 P/Invoke 来源會忽略方法'{0}'。</target>
         <note />
       </trans-unit>
+      <trans-unit id="InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttributeMessage">
+        <source>Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </source>
+        <target state="new">Containing type of method with VirtualMethodIndexAttribute does not have a UnmanagedObjectUnwrapperAttribute. </target>
+        <note />
+      </trans-unit>
       <trans-unit id="InvalidAttributedMethodDescription">
         <source>Methods marked with 'LibraryImportAttribute' should be 'static', 'partial', and non-generic. P/Invoke source generation will ignore methods that are non-'static', non-'partial', or generic.</source>
         <target state="translated">以 'LibraryImportAttribute' 標示的方法應該是 'static'、'partial' 和非泛型。產生 P/Invoke 来源會忽略非'static'、non-'partial' 或一般的方法。</target>
index e231025..9ff0512 100644 (file)
@@ -336,7 +336,7 @@ namespace Microsoft.Interop
 
             var interfaceType = ManagedTypeInfo.CreateTypeInfoForTypeSymbol(symbol.ContainingType);
 
-            INamedTypeSymbol expectedUnmanagedInterfaceType = iUnmanagedInterfaceTypeType.Construct(symbol.ContainingType);
+            INamedTypeSymbol expectedUnmanagedInterfaceType = iUnmanagedInterfaceTypeType;
 
             bool implementsIUnmanagedInterfaceOfSelf = symbol.ContainingType.AllInterfaces.Any(iface => SymbolEqualityComparer.Default.Equals(iface, expectedUnmanagedInterfaceType));
             if (!implementsIUnmanagedInterfaceOfSelf)
@@ -344,6 +344,13 @@ namespace Microsoft.Interop
                 // TODO: Report invalid configuration
             }
 
+            var unmanagedObjectUnwrapper = symbol.ContainingType.GetAttributes().FirstOrDefault(att => att.AttributeClass.IsOfType(TypeNames.UnmanagedObjectUnwrapperAttribute));
+            if (unmanagedObjectUnwrapper is null)
+            {
+                // TODO: report invalid configuration - or ensure that this will never happen at this point
+            }
+            var unwrapperSyntax = ParseTypeName(unmanagedObjectUnwrapper.AttributeClass.TypeArguments[0].ToDisplayString());
+
             MarshallingInfo exceptionMarshallingInfo = CreateExceptionMarshallingInfo(virtualMethodIndexAttr, symbol, environment.Compilation, generatorDiagnostics, virtualMethodIndexData);
 
             return new IncrementalMethodStubGenerationContext(
@@ -357,7 +364,8 @@ namespace Microsoft.Interop
                 ComInterfaceGeneratorHelpers.CreateGeneratorFactory(environment, MarshalDirection.ManagedToUnmanaged),
                 ComInterfaceGeneratorHelpers.CreateGeneratorFactory(environment, MarshalDirection.UnmanagedToManaged),
                 interfaceType,
-                new SequenceEqualImmutableArray<Diagnostic>(generatorDiagnostics.Diagnostics.ToImmutableArray()));
+                new SequenceEqualImmutableArray<Diagnostic>(generatorDiagnostics.Diagnostics.ToImmutableArray()),
+                unwrapperSyntax);
         }
 
         private static MarshallingInfo CreateExceptionMarshallingInfo(AttributeData virtualMethodIndexAttr, ISymbol symbol, Compilation compilation, GeneratorDiagnostics diagnostics, VirtualMethodIndexCompilationData virtualMethodIndexData)
@@ -497,7 +505,7 @@ namespace Microsoft.Interop
 
             var elements = ImmutableArray.CreateBuilder<TypePositionInfo>(originalElements.Length + 2);
 
-            elements.Add(new TypePositionInfo(methodStub.TypeKeyOwner, NativeThisInfo.Instance)
+            elements.Add(new TypePositionInfo(methodStub.TypeKeyOwner, new NativeThisInfo(methodStub.UnwrapperSyntax))
             {
                 InstanceIdentifier = ThisParameterIdentifier,
                 NativeIndex = 0,
@@ -553,6 +561,15 @@ namespace Microsoft.Interop
                 return Diagnostic.Create(GeneratorDiagnostics.ReturnConfigurationNotSupported, methodSyntax.Identifier.GetLocation(), "ref return", method.ToDisplayString());
             }
 
+            // Verify there is an [UnmanagedObjectUnwrapperAttribute<TMapper>]
+            if (!method.ContainingType.GetAttributes().Any(att => att.AttributeClass.IsOfType(TypeNames.UnmanagedObjectUnwrapperAttribute)))
+            //!method.ContainingType.GetAttributes().Any(att =>
+            //att.AttributeClass.MetadataName == TypeNames.UnmanagedObjectUnwrapperAttribute.Substring(TypeNames.UnmanagedObjectUnwrapperAttribute.LastIndexOf('.') + 1)
+            //&& att.AttributeClass.OriginalDefinition.ToDisplayString().Substring(0, att.AttributeClass.OriginalDefinition.ToDisplayString().LastIndexOf(att.AttributeClass.ToDisplayString())) == TypeNames.UnmanagedObjectUnwrapperAttribute.Substring(0, TypeNames.UnmanagedObjectUnwrapperAttribute.LastIndexOf('.'))))
+            {
+                return Diagnostic.Create(GeneratorDiagnostics.InvalidAttributedMethodContainingTypeMissingUnmanagedObjectUnwrapperAttribute, methodSyntax.Identifier.GetLocation(), method.Name);
+            }
+
             return null;
         }
 
@@ -574,20 +591,20 @@ namespace Microsoft.Interop
                 .WithModifiers(TokenList(Token(SyntaxKind.InternalKeyword), Token(SyntaxKind.StaticKeyword)))
                 .AddParameterListParameters(
                     Parameter(Identifier(vtableParameter))
-                    .WithType(GenericName(TypeNames.System_Span).AddTypeArgumentListArguments(IdentifierName("nint"))));
+                    .WithType(PointerType(PointerType(PredefinedType(Token(SyntaxKind.VoidKeyword))))));
 
             foreach (var method in vtableMethods)
             {
                 FunctionPointerTypeSyntax functionPointerType = GenerateUnmanagedFunctionPointerTypeForMethod(method);
 
-                // <vtableParameter>[<index>] = (nint)(<functionPointerType>)&ABI_<methodIdentifier>;
+                // <vtableParameter>[<index>] = (void*)(<functionPointerType>)&ABI_<methodIdentifier>;
                 populateVtableMethod = populateVtableMethod.AddBodyStatements(
                     ExpressionStatement(
                         AssignmentExpression(SyntaxKind.SimpleAssignmentExpression,
                             ElementAccessExpression(
                                 IdentifierName(vtableParameter))
                             .AddArgumentListArguments(Argument(LiteralExpression(SyntaxKind.NumericLiteralExpression, Literal(method.VtableIndexData.Index)))),
-                            CastExpression(IdentifierName("nint"),
+                            CastExpression(PointerType(PredefinedType(Token(SyntaxKind.VoidKeyword))),
                                 CastExpression(functionPointerType,
                                     PrefixUnaryExpression(SyntaxKind.AddressOfExpression,
                                         IdentifierName($"ABI_{method.StubMethodSyntaxTemplate.Identifier}")))))));
index 60c3f39..0a5b8ac 100644 (file)
@@ -36,9 +36,9 @@ namespace Microsoft.Interop
 
         public const string VirtualMethodIndexAttribute = "System.Runtime.InteropServices.Marshalling.VirtualMethodIndexAttribute";
 
-        public const string IUnmanagedVirtualMethodTableProvider = "System.Runtime.InteropServices.IUnmanagedVirtualMethodTableProvider";
+        public const string IUnmanagedVirtualMethodTableProvider = "System.Runtime.InteropServices.Marshalling.IUnmanagedVirtualMethodTableProvider";
 
-        public const string IUnmanagedInterfaceType_Metadata = "System.Runtime.InteropServices.IUnmanagedInterfaceType`1";
+        public const string IUnmanagedInterfaceType_Metadata = "System.Runtime.InteropServices.Marshalling.IUnmanagedInterfaceType";
 
         public const string System_Span_Metadata = "System.Span`1";
         public const string System_Span = "System.Span";
@@ -105,5 +105,10 @@ namespace Microsoft.Interop
         public const string InterfaceTypeAttribute = "System.Runtime.InteropServices.InterfaceTypeAttribute";
         public const string ComInterfaceTypeAttribute = "System.Runtime.InteropServices.ComInterfaceType";
         public const string System_Runtime_InteropServices_ComWrappers_ComInterfaceDispatch = "System.Runtime.InteropServices.ComWrappers.ComInterfaceDispatch";
+        public const string ComWrappersUnwrapper = "System.Runtime.InteropServices.Marshalling.ComWrappersUnwrapper";
+        public const string UnmanagedObjectUnwrapperAttribute = "System.Runtime.InteropServices.Marshalling.UnmanagedObjectUnwrapperAttribute`1";
+
+        public const string IUnmanagedObjectUnwrapper = "System.Runtime.InteropServices.Marshalling.IUnmanagedObjectUnwrapper";
+        public const string UnmanagedObjectUnwrapper = "System.Runtime.InteropServices.Marshalling.UnmanagedObjectUnwrapper";
     }
 }
index 154c931..1affbba 100644 (file)
@@ -300,5 +300,25 @@ namespace Microsoft.Interop
             }
             return (typeArguments.ToImmutable(), nullableAnnotations.ToImmutable());
         }
+
+        /// <summary>
+        /// Returns if the type is of the string representation of a type
+        /// </summary>
+        public static bool IsOfType(this INamedTypeSymbol type, string typeName)
+        {
+            if (typeName.Contains('<') || typeName.Contains('+') || typeName.Contains('/'))
+                throw new ArgumentException($"Cannot handle type name in the format provided: {typeName}", nameof(typeName));
+            string[] typeNameParts = typeName.Split('.');
+            INamespaceOrTypeSymbol current = type;
+            for (int i = typeNameParts.Length - 1; i >= 0; i--)
+            {
+                if (current == null)
+                    return false;
+                if (current.MetadataName != typeNameParts[i])
+                    return false;
+                current = (INamespaceOrTypeSymbol)current.ContainingType ?? current.ContainingNamespace;
+            }
+            return true;
+        }
     }
 }
diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ComObject.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ComObject.cs
new file mode 100644 (file)
index 0000000..c66d4a7
--- /dev/null
@@ -0,0 +1,131 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+// This type is for the COM source generator and implements part of the COM-specific interactions.
+// This API need to be exposed to implement the COM source generator in one form or another.
+
+using System.Diagnostics;
+
+namespace System.Runtime.InteropServices.Marshalling
+{
+    /// <summary>
+    /// Base class for all COM source generated Runtime Callable Wrapper (RCWs).
+    /// </summary>
+    public sealed unsafe class ComObject : IDynamicInterfaceCastable, IUnmanagedVirtualMethodTableProvider
+    {
+        private readonly void* _instancePointer;
+
+        /// <summary>
+        /// Initialize ComObject instance.
+        /// </summary>
+        /// <param name="interfaceDetailsStrategy">Strategy for getting details</param>
+        /// <param name="iunknownStrategy">Interaction strategy for IUnknown</param>
+        /// <param name="cacheStrategy">Caching strategy</param>
+        /// <param name="thisPointer">Pointer to the identity IUnknown interface for the object.</param>
+        internal ComObject(IIUnknownInterfaceDetailsStrategy interfaceDetailsStrategy, IIUnknownStrategy iunknownStrategy, IIUnknownCacheStrategy cacheStrategy, void* thisPointer)
+        {
+            InterfaceDetailsStrategy = interfaceDetailsStrategy;
+            IUnknownStrategy = iunknownStrategy;
+            CacheStrategy = cacheStrategy;
+            _instancePointer = IUnknownStrategy.CreateInstancePointer(thisPointer);
+        }
+
+        ~ComObject()
+        {
+            CacheStrategy.Clear(IUnknownStrategy);
+            IUnknownStrategy.Release(_instancePointer);
+        }
+
+        /// <summary>
+        /// Interface details strategy.
+        /// </summary>
+        private IIUnknownInterfaceDetailsStrategy InterfaceDetailsStrategy { get; }
+
+        /// <summary>
+        /// IUnknown interaction strategy.
+        /// </summary>
+        private IIUnknownStrategy IUnknownStrategy { get; }
+
+        /// <summary>
+        /// Caching strategy.
+        /// </summary>
+        private IIUnknownCacheStrategy CacheStrategy { get; }
+
+        /// <summary>
+        /// Returns an IDisposable that can be used to perform a final release
+        /// on this COM object wrapper.
+        /// </summary>
+        /// <remarks>
+        /// This property will only be non-null if the ComObject was created using
+        /// CreateObjectFlags.UniqueInstance.
+        /// </remarks>
+        public IDisposable? FinalRelease { get; internal init; }
+
+        /// <inheritdoc />
+        RuntimeTypeHandle IDynamicInterfaceCastable.GetInterfaceImplementation(RuntimeTypeHandle interfaceType)
+        {
+            if (!LookUpVTableInfo(interfaceType, out IIUnknownCacheStrategy.TableInfo info, out int qiResult))
+            {
+                Marshal.ThrowExceptionForHR(qiResult);
+            }
+            return info.ManagedType;
+        }
+
+        /// <inheritdoc />
+        bool IDynamicInterfaceCastable.IsInterfaceImplemented(RuntimeTypeHandle interfaceType, bool throwIfNotImplemented)
+        {
+            if (!LookUpVTableInfo(interfaceType, out _, out int qiResult))
+            {
+                if (throwIfNotImplemented)
+                {
+                    Marshal.ThrowExceptionForHR(qiResult);
+                }
+                return false;
+            }
+            return true;
+        }
+
+        private bool LookUpVTableInfo(RuntimeTypeHandle handle, out IIUnknownCacheStrategy.TableInfo result, out int qiHResult)
+        {
+            qiHResult = 0;
+            if (!CacheStrategy.TryGetTableInfo(handle, out result))
+            {
+                IUnknownDerivedDetails? details = InterfaceDetailsStrategy.GetIUnknownDerivedDetails(handle);
+                if (details is null)
+                {
+                    return false;
+                }
+                int hr = IUnknownStrategy.QueryInterface(_instancePointer, details.Iid, out void* ppv);
+                if (hr < 0)
+                {
+                    qiHResult = hr;
+                    return false;
+                }
+
+                result = CacheStrategy.ConstructTableInfo(handle, details, ppv);
+
+                // Update some local cache. If the update fails, we lost the race and
+                // then are responsible for calling Release().
+                if (!CacheStrategy.TrySetTableInfo(handle, result))
+                {
+                    bool found = CacheStrategy.TryGetTableInfo(handle, out result);
+                    Debug.Assert(found);
+                    _ = IUnknownStrategy.Release(ppv);
+                }
+            }
+
+            return true;
+        }
+
+        /// <inheritdoc />
+        VirtualMethodTableInfo IUnmanagedVirtualMethodTableProvider.GetVirtualMethodTableInfoForKey(Type type)
+        {
+            if (!LookUpVTableInfo(type.TypeHandle, out IIUnknownCacheStrategy.TableInfo result, out int qiHResult))
+            {
+                Marshal.ThrowExceptionForHR(qiHResult);
+            }
+
+            return new(result.ThisPtr, result.Table);
+        }
+    }
+}
diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ComWrappersUnwrapper.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/ComWrappersUnwrapper.cs
new file mode 100644 (file)
index 0000000..2b5ecc3
--- /dev/null
@@ -0,0 +1,19 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+// Types that are only needed for the VTable source generator or to provide abstract concepts that the COM generator would use under the hood.
+// These are types that we can exclude from the API proposals and either inline into the generated code, provide as file-scoped types, or not provide publicly (indicated by comments on each type).
+
+namespace System.Runtime.InteropServices.Marshalling
+{
+    // This type implements the logic to get the managed object from the unmanaged "this" pointer.
+    // If we decide to not expose the VTable source generator, we don't need to expose this and we can just inline the logic
+    // into the generated code in the source generator.
+    internal sealed unsafe class ComWrappersUnwrapper : IUnmanagedObjectUnwrapper
+    {
+        public static object GetObjectForUnmanagedWrapper(void* ptr)
+        {
+            return ComWrappers.ComInterfaceDispatch.GetInstance<object>((ComWrappers.ComInterfaceDispatch*)ptr);
+        }
+    }
+}
diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/DefaultCaching.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/DefaultCaching.cs
new file mode 100644 (file)
index 0000000..07152e0
--- /dev/null
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+// Implementations of the COM strategy interfaces defined in Com.cs that we would want to ship (can be internal only if we don't want to allow users to provide their own implementations in v1).
+using System.Collections.Generic;
+
+namespace System.Runtime.InteropServices.Marshalling
+{
+    internal sealed unsafe class DefaultCaching : IIUnknownCacheStrategy
+    {
+        // [TODO] Implement some smart/thread-safe caching
+        private readonly Dictionary<RuntimeTypeHandle, IIUnknownCacheStrategy.TableInfo> _cache = new();
+
+        IIUnknownCacheStrategy.TableInfo IIUnknownCacheStrategy.ConstructTableInfo(RuntimeTypeHandle handle, IUnknownDerivedDetails details, void* ptr)
+        {
+            var obj = (void***)ptr;
+            return new IIUnknownCacheStrategy.TableInfo()
+            {
+                ThisPtr = obj,
+                Table = *obj,
+                ManagedType = details.Implementation.TypeHandle
+            };
+        }
+
+        bool IIUnknownCacheStrategy.TryGetTableInfo(RuntimeTypeHandle handle, out IIUnknownCacheStrategy.TableInfo info)
+        {
+            return _cache.TryGetValue(handle, out info);
+        }
+
+        bool IIUnknownCacheStrategy.TrySetTableInfo(RuntimeTypeHandle handle, IIUnknownCacheStrategy.TableInfo info)
+        {
+            return _cache.TryAdd(handle, info);
+        }
+
+        void IIUnknownCacheStrategy.Clear(IIUnknownStrategy unknownStrategy)
+        {
+            foreach (var info in _cache.Values)
+            {
+                _ = unknownStrategy.Release(info.ThisPtr);
+            }
+            _cache.Clear();
+        }
+    }
+}
diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/DefaultIUnknownInterfaceDetailsStrategy.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/DefaultIUnknownInterfaceDetailsStrategy.cs
new file mode 100644 (file)
index 0000000..b1c3ff0
--- /dev/null
@@ -0,0 +1,15 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace System.Runtime.InteropServices.Marshalling
+{
+    internal sealed class DefaultIUnknownInterfaceDetailsStrategy : IIUnknownInterfaceDetailsStrategy
+    {
+        public static readonly IIUnknownInterfaceDetailsStrategy Instance = new DefaultIUnknownInterfaceDetailsStrategy();
+
+        public IUnknownDerivedDetails? GetIUnknownDerivedDetails(RuntimeTypeHandle type)
+        {
+            return IUnknownDerivedDetails.GetFromAttribute(type);
+        }
+    }
+}
index 22748d6..10fcf69 100644 (file)
@@ -8,13 +8,24 @@ using System.Numerics;
 using System.Text;
 using System.Threading.Tasks;
 
+// This type is only needed for the VTable source generator or to provide abstract concepts that the COM generator would use under the hood.
+// These are types that we can exclude from the API proposals and either inline into the generated code, provide as file-scoped types, or not provide publicly (indicated by comments on each type).
+
 namespace System.Runtime.InteropServices.Marshalling
 {
     /// <summary>
     /// Marshals an exception object to the value of its <see cref="Exception.HResult"/> converted to <typeparamref name="T"/>.
     /// </summary>
     /// <typeparam name="T">The unmanaged type to convert the HResult to.</typeparam>
-    [CustomMarshaller(typeof(Exception), MarshalMode.UnmanagedToManagedOut, typeof(ExceptionDefaultMarshaller<>))]
+    /// <remarks>
+    /// This type is used by the COM source generator to enable marshalling exceptions to the HResult of the exception.
+    /// We can skip the exposing the exception marshallers if we decide to not expose the VTable source generator.
+    /// In that case, we'd hard-code the implementations of these marshallers into the COM source generator.
+    /// </remarks>
+#pragma warning disable SYSLIB1055 // The managed type 'System.Exception' for entry-point marshaller type 'System.Runtime.InteropServices.Marshalling.ExceptionHResultMarshaller<T>' must be a closed generic type, have the same arity as the managed type if it is a value marshaller, or have one additional generic parameter if it is a collection marshaller.
+
+    [CustomMarshaller(typeof(Exception), MarshalMode.UnmanagedToManagedOut, typeof(ExceptionHResultMarshaller<>))]
+#pragma warning restore SYSLIB1055
     public static class ExceptionHResultMarshaller<T>
         where T : unmanaged, INumber<T>
     {
diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/FreeThreadedStrategy.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/FreeThreadedStrategy.cs
new file mode 100644 (file)
index 0000000..e318b42
--- /dev/null
@@ -0,0 +1,35 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+// Implementations of the COM strategy interfaces defined in Com.cs that we would want to ship (can be internal only if we don't want to allow users to provide their own implementations in v1).
+using System.Runtime.CompilerServices;
+
+namespace System.Runtime.InteropServices.Marshalling
+{
+    internal sealed unsafe class FreeThreadedStrategy : IIUnknownStrategy
+    {
+        public static readonly IIUnknownStrategy Instance = new FreeThreadedStrategy();
+
+        void* IIUnknownStrategy.CreateInstancePointer(void* unknown)
+        {
+            return unknown;
+        }
+
+        unsafe int IIUnknownStrategy.QueryInterface(void* thisPtr, in Guid handle, out void* ppObj)
+        {
+            int hr = Marshal.QueryInterface((nint)thisPtr, ref Unsafe.AsRef(in handle), out nint ppv);
+            if (hr < 0)
+            {
+                ppObj = null;
+            }
+            else
+            {
+                ppObj = (void*)ppv;
+            }
+            return hr;
+        }
+
+        unsafe int IIUnknownStrategy.Release(void* thisPtr)
+            => Marshal.Release((nint)thisPtr);
+    }
+}
index dfd26a1..d8a5ac0 100644 (file)
@@ -5,22 +5,6 @@ namespace System.Runtime.InteropServices.Marshalling
 {
     public interface IComObjectWrapper<T> { }
 
-    public class ComWrappers { }
-
-    public class ComObject : IDynamicInterfaceCastable, IComObjectWrapper<ComObject>
-    {
-        public bool IsInterfaceImplemented(RuntimeTypeHandle th, bool b) => true;
-        public RuntimeTypeHandle GetInterfaceImplementation(RuntimeTypeHandle th) => th;
-        // Implement support for casting through IUnknown.
-        // No thread-affinity aware support.
-        // No IDispatch support.
-        // No aggregation support.
-    }
-
-    public abstract class GeneratedComWrappersBase<TComObject> : ComWrappers
-    {
-    }
-
     [AttributeUsage(AttributeTargets.Interface)]
     public class GeneratedComInterfaceAttribute : Attribute
     {
diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/GeneratedComWrappersBase.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/GeneratedComWrappersBase.cs
new file mode 100644 (file)
index 0000000..7f3f420
--- /dev/null
@@ -0,0 +1,51 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+// This type is for the COM source generator and implements part of the COM-specific interactions.
+// This API need to be exposed to implement the COM source generator in one form or another.
+
+using System.Collections;
+
+namespace System.Runtime.InteropServices.Marshalling
+{
+    public abstract class GeneratedComWrappersBase : ComWrappers
+    {
+        protected virtual IIUnknownInterfaceDetailsStrategy CreateInterfaceDetailsStrategy() => DefaultIUnknownInterfaceDetailsStrategy.Instance;
+
+        protected virtual IIUnknownStrategy CreateIUnknownStrategy() => FreeThreadedStrategy.Instance;
+
+        protected virtual IIUnknownCacheStrategy CreateCacheStrategy() => new DefaultCaching();
+
+        protected override sealed unsafe object CreateObject(nint externalComObject, CreateObjectFlags flags)
+        {
+            if (flags.HasFlag(CreateObjectFlags.TrackerObject)
+                || flags.HasFlag(CreateObjectFlags.Aggregation))
+            {
+                throw new NotSupportedException();
+            }
+
+            var rcw = new ComObject(CreateInterfaceDetailsStrategy(), CreateIUnknownStrategy(), CreateCacheStrategy(), (void*)externalComObject);
+            if (flags.HasFlag(CreateObjectFlags.UniqueInstance))
+            {
+                // Set value on MyComObject to enable the FinalRelease option.
+                // This could also be achieved through an internal factory
+                // function on ComObject type.
+            }
+            return rcw;
+        }
+
+        protected override sealed void ReleaseObjects(IEnumerable objects)
+        {
+            throw new NotImplementedException();
+        }
+
+        public ComObject GetOrCreateUniqueObjectForComInstance(nint comInstance, CreateObjectFlags flags)
+        {
+            if (flags.HasFlag(CreateObjectFlags.Unwrap))
+            {
+                throw new ArgumentException("Cannot create a unique object if unwrapping a ComWrappers-based COM object is requested.", nameof(flags));
+            }
+            return (ComObject)GetOrCreateObjectForComInstance(comInstance, flags | CreateObjectFlags.UniqueInstance);
+        }
+    }
+}
diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/IIUnknownCacheStrategy.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/IIUnknownCacheStrategy.cs
new file mode 100644 (file)
index 0000000..d043344
--- /dev/null
@@ -0,0 +1,52 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+// This type is for the COM source generator and implements part of the COM-specific interactions.
+// This API need to be exposed to implement the COM source generator in one form or another.
+
+namespace System.Runtime.InteropServices.Marshalling
+{
+    /// <summary>
+    /// Unmanaged virtual method table look up strategy.
+    /// </summary>
+    public unsafe interface IIUnknownCacheStrategy
+    {
+        public readonly struct TableInfo
+        {
+            public void* ThisPtr { get; init; }
+            public void** Table { get; init; }
+            public RuntimeTypeHandle ManagedType { get; init; }
+        }
+
+        /// <summary>
+        /// Construct a <see cref="TableInfo"/> instance.
+        /// </summary>
+        /// <param name="handle">RuntimeTypeHandle instance</param>
+        /// <param name="ptr">Pointer to the instance to query</param>
+        /// <param name="info">A <see cref="TableInfo"/> instance</param>
+        /// <returns>True if success, otherwise false.</returns>
+        TableInfo ConstructTableInfo(RuntimeTypeHandle handle, IUnknownDerivedDetails interfaceDetails, void* ptr);
+
+        /// <summary>
+        /// Get associated <see cref="TableInfo"/>.
+        /// </summary>
+        /// <param name="handle">RuntimeTypeHandle instance</param>
+        /// <param name="info">A <see cref="TableInfo"/> instance</param>
+        /// <returns>True if found, otherwise false.</returns>
+        bool TryGetTableInfo(RuntimeTypeHandle handle, out TableInfo info);
+
+        /// <summary>
+        /// Set associated <see cref="TableInfo"/>.
+        /// </summary>
+        /// <param name="handle">RuntimeTypeHandle instance</param>
+        /// <param name="info">A <see cref="TableInfo"/> instance</param>
+        /// <returns>True if set, otherwise false.</returns>
+        bool TrySetTableInfo(RuntimeTypeHandle handle, TableInfo info);
+
+        /// <summary>
+        /// Clear the cache
+        /// </summary>
+        /// <param name="unknownStrategy">The <see cref="IIUnknownStrategy"/> to use for clearing</param>
+        void Clear(IIUnknownStrategy unknownStrategy);
+    }
+}
diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/IIUnknownInterfaceDetailsStrategy.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/IIUnknownInterfaceDetailsStrategy.cs
new file mode 100644 (file)
index 0000000..cd9f849
--- /dev/null
@@ -0,0 +1,21 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+// This type is for the COM source generator and implements part of the COM-specific interactions.
+// This API need to be exposed to implement the COM source generator in one form or another.
+
+namespace System.Runtime.InteropServices.Marshalling
+{
+    /// <summary>
+    /// Strategy for acquiring interface details.
+    /// </summary>
+    public interface IIUnknownInterfaceDetailsStrategy
+    {
+        /// <summary>
+        /// Given a <see cref="RuntimeTypeHandle"/> get the IUnknown details.
+        /// </summary>
+        /// <param name="type">RuntimeTypeHandle instance</param>
+        /// <returns>Details if type is known.</returns>
+        IUnknownDerivedDetails? GetIUnknownDerivedDetails(RuntimeTypeHandle type);
+    }
+}
diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/IIUnknownInterfaceType.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/IIUnknownInterfaceType.cs
new file mode 100644 (file)
index 0000000..ccffb1e
--- /dev/null
@@ -0,0 +1,13 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+// This type is for the COM source generator and implements part of the COM-specific interactions.
+// This API need to be exposed to implement the COM source generator in one form or another.
+
+namespace System.Runtime.InteropServices.Marshalling
+{
+    public interface IIUnknownInterfaceType : IUnmanagedInterfaceType
+    {
+        public abstract static Guid Iid { get; }
+    }
+}
diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/IIUnknownStrategy.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/IIUnknownStrategy.cs
new file mode 100644 (file)
index 0000000..597c811
--- /dev/null
@@ -0,0 +1,45 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+// This type is for the COM source generator and implements part of the COM-specific interactions.
+// This API need to be exposed to implement the COM source generator in one form or another.
+
+namespace System.Runtime.InteropServices.Marshalling
+{
+    /// <summary>
+    /// IUnknown interaction strategy.
+    /// </summary>
+    public unsafe interface IIUnknownStrategy
+    {
+        /// <summary>
+        /// Create an instance pointer that represents the provided IUnknown instance.
+        /// </summary>
+        /// <param name="unknown">The IUnknown instance.</param>
+        /// <returns>A pointer representing the unmanaged instance.</returns>
+        /// <remarks>
+        /// This method is used to create an instance pointer that can be used to interact with the other members of this interface.
+        /// For example, this method can return an IAgileReference instance for the provided IUnknown instance
+        /// that can be used in the QueryInterface and Release methods to enable creating thread-local instance pointers to us
+        /// through the IAgileReference APIs instead of directly calling QueryInterface on the IUnknown.
+        /// </remarks>
+        public void* CreateInstancePointer(void* unknown);
+
+        /// <summary>
+        /// Perform a QueryInterface() for an IID on the unmanaged instance.
+        /// </summary>
+        /// <param name="instancePtr">A pointer representing the unmanaged instance.</param>
+        /// <param name="iid">The IID (Interface ID) to query for.</param>
+        /// <param name="ppObj">The resulting interface</param>
+        /// <returns>Returns an HRESULT represents the success of the operation</returns>
+        /// <seealso cref="Marshal.QueryInterface(nint, ref Guid, out nint)"/>
+        public int QueryInterface(void* instancePtr, in Guid iid, out void* ppObj);
+
+        /// <summary>
+        /// Perform a Release() call on the supplied unmanaged instance.
+        /// </summary>
+        /// <param name="instancePtr">A pointer representing the unmanaged instance.</param>
+        /// <returns>The current reference count.</returns>
+        /// <seealso cref="Marshal.Release(nint)"/>
+        public int Release(void* instancePtr);
+    }
+}
diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/IUnknownDerivedAttribute.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/IUnknownDerivedAttribute.cs
new file mode 100644 (file)
index 0000000..9addfc0
--- /dev/null
@@ -0,0 +1,27 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+// This type is for the COM source generator and implements part of the COM-specific interactions.
+// This API need to be exposed to implement the COM source generator in one form or another.
+
+namespace System.Runtime.InteropServices.Marshalling
+{
+    [AttributeUsage(AttributeTargets.Interface)]
+    public class IUnknownDerivedAttribute<T, TImpl> : Attribute, IUnknownDerivedDetails
+        where T : IIUnknownInterfaceType
+        where TImpl : T
+    {
+        public IUnknownDerivedAttribute()
+        {
+        }
+
+        /// <inheritdoc />
+        public Guid Iid => T.Iid;
+
+        /// <inheritdoc />
+        public Type Implementation => typeof(TImpl);
+
+        /// <inheritdoc />
+        public unsafe void* VirtualMethodTableManagedImplementation => T.VirtualMethodTableManagedImplementation;
+    }
+}
diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/IUnknownDerivedDetails.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/IUnknownDerivedDetails.cs
new file mode 100644 (file)
index 0000000..ecd5a54
--- /dev/null
@@ -0,0 +1,41 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+// This type is for the COM source generator and implements part of the COM-specific interactions.
+// This API need to be exposed to implement the COM source generator in one form or another.
+
+using System.Reflection;
+
+namespace System.Runtime.InteropServices.Marshalling
+{
+    /// <summary>
+    /// Details for the IUnknown derived interface.
+    /// </summary>
+    public interface IUnknownDerivedDetails
+    {
+        /// <summary>
+        /// Interface ID.
+        /// </summary>
+        public Guid Iid { get; }
+
+        /// <summary>
+        /// Managed type used to project the IUnknown derived interface.
+        /// </summary>
+        public Type Implementation { get; }
+
+        /// <summary>
+        /// A pointer to the virtual method table to enable unmanaged callers to call a managed implementation of the interface.
+        /// </summary>
+        public unsafe void* VirtualMethodTableManagedImplementation { get; }
+
+        internal static IUnknownDerivedDetails? GetFromAttribute(RuntimeTypeHandle handle)
+        {
+            var type = Type.GetTypeFromHandle(handle);
+            if (type is null)
+            {
+                return null;
+            }
+            return (IUnknownDerivedDetails?)type.GetCustomAttribute(typeof(IUnknownDerivedAttribute<,>));
+        }
+    }
+}
diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/IUnmanagedInterfaceType.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/IUnmanagedInterfaceType.cs
new file mode 100644 (file)
index 0000000..cbccd8d
--- /dev/null
@@ -0,0 +1,29 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace System.Runtime.InteropServices.Marshalling
+{
+    /// <summary>
+    /// This interface allows another interface to define that it represents a managed projection of an unmanaged interface from some unmanaged type system.
+    /// </summary>
+    /// <typeparam name="TInterface">The managed interface.</typeparam>
+    /// <typeparam name="TKey">The type of a value that can represent types from the corresponding unmanaged type system.</typeparam>
+    public unsafe interface IUnmanagedInterfaceType
+    {
+        /// <summary>
+        /// Get a pointer to the virtual method table of managed implementations of the unmanaged interface type.
+        /// </summary>
+        /// <returns>A pointer to the virtual method table of managed implementations of the unmanaged interface type</returns>
+        /// <remarks>
+        /// Implementation will be provided by a source generator if not explicitly implemented.
+        /// This property can return <c>null</c>. If it does, then the interface is not supported for passing managed implementations to unmanaged code.
+        /// </remarks>
+        public abstract static void* VirtualMethodTableManagedImplementation { get; }
+    }
+}
diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/IUnmanagedObjectUnwrapper.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/IUnmanagedObjectUnwrapper.cs
new file mode 100644 (file)
index 0000000..51cc064
--- /dev/null
@@ -0,0 +1,27 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+// This type is only needed for the VTable source generator or to provide abstract concepts that the COM generator would use under the hood.
+// These are types that we can exclude from the API proposals and either inline into the generated code, provide as file-scoped types, or not provide publicly (indicated by comments on each type).
+
+using System.Numerics;
+
+namespace System.Runtime.InteropServices.Marshalling
+{
+    /// <summary>
+    /// A factory to create an unmanaged "this pointer" from a managed object and to get a managed object from an unmanaged "this pointer".
+    /// </summary>
+    /// <remarks>
+    /// This interface would be used by the VTable source generator to enable users to indicate how to get the managed object from the "this pointer".
+    /// We can hard-code the ComWrappers logic here if we don't want to ship this interface.
+    /// </remarks>
+    public unsafe interface IUnmanagedObjectUnwrapper
+    {
+        /// <summary>
+        /// Get the object wrapped by <paramref name="ptr"/>.
+        /// </summary>
+        /// <param name="ptr">A an unmanaged "this pointer".</param>
+        /// <returns>The object wrapped by <paramref name="ptr"/>.</returns>
+        public static abstract object GetObjectForUnmanagedWrapper(void* ptr);
+    }
+}
index 99e4309..bcf46ba 100644 (file)
@@ -1,56 +1,12 @@
 // Licensed to the .NET Foundation under one or more agreements.
 // The .NET Foundation licenses this file to you under the MIT license.
 
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-
-namespace System.Runtime.InteropServices
+// This type is for the COM Source Generator and defines basic vtable interactions that we would need in the COM source generator in one form or another.
+namespace System.Runtime.InteropServices.Marshalling
 {
     /// <summary>
-    /// Information about a virtual method table and the unmanaged instance pointer.
+    /// This interface allows an object to provide information about a virtual method table for a managed interface to enable invoking methods in the virtual method table.
     /// </summary>
-    public readonly ref struct VirtualMethodTableInfo
-    {
-        /// <summary>
-        /// Construct a <see cref="VirtualMethodTableInfo"/> from a given instance pointer and table memory.
-        /// </summary>
-        /// <param name="thisPointer">The pointer to the instance.</param>
-        /// <param name="virtualMethodTable">The block of memory that represents the virtual method table.</param>
-        public VirtualMethodTableInfo(IntPtr thisPointer, ReadOnlySpan<IntPtr> virtualMethodTable)
-        {
-            ThisPointer = thisPointer;
-            VirtualMethodTable = virtualMethodTable;
-        }
-
-        /// <summary>
-        /// The unmanaged instance pointer
-        /// </summary>
-        public IntPtr ThisPointer { get; }
-
-        /// <summary>
-        /// The virtual method table.
-        /// </summary>
-        public ReadOnlySpan<IntPtr> VirtualMethodTable { get; }
-
-        /// <summary>
-        /// Deconstruct this structure into its two fields.
-        /// </summary>
-        /// <param name="thisPointer">The <see cref="ThisPointer"/> result</param>
-        /// <param name="virtualMethodTable">The <see cref="VirtualMethodTable"/> result</param>
-        public void Deconstruct(out IntPtr thisPointer, out ReadOnlySpan<IntPtr> virtualMethodTable)
-        {
-            thisPointer = ThisPointer;
-            virtualMethodTable = VirtualMethodTable;
-        }
-    }
-
-    /// <summary>
-    /// This interface allows an object to provide information about a virtual method table for a managed interface that implements <see cref="IUnmanagedInterfaceType{TInterface}"/> to enable invoking methods in the virtual method table.
-    /// </summary>
-    /// <typeparam name="T">The type to use to represent the the identity of the unmanaged type.</typeparam>
     public unsafe interface IUnmanagedVirtualMethodTableProvider
     {
         /// <summary>
@@ -58,98 +14,6 @@ namespace System.Runtime.InteropServices
         /// </summary>
         /// <param name="type">The managed type for the unmanaged interface.</param>
         /// <returns>The virtual method table information for the unmanaged interface.</returns>
-        protected VirtualMethodTableInfo GetVirtualMethodTableInfoForKey(Type type);
-
-        /// <summary>
-        /// Get the information about the virtual method table for the given unmanaged interface type.
-        /// </summary>
-        /// <typeparam name="TUnmanagedInterfaceType">The managed interface type that represents the unmanaged interface.</typeparam>
-        /// <returns>The virtual method table information for the unmanaged interface.</returns>
-        public sealed VirtualMethodTableInfo GetVirtualMethodTableInfoForKey<TUnmanagedInterfaceType>()
-            where TUnmanagedInterfaceType : IUnmanagedInterfaceType<TUnmanagedInterfaceType>
-        {
-            return GetVirtualMethodTableInfoForKey(typeof(TUnmanagedInterfaceType));
-        }
-
-        /// <summary>
-        /// Get the length of the virtual method table for the given unmanaged interface type.
-        /// </summary>
-        /// <typeparam name="TUnmanagedInterfaceType">The managed interface type that represents the unmanaged interface.</typeparam>
-        /// <returns>The length of the virtual method table for the unmanaged interface.</returns>
-        public static int GetVirtualMethodTableLength<TUnmanagedInterfaceType>()
-            where TUnmanagedInterfaceType : IUnmanagedInterfaceType<TUnmanagedInterfaceType>
-        {
-            return TUnmanagedInterfaceType.VirtualMethodTableLength;
-        }
-
-        /// <summary>
-        /// Get a pointer to the virtual method table  of managed implementations of the unmanaged interface type.
-        /// </summary>
-        /// <typeparam name="TUnmanagedInterfaceType">The managed interface type that represents the unmanaged interface.</typeparam>
-        /// <returns>A pointer to the virtual method table  of managed implementations of the unmanaged interface type</returns>
-        public static void* GetVirtualMethodTableManagedImplementation<TUnmanagedInterfaceType>()
-            where TUnmanagedInterfaceType : IUnmanagedInterfaceType<TUnmanagedInterfaceType>
-        {
-            return TUnmanagedInterfaceType.VirtualMethodTableManagedImplementation;
-        }
-
-        /// <summary>
-        /// Get a pointer that wraps a managed implementation of an unmanaged interface that can be passed to unmanaged code.
-        /// </summary>
-        /// <typeparam name="TUnmanagedInterfaceType">The managed type that represents the unmanaged interface.</typeparam>
-        /// <param name="obj">The managed object that implements the unmanaged interface.</param>
-        /// <returns>A pointer-sized value that can be passed to unmanaged code that represents <paramref name="obj"/></returns>
-        public static void* GetUnmanagedWrapperForObject<TUnmanagedInterfaceType>(TUnmanagedInterfaceType obj)
-            where TUnmanagedInterfaceType : IUnmanagedInterfaceType<TUnmanagedInterfaceType>
-        {
-            return TUnmanagedInterfaceType.GetUnmanagedWrapperForObject(obj);
-        }
-
-        /// <summary>
-        /// Get the object wrapped by <paramref name="ptr"/>.
-        /// </summary>
-        /// <typeparam name="TUnmanagedInterfaceType">The managed type that represents the unmanaged interface.</typeparam>
-        /// <param name="ptr">A pointer-sized value returned by <see cref="GetUnmanagedWrapperForObject{TUnmanagedInterfaceType}(TUnmanagedInterfaceType)"/> or <see cref="IUnmanagedInterfaceType{TInterface, TKey}.GetUnmanagedWrapperForObject(TInterface)"/>.</param>
-        /// <returns>The object wrapped by <paramref name="ptr"/>.</returns>
-        public static TUnmanagedInterfaceType GetObjectForUnmanagedWrapper<TUnmanagedInterfaceType>(void* ptr)
-            where TUnmanagedInterfaceType : IUnmanagedInterfaceType<TUnmanagedInterfaceType>
-        {
-            return TUnmanagedInterfaceType.GetObjectForUnmanagedWrapper(ptr);
-        }
-    }
-
-    /// <summary>
-    /// This interface allows another interface to define that it represents a managed projection of an unmanaged interface from some unmanaged type system.
-    /// </summary>
-    /// <typeparam name="TInterface">The managed interface.</typeparam>
-    /// <typeparam name="TKey">The type of a value that can represent types from the corresponding unmanaged type system.</typeparam>
-    public unsafe interface IUnmanagedInterfaceType<TInterface>
-        where TInterface : IUnmanagedInterfaceType<TInterface>
-    {
-        /// <summary>
-        /// Get the length of the virtual method table for the given unmanaged interface type.
-        /// </summary>
-        /// <returns>The length of the virtual method table for the unmanaged interface.</returns>
-        public static abstract int VirtualMethodTableLength { get; }
-
-        /// <summary>
-        /// Get a pointer to the virtual method table  of managed implementations of the unmanaged interface type.
-        /// </summary>
-        /// <returns>A pointer to the virtual method table  of managed implementations of the unmanaged interface type</returns>
-        public static abstract void* VirtualMethodTableManagedImplementation { get; }
-
-        /// <summary>
-        /// Get a pointer that wraps a managed implementation of an unmanaged interface that can be passed to unmanaged code.
-        /// </summary>
-        /// <param name="obj">The managed object that implements the unmanaged interface.</param>
-        /// <returns>A pointer-sized value that can be passed to unmanaged code that represents <paramref name="obj"/></returns>
-        public static abstract void* GetUnmanagedWrapperForObject(TInterface obj);
-
-        /// <summary>
-        /// Get the object wrapped by <paramref name="ptr"/>.
-        /// </summary>
-        /// <param name="ptr">A pointer-sized value returned by <see cref="IUnmanagedVirtualMethodTableProvider{TKey}.GetUnmanagedWrapperForObject{IUnmanagedInterfaceType{TInterface, TKey}}(IUnmanagedInterfaceType{TInterface, TKey})"/> or <see cref="GetUnmanagedWrapperForObject(TInterface)"/>.</param>
-        /// <returns>The object wrapped by <paramref name="ptr"/>.</returns>
-        public static abstract TInterface GetObjectForUnmanagedWrapper(void* ptr);
+        public VirtualMethodTableInfo GetVirtualMethodTableInfoForKey(Type type);
     }
 }
diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/UnmanagedObjectUnwrapper.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/UnmanagedObjectUnwrapper.cs
new file mode 100644 (file)
index 0000000..4494942
--- /dev/null
@@ -0,0 +1,20 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+namespace System.Runtime.InteropServices.Marshalling;
+
+// This type should be inlined in the COM source generator and made internal
+// This type allows the generated code to call a private explicit implementation of IUnmanagedObjectUnwrapper.GetObjectForUnmanagedWrapper
+public unsafe static class UnmanagedObjectUnwrapper
+{
+    public static object GetObjectForUnmanagedWrapper<T>(void* ptr) where T : IUnmanagedObjectUnwrapper
+    {
+        return T.GetObjectForUnmanagedWrapper(ptr);
+    }
+
+    // This type is provided for the unit tests that only confirm the generated code compiles
+    public class TestUnwrapper : IUnmanagedObjectUnwrapper
+    {
+        public static object GetObjectForUnmanagedWrapper(void* ptr) => throw new NotImplementedException();
+    }
+}
diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/UnmanagedObjectUnwrapperAttribute.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/UnmanagedObjectUnwrapperAttribute.cs
new file mode 100644 (file)
index 0000000..128eb12
--- /dev/null
@@ -0,0 +1,16 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+// This type only needed for the VTable source generator or to provide abstract concepts that the COM generator would use under the hood.
+// These are types that we can exclude from the API proposals and either inline into the generated code, provide as file-scoped types, or not provide publicly (indicated by comments on each type).
+
+namespace System.Runtime.InteropServices.Marshalling
+{
+    // This attribute provides the mechanism for the VTable source generator to know which type to use to get the managed object
+    // from the unmanaged "this" pointer. If we decide to not expose VirtualMethodIndexAttribute, we don't need to expose this.
+    [AttributeUsage(AttributeTargets.Interface)]
+    public class UnmanagedObjectUnwrapperAttribute<TMapper> : Attribute
+        where TMapper : IUnmanagedObjectUnwrapper
+    {
+    }
+}
index 3110fac..a248a79 100644 (file)
@@ -10,6 +10,8 @@ using System.Threading.Tasks;
 
 namespace System.Runtime.InteropServices.Marshalling
 {
+    // This type is only needed for the VTable source generator or to provide abstract concepts that the COM generator would use under the hood.
+    // These are types that we can exclude from the API proposals and either inline into the generated code, provide as file-scoped types, or not provide publicly (indicated by comments on each type).
     [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
     public class VirtualMethodIndexAttribute : Attribute
     {
diff --git a/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/VirtualMethodTableInfo.cs b/src/libraries/System.Runtime.InteropServices/tests/Ancillary.Interop/VirtualMethodTableInfo.cs
new file mode 100644 (file)
index 0000000..498102f
--- /dev/null
@@ -0,0 +1,44 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+
+// This type is for the COM Source Generator and defines basic vtable interactions that we would need in the COM source generator in one form or another.
+namespace System.Runtime.InteropServices.Marshalling
+{
+    /// <summary>
+    /// Information about a virtual method table and the unmanaged instance pointer.
+    /// </summary>
+    public readonly unsafe struct VirtualMethodTableInfo
+    {
+        /// <summary>
+        /// Construct a <see cref="VirtualMethodTableInfo"/> from a given instance pointer and table memory.
+        /// </summary>
+        /// <param name="thisPointer">The pointer to the instance.</param>
+        /// <param name="virtualMethodTable">The block of memory that represents the virtual method table.</param>
+        public VirtualMethodTableInfo(void* thisPointer, void** virtualMethodTable)
+        {
+            ThisPointer = thisPointer;
+            VirtualMethodTable = virtualMethodTable;
+        }
+
+        /// <summary>
+        /// The unmanaged instance pointer
+        /// </summary>
+        public void* ThisPointer { get; }
+
+        /// <summary>
+        /// The virtual method table.
+        /// </summary>
+        public void** VirtualMethodTable { get; }
+
+        /// <summary>
+        /// Deconstruct this structure into its two fields.
+        /// </summary>
+        /// <param name="thisPointer">The <see cref="ThisPointer"/> result</param>
+        /// <param name="virtualMethodTable">The <see cref="VirtualMethodTable"/> result</param>
+        public void Deconstruct(out void* thisPointer, out void** virtualMethodTable)
+        {
+            thisPointer = ThisPointer;
+            virtualMethodTable = VirtualMethodTable;
+        }
+    }
+}
index 55174ae..e6214e7 100644 (file)
@@ -5,6 +5,7 @@ using System;
 using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using System.Runtime.InteropServices.Marshalling;
+using ComInterfaceGenerator.Tests;
 using Xunit;
 
 namespace ComInterfaceGenerator.Tests
@@ -13,34 +14,23 @@ namespace ComInterfaceGenerator.Tests
     {
         internal partial class ImplicitThis
         {
-            internal partial interface INativeObject : IUnmanagedInterfaceType<INativeObject>
+            [UnmanagedObjectUnwrapperAttribute<VTableGCHandlePair<INativeObject>>]
+            internal partial interface INativeObject : IUnmanagedInterfaceType
             {
-                static int IUnmanagedInterfaceType<INativeObject>.VirtualMethodTableLength => 2;
 
-
-                private static void** s_vtable = (void**)RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(INativeObject), sizeof(void*) * IUnmanagedVirtualMethodTableProvider.GetVirtualMethodTableLength<INativeObject>());
-                static void* IUnmanagedInterfaceType<INativeObject>.VirtualMethodTableManagedImplementation
+                private static void** s_vtable = (void**)RuntimeHelpers.AllocateTypeAssociatedMemory(typeof(INativeObject), sizeof(void*) * 2);
+                static void* IUnmanagedInterfaceType.VirtualMethodTableManagedImplementation
                 {
                     get
                     {
                         if (s_vtable[0] == null)
                         {
-                            Native.PopulateUnmanagedVirtualMethodTable(new Span<IntPtr>(s_vtable, IUnmanagedVirtualMethodTableProvider.GetVirtualMethodTableLength<INativeObject>()));
+                            Native.PopulateUnmanagedVirtualMethodTable(s_vtable);
                         }
                         return s_vtable;
                     }
                 }
 
-                static void* IUnmanagedInterfaceType<INativeObject>.GetUnmanagedWrapperForObject(INativeObject obj)
-                {
-                    return VTableGCHandlePair<INativeObject>.Allocate(obj);
-                }
-
-                static INativeObject IUnmanagedInterfaceType<INativeObject>.GetObjectForUnmanagedWrapper(void* ptr)
-                {
-                    return VTableGCHandlePair<INativeObject>.GetObject(ptr);
-                }
-
                 [VirtualMethodIndex(0, ImplicitThisParameter = true)]
                 int GetData();
                 [VirtualMethodIndex(1, ImplicitThisParameter = true)]
@@ -60,7 +50,7 @@ namespace ComInterfaceGenerator.Tests
                 public VirtualMethodTableInfo GetVirtualMethodTableInfoForKey(Type type)
                 {
                     Assert.Equal(typeof(INativeObject), type);
-                    return new VirtualMethodTableInfo((IntPtr)_pointer, new ReadOnlySpan<IntPtr>(*(void**)_pointer, 2));
+                    return new VirtualMethodTableInfo(_pointer, *(void***)_pointer);
                 }
 
                 public void Dispose()
@@ -113,7 +103,7 @@ namespace ComInterfaceGenerator.Tests
 
             ManagedObjectImplementation impl = new ManagedObjectImplementation(startingValue);
 
-            void* wrapper = IUnmanagedVirtualMethodTableProvider.GetUnmanagedWrapperForObject<NativeExportsNE.ImplicitThis.INativeObject>(impl);
+            void* wrapper = VTableGCHandlePair<NativeExportsNE.ImplicitThis.INativeObject>.Allocate(impl);
 
             Assert.Equal(startingValue, NativeExportsNE.ImplicitThis.GetNativeObjectData(wrapper));
             NativeExportsNE.ImplicitThis.SetNativeObjectData(wrapper, newValue);
index fd0d0a4..e86ae01 100644 (file)
@@ -12,14 +12,10 @@ namespace ComInterfaceGenerator.Tests
     {
         internal partial class NoImplicitThis
         {
-            internal partial interface IStaticMethodTable : IUnmanagedInterfaceType<IStaticMethodTable>
+            [UnmanagedObjectUnwrapperAttribute<VTableGCHandlePair<IStaticMethodTable>>]
+            internal partial interface IStaticMethodTable : IUnmanagedInterfaceType
             {
-                static int IUnmanagedInterfaceType<IStaticMethodTable>.VirtualMethodTableLength => 2;
-                static void* IUnmanagedInterfaceType<IStaticMethodTable>.VirtualMethodTableManagedImplementation => null;
-
-                static void* IUnmanagedInterfaceType<IStaticMethodTable>.GetUnmanagedWrapperForObject(IStaticMethodTable obj) => null;
-
-                static IStaticMethodTable IUnmanagedInterfaceType<IStaticMethodTable>.GetObjectForUnmanagedWrapper(void* ptr) => null;
+                static void* IUnmanagedInterfaceType.VirtualMethodTableManagedImplementation => null;
 
                 [VirtualMethodIndex(0, Direction = MarshalDirection.ManagedToUnmanaged, ImplicitThisParameter = false)]
                 int Add(int x, int y);
@@ -40,7 +36,7 @@ namespace ComInterfaceGenerator.Tests
                 public VirtualMethodTableInfo GetVirtualMethodTableInfoForKey(Type type)
                 {
                     Assert.Equal(typeof(IStaticMethodTable), type);
-                    return new VirtualMethodTableInfo(IntPtr.Zero, new ReadOnlySpan<IntPtr>(_vtableStart, IUnmanagedVirtualMethodTableProvider.GetVirtualMethodTableLength<IStaticMethodTable>()));
+                    return new VirtualMethodTableInfo((void*)null, (void**)_vtableStart);
                 }
             }
 
index c6ee2cd..30a7946 100644 (file)
@@ -2,15 +2,16 @@
 // The .NET Foundation licenses this file to you under the MIT license.
 
 using System.Runtime.InteropServices;
+using System.Runtime.InteropServices.Marshalling;
 
 namespace ComInterfaceGenerator.Tests
 {
-    public static unsafe class VTableGCHandlePair<TUnmanagedInterface>
-        where TUnmanagedInterface : IUnmanagedInterfaceType<TUnmanagedInterface>
+    public unsafe class VTableGCHandlePair<TUnmanagedInterface> : IUnmanagedObjectUnwrapper
+        where TUnmanagedInterface : IUnmanagedInterfaceType
     {
         public static void* Allocate(TUnmanagedInterface obj)
         {
-            void** unmanaged = (void**)NativeMemory.Alloc((nuint)sizeof(void*) * (nuint)IUnmanagedVirtualMethodTableProvider.GetVirtualMethodTableLength<TUnmanagedInterface>());
+            void** unmanaged = (void**)NativeMemory.Alloc((nuint)sizeof(void*) * 2);
             unmanaged[0] = TUnmanagedInterface.VirtualMethodTableManagedImplementation;
             unmanaged[1] = (void*)GCHandle.ToIntPtr(GCHandle.Alloc(obj));
             return unmanaged;
@@ -26,5 +27,8 @@ namespace ComInterfaceGenerator.Tests
         {
             return (TUnmanagedInterface)GCHandle.FromIntPtr((nint)((void**)pair)[1]).Target;
         }
+
+        static object IUnmanagedObjectUnwrapper.GetObjectForUnmanagedWrapper(void* ptr) => 
+            (TUnmanagedInterface)GCHandle.FromIntPtr((nint)((void**)ptr)[1]).Target;
     }
 }
index d8033b5..72fe813 100644 (file)
@@ -23,7 +23,8 @@ namespace ComInterfaceGenerator.Unit.Tests
                 using System.Runtime.InteropServices;
                 using System.Runtime.InteropServices.Marshalling;
 
-                partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+                [UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+                partial interface INativeAPI : IUnmanagedInterfaceType
                 {
                     {{CodeSnippets.INativeAPI_IUnmanagedInterfaceTypeMethodImpl}}
                     [VirtualMethodIndex(0)]
@@ -49,7 +50,8 @@ namespace ComInterfaceGenerator.Unit.Tests
                 using System.Runtime.InteropServices;
                 using System.Runtime.InteropServices.Marshalling;
 
-                partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+                [UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+                partial interface INativeAPI : IUnmanagedInterfaceType
                 {
                     {{CodeSnippets.INativeAPI_IUnmanagedInterfaceTypeMethodImpl}}
                     [SuppressGCTransitionAttribute]
@@ -76,7 +78,8 @@ namespace ComInterfaceGenerator.Unit.Tests
                 using System.Runtime.InteropServices;
                 using System.Runtime.InteropServices.Marshalling;
 
-                partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+                [UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+                partial interface INativeAPI : IUnmanagedInterfaceType
                 {
                     {{CodeSnippets.INativeAPI_IUnmanagedInterfaceTypeMethodImpl}}
                     [UnmanagedCallConv]
@@ -103,7 +106,8 @@ namespace ComInterfaceGenerator.Unit.Tests
                 using System.Runtime.InteropServices;
                 using System.Runtime.InteropServices.Marshalling;
 
-                partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+                [UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+                partial interface INativeAPI : IUnmanagedInterfaceType
                 {
                     {{CodeSnippets.INativeAPI_IUnmanagedInterfaceTypeMethodImpl}}
                     [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })]
@@ -130,7 +134,8 @@ namespace ComInterfaceGenerator.Unit.Tests
                 using System.Runtime.InteropServices;
                 using System.Runtime.InteropServices.Marshalling;
 
-                partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+                [UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+                partial interface INativeAPI : IUnmanagedInterfaceType
                 {
                     {{CodeSnippets.INativeAPI_IUnmanagedInterfaceTypeMethodImpl}}
                     [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl), typeof(CallConvMemberFunction) })]
@@ -163,7 +168,8 @@ namespace ComInterfaceGenerator.Unit.Tests
                 using System.Runtime.InteropServices;
                 using System.Runtime.InteropServices.Marshalling;
 
-                partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+                [UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+                partial interface INativeAPI : IUnmanagedInterfaceType
                 {
                     {{CodeSnippets.INativeAPI_IUnmanagedInterfaceTypeMethodImpl}}
                     [SuppressGCTransition]
index ef02fb3..9314731 100644 (file)
@@ -18,10 +18,7 @@ namespace ComInterfaceGenerator.Unit.Tests
             """;
 
         public const string INativeAPI_IUnmanagedInterfaceTypeMethodImpl = """
-                static int IUnmanagedInterfaceType<INativeAPI>.VirtualMethodTableLength => 1;
-                static unsafe void* IUnmanagedInterfaceType<INativeAPI>.VirtualMethodTableManagedImplementation => null;
-                static unsafe void* IUnmanagedInterfaceType<INativeAPI>.GetUnmanagedWrapperForObject(INativeAPI obj) => null;
-                static unsafe INativeAPI IUnmanagedInterfaceType<INativeAPI>.GetObjectForUnmanagedWrapper(void* ptr) => null;
+                static unsafe void* IUnmanagedInterfaceType.VirtualMethodTableManagedImplementation => null;
             """;
 
         public static string NativeInterfaceUsage() => @"
@@ -36,7 +33,8 @@ sealed class NativeAPI : IUnmanagedVirtualMethodTableProvider, INativeAPI.Native
 using System.Runtime.InteropServices;
 using System.Runtime.InteropServices.Marshalling;
 
-partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+[UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+partial interface INativeAPI : IUnmanagedInterfaceType
 {
     [VirtualMethodIndex(0)]
     void Method();
@@ -46,7 +44,8 @@ partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
 using System.Runtime.InteropServices;
 using System.Runtime.InteropServices.Marshalling;
 
-partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+[UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+partial interface INativeAPI : IUnmanagedInterfaceType
 {
     [VirtualMethodIndex(0, ImplicitThisParameter = false)]
     void Method();
@@ -57,7 +56,8 @@ using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using System.Runtime.InteropServices.Marshalling;
 
-partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+[UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+partial interface INativeAPI : IUnmanagedInterfaceType
 {
 
     [UnmanagedCallConv(CallConvs = new[] { typeof(CallConvCdecl) })]
@@ -89,7 +89,8 @@ using System.Runtime.InteropServices.Marshalling;
 
 [assembly:DisableRuntimeMarshalling]
 
-partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+[UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+partial interface INativeAPI : IUnmanagedInterfaceType
 {{
     [VirtualMethodIndex(0)]
     {typeName} Method({typeName} value, in {typeName} inValue, ref {typeName} refValue, out {typeName} outValue);
@@ -102,7 +103,8 @@ using System.Runtime.InteropServices.Marshalling;
 
 [assembly:DisableRuntimeMarshalling]
 
-partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+[UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+partial interface INativeAPI : IUnmanagedInterfaceType
 {{
     [VirtualMethodIndex(0, Direction = MarshalDirection.ManagedToUnmanaged)]
     {typeName} Method({typeName} value, in {typeName} inValue, ref {typeName} refValue, out {typeName} outValue);
@@ -116,7 +118,8 @@ using System.Runtime.InteropServices.Marshalling;
 
 [assembly:DisableRuntimeMarshalling]
 
-partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+[UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+partial interface INativeAPI : IUnmanagedInterfaceType
 {{
     [VirtualMethodIndex(0)]
     {typeName} Method({typeName} value, in {typeName} inValue, out {typeName} outValue);
@@ -126,7 +129,8 @@ using System.Runtime.CompilerServices;
 using System.Runtime.InteropServices;
 using System.Runtime.InteropServices.Marshalling;
 
-partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+[UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+partial interface INativeAPI : IUnmanagedInterfaceType
 {{
     [VirtualMethodIndex(0, ImplicitThisParameter = false)]
     {typeName} Method({typeName} value, in {typeName} inValue, ref {typeName} refValue, out {typeName} outValue);
@@ -140,7 +144,8 @@ using System.Runtime.InteropServices;
 using System.Runtime.InteropServices.Marshalling;
 [assembly:DisableRuntimeMarshalling]
 
-partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+[UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+partial interface INativeAPI : IUnmanagedInterfaceType
 {{
     [VirtualMethodIndex(0)]
     [return:MarshalUsing(ConstantElementCount=10)]
@@ -159,7 +164,8 @@ using System.Runtime.InteropServices;
 using System.Runtime.InteropServices.Marshalling;
 {preDeclaration}
 
-partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+[UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+partial interface INativeAPI : IUnmanagedInterfaceType
 {{
     [VirtualMethodIndex(0, ExceptionMarshalling = ExceptionMarshalling.Com)]
     {typeName} Method();
@@ -171,7 +177,8 @@ using System.Runtime.InteropServices;
 using System.Runtime.InteropServices.Marshalling;
 {preDeclaration}
 
-partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+[UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+partial interface INativeAPI : IUnmanagedInterfaceType
 {{
     [VirtualMethodIndex(0, CustomExceptionMarshallingType = typeof({customExceptionType}))]
     {typeName} Method();
index 7f34b24..d93701c 100644 (file)
@@ -35,8 +35,9 @@ namespace ComInterfaceGenerator.Unit.Tests
                         void Bar() {}
                     }
 
-                    public partial class MyComWrappers : GeneratedComWrappersBase<ComObject>
+                    public unsafe partial class MyComWrappers : GeneratedComWrappersBase
                     {
+                        protected override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) {count = 0; return null;}
                     }
 
                     """;
@@ -54,8 +55,9 @@ namespace ComInterfaceGenerator.Unit.Tests
                         void Bar() {}
                     }
 
-                    public partial class MyComWrappers : GeneratedComWrappersBase<ComObject>
+                    public unsafe partial class MyComWrappers : GeneratedComWrappersBase
                     {
+                        protected override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) {count = 0; return null;}
                     }
 
                     """;
@@ -74,8 +76,10 @@ namespace ComInterfaceGenerator.Unit.Tests
                     void Bar() {}
                 }
 
-                public partial class MyComWrappers : GeneratedComWrappersBase<ComObject>
+                
+                public unsafe partial class MyComWrappers : GeneratedComWrappersBase
                 {
+                    protected override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) {count = 0; return null;}
                 }
 
                 """;
@@ -94,8 +98,9 @@ namespace ComInterfaceGenerator.Unit.Tests
                     void Bar() {}
                 }
 
-                public partial class MyComWrappers : GeneratedComWrappersBase<ComObject>
+                public unsafe partial class MyComWrappers : GeneratedComWrappersBase
                 {
+                    protected override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) {count = 0; return null;}
                 }
 
                 """;
@@ -114,8 +119,9 @@ namespace ComInterfaceGenerator.Unit.Tests
                     void Bar() {}
                 }
 
-                public partial class MyComWrappers : GeneratedComWrappersBase<ComObject>
+                public unsafe partial class MyComWrappers : GeneratedComWrappersBase
                 {
+                    protected override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) {count = 0; return null;}
                 }
 
                 """;
@@ -134,8 +140,9 @@ namespace ComInterfaceGenerator.Unit.Tests
                     void Bar() {}
                 }
 
-                public partial class MyComWrappers : GeneratedComWrappersBase<ComObject>
+                public unsafe partial class MyComWrappers : GeneratedComWrappersBase
                 {
+                    protected override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) {count = 0; return null;}
                 }
 
                 """;
@@ -154,8 +161,9 @@ namespace ComInterfaceGenerator.Unit.Tests
                     void Bar() {}
                 }
 
-                public partial class MyComWrappers : GeneratedComWrappersBase<ComObject>
+                public unsafe partial class MyComWrappers : GeneratedComWrappersBase
                 {
+                    protected override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) {count = 0; return null;}
                 }
 
                 """;
@@ -174,8 +182,9 @@ namespace ComInterfaceGenerator.Unit.Tests
                     void Bar() {}
                 }
 
-                public partial class MyComWrappers : GeneratedComWrappersBase<ComObject>
+                public unsafe partial class MyComWrappers : GeneratedComWrappersBase
                 {
+                    protected override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) {count = 0; return null;}
                 }
 
                 """;
@@ -198,8 +207,9 @@ namespace ComInterfaceGenerator.Unit.Tests
                     void Bar() {}
                 }
 
-                public partial class MyComWrappers : GeneratedComWrappersBase<ComObject>
+                public unsafe partial class MyComWrappers : GeneratedComWrappersBase
                 {
+                    protected override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) {count = 0; return null;}
                 }
 
                 """;
@@ -223,8 +233,9 @@ namespace ComInterfaceGenerator.Unit.Tests
                     void Bar() {}
                 }
 
-                public partial class MyComWrappers : GeneratedComWrappersBase<ComObject>
+                public unsafe partial class MyComWrappers : GeneratedComWrappersBase
                 {
+                    protected override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) {count = 0; return null;}
                 }
 
                 """;
@@ -244,8 +255,9 @@ namespace ComInterfaceGenerator.Unit.Tests
                     void Bar() {}
                 }
 
-                public partial class MyComWrappers : GeneratedComWrappersBase<ComObject>
+                public unsafe partial class MyComWrappers : GeneratedComWrappersBase
                 {
+                    protected override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) {count = 0; return null;}
                 }
 
                 """;
@@ -265,8 +277,9 @@ namespace ComInterfaceGenerator.Unit.Tests
                     void Bar() {}
                 }
 
-                public partial class MyComWrappers : GeneratedComWrappersBase<ComObject>
+                public unsafe partial class MyComWrappers : GeneratedComWrappersBase
                 {
+                    protected override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) {count = 0; return null;}
                 }
 
                 """;
@@ -290,8 +303,9 @@ namespace ComInterfaceGenerator.Unit.Tests
                     void Bar() {}
                 }
 
-                public partial class MyComWrappers : GeneratedComWrappersBase<ComObject>
+                public unsafe partial class MyComWrappers : GeneratedComWrappersBase
                 {
+                    protected override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) {count = 0; return null;}
                 }
 
                 """;
@@ -315,8 +329,9 @@ namespace ComInterfaceGenerator.Unit.Tests
                     void Bar() {}
                 }
 
-                public partial class MyComWrappers : GeneratedComWrappersBase<ComObject>
+                public unsafe partial class MyComWrappers : GeneratedComWrappersBase
                 {
+                    protected override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) {count = 0; return null;}
                 }
 
                 """;
@@ -340,8 +355,9 @@ namespace ComInterfaceGenerator.Unit.Tests
                     void Bar() {}
                 }
 
-                public partial class MyComWrappers : GeneratedComWrappersBase<ComObject>
+                public unsafe partial class MyComWrappers : GeneratedComWrappersBase
                 {
+                    protected override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) {count = 0; return null;}
                 }
 
                 """;
@@ -365,8 +381,9 @@ namespace ComInterfaceGenerator.Unit.Tests
                     void Bar() {}
                 }
 
-                public partial class MyComWrappers : GeneratedComWrappersBase<ComObject>
+                public unsafe partial class MyComWrappers : GeneratedComWrappersBase
                 {
+                    protected override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) {count = 0; return null;}
                 }
 
                 """;
@@ -390,8 +407,9 @@ namespace ComInterfaceGenerator.Unit.Tests
                     void Bar() {}
                 }
 
-                public partial class MyComWrappers : GeneratedComWrappersBase<ComObject>
+                public unsafe partial class MyComWrappers : GeneratedComWrappersBase
                 {
+                    protected override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) {count = 0; return null;}
                 }
 
                 """;
@@ -421,8 +439,9 @@ namespace ComInterfaceGenerator.Unit.Tests
                 [GeneratedComInterface(typeof(MyComWrappers))]
                 partial interface IFoo { }
 
-                public partial class MyComWrappers : GeneratedComWrappersBase<ComObject>
+                public unsafe partial class MyComWrappers : GeneratedComWrappersBase
                 {
+                    protected override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) {count = 0; return null;}
                 }
 
                 """;
@@ -444,8 +463,9 @@ namespace ComInterfaceGenerator.Unit.Tests
                 [GeneratedComInterface(typeof(MyComWrappers))]
                 partial interface IFoo { }
 
-                public partial class MyComWrappers : GeneratedComWrappersBase<ComObject>
+                public unsafe partial class MyComWrappers : GeneratedComWrappersBase
                 {
+                    protected override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) {count = 0; return null;}
                 }
 
                 """;
@@ -467,8 +487,9 @@ namespace ComInterfaceGenerator.Unit.Tests
                 [GeneratedComInterface(typeof(MyComWrappers))]
                 partial interface IFoo { }
 
-                public partial class MyComWrappers : GeneratedComWrappersBase<ComObject>
+                public unsafe partial class MyComWrappers : GeneratedComWrappersBase
                 {
+                    protected override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) {count = 0; return null;}
                 }
 
                 """;
@@ -494,8 +515,9 @@ namespace ComInterfaceGenerator.Unit.Tests
                 [GeneratedComInterface(typeof(MyComWrappers))]
                 partial interface IFoo { }
 
-                public partial class MyComWrappers : GeneratedComWrappersBase<ComObject>
+                public unsafe partial class MyComWrappers : GeneratedComWrappersBase
                 {
+                    protected override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) {count = 0; return null;}
                 }
 
                 """;
@@ -521,8 +543,9 @@ namespace ComInterfaceGenerator.Unit.Tests
                 [GeneratedComInterface(typeof(MyComWrappers))]
                 partial interface IFoo { }
 
-                public partial class MyComWrappers : GeneratedComWrappersBase<ComObject>
+                public unsafe partial class MyComWrappers : GeneratedComWrappersBase
                 {
+                    protected override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) {count = 0; return null;}
                 }
 
                 """;
@@ -548,8 +571,9 @@ namespace ComInterfaceGenerator.Unit.Tests
                 [GeneratedComInterface(typeof(MyComWrappers))]
                 partial interface IFoo { }
 
-                public partial class MyComWrappers : GeneratedComWrappersBase<ComObject>
+                public unsafe partial class MyComWrappers : GeneratedComWrappersBase
                 {
+                    protected override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) {count = 0; return null;}
                 }
 
                 """;
@@ -575,8 +599,9 @@ namespace ComInterfaceGenerator.Unit.Tests
                 [GeneratedComInterface(typeof(MyComWrappers))]
                 partial interface IFoo { }
 
-                public partial class MyComWrappers : GeneratedComWrappersBase<ComObject>
+                public unsafe partial class MyComWrappers : GeneratedComWrappersBase
                 {
+                    protected override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) {count = 0; return null;}
                 }
 
                 """;
@@ -602,8 +627,9 @@ namespace ComInterfaceGenerator.Unit.Tests
                 [GeneratedComInterface(typeof(MyComWrappers))]
                 partial interface IFoo { }
 
-                public partial class MyComWrappers : GeneratedComWrappersBase<ComObject>
+                public unsafe partial class MyComWrappers : GeneratedComWrappersBase
                 {
+                    protected override ComInterfaceEntry* ComputeVtables(object obj, CreateComInterfaceFlags flags, out int count) {count = 0; return null;}
                 }
 
                 """;
index 8ad0d29..dc683b4 100644 (file)
@@ -27,10 +27,7 @@ namespace ComInterfaceGenerator.Unit.Tests
             """;
 
         public const string INativeAPI_IUnmanagedInterfaceTypeMethodImpl = """
-                static int IUnmanagedInterfaceType<INativeAPI>.VirtualMethodTableLength => 1;
-                static unsafe void* IUnmanagedInterfaceType<INativeAPI>.VirtualMethodTableManagedImplementation => null;
-                static unsafe void* IUnmanagedInterfaceType<INativeAPI>.GetUnmanagedWrapperForObject(INativeAPI obj) => null;
-                static unsafe INativeAPI IUnmanagedInterfaceType<INativeAPI>.GetObjectForUnmanagedWrapper(void* ptr) => null;
+                static unsafe void* IUnmanagedInterfaceType.VirtualMethodTableManagedImplementation => null;
             """;
 
         public static abstract string NativeInterfaceUsage();
@@ -42,7 +39,8 @@ using System.Runtime.InteropServices.Marshalling;
 
 [assembly:DisableRuntimeMarshalling]
 
-partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+[UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+partial interface INativeAPI : IUnmanagedInterfaceType
 {{
     [VirtualMethodIndex(0, ImplicitThisParameter = {TProvider.ImplicitThisParameter.ToString().ToLowerInvariant()}, Direction = MarshalDirection.{TProvider.Direction})]
     {typeName} Method({typeName} value, in {typeName} inValue, ref {typeName} refValue, out {typeName} outValue);
@@ -55,7 +53,8 @@ using System.Runtime.InteropServices.Marshalling;
 
 [assembly:DisableRuntimeMarshalling]
 
-partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+[UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+partial interface INativeAPI : IUnmanagedInterfaceType
 {{
     [VirtualMethodIndex(0, ImplicitThisParameter = {TProvider.ImplicitThisParameter.ToString().ToLowerInvariant()}, Direction = MarshalDirection.{TProvider.Direction})]
     {typeName} Method({typeName} value, in {typeName} inValue, out {typeName} outValue);
@@ -67,7 +66,8 @@ using System.Runtime.InteropServices;
 using System.Runtime.InteropServices.Marshalling;
 {preDeclaration}
 
-partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+[UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+partial interface INativeAPI : IUnmanagedInterfaceType
 {{
     [VirtualMethodIndex(0, ImplicitThisParameter = {TProvider.ImplicitThisParameter.ToString().ToLowerInvariant()}, Direction = MarshalDirection.{TProvider.Direction})]
     void Method({typeName} value);
@@ -81,7 +81,8 @@ using System.Runtime.InteropServices.Marshalling;
 
 [assembly:DisableRuntimeMarshalling]
 
-partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+[UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+partial interface INativeAPI : IUnmanagedInterfaceType
 {{
     [VirtualMethodIndex(0, ImplicitThisParameter = {TProvider.ImplicitThisParameter.ToString().ToLowerInvariant()}, Direction = MarshalDirection.{TProvider.Direction})]
     void Method({modifier} {typeName} value);
@@ -92,7 +93,8 @@ using System.Runtime.InteropServices;
 using System.Runtime.InteropServices.Marshalling;
 {preDeclaration}
 
-partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+[UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+partial interface INativeAPI : IUnmanagedInterfaceType
 {{
     [VirtualMethodIndex(0, ImplicitThisParameter = {TProvider.ImplicitThisParameter.ToString().ToLowerInvariant()}, Direction = MarshalDirection.{TProvider.Direction})]
     {typeName} Method();
@@ -103,7 +105,8 @@ using System.Runtime.InteropServices;
 using System.Runtime.InteropServices.Marshalling;
 {preDeclaration}
 
-partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+[UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+partial interface INativeAPI : IUnmanagedInterfaceType
 {{
     [VirtualMethodIndex(0, ImplicitThisParameter = {TProvider.ImplicitThisParameter.ToString().ToLowerInvariant()}, Direction = MarshalDirection.{TProvider.Direction})]
     [return: MarshalUsing(typeof({marshallerTypeName}))]
@@ -119,7 +122,8 @@ using System.Runtime.InteropServices;
 using System.Runtime.InteropServices.Marshalling;
 [assembly:DisableRuntimeMarshalling]
 
-partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+[UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+partial interface INativeAPI : IUnmanagedInterfaceType
 {{
     [VirtualMethodIndex(0, ImplicitThisParameter = {TProvider.ImplicitThisParameter.ToString().ToLowerInvariant()}, Direction = MarshalDirection.{TProvider.Direction})]
     [return:MarshalUsing(ConstantElementCount=10)]
@@ -138,7 +142,8 @@ using System.Runtime.InteropServices.Marshalling;
 
 [assembly:DisableRuntimeMarshalling]
 
-partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+[UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+partial interface INativeAPI : IUnmanagedInterfaceType
 {{
     [VirtualMethodIndex(0, ImplicitThisParameter = {TProvider.ImplicitThisParameter.ToString().ToLowerInvariant()}, Direction = MarshalDirection.{TProvider.Direction})]
     [return:MarshalUsing(typeof({marshallerType}), ConstantElementCount=10)]
@@ -158,7 +163,8 @@ using System.Runtime.InteropServices.Marshalling;
 
 [assembly:DisableRuntimeMarshalling]
 
-partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+[UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+partial interface INativeAPI : IUnmanagedInterfaceType
 {{
     [VirtualMethodIndex(0, ImplicitThisParameter = {TProvider.ImplicitThisParameter.ToString().ToLowerInvariant()}, Direction = MarshalDirection.{TProvider.Direction})]
     int Method(
@@ -174,7 +180,8 @@ using System.Runtime.InteropServices.Marshalling;
 
 [assembly:DisableRuntimeMarshalling]
 
-partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+[UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+partial interface INativeAPI : IUnmanagedInterfaceType
 {{
     [VirtualMethodIndex(0, ImplicitThisParameter = {TProvider.ImplicitThisParameter.ToString().ToLowerInvariant()}, Direction = MarshalDirection.{TProvider.Direction})]
     int Method(
@@ -190,7 +197,8 @@ using System.Runtime.InteropServices.Marshalling;
 
 [assembly:DisableRuntimeMarshalling]
 
-partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+[UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+partial interface INativeAPI : IUnmanagedInterfaceType
 {{
     [VirtualMethodIndex(0, ImplicitThisParameter = {TProvider.ImplicitThisParameter.ToString().ToLowerInvariant()}, Direction = MarshalDirection.{TProvider.Direction})]
     [return:MarshalUsing(ConstantElementCount = 10)]
@@ -205,7 +213,8 @@ using System.Runtime.InteropServices.Marshalling;
 
 [assembly:DisableRuntimeMarshalling]
 
-partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+[UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+partial interface INativeAPI : IUnmanagedInterfaceType
 {{
     [VirtualMethodIndex(0, ImplicitThisParameter = {TProvider.ImplicitThisParameter.ToString().ToLowerInvariant()}, Direction = MarshalDirection.{TProvider.Direction})]
     [return:MarshalUsing(ConstantElementCount=10)]
index 6fa6406..fefc922 100644 (file)
@@ -23,7 +23,8 @@ namespace ComInterfaceGenerator.Unit.Tests
                 using System.Runtime.InteropServices;
                 using System.Runtime.InteropServices.Marshalling;
 
-                partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+                [UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+                partial interface INativeAPI : IUnmanagedInterfaceType
                 {
                     {{CodeSnippets.INativeAPI_IUnmanagedInterfaceTypeMethodImpl}}
                     [VirtualMethodIndex(0)]
@@ -49,7 +50,8 @@ namespace ComInterfaceGenerator.Unit.Tests
                 using System.Runtime.InteropServices;
                 using System.Runtime.InteropServices.Marshalling;
 
-                partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+                [UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+                partial interface INativeAPI : IUnmanagedInterfaceType
                 {
                     {{CodeSnippets.INativeAPI_IUnmanagedInterfaceTypeMethodImpl}}
                     [VirtualMethodIndex(0)]
@@ -75,7 +77,8 @@ namespace ComInterfaceGenerator.Unit.Tests
                 using System.Runtime.InteropServices;
                 using System.Runtime.InteropServices.Marshalling;
 
-                partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+                [UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+                partial interface INativeAPI : IUnmanagedInterfaceType
                 {
                     {{CodeSnippets.INativeAPI_IUnmanagedInterfaceTypeMethodImpl}}
                     [VirtualMethodIndex(0)]
@@ -106,7 +109,8 @@ namespace ComInterfaceGenerator.Unit.Tests
                 using System.Runtime.InteropServices;
                 using System.Runtime.InteropServices.Marshalling;
 
-                partial interface INativeAPI : IUnmanagedInterfaceType<INativeAPI>
+                [UnmanagedObjectUnwrapper<UnmanagedObjectUnwrapper.TestUnwrapper>]
+                partial interface INativeAPI : IUnmanagedInterfaceType
                 {
                     {{CodeSnippets.INativeAPI_IUnmanagedInterfaceTypeMethodImpl}}
                     [VirtualMethodIndex(0)]