@@ -82,6 +82,7 @@ public class Generator : IDisposable
8282    private  const  string  OriginalDelegateAnnotation  =  "OriginalDelegate" ; 
8383
8484    private  static readonly  Dictionary < string ,  MethodDeclarationSyntax >  PInvokeHelperMethods ; 
85+     private  static readonly  Dictionary < string ,  MethodDeclarationSyntax >  PInvokeMacros ; 
8586
8687    private  static readonly  string  AutoGeneratedHeader  =  @"// ------------------------------------------------------------------------------ 
8788// <auto-generated> 
@@ -98,6 +99,12 @@ public class Generator : IDisposable
9899/// <content> 
99100/// Contains extern methods from ""{0}"". 
100101/// </content> 
102+ " . Replace ( "\r \n " ,  "\n " ) ; 
103+ 
104+     private  static readonly  string  PartialPInvokeMacrosContentComment  =  @" 
105+ /// <content> 
106+ /// Contains macros. 
107+ /// </content> 
101108" . Replace ( "\r \n " ,  "\n " ) ; 
102109
103110    private  static readonly  SyntaxTriviaList  InlineArrayUnsafeAsSpanComment  =  ParseLeadingTrivia ( @"/// <summary> 
@@ -348,6 +355,7 @@ public class Generator : IDisposable
348355    private  readonly  IdentifierNameSyntax  methodsAndConstantsClassName ; 
349356    private  readonly  HashSet < string >  injectedPInvokeHelperMethods  =  new ( ) ; 
350357    private  readonly  HashSet < string >  injectedPInvokeHelperMethodsToFriendlyOverloadsExtensions  =  new ( ) ; 
358+     private  readonly  HashSet < string >  injectedPInvokeMacros  =  new ( ) ; 
351359    private  readonly  Dictionary < TypeDefinitionHandle ,  bool >  managedTypesCheck  =  new ( ) ; 
352360    private  bool  needsWinRTCustomMarshaler ; 
353361
@@ -359,6 +367,13 @@ static Generator()
359367        } 
360368
361369        PInvokeHelperMethods  =  ( ( ClassDeclarationSyntax ) member ) . Members . OfType < MethodDeclarationSyntax > ( ) . ToDictionary ( m =>  m . Identifier . ValueText ,  m =>  m ) ; 
370+ 
371+         if  ( ! TryFetchTemplate ( "PInvokeClassMacros" ,  null ,  out  member ) ) 
372+         { 
373+             throw  new  GenerationFailedException ( "Missing embedded resource." ) ; 
374+         } 
375+ 
376+         PInvokeMacros  =  ( ( ClassDeclarationSyntax ) member ) . Members . OfType < MethodDeclarationSyntax > ( ) . ToDictionary ( m =>  m . Identifier . ValueText ,  m =>  m ) ; 
362377    } 
363378
364379    /// <summary> 
@@ -477,34 +492,35 @@ private IEnumerable<MemberDeclarationSyntax> NamespaceMembers
477492        { 
478493            IEnumerable < IGrouping < string ,  MemberDeclarationSyntax > >  members  =  this . committedCode . MembersByModule ; 
479494            IEnumerable < MemberDeclarationSyntax >  result  =  Enumerable . Empty < MemberDeclarationSyntax > ( ) ; 
480-             for  ( int  i  =  0 ;  i  <  members . Count ( ) ;  i ++ ) 
495+             int  i  =  0 ; 
496+             foreach  ( IGrouping < string ,  MemberDeclarationSyntax >  entry  in  members ) 
481497            { 
482-                 IGrouping < string ,  MemberDeclarationSyntax >  entry  =  members . ElementAt ( i ) ; 
483-                 if  ( i  ==  0 ) 
498+                 ClassDeclarationSyntax  partialClass  =  DeclarePInvokeClass ( entry . Key ) 
499+                     . AddMembers ( entry . ToArray ( ) ) 
500+                     . WithLeadingTrivia ( ParseLeadingTrivia ( string . Format ( CultureInfo . InvariantCulture ,  PartialPInvokeContentComment ,  entry . Key ) ) ) ; 
501+                 if  ( i ++  ==  0 ) 
484502                { 
485-                     result  =  result . Concat ( new  MemberDeclarationSyntax [ ] 
486-                     { 
487-                         ClassDeclaration ( Identifier ( this . options . ClassName ) ) 
488-                         . AddModifiers ( TokenWithSpace ( this . Visibility ) ,  TokenWithSpace ( SyntaxKind . StaticKeyword ) ,  TokenWithSpace ( SyntaxKind . PartialKeyword ) ) 
489-                         . AddMembers ( entry . ToArray ( ) ) 
503+                     partialClass  =  partialClass 
504+                         . WithoutLeadingTrivia ( ) 
490505                        . AddAttributeLists ( AttributeList ( ) . AddAttributes ( GeneratedCodeAttribute ) ) 
491-                         . WithLeadingTrivia ( ParseLeadingTrivia ( string . Format ( CultureInfo . InvariantCulture ,  PartialPInvokeContentComment ,  entry . Key ) ) ) 
492-                         . WithAdditionalAnnotations ( new  SyntaxAnnotation ( SimpleFileNameAnnotation ,  $ "{ this . options . ClassName } .{ entry . Key } ") ) , 
493-                     } ) ; 
494-                 } 
495-                 else 
496-                 { 
497-                     result  =  result . Concat ( new  MemberDeclarationSyntax [ ] 
498-                     { 
499-                         ClassDeclaration ( Identifier ( this . options . ClassName ) ) 
500-                         . AddModifiers ( TokenWithSpace ( this . Visibility ) ,  TokenWithSpace ( SyntaxKind . StaticKeyword ) ,  TokenWithSpace ( SyntaxKind . PartialKeyword ) ) 
501-                         . AddMembers ( entry . ToArray ( ) ) 
502-                         . WithLeadingTrivia ( ParseLeadingTrivia ( string . Format ( CultureInfo . InvariantCulture ,  PartialPInvokeContentComment ,  entry . Key ) ) ) 
503-                         . WithAdditionalAnnotations ( new  SyntaxAnnotation ( SimpleFileNameAnnotation ,  $ "{ this . options . ClassName } .{ entry . Key } ") ) , 
504-                     } ) ; 
506+                         . WithLeadingTrivia ( partialClass . GetLeadingTrivia ( ) ) ; 
505507                } 
508+ 
509+                 result  =  result . Concat ( new  MemberDeclarationSyntax [ ]  {  partialClass  } ) ; 
506510            } 
507511
512+             ClassDeclarationSyntax  macrosPartialClass  =  DeclarePInvokeClass ( "Macros" ) 
513+                 . AddMembers ( this . committedCode . Macros . ToArray ( ) ) 
514+                 . WithLeadingTrivia ( ParseLeadingTrivia ( PartialPInvokeMacrosContentComment ) ) ; 
515+             if  ( macrosPartialClass . Members . Count  >  0 ) 
516+             { 
517+                 result  =  result . Concat ( new  MemberDeclarationSyntax [ ]  {  macrosPartialClass  } ) ; 
518+             } 
519+ 
520+             ClassDeclarationSyntax  DeclarePInvokeClass ( string  fileNameKey )  =>  ClassDeclaration ( Identifier ( this . options . ClassName ) ) 
521+                 . AddModifiers ( TokenWithSpace ( this . Visibility ) ,  TokenWithSpace ( SyntaxKind . StaticKeyword ) ,  TokenWithSpace ( SyntaxKind . PartialKeyword ) ) 
522+                 . WithAdditionalAnnotations ( new  SyntaxAnnotation ( SimpleFileNameAnnotation ,  $ "{ this . options . ClassName } .{ fileNameKey } ") ) ; 
523+ 
508524            result  =  result . Concat ( this . committedCode . GeneratedTypes ) ; 
509525
510526            ClassDeclarationSyntax  inlineArrayIndexerExtensionsClass  =  this . DeclareInlineArrayIndexerExtensionsClass ( ) ; 
@@ -574,6 +590,8 @@ public void GenerateAll(CancellationToken cancellationToken)
574590        this . RequestAllInteropTypes ( cancellationToken ) ; 
575591
576592        this . GenerateAllConstants ( cancellationToken ) ; 
593+ 
594+         this . GenerateAllMacros ( cancellationToken ) ; 
577595    } 
578596
579597    /// <inheritdoc cref="TryGenerate(string, out IReadOnlyList{string}, CancellationToken)"/> 
@@ -645,6 +663,12 @@ public bool TryGenerate(string apiNameOrModuleWildcard, out IReadOnlyList<string
645663                return  result ; 
646664            } 
647665
666+             result  =  this . TryGenerateMacro ( apiNameOrModuleWildcard ,  out  preciseApi ) ; 
667+             if  ( result  ||  preciseApi . Count  >  1 ) 
668+             { 
669+                 return  result ; 
670+             } 
671+ 
648672            return  false ; 
649673        } 
650674    } 
@@ -767,6 +791,30 @@ public void GenerateAllConstants(CancellationToken cancellationToken)
767791        } 
768792    } 
769793
794+     /// <summary> 
795+     /// Generates a projection of all macros. 
796+     /// </summary> 
797+     /// <param name="cancellationToken">A cancellation token.</param> 
798+     public  void  GenerateAllMacros ( CancellationToken  cancellationToken ) 
799+     { 
800+         foreach  ( KeyValuePair < string ,  MethodDeclarationSyntax >  macro  in  PInvokeMacros ) 
801+         { 
802+             cancellationToken . ThrowIfCancellationRequested ( ) ; 
803+ 
804+             try 
805+             { 
806+                 this . volatileCode . GenerationTransaction ( delegate 
807+                 { 
808+                     this . RequestMacro ( macro . Value ) ; 
809+                 } ) ; 
810+             } 
811+             catch  ( GenerationFailedException  ex )  when  ( IsPlatformCompatibleException ( ex ) ) 
812+             { 
813+                 // Something transitively required for this field is not available for this platform, so skip this method. 
814+             } 
815+         } 
816+     } 
817+ 
770818    /// <summary> 
771819    /// Generates all extern methods exported from a particular module, along with all their supporting types. 
772820    /// </summary> 
@@ -1038,6 +1086,34 @@ public bool TryGenerateConstant(string possiblyQualifiedName, out IReadOnlyList<
10381086        return  false ; 
10391087    } 
10401088
1089+     /// <summary> 
1090+     /// Generate code for the named macro, if it is recognized. 
1091+     /// </summary> 
1092+     /// <param name="macroName">The name of the macro. Never qualified with a namespace.</param> 
1093+     /// <param name="preciseApi">Receives the canonical API names that <paramref name="macroName"/> matched on.</param> 
1094+     /// <returns><see langword="true"/> if a match was found and the macro generated; otherwise <see langword="false"/>.</returns> 
1095+     public  bool  TryGenerateMacro ( string  macroName ,  out  IReadOnlyList < string >  preciseApi ) 
1096+     { 
1097+         if  ( macroName  is  null ) 
1098+         { 
1099+             throw  new  ArgumentNullException ( nameof ( macroName ) ) ; 
1100+         } 
1101+ 
1102+         if  ( ! PInvokeMacros . TryGetValue ( macroName ,  out  MethodDeclarationSyntax  macro ) ) 
1103+         { 
1104+             preciseApi  =  Array . Empty < string > ( ) ; 
1105+             return  false ; 
1106+         } 
1107+ 
1108+         this . volatileCode . GenerationTransaction ( delegate 
1109+         { 
1110+             this . RequestMacro ( macro ) ; 
1111+         } ) ; 
1112+ 
1113+         preciseApi  =  ImmutableList . Create ( macroName ) ; 
1114+         return  true ; 
1115+     } 
1116+ 
10411117    /// <summary> 
10421118    /// Produces a sequence of suggested APIs with a similar name to the specified one. 
10431119    /// </summary> 
@@ -1525,6 +1601,24 @@ internal void RequestConstant(FieldDefinitionHandle fieldDefHandle)
15251601        } ) ; 
15261602    } 
15271603
1604+     internal  void  RequestMacro ( MethodDeclarationSyntax  macro ) 
1605+     { 
1606+         this . volatileCode . GenerateMacro ( macro . Identifier . ValueText ,  delegate 
1607+         { 
1608+             this . volatileCode . AddMacro ( macro . Identifier . ValueText ,  ( MethodDeclarationSyntax ) this . ElevateVisibility ( macro ) ) ; 
1609+ 
1610+             // Generate any additional types that this macro relies on. 
1611+             foreach  ( QualifiedNameSyntax  identifier  in  macro . DescendantNodes ( ) . OfType < QualifiedNameSyntax > ( ) ) 
1612+             { 
1613+                 string  identifierString  =  identifier . ToString ( ) ; 
1614+                 if  ( identifierString . StartsWith ( GlobalNamespacePrefix ,  StringComparison . Ordinal ) ) 
1615+                 { 
1616+                     this . TryGenerateType ( identifierString . Substring ( GlobalNamespacePrefix . Length ) ) ; 
1617+                 } 
1618+             } 
1619+         } ) ; 
1620+     } 
1621+ 
15281622    internal  TypeSyntax ?  RequestSafeHandle ( string  releaseMethod ) 
15291623    { 
15301624        if  ( ! this . options . UseSafeHandles ) 
@@ -5901,6 +5995,8 @@ private class GeneratedCode
59015995
59025996        private  readonly  Dictionary < string ,  ( MemberDeclarationSyntax  Type ,  bool  TopLevel ) >  specialTypes  =  new ( StringComparer . Ordinal ) ; 
59035997
5998+         private  readonly  Dictionary < string ,  MethodDeclarationSyntax >  macros  =  new ( StringComparer . Ordinal ) ; 
5999+ 
59046000        /// <summary> 
59056001        /// The set of types that are or have been generated so we don't stack overflow for self-referencing types. 
59066002        /// </summary> 
@@ -5934,7 +6030,7 @@ internal GeneratedCode(GeneratedCode parent)
59346030        } 
59356031
59366032        internal  bool  IsEmpty  =>  this . modulesAndMembers . Count  ==  0  &&  this . types . Count  ==  0  &&  this . fieldsToSyntax . Count  ==  0  &&  this . safeHandleTypes . Count  ==  0  &&  this . specialTypes . Count  ==  0 
5937-             &&  this . inlineArrayIndexerExtensionsMembers . Count  ==  0  &&  this . comInterfaceFriendlyExtensionsMembers . Count  ==  0 ; 
6033+             &&  this . inlineArrayIndexerExtensionsMembers . Count  ==  0  &&  this . comInterfaceFriendlyExtensionsMembers . Count  ==  0   &&   this . macros . Count   ==   0 ; 
59386034
59396035        internal  IEnumerable < MemberDeclarationSyntax >  GeneratedTypes  =>  this . GetTypesWithInjectedFields ( ) 
59406036            . Concat ( this . specialTypes . Values . Where ( st =>  ! st . TopLevel ) . Select ( st =>  st . Type ) ) 
@@ -5961,6 +6057,8 @@ internal IEnumerable<IGrouping<string, MemberDeclarationSyntax>> MembersByModule
59616057            } 
59626058        } 
59636059
6060+         internal  IEnumerable < MethodDeclarationSyntax >  Macros  =>  this . macros . Values ; 
6061+ 
59646062        internal  void  AddSafeHandleType ( ClassDeclarationSyntax  safeHandleDeclaration ) 
59656063        { 
59666064            this . ThrowIfNotGenerating ( ) ; 
@@ -5998,6 +6096,12 @@ internal void AddConstant(FieldDefinitionHandle fieldDefHandle, FieldDeclaration
59986096            this . fieldsToSyntax . Add ( fieldDefHandle ,  ( constantDeclaration ,  fieldType ) ) ; 
59996097        } 
60006098
6099+         internal  void  AddMacro ( string  macroName ,  MethodDeclarationSyntax  macro ) 
6100+         { 
6101+             this . ThrowIfNotGenerating ( ) ; 
6102+             this . macros . Add ( macroName ,  macro ) ; 
6103+         } 
6104+ 
60016105        internal  void  AddInlineArrayIndexerExtension ( MethodDeclarationSyntax  inlineIndexer ) 
60026106        { 
60036107            this . ThrowIfNotGenerating ( ) ; 
@@ -6161,6 +6265,18 @@ internal void GenerateConstant(FieldDefinitionHandle fieldDefinitionHandle, Acti
61616265            generator ( ) ; 
61626266        } 
61636267
6268+         internal  void  GenerateMacro ( string  macroName ,  Action  generator ) 
6269+         { 
6270+             this . ThrowIfNotGenerating ( ) ; 
6271+ 
6272+             if  ( this . macros . ContainsKey ( macroName )  ||  this . parent ? . macros . ContainsKey ( macroName )  is  true ) 
6273+             { 
6274+                 return ; 
6275+             } 
6276+ 
6277+             generator ( ) ; 
6278+         } 
6279+ 
61646280        internal  bool  TryGetSafeHandleForReleaseMethod ( string  releaseMethod ,  out  TypeSyntax ?  safeHandleType ) 
61656281        { 
61666282            return  this . releaseMethodsWithSafeHandleTypesGenerating . TryGetValue ( releaseMethod ,  out  safeHandleType ) 
@@ -6219,6 +6335,7 @@ private void Commit(GeneratedCode? parent)
62196335            Commit ( this . safeHandleTypes ,  parent ? . safeHandleTypes ) ; 
62206336            Commit ( this . specialTypes ,  parent ? . specialTypes ) ; 
62216337            Commit ( this . typesGenerating ,  parent ? . typesGenerating ) ; 
6338+             Commit ( this . macros ,  parent ? . macros ) ; 
62226339            Commit ( this . methodsGenerating ,  parent ? . methodsGenerating ) ; 
62236340            Commit ( this . specialTypesGenerating ,  parent ? . specialTypesGenerating ) ; 
62246341            Commit ( this . releaseMethodsWithSafeHandleTypesGenerating ,  parent ? . releaseMethodsWithSafeHandleTypesGenerating ) ; 
0 commit comments