From 958536ed0fef2c45b3bb349e166c93cde0ef9977 Mon Sep 17 00:00:00 2001 From: Kevin Ring Date: Tue, 28 Jan 2025 15:45:05 +1100 Subject: [PATCH] Exception handling for fields, too. And handle the possibility that the NativeImplementation property is called on an invalid object (it will now return nullptr). --- Reinterop~/Fields.cs | 28 ++++++++++++++++++--- Reinterop~/Interop.cs | 35 +++++++++++++++++++++++---- Reinterop~/MethodsImplementedInCpp.cs | 5 +++- 3 files changed, 59 insertions(+), 9 deletions(-) diff --git a/Reinterop~/Fields.cs b/Reinterop~/Fields.cs index 71518291..4e474b64 100644 --- a/Reinterop~/Fields.cs +++ b/Reinterop~/Fields.cs @@ -90,6 +90,10 @@ private static void GenerateSingleFieldAccessors(CppGenerationContext context, T bool hasStructRewrite = Interop.RewriteStructReturn(ref getParameters, ref getType, ref getInteropType); + // Add a parameter in which to return the exception, if there is one. + getParameters = getParameters.Concat(new[] { (ParameterName: "reinteropException", CallSiteName: "&reinteropException", Type: CppType.VoidPointerPointer, InteropType: CppType.VoidPointerPointer) }); + interopSetParameters = interopSetParameters + ", void** reinteropException"; + var interopGetParameters = getParameters.Select(parameter => $"{parameter.InteropType.GetFullyQualifiedName()} {parameter.ParameterName}"); var interopGetParametersCall = getParameters.Select(parameter => parameter.Type.GetConversionToInteropType(context, parameter.CallSiteName)); @@ -145,7 +149,11 @@ private static void GenerateSingleFieldAccessors(CppGenerationContext context, T string[] invocation = new[] { + $"void* reinteropException = nullptr;", $"auto result = Field_get_{field.Name}({string.Join(", ", interopGetParametersCall)});", + $"if (reinteropException != nullptr) {{", + $" throw Reinterop::ReinteropNativeException(::DotNet::System::Exception(::DotNet::Reinterop::ObjectHandle(reinteropException)));", + $"}}", $"return {getType.GetConversionFromInteropType(context, "result")};" }; if (hasStructRewrite) @@ -154,8 +162,12 @@ private static void GenerateSingleFieldAccessors(CppGenerationContext context, T { invocation = new[] { + $"void* reinteropException = nullptr;", $"{getType.GenericArguments.FirstOrDefault().GetFullyQualifiedName()} result;", $"std::uint8_t resultIsValid = Field_get_{field.Name}({string.Join(", ", interopGetParametersCall)});", + $"if (reinteropException != nullptr) {{", + $" throw Reinterop::ReinteropNativeException(::DotNet::System::Exception(::DotNet::Reinterop::ObjectHandle(reinteropException)));", + $"}}", $"return resultIsValid ? std::make_optional(std::move({getType.GetConversionFromInteropType(context, "result")})) : std::nullopt;" }; } @@ -163,8 +175,12 @@ private static void GenerateSingleFieldAccessors(CppGenerationContext context, T { invocation = new[] { + $"void* reinteropException = nullptr;", $"{getType.GetFullyQualifiedName()} result;", $"Field_get_{field.Name}({string.Join(", ", interopGetParametersCall)});", + $"if (reinteropException != nullptr) {{", + $" throw Reinterop::ReinteropNativeException(::DotNet::System::Exception(::DotNet::Reinterop::ObjectHandle(reinteropException)));", + $"}}", $"return {getType.GetConversionFromInteropType(context, "result")};" }; } @@ -181,7 +197,8 @@ private static void GenerateSingleFieldAccessors(CppGenerationContext context, T { definition.Type, getType, - CppObjectHandle.GetCppType(context) + CppObjectHandle.GetCppType(context), + CppReinteropException.GetCppType(context) } )); @@ -189,14 +206,19 @@ private static void GenerateSingleFieldAccessors(CppGenerationContext context, T Content: $$""" void {{definition.Type.Name}}::{{field.Name}}({{setType.GetFullyQualifiedName()}} value){{(field.IsStatic ? "" : " const")}} { - Field_set_{{field.Name}}({{interopSetParametersCall}}); + void* reinteropException = nullptr; + Field_set_{{field.Name}}({{interopSetParametersCall}}, &reinteropException); + if (reinteropException != nullptr) { + throw Reinterop::ReinteropNativeException(::DotNet::System::Exception(::DotNet::Reinterop::ObjectHandle(reinteropException))); + } } """, TypeDefinitionsReferenced: new[] { definition.Type, setType, - CppObjectHandle.GetCppType(context) + CppObjectHandle.GetCppType(context), + CppReinteropException.GetCppType(context) } )); } diff --git a/Reinterop~/Interop.cs b/Reinterop~/Interop.cs index ed052f0f..b1ced04e 100644 --- a/Reinterop~/Interop.cs +++ b/Reinterop~/Interop.cs @@ -78,9 +78,6 @@ public static (string Name, string Content) CreateCSharpDelegateInit( invocationTarget = $"{csType.GetFullyQualifiedName()}{accessName}"; } - // Add a parameter in which to return the exception, if there is one. - CSharpType exceptionCsType = CSharpType.FromSymbol(context, context.Compilation.GetSpecialType(SpecialType.System_IntPtr)).AsPointer(); - CSharpType csReturnType = CSharpType.FromSymbol(context, returnType); CSharpType csInteropReturnType = csReturnType.AsInteropTypeReturn(); @@ -102,6 +99,8 @@ public static (string Name, string Content) CreateCSharpDelegateInit( }); } + // Add a parameter in which to return the exception, if there is one. + CSharpType exceptionCsType = CSharpType.FromSymbol(context, context.Compilation.GetSpecialType(SpecialType.System_IntPtr)).AsPointer(); interopParameterDetails = interopParameterDetails.Concat(new[] { (Name: "reinteropException", Type: exceptionCsType, InteropType: exceptionCsType.AsInteropTypeParameter()) }); string interopReturnTypeString = csInteropReturnType.GetFullyQualifiedName(); @@ -257,7 +256,7 @@ public static (string Name, string Content) CreateCSharpDelegateInit( { try { - {{implementation.Replace(Environment.NewLine, Environment.NewLine + " ")}} + {{implementation.Replace(Environment.NewLine, Environment.NewLine + " ")}} } catch (Exception e) { @@ -328,6 +327,10 @@ public static (string Name, string Content) CreateCSharpDelegateInit( }); } + // Add a parameter in which to return the exception, if there is one. + CSharpType exceptionCsType = CSharpType.FromSymbol(context, context.Compilation.GetSpecialType(SpecialType.System_IntPtr)).AsPointer(); + interopParameterDetails = interopParameterDetails.Concat(new[] { (Name: "reinteropException", Type: exceptionCsType, InteropType: exceptionCsType.AsInteropTypeParameter()) }); + string interopReturnTypeString = csInteropReturnType.GetFullyQualifiedName(); string callParameterList = string.Join(", ", callParameterDetails.Select(parameter => parameter.Type.GetParameterConversionFromInteropType(parameter.Name))); string interopParameterList = string.Join(", ", interopParameterDetails.Select(parameter => $"{parameter.InteropType.GetFullyQualifiedName()} {parameter.Name}")); @@ -359,6 +362,20 @@ public static (string Name, string Content) CreateCSharpDelegateInit( string baseName = $"{GetUniqueNameForType(csType)}_Field_{(isGet ? "get" : "set")}_{field.Name}"; + string returnDefaultInstance = ""; + if (csInteropReturnType.SpecialType != SpecialType.System_Void) + { + if (csInteropReturnType.Symbol != null && + (csInteropReturnType.Symbol.TypeKind == TypeKind.Pointer || csInteropReturnType.Symbol.TypeKind == TypeKind.Class)) + { + returnDefaultInstance = "return null;"; + } + else + { + returnDefaultInstance = $$"""return new {{interopReturnTypeString}}();"""; + } + } + return ( Name: $"{baseName}Delegate", Content: @@ -369,7 +386,15 @@ public static (string Name, string Content) CreateCSharpDelegateInit( [AOT.MonoPInvokeCallback(typeof({{baseName}}Type))] private static unsafe {{interopReturnTypeString}} {{baseName}}({{interopParameterList}}) { - {{implementation.Replace(Environment.NewLine, Environment.NewLine + " ")}} + try + { + {{implementation.Replace(Environment.NewLine, Environment.NewLine + " ")}} + } + catch (Exception e) + { + *reinteropException = Reinterop.ObjectHandleUtility.CreateHandle(e); + {{returnDefaultInstance}} + } } """ ); diff --git a/Reinterop~/MethodsImplementedInCpp.cs b/Reinterop~/MethodsImplementedInCpp.cs index 9f22bfaf..39e756c6 100644 --- a/Reinterop~/MethodsImplementedInCpp.cs +++ b/Reinterop~/MethodsImplementedInCpp.cs @@ -208,7 +208,10 @@ protected void DisposeImplementation() [AOT.MonoPInvokeCallback(typeof({{baseName}}Type))] private static unsafe System.IntPtr {{baseName}}(IntPtr thiz) { - return ({{csWrapperType.GetParameterConversionFromInteropType("thiz")}}).NativeImplementation.DangerousGetHandle(); + var o = {{csWrapperType.GetParameterConversionFromInteropType("thiz")}}; + if (o == null) + return System.IntPtr.Zero; + return o.NativeImplementation.DangerousGetHandle(); } """ ));