Delegate-based C# P/Invoke alternative - compatible with all platforms and runtimes.
AdvancedDLSupport also allows you to easily use more complex types than traditional P/Invoke. Chief among these are the following, which can be used just like you’d use them in C#.
string
Nullable<T>
bool
Complex types are handled much in the same way as compilers handle syntactic sugar (or “compiler magic”) - custom compiler lowering) by generating automatic wrapper constructs that take care of all the tedious marshalling and interoperation for you.
Thus, constructs like this is a simple matter for AdvancedDLSupport:
Taken from the PulseAudio source code
typedef struct pa_simple pa_simple;
pa_simple* pa_simple_new(
const char *server,
const char *name,
pa_stream_direction_t dir,
const char *dev,
const char *stream_name,
const pa_sample_spec *ss,
const pa_channel_map *map,
const pa_buffer_attr *attr,
int *error
);
void pa_simple_free(pa_simple *s);
int pa_simple_write(pa_simple *s, const void *data, size_t bytes, int *error);
int pa_simple_drain(pa_simple *s, int *error);
int pa_simple_read(
pa_simple *s,
void *data,
size_t bytes,
int *error
);
pa_usec_t pa_simple_get_latency(pa_simple *s, int *error);
int pa_simple_flush(pa_simple *s, int *error);
public interface IPulseSimple
{
IntPtr pa_simple_new
(
string server,
string name,
StreamDirection dir,
string dev,
string stream_name,
ref SampleSpecification ss,
ref ChannelMap? map,
ref BufferingAttributes? attr,
out int error
);
void pa_simple_free(IntPtr s);
int pa_simple_write(IntPtr s, byte[] data, UIntPtr bytes, out int error);
int pa_simple_drain(IntPtr s, out int error);
int pa_simple_read
(
IntPtr s,
byte[] data,
UIntPtr bytes,
out int error;
);
ulong pa_simple_get_latency(IntPtr s, out int error);
int pa_simple_flush(IntPtr s, out int error);
}
Of note is string handling, which traditional P/Invoke handles via the MarshalAs
attribute. ADL also respects the
MarshalAs
attribute, and defaults to marshalling string parameters as uchar8_t*
. The typical StringBuilder
construct
is also supported.
When running under Mono, LPTSTR
is handled as a unicode string.
public interface IMyStringLibrary
{
string GetSomeString();
int GetWStrLength([MarshalAs(UnmanagedType.LPWStr)] string uniString);
[return: MarshalAs(UnmanagedType(LPWStr)]
string GetSomeWString();
}
You, the developer, can also decide who should clean up the unmanaged memory allocated for the parameter. By annotating
a parameter or return value with the CallerFree
attribute, ADL will automatically free the unmanaged memory.
[return: CallerFree]
string GetStringAndFree();
UIntPtr GetStringLengthAndFree([CallerFree] string value);
[return: CallerFree]
MyStruct? GetStructAndFree();
int GetStructValueAndFree([CallerFree] MyStruct? value);
[CallerFree]
only has an effect for string
and T?
parameters.