C
C#3mo ago
WhiteFalcon

Sharing the custom marshalled type across libraries

I followed the guide thoroughly https://learn.microsoft.com/en-us/dotnet/standard/native-interop/tutorial-custom-marshaller and source code is in here https://github.com/dotnet/samples/blob/main/core/interop/source-generation/custom-marshalling/src/custommarshalling/NativeLib.cs so far it works, but things goes south when i try to use the ErrorData outside of host library code used to test it out:
C#
using CustomMarshalling;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;

namespace CustomMarshalling2
{
internal partial class NativeLib2
{
private const string LibName = "nativelib2";

[LibraryImport(LibName)]
internal static partial void PrintErrorData(ErrorData errorData);

[LibraryImport(LibName)]
internal static partial ErrorData GetFatalErrorIfNegative(int code);

[LibraryImport(LibName)]
[return: MarshalUsing(CountElementName = "len")]
internal static partial ErrorData[] GetErrors(int[] codes, int len);

[LibraryImport(LibName)]
internal static partial void GetErrorCodes(ErrorBuffer buffer, int[] codes);
}
}
C#
using CustomMarshalling;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;

namespace CustomMarshalling2
{
internal partial class NativeLib2
{
private const string LibName = "nativelib2";

[LibraryImport(LibName)]
internal static partial void PrintErrorData(ErrorData errorData);

[LibraryImport(LibName)]
internal static partial ErrorData GetFatalErrorIfNegative(int code);

[LibraryImport(LibName)]
[return: MarshalUsing(CountElementName = "len")]
internal static partial ErrorData[] GetErrors(int[] codes, int len);

[LibraryImport(LibName)]
internal static partial void GetErrorCodes(ErrorBuffer buffer, int[] codes);
}
}
PS: unlike the original source code, i've made modification to ErrorData and their marshallers by making everything public just for testing. it generates SYSLIB1051 error error SYSLIB1051: Runtime marshalling must be disabled in this project by applying the 'System.Runtime.CompilerServices.DisableRuntimeMarshallingAttribute' to the assembly to enable marshalling this type. The generated source will not handle marshalling of parameter 'errorData'. (https://learn.microsoft.com/dotnet/fundamentals/syslib-diagnostics/syslib1051)
Use custom marshallers in source-generated P/Invokes - .NET
Learn how to use the CustomMarshallerAttribute and implement a custom marshaller for use with source generation.
GitHub
samples/core/interop/source-generation/custom-marshalling/src/custo...
Sample code referenced by the .NET documentation. Contribute to dotnet/samples development by creating an account on GitHub.
3 Replies
WhiteFalcon
WhiteFalconOP3mo ago
TLDR:
1) Library A defines publicly ErrorData and custom marshallers
2) Library A imports native library and uses the ErrorData as arguments/return type, everything compiles fine so far
3) Library B links against A
4) Library B imports another native library(or same) that also uses ErrorData; SYSLIB1051 error is generated
1) Library A defines publicly ErrorData and custom marshallers
2) Library A imports native library and uses the ErrorData as arguments/return type, everything compiles fine so far
3) Library B links against A
4) Library B imports another native library(or same) that also uses ErrorData; SYSLIB1051 error is generated
The error still persists if i removed the NativeMarshalling attribute and manually added MarshalUsing to each argument/return
C#
using CustomMarshalling;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;

namespace CustomMarshalling2
{
internal partial class NativeLib2
{
private const string LibName = "nativelib2";

[LibraryImport(LibName)]
internal static partial void PrintErrorData([MarshalUsing(typeof(ErrorDataMarshaller))] ErrorData errorData);

[LibraryImport(LibName)]
[return: MarshalUsing(typeof(ErrorDataMarshaller))]
internal static partial ErrorData GetFatalErrorIfNegative(int code);
}
}
C#
using CustomMarshalling;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.Marshalling;

namespace CustomMarshalling2
{
internal partial class NativeLib2
{
private const string LibName = "nativelib2";

[LibraryImport(LibName)]
internal static partial void PrintErrorData([MarshalUsing(typeof(ErrorDataMarshaller))] ErrorData errorData);

[LibraryImport(LibName)]
[return: MarshalUsing(typeof(ErrorDataMarshaller))]
internal static partial ErrorData GetFatalErrorIfNegative(int code);
}
}
I guess the solution was to disable runtime marshalling with [assembly: System.Runtime.CompilerServices.DisableRuntimeMarshalling] The issue with such solution for me was that it triggers CA1420: Property, type, or attribute requires runtime marshalling for delegates marked with [UnmanagedFunctionPointer(CallingConvention.Cdecl)] or any use of Marshal.GetFunctionPointerForDelegate with delegates managed types (even if they have NativeMarshaller)
jcotton42
jcotton423mo ago
Function pointers - C# feature specifications
This feature specification describes function pointers, which are unmanaged delegates. They are typically used to avoid the allocations necessary to instantiate a delegate object.
WhiteFalcon
WhiteFalconOP3mo ago
that would restrict me from using the managed types aswell as making the function static, right? thank you for the suggestion, i'll do that
Want results from more Discord servers?
Add your server