From 5b2f46a9489adff1eb50bd44808d128eae22c601 Mon Sep 17 00:00:00 2001 From: campersau Date: Tue, 23 Aug 2022 21:33:25 +0200 Subject: [PATCH] Keep reference to generic server function delegates so they don't get GCed and crash the application --- src/SapNwRfc/Internal/Interop/RfcInterop.cs | 2 +- src/SapNwRfc/SapServer.cs | 49 ++++++++++++++++----- 2 files changed, 40 insertions(+), 11 deletions(-) diff --git a/src/SapNwRfc/Internal/Interop/RfcInterop.cs b/src/SapNwRfc/Internal/Interop/RfcInterop.cs index 11c7b7f..e188a1a 100644 --- a/src/SapNwRfc/Internal/Interop/RfcInterop.cs +++ b/src/SapNwRfc/Internal/Interop/RfcInterop.cs @@ -329,7 +329,7 @@ public virtual IntPtr AppendNewRow(IntPtr tableHandle, out RfcErrorInfo errorInf public delegate RfcResultCode RfcServerFunction(IntPtr connectionHandle, IntPtr functionHandle, out RfcErrorInfo errorInfo); [UnmanagedFunctionPointer(CallingConvention.StdCall, CharSet = CharSet.Unicode)] - public delegate RfcResultCode RfcFunctionDescriptionCallback(string functionName, RfcAttributes attributes, ref IntPtr funcDescHandle); + public delegate RfcResultCode RfcFunctionDescriptionCallback(string functionName, RfcAttributes attributes, out IntPtr funcDescHandle); [UnmanagedFunctionPointer(CallingConvention.StdCall)] public delegate void RfcServerErrorListener(IntPtr serverHandle, in RfcAttributes clientInfo, in RfcErrorInfo errorInfo); diff --git a/src/SapNwRfc/SapServer.cs b/src/SapNwRfc/SapServer.cs index 8df68c0..d6b3a3c 100644 --- a/src/SapNwRfc/SapServer.cs +++ b/src/SapNwRfc/SapServer.cs @@ -166,20 +166,44 @@ public static void InstallGenericServerFunctionHandler(SapConnectionParameters p InstallGenericServerFunctionHandler(new RfcInterop(), parameters, action); } + // Keep a reference to the generic server function delegates so they don't get GCed + private static readonly RfcInterop.RfcServerFunction ServerFunction = HandleGenericFunction; + private static readonly RfcInterop.RfcFunctionDescriptionCallback GenericMetadata = HandleGenericMetadata; + +#pragma warning disable SA1306 // Field names should begin with lower-case letter + private static bool GenericServerFunctionHandlerInstalled; + private static (RfcInterop Interop, SapConnectionParameters Parameters, Action Action) GenericServerFunctionHandler; +#pragma warning restore SA1306 // Field names should begin with lower-case letter + private static void InstallGenericServerFunctionHandler(RfcInterop interop, SapConnectionParameters parameters, Action action) { - RfcResultCode resultCode = interop.InstallGenericServerFunction( - serverFunction: (IntPtr connectionHandle, IntPtr functionHandle, out RfcErrorInfo errorInfo) - => HandleGenericFunction(interop, action, connectionHandle, functionHandle, out errorInfo), - funcDescPointer: (string functionName, RfcAttributes attributes, ref IntPtr funcDescHandle) - => HandleGenericMetadata(interop, parameters, functionName, out funcDescHandle), - out RfcErrorInfo installFunctionErrorInfo); + GenericServerFunctionHandler = (interop, parameters, action); + + if (!GenericServerFunctionHandlerInstalled) + { + RfcResultCode resultCode = interop.InstallGenericServerFunction( + serverFunction: ServerFunction, + funcDescPointer: GenericMetadata, + out RfcErrorInfo installFunctionErrorInfo); - resultCode.ThrowOnError(installFunctionErrorInfo); + resultCode.ThrowOnError(installFunctionErrorInfo); + + GenericServerFunctionHandlerInstalled = true; + } } - private static RfcResultCode HandleGenericFunction(RfcInterop interop, Action action, IntPtr connectionHandle, IntPtr functionHandle, out RfcErrorInfo errorInfo) + private static RfcResultCode HandleGenericFunction(IntPtr connectionHandle, IntPtr functionHandle, out RfcErrorInfo errorInfo) { + (RfcInterop interop, _, Action action) = GenericServerFunctionHandler; + if (interop == null || action == null) + { + errorInfo = new RfcErrorInfo + { + Code = RfcResultCode.RFC_EXTERNAL_FAILURE, + }; + return RfcResultCode.RFC_EXTERNAL_FAILURE; + } + IntPtr functionDesc = interop.DescribeFunction( rfcHandle: functionHandle, errorInfo: out RfcErrorInfo functionDescErrorInfo); @@ -211,8 +235,14 @@ private static RfcResultCode HandleGenericFunction(RfcInterop interop, Action