diff --git a/src/Assimp/Silk.NET.Assimp/Assimp.cs b/src/Assimp/Silk.NET.Assimp/Assimp.cs
index 1a3163b0b2..da9673ac3c 100644
--- a/src/Assimp/Silk.NET.Assimp/Assimp.cs
+++ b/src/Assimp/Silk.NET.Assimp/Assimp.cs
@@ -1,4 +1,5 @@
using System;
+using System.Runtime.InteropServices;
using Silk.NET.Core.Contexts;
using Silk.NET.Core.Loader;
using Silk.NET.Core.Native;
@@ -7,6 +8,7 @@
namespace Silk.NET.Assimp
{
+ [NativeApi(Convention = CallingConvention.Winapi)]
public partial class Assimp
{
public static Assimp GetApi()
diff --git a/src/Core/Silk.NET.Core/Native/SilkMarshal.cs b/src/Core/Silk.NET.Core/Native/SilkMarshal.cs
index ef5c7a6007..c84d5d49ee 100644
--- a/src/Core/Silk.NET.Core/Native/SilkMarshal.cs
+++ b/src/Core/Silk.NET.Core/Native/SilkMarshal.cs
@@ -9,8 +9,6 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
-using System.Threading;
-using Silk.NET.Core.Loader;
namespace Silk.NET.Core.Native
{
@@ -19,6 +17,25 @@ namespace Silk.NET.Core.Native
///
public static class SilkMarshal
{
+ ///
+ /// Gets a value indicating whether is equivalent to
+ /// .
+ ///
+ ///
+ /// If false, can be generally assumed to be equivalent to
+ /// .
+ ///
+ public static readonly bool IsWinapiStdcall;
+
+ static SilkMarshal()
+ {
+#if NET5_0
+ IsWinapiStdcall = OperatingSystem.IsWindows();
+#else
+ IsWinapiStdcall = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
+#endif
+ }
+
///
/// Allocate a new BStr pointer.
///
diff --git a/src/Core/Silk.NET.SilkTouch/MarshalContext.cs b/src/Core/Silk.NET.SilkTouch/MarshalContext.cs
index b5798a40c8..e2b0017624 100644
--- a/src/Core/Silk.NET.SilkTouch/MarshalContext.cs
+++ b/src/Core/Silk.NET.SilkTouch/MarshalContext.cs
@@ -423,6 +423,7 @@ public void DeclareExtraRef(int id, int amount = 1)
public BlockSyntax BuildFinalBlock()
{
+
// add return
if (!ReturnsVoid)
{
diff --git a/src/Core/Silk.NET.SilkTouch/NativeApiGenerator.cs b/src/Core/Silk.NET.SilkTouch/NativeApiGenerator.cs
index 379de67bc3..8e6b7ec3df 100644
--- a/src/Core/Silk.NET.SilkTouch/NativeApiGenerator.cs
+++ b/src/Core/Silk.NET.SilkTouch/NativeApiGenerator.cs
@@ -392,40 +392,66 @@ private static void ProcessMethod
SyntaxList generationusings
)
{
- void BuildLoadInvoke(ref IMarshalContext ctx, Action next)
- {
- ctx.TransitionTo(SilkTouchStage.PreLoad);
-
- // this is terminal, we never call next
-
- var parameters = ctx.ResolveAllLoadParameters();
-
- var fPtrType = FunctionPointerType
+ const string invocationShimName = "StCall";
+ static FunctionPointerTypeSyntax GetFuncPtrType
+ (
+ CallingConvention callingConvention,
+ ITypeSymbol[] loadTypes
+ ) => FunctionPointerType
+ (
+ callingConvention == CallingConvention.Winapi ? FunctionPointerCallingConvention
+ (
+ Token(SyntaxKind.UnmanagedKeyword)
+ ) : FunctionPointerCallingConvention
(
- FunctionPointerCallingConvention
+ Token(SyntaxKind.UnmanagedKeyword),
+ FunctionPointerUnmanagedCallingConventionList
(
- Token(SyntaxKind.UnmanagedKeyword),
- FunctionPointerUnmanagedCallingConventionList
+ SingletonSeparatedList
(
- SingletonSeparatedList
- (
- FunctionPointerUnmanagedCallingConvention
- (Identifier(GetCallingConvention(callingConvention)))
- )
+ FunctionPointerUnmanagedCallingConvention
+ (Identifier(GetCallingConvention(callingConvention)))
)
- ),
- FunctionPointerParameterList
+ )
+ ),
+ FunctionPointerParameterList
+ (
+ SeparatedList
(
- SeparatedList
+ loadTypes.Select
(
- ctx.LoadTypes.Select
- (
- x => FunctionPointerParameter
- (IdentifierName(x.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)))
- )
+ x => FunctionPointerParameter
+ (IdentifierName(x.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)))
)
)
- );
+ )
+ );
+
+ static MemberAccessExpressionSyntax GetFuncPtrExpr
+ (
+ string generatedVTableName,
+ string entryPoint
+ ) => MemberAccessExpression
+ (
+ SyntaxKind.SimpleMemberAccessExpression,
+ ParenthesizedExpression
+ (
+ BinaryExpression
+ (
+ SyntaxKind.AsExpression, IdentifierName("CurrentVTable"),
+ IdentifierName(generatedVTableName)
+ )
+ ), IdentifierName(FirstLetterToUpper(entryPoint))
+ );
+
+ void BuildLoadInvoke(ref IMarshalContext ctx, Action next)
+ {
+ ctx.TransitionTo(SilkTouchStage.PreLoad);
+
+ // this is terminal, we never call next
+
+ var parameters = ctx.ResolveAllLoadParameters();
+
entryPoints.Add(entryPoint);
processedEntrypoints.Add
@@ -445,34 +471,45 @@ void BuildLoadInvoke(ref IMarshalContext ctx, Action next)
Func expression;
+ var defs = declaration.SyntaxTree.Options.PreprocessorSymbolNames;
+
+ // ReSharper disable PossibleMultipleEnumeration - just not an issue
+ var hasFastWinapi = defs.Contains("NET5_0") ||
+ defs.Contains("NET6_0") ||
+ defs.Contains("NET5_0_OR_GREATER"); // newer SDKs (circa .NET 6) have _OR_GREATER
+ // ReSharper restore PossibleMultipleEnumeration
+
+ var needsInvocationShim = callingConvention == CallingConvention.Winapi && !hasFastWinapi;
+
if ((classIsSealed || generateSeal) && generateVTable)
{
// build load + invocation
- expression = ctx => InvocationExpression
- (
- ParenthesizedExpression
+ expression = ctx =>
+ {
+ var fPtrType = GetFuncPtrType(callingConvention, ctx.LoadTypes);
+ return InvocationExpression
(
- CastExpression
+ needsInvocationShim ? IdentifierName(invocationShimName) : ParenthesizedExpression
(
- fPtrType, MemberAccessExpression
+ CastExpression
(
- SyntaxKind.SimpleMemberAccessExpression,
- ParenthesizedExpression
- (
- BinaryExpression
- (
- SyntaxKind.AsExpression, IdentifierName("CurrentVTable"), IdentifierName(generatedVTableName)
- )
- ), IdentifierName(FirstLetterToUpper(entryPoint))
+ fPtrType,
+ GetFuncPtrExpr(generatedVTableName, entryPoint)
)
- )
- ), ArgumentList(SeparatedList(parameters.Select(x => Argument(x.Value))))
- );
+ ), ArgumentList(SeparatedList(parameters.Select(x => Argument(x.Value))))
+ );
+ };
}
else
{
throw new Exception("FORCE-USE-VTABLE");
}
+
+
+ if (needsInvocationShim)
+ {
+ ctx.AddSideEffect(ManualWinapiInvokeShim);
+ }
if (ctx.ReturnsVoid)
{
@@ -512,8 +549,7 @@ void BuildLoadInvoke(ref IMarshalContext ctx, Action next)
block = Block(UnsafeStatement(Token(SyntaxKind.UnsafeKeyword), block));
}
- var method = declaration.WithBody
- (block)
+ var method = declaration.WithBody(block)
.WithAttributeLists(default)
.WithSemicolonToken(default)
.WithParameterList
@@ -572,6 +608,109 @@ void BuildLoadInvoke(ref IMarshalContext ctx, Action next)
sourceContext.ReportDiagnostic
(Diagnostic.Create(Diagnostics.MethodClassFailure, declaration.GetLocation(), ex.ToString()));
}
+
+ InvocationExpressionSyntax ManualWinapiInvokeInnerExpr
+ (
+ IMarshalContext ctx,
+ CallingConvention callingConvention
+ ) => InvocationExpression
+ (
+ ParenthesizedExpression
+ (
+ CastExpression
+ (
+ GetFuncPtrType(callingConvention, ctx.LoadTypes),
+ GetFuncPtrExpr(generatedVTableName, entryPoint)
+ )
+ ),
+ ArgumentList
+ (
+ SeparatedList
+ (
+ Enumerable.Range
+ (0, ctx.LoadTypes.Length - 1)
+ .Select(x => Argument(IdentifierName($"arg{x}")))
+ )
+ )
+ );
+
+ StatementSyntax ManualWinapiInvokeShim(IMarshalContext ctx)
+ {
+ var stdCallStmt = ManualWinapiInvokeInnerExpr(ctx, CallingConvention.StdCall);
+ var cdeclStmt = ManualWinapiInvokeInnerExpr(ctx, CallingConvention.Cdecl);
+ return LocalFunctionStatement
+ (
+ IdentifierName(ctx.ReturnLoadType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)),
+ invocationShimName
+ )
+ .WithParameterList
+ (
+ ParameterList
+ (
+ SeparatedList
+ (
+ new ArraySegment(ctx.LoadTypes, 0, ctx.LoadTypes.Length - 1).Select
+ (
+ (x, i) => Parameter(Identifier($"arg{i}"))
+ .WithType
+ (
+ IdentifierName(x.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat))
+ )
+ )
+ )
+ )
+ )
+ .WithBody
+ (
+ Block
+ (
+ IfStatement
+ (
+ MemberAccessExpression
+ (
+ SyntaxKind.SimpleMemberAccessExpression,
+ MemberAccessExpression
+ (
+ SyntaxKind.SimpleMemberAccessExpression,
+ MemberAccessExpression
+ (
+ SyntaxKind.SimpleMemberAccessExpression,
+ MemberAccessExpression
+ (
+ SyntaxKind.SimpleMemberAccessExpression,
+ MemberAccessExpression
+ (
+ SyntaxKind.SimpleMemberAccessExpression, IdentifierName("Silk"),
+ IdentifierName("NET")
+ ), IdentifierName("Core")
+ ), IdentifierName("Native")
+ ), IdentifierName("SilkMarshal")
+ ), IdentifierName("IsWinapiStdcall")
+ ),
+ Block
+ (
+ ctx.ReturnsVoid
+ ? ExpressionStatement(stdCallStmt)
+ .WithSemicolonToken(Token(SyntaxKind.SemicolonToken))
+ : ReturnStatement(stdCallStmt)
+ .WithSemicolonToken(Token(SyntaxKind.SemicolonToken))
+ ),
+ ElseClause
+ (
+ Block
+ (
+ ctx.ReturnsVoid
+ ? ExpressionStatement(cdeclStmt)
+ .WithSemicolonToken(Token(SyntaxKind.SemicolonToken))
+ : ReturnStatement(cdeclStmt)
+ .WithSemicolonToken(Token(SyntaxKind.SemicolonToken))
+ )
+ )
+ )
+ )
+ )
+ .WithSemicolonToken(Token(SyntaxKind.SemicolonToken));
+ }
}
private static string GetCallingConvention(CallingConvention convention)