11using System ;
22using System . Collections . Generic ;
3+ using System . Diagnostics ;
4+ using System . Linq ;
35using System . Runtime . InteropServices ;
46using System . Text ;
57
@@ -133,6 +135,44 @@ private string GetSourceText(CallingConvention callingConvention, string? classS
133135 GetFromFunctionPointerConstructor ( classSuffix ) :
134136 GetFromDelegateConstructor ( classSuffix ) ;
135137 var interfaceFullName = Method . ContainingInterface . FullName ;
138+ string ? baseInterfaceFullName ;
139+ string ? unmanagedProperties ;
140+ if ( Method . ContainingInterface . IsUnmanaged )
141+ {
142+ var typeArguments = Method . ContainingInterface . TypeArguments ;
143+ var baseTypeArguments = typeArguments . Take ( typeArguments . Count / 2 ) ;
144+ var baseTypeArgumentList = $ "<{ string . Join ( ", " , baseTypeArguments ) } >";
145+ baseInterfaceFullName =
146+ $ "{ Method . ContainingInterface . Name . Replace ( "Unmanaged" , "Native" ) } { baseTypeArgumentList } ";
147+ var unmanagedTypeArgumentList = Method . ContainingInterface . UnmanagedTypeArgumentList ;
148+ unmanagedProperties =
149+ $@ "
150+
151+ #if UNSAFE
152+ public unsafe delegate* unmanaged[Cdecl]{ unmanagedTypeArgumentList } AsCdeclPtr
153+ {{
154+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
155+ get => { GetPointerSourceText ( callingConvention , CallingConvention . Cdecl , unmanagedTypeArgumentList ) } ;
156+ }}
157+
158+ public unsafe delegate* unmanaged[Stdcall]{ unmanagedTypeArgumentList } AsStdCallPtr
159+ {{
160+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
161+ get => { GetPointerSourceText ( callingConvention , CallingConvention . StdCall , unmanagedTypeArgumentList ) } ;
162+ }}
163+
164+ public unsafe delegate* unmanaged[Thiscall]{ unmanagedTypeArgumentList } AsThisCallPtr
165+ {{
166+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
167+ get => { GetPointerSourceText ( callingConvention , CallingConvention . ThisCall , unmanagedTypeArgumentList ) } ;
168+ }}
169+ #endif // UNSAFE" ;
170+ }
171+ else
172+ {
173+ baseInterfaceFullName = interfaceFullName ;
174+ unmanagedProperties = string . Empty ;
175+ }
136176 var invokeParameterCount = Method . ContainingInterface . InvokeParameterCount ;
137177 var invokeParameters = GetInvokeParameters ( ) ;
138178 var returnMarshalAsAttribute = MarshalInfo . MarshalReturnAs is not null ?
@@ -154,7 +194,7 @@ private string GetSourceText(CallingConvention callingConvention, string? classS
154194 private readonly nint functionPtr;
155195
156196 [UnmanagedFunctionPointer(CallingConvention.{ callingConvention } )]
157- { returnMarshalAsAttribute } public delegate { returnType } Handler{ invokeParameters } ;
197+ { returnMarshalAsAttribute } public delegate { returnType } Handler{ invokeParameters } ;{ unmanagedProperties }
158198
159199 { constructor }
160200
@@ -167,10 +207,48 @@ private string GetSourceText(CallingConvention callingConvention, string? classS
167207 { returnKeyword } handler({ Constants . Arguments [ invokeParameterCount ] } );
168208 }}
169209
170- object { interfaceFullName } .Target => handler.Target;
171- MethodInfo { interfaceFullName } .Method => handler.Method;{ interceptor }
210+ object { baseInterfaceFullName } .Target => handler.Target;
211+ MethodInfo { baseInterfaceFullName } .Method => handler.Method;{ interceptor }
172212 }}
173213 " ;
174214 }
215+
216+ private static string GetPointerSourceText
217+ (
218+ CallingConvention actual ,
219+ CallingConvention expected ,
220+ string typeArgumentList
221+ )
222+ {
223+ if ( actual == CallingConvention . Winapi )
224+ {
225+ return expected switch
226+ {
227+ CallingConvention . Cdecl =>
228+ $ "NativeGenericDelegates.PlatformDefaultCallingConvention == CallingConvention.Cdecl ?" +
229+ Constants . NewLineIndent4 +
230+ GetPointerSourceText ( CallingConvention . Cdecl , expected , typeArgumentList ) +
231+ $ " : { Constants . NewLineIndent4 } null",
232+ CallingConvention . StdCall =>
233+ $ "NativeGenericDelegates.PlatformDefaultCallingConvention == CallingConvention.StdCall ?" +
234+ Constants . NewLineIndent4 +
235+ GetPointerSourceText ( CallingConvention . StdCall , expected , typeArgumentList ) +
236+ $ " : { Constants . NewLineIndent4 } null",
237+ _ => "null" ,
238+ } ;
239+ }
240+ if ( actual != expected )
241+ {
242+ return "null" ;
243+ }
244+ var callingConvention = actual switch
245+ {
246+ CallingConvention . Cdecl => "Cdecl" ,
247+ CallingConvention . StdCall => "Stdcall" ,
248+ CallingConvention . ThisCall => "Thiscall" ,
249+ _ => throw new UnreachableException ( )
250+ } ;
251+ return $ "(delegate* unmanaged[{ callingConvention } ]{ typeArgumentList } )functionPtr";
252+ }
175253 }
176254}
0 commit comments