Skip to content

Commit

Permalink
Keep reference to generic server function delegates so they don't get…
Browse files Browse the repository at this point in the history
… GCed and crash the application
  • Loading branch information
campersau committed Aug 24, 2022
1 parent acdef8b commit f92a55c
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 11 deletions.
2 changes: 1 addition & 1 deletion src/SapNwRfc/Internal/Interop/RfcInterop.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
49 changes: 39 additions & 10 deletions src/SapNwRfc/SapServer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -166,20 +166,44 @@ public static void InstallGenericServerFunctionHandler(SapConnectionParameters p
InstallGenericServerFunctionHandler(new RfcInterop(), parameters, action);
}

#pragma warning disable SA1306 // Field names should begin with lower-case letter
// 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;

private static bool GenericServerFunctionHandlerInstalled;
private static (RfcInterop Interop, SapConnectionParameters Parameters, Action<ISapServerConnection, ISapServerFunction> Action) GenericServerFunctionHandler;
#pragma warning restore SA1306 // Field names should begin with lower-case letter

private static void InstallGenericServerFunctionHandler(RfcInterop interop, SapConnectionParameters parameters, Action<ISapServerConnection, ISapServerFunction> 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<ISapServerConnection, ISapServerFunction> action, IntPtr connectionHandle, IntPtr functionHandle, out RfcErrorInfo errorInfo)
private static RfcResultCode HandleGenericFunction(IntPtr connectionHandle, IntPtr functionHandle, out RfcErrorInfo errorInfo)
{
(RfcInterop interop, _, Action<ISapServerConnection, ISapServerFunction> 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);
Expand Down Expand Up @@ -211,8 +235,14 @@ private static RfcResultCode HandleGenericFunction(RfcInterop interop, Action<IS
}
}

private static RfcResultCode HandleGenericMetadata(RfcInterop interop, SapConnectionParameters parameters, string functionName, out IntPtr funcDescHandle)
private static RfcResultCode HandleGenericMetadata(string functionName, RfcAttributes attributes, out IntPtr funcDescHandle)
{
funcDescHandle = IntPtr.Zero;

(RfcInterop interop, SapConnectionParameters parameters, _) = GenericServerFunctionHandler;
if (interop == null || parameters == null)
return RfcResultCode.RFC_NOT_FOUND;

RfcConnectionParameter[] interopParameters = parameters.ToInterop();

IntPtr connection = interop.OpenConnection(
Expand All @@ -222,7 +252,6 @@ private static RfcResultCode HandleGenericMetadata(RfcInterop interop, SapConnec

if (connectionErrorInfo.Code != RfcResultCode.RFC_OK)
{
funcDescHandle = IntPtr.Zero;
return connectionErrorInfo.Code;
}

Expand Down

0 comments on commit f92a55c

Please sign in to comment.