@@ -5,7 +5,7 @@ namespace Microsoft.Windows.CsWin32;
55
66public partial class Generator
77{
8- internal string RequestCustomEnumMarshaler ( string qualifiedEnumTypeName , UnmanagedType unmanagedType )
8+ internal string RequestCustomEnumMarshaller ( string qualifiedEnumTypeName , UnmanagedType unmanagedType )
99 {
1010 // Create type syntax for the unmanaged type (uint for U4)
1111 TypeSyntax unmanagedTypeSyntax = unmanagedType switch
@@ -22,12 +22,12 @@ internal string RequestCustomEnumMarshaler(string qualifiedEnumTypeName, Unmanag
2222 throw new InvalidOperationException ( $ "This generator doesn't share a prefix with this enum { qualifiedEnumTypeName } ") ;
2323 }
2424
25- // Custom marshalers should go in a InteropServices sub-namespace.
25+ // Custom marshallers should go in a InteropServices sub-namespace.
2626 shortNamespace += ".InteropServices" ;
2727
28- string customTypeMarshalerName = $ "{ enumTypeName } To{ unmanagedType } Marshaler ";
28+ string customTypeMarshallerName = $ "{ enumTypeName } To{ unmanagedType } Marshaller ";
2929
30- return this . volatileCode . GenerateCustomTypeMarshaler ( customTypeMarshalerName , delegate
30+ return this . volatileCode . GenerateCustomTypeMarshaller ( customTypeMarshallerName , delegate
3131 {
3232 // Create type syntax for the enum type
3333 TypeSyntax enumTypeSyntax = IdentifierName ( enumTypeName ) ;
@@ -57,7 +57,7 @@ internal string RequestCustomEnumMarshaler(string qualifiedEnumTypeName, Unmanag
5757 SyntaxKind . SimpleMemberAccessExpression ,
5858 ParseName ( "global::System.Runtime.InteropServices.Marshalling.MarshalMode" ) ,
5959 IdentifierName ( mode ) ) ) ,
60- AttributeArgument ( TypeOfExpression ( IdentifierName ( customTypeMarshalerName ) ) ) ) )
60+ AttributeArgument ( TypeOfExpression ( IdentifierName ( customTypeMarshallerName ) ) ) ) )
6161 . ToArray ( ) ;
6262
6363 // Create ConvertToManaged method
@@ -92,24 +92,78 @@ internal string RequestCustomEnumMarshaler(string qualifiedEnumTypeName, Unmanag
9292 . WithBody ( Block ( ) ) ; // Empty body
9393
9494 // Create the class declaration
95- ClassDeclarationSyntax marshalerClass = ClassDeclaration ( Identifier ( customTypeMarshalerName ) )
95+ ClassDeclarationSyntax marshallerClass = ClassDeclaration ( Identifier ( customTypeMarshallerName ) )
9696 . AddModifiers ( TokenWithSpace ( this . Visibility ) , TokenWithSpace ( SyntaxKind . StaticKeyword ) )
9797 . AddAttributeLists ( customMarshallerAttributes . Select ( attr => AttributeList ( ) . AddAttributes ( attr ) ) . ToArray ( ) )
9898 . AddMembers ( convertToManagedMethod , convertToUnmanagedMethod , freeMethod ) ;
9999
100- marshalerClass = marshalerClass . WithAdditionalAnnotations ( new SyntaxAnnotation ( NamespaceContainerAnnotation , shortNamespace ) ) ;
100+ marshallerClass = marshallerClass . WithAdditionalAnnotations ( new SyntaxAnnotation ( NamespaceContainerAnnotation , shortNamespace ) ) ;
101101
102- string qualifiedName = $ "global::{ this . Namespace } .{ shortNamespace } .{ customTypeMarshalerName } ";
102+ string qualifiedName = $ "global::{ this . Namespace } .{ shortNamespace } .{ customTypeMarshallerName } ";
103103
104- CustomMarshalerTypeRecord typeRecord = new ( marshalerClass , qualifiedName ) ;
104+ CustomMarshallerTypeRecord typeRecord = new ( marshallerClass , qualifiedName ) ;
105105
106- this . volatileCode . AddCustomTypeMarshaler ( customTypeMarshalerName , typeRecord ) ;
106+ this . volatileCode . AddCustomTypeMarshaller ( customTypeMarshallerName , typeRecord ) ;
107107
108108 return typeRecord ;
109109 } ) ;
110110 }
111111
112- internal string RequestCustomWinRTMarshaler ( string qualifiedWinRTTypeName )
112+ internal string RequestCustomTypeDefMarshaller ( string fullyQualifiedTypeName , TypeSyntax unmanagedTypeSyntax )
113+ {
114+ if ( ! TrySplitPossiblyQualifiedName ( fullyQualifiedTypeName , out string ? @namespace , out string typeDefName ) ||
115+ ! this . TryStripCommonNamespace ( @namespace , out string ? shortNamespace ) )
116+ {
117+ throw new InvalidOperationException ( $ "This generator doesn't share a prefix with this enum { fullyQualifiedTypeName } ") ;
118+ }
119+
120+ // Custom marshallers should go in a InteropServices sub-namespace.
121+ shortNamespace += ".InteropServices" ;
122+
123+ string customTypeMarshallerName = $ "{ typeDefName } Marshaller";
124+
125+ return this . volatileCode . GenerateCustomTypeMarshaller ( customTypeMarshallerName , delegate
126+ {
127+ // Type syntax for the typedef type (unqualified within its namespace container).
128+ TypeSyntax typedefTypeSyntax = ParseName ( fullyQualifiedTypeName ) ;
129+
130+ // Single CustomMarshaller attribute for MarshalMode.Default.
131+ AttributeSyntax attribute = Attribute ( ParseName ( "global::System.Runtime.InteropServices.Marshalling.CustomMarshaller" ) )
132+ . AddArgumentListArguments (
133+ AttributeArgument ( TypeOfExpression ( typedefTypeSyntax ) ) ,
134+ AttributeArgument ( MemberAccessExpression (
135+ SyntaxKind . SimpleMemberAccessExpression ,
136+ ParseName ( "global::System.Runtime.InteropServices.Marshalling.MarshalMode" ) ,
137+ IdentifierName ( "Default" ) ) ) ,
138+ AttributeArgument ( TypeOfExpression ( IdentifierName ( customTypeMarshallerName ) ) ) ) ;
139+
140+ // public static unsafe void* ConvertToUnmanaged(HWND managed) => managed.Value;
141+ MethodDeclarationSyntax toUnmanaged = MethodDeclaration ( unmanagedTypeSyntax , Identifier ( "ConvertToUnmanaged" ) )
142+ . AddModifiers ( TokenWithSpace ( SyntaxKind . PublicKeyword ) , TokenWithSpace ( SyntaxKind . StaticKeyword ) , TokenWithSpace ( SyntaxKind . UnsafeKeyword ) )
143+ . AddParameterListParameters ( Parameter ( Identifier ( "managed" ) ) . WithType ( typedefTypeSyntax . WithTrailingTrivia ( Space ) ) )
144+ . WithBody ( Block ( ReturnStatement ( MemberAccessExpression ( SyntaxKind . SimpleMemberAccessExpression , IdentifierName ( "managed" ) , IdentifierName ( "Value" ) ) ) ) ) ;
145+
146+ // public static unsafe HWND ConvertToManaged(void* unmanaged) => new(unmanaged);
147+ MethodDeclarationSyntax toManaged = MethodDeclaration ( typedefTypeSyntax , Identifier ( "ConvertToManaged" ) )
148+ . AddModifiers ( TokenWithSpace ( SyntaxKind . PublicKeyword ) , TokenWithSpace ( SyntaxKind . StaticKeyword ) , TokenWithSpace ( SyntaxKind . UnsafeKeyword ) )
149+ . AddParameterListParameters ( Parameter ( Identifier ( "unmanaged" ) ) . WithType ( unmanagedTypeSyntax . WithTrailingTrivia ( Space ) ) )
150+ . WithBody ( Block ( ReturnStatement ( ObjectCreationExpression ( typedefTypeSyntax )
151+ . WithArgumentList ( ArgumentList ( SingletonSeparatedList ( Argument ( IdentifierName ( "unmanaged" ) ) ) ) ) ) ) ) ;
152+
153+ ClassDeclarationSyntax marshallerClass = ClassDeclaration ( Identifier ( customTypeMarshallerName ) )
154+ . AddModifiers ( TokenWithSpace ( this . Visibility ) , TokenWithSpace ( SyntaxKind . StaticKeyword ) )
155+ . AddAttributeLists ( AttributeList ( ) . AddAttributes ( attribute ) )
156+ . AddMembers ( toUnmanaged , toManaged )
157+ . WithAdditionalAnnotations ( new SyntaxAnnotation ( NamespaceContainerAnnotation , shortNamespace ) ) ;
158+
159+ string qualifiedName = $ "global::{ this . Namespace } .{ shortNamespace } .{ customTypeMarshallerName } ";
160+ CustomMarshallerTypeRecord typeRecord = new ( marshallerClass , qualifiedName ) ;
161+ this . volatileCode . AddCustomTypeMarshaller ( customTypeMarshallerName , typeRecord ) ;
162+ return typeRecord ;
163+ } ) ;
164+ }
165+
166+ internal string RequestCustomWinRTMarshaller ( string qualifiedWinRTTypeName )
113167 {
114168 if ( ! TrySplitPossiblyQualifiedName ( qualifiedWinRTTypeName , out string ? @namespace , out string winrtTypeName ) )
115169 {
@@ -118,11 +172,11 @@ internal string RequestCustomWinRTMarshaler(string qualifiedWinRTTypeName)
118172 @namespace = string . Empty ;
119173 }
120174
121- string customTypeMarshalerName = $ "WinRTMarshaler { winrtTypeName } ";
175+ string customTypeMarshallerName = $ "WinRTMarshaller { winrtTypeName } ";
122176
123- string marshalerNamespace = "CsWin32.InteropServices" ;
177+ string marshallerNamespace = "CsWin32.InteropServices" ;
124178
125- return this . volatileCode . GenerateCustomTypeMarshaler ( customTypeMarshalerName , delegate
179+ return this . volatileCode . GenerateCustomTypeMarshaller ( customTypeMarshallerName , delegate
126180 {
127181 // Create type syntax for the WinRT type (using the qualified name)
128182 TypeSyntax winrtTypeSyntax = string . IsNullOrEmpty ( @namespace )
@@ -151,7 +205,7 @@ internal string RequestCustomWinRTMarshaler(string qualifiedWinRTTypeName)
151205 SyntaxKind . SimpleMemberAccessExpression ,
152206 ParseName ( "global::System.Runtime.InteropServices.Marshalling.MarshalMode" ) ,
153207 IdentifierName ( mode ) ) ) ,
154- AttributeArgument ( TypeOfExpression ( IdentifierName ( customTypeMarshalerName ) ) ) ) )
208+ AttributeArgument ( TypeOfExpression ( IdentifierName ( customTypeMarshallerName ) ) ) ) )
155209 . ToArray ( ) ;
156210
157211 // Create ConvertToManaged method
@@ -206,24 +260,24 @@ internal string RequestCustomWinRTMarshaler(string qualifiedWinRTTypeName)
206260 ArgumentList ( ) . AddArguments ( Argument ( IdentifierName ( "unmanaged" ) ) ) ) ) ) ) ;
207261
208262 // Create the class declaration
209- ClassDeclarationSyntax marshalerClass = ClassDeclaration ( Identifier ( customTypeMarshalerName ) )
263+ ClassDeclarationSyntax marshallerClass = ClassDeclaration ( Identifier ( customTypeMarshallerName ) )
210264 . AddModifiers ( TokenWithSpace ( this . Visibility ) , TokenWithSpace ( SyntaxKind . StaticKeyword ) )
211265 . AddAttributeLists ( customMarshallerAttributes . Select ( attr => AttributeList ( ) . AddAttributes ( attr ) ) . ToArray ( ) )
212266 . AddMembers ( convertToManagedMethod , convertToUnmanagedMethod , freeMethod ) ;
213267
214- marshalerClass = marshalerClass . WithAdditionalAnnotations ( new SyntaxAnnotation ( NamespaceContainerAnnotation , marshalerNamespace ) ) ;
268+ marshallerClass = marshallerClass . WithAdditionalAnnotations ( new SyntaxAnnotation ( NamespaceContainerAnnotation , marshallerNamespace ) ) ;
215269
216- string qualifiedName = $ "global::{ this . Namespace } .{ marshalerNamespace } .{ customTypeMarshalerName } ";
270+ string qualifiedName = $ "global::{ this . Namespace } .{ marshallerNamespace } .{ customTypeMarshallerName } ";
217271
218- CustomMarshalerTypeRecord typeRecord = new ( marshalerClass , qualifiedName ) ;
272+ CustomMarshallerTypeRecord typeRecord = new ( marshallerClass , qualifiedName ) ;
219273
220274 // For WinRT types, we generally don't need a specific namespace container annotation
221275 // since they're typically in the global namespace context
222- this . volatileCode . AddCustomTypeMarshaler ( customTypeMarshalerName , typeRecord ) ;
276+ this . volatileCode . AddCustomTypeMarshaller ( customTypeMarshallerName , typeRecord ) ;
223277
224278 return typeRecord ;
225279 } ) ;
226280 }
227281
228- private record CustomMarshalerTypeRecord ( ClassDeclarationSyntax ClassDeclaration , string QualifiedName ) ;
282+ private record CustomMarshallerTypeRecord ( ClassDeclarationSyntax ClassDeclaration , string QualifiedName ) ;
229283}
0 commit comments