EzDev.org

CppSharp

CppSharp - Tools and libraries to glue C/C++ APIs to high-level languages


C# bindings for a c++ library

I've created a c# bindings for libpostal library (link to LibPostalNet).

I've used CppSharp to create bindings. It works but I don't how to convert this code :

typedef struct libpostal_address_parser_response
{
    size_t num_components;
    char** components;
    char** labels;
}
libpostal_address_parser_response_t;

CppSharp converts code in this way :

public sbyte** Components
{
    get
    {
        return (sbyte**)((global::LibPostalNet.LibpostalAddressParserResponse.__Internal*)__Instance)->components;
    }

    set
    {
        ((global::LibPostalNet.LibpostalAddressParserResponse.__Internal*)__Instance)->components = (global::System.IntPtr)value;
    }
}

public sbyte** Labels
{
    get
    {
        return (sbyte**)((global::LibPostalNet.LibpostalAddressParserResponse.__Internal*)__Instance)->labels;
    }

    set
    {
        ((global::LibPostalNet.LibpostalAddressParserResponse.__Internal*)__Instance)->labels = (global::System.IntPtr)value;
    }
}

Code should return a string array of num_components length.

Can you help me to solve this?


Source: (StackOverflow)

CppSharp generates the wrong code

TL;DR: CppSharp generates the wrong binding code for a particular C++ method signature. How do I use TypeMaps and or passes to fix this? Is there documentation or examples of type transformations I can use?

I'm using CppSharp to generate C# bindings for OBS studio, in order to write a plugin for it.

When generating code from OBS.h using the following generator:

class OBSBindingsGenerator: ILibrary
{
    public void Postprocess(Driver driver, ASTContext ctx)
    {
    }

    public void Preprocess(Driver driver, ASTContext ctx)
    {
    }

    public void Setup(Driver driver)
    {
        var options = driver.Options;
        options.GeneratorKind = CppSharp.Generators.GeneratorKind.CSharp;
        var module = options.AddModule("OBS");
        module.IncludeDirs.Add(@"path\to\libobs");
        module.Headers.Add("obs.h");
    }

    public void SetupPasses(Driver driver)
    {
    }
}

class Program
{
    static void Main(string[] args)
    {
        ConsoleDriver.Run(new OBSBindingsGenerator());
    }
}

I find that it generates:

    [SuppressUnmanagedCodeSecurity]
    [DllImport("OBS", CallingConvention = global::System.Runtime.InteropServices.CallingConvention.Cdecl,
        EntryPoint="video_format_get_parameters")]
    [return: MarshalAs(UnmanagedType.I1)]
    internal static extern bool VideoFormatGetParameters_0(global::OBS.VideoColorspace color_space, global::OBS.VideoRangeType range, float matrix, float min_range, float max_range);

and the corresponding public method

public static bool VideoFormatGetParameters(global::OBS.VideoColorspace color_space, global::OBS.VideoRangeType range, float[] matrix, float[] min_range, float[] max_range)
{
    ... // Code snipped for brevity
    fixed (float* __ptr4 = max_range)
    {
        var __arg4 = new global::System.IntPtr(__ptr4);
        // See here that __arg4 is an IntPtr argument and is being passed to a float parameter
        var __ret = __Internal.VideoFormatGetParameters_0(color_space, range, __arg2, __arg3, __arg4);
        return __ret;
    }
}

This obviously does not compile. The C++ definition is:

EXPORT bool video_format_get_parameters(enum video_colorspace color_space,
    enum video_range_type range, float matrix[16],
    float min_range[3], float max_range[3]);

In hand-written PInvoke, this can be fixed in many ways (declare a struct with the right number of float members, or a [MarshalAs(UnmanagedType.LPArray, SizeConst = 3)] and a float[] passthrough or declare the PInvoke parameter as an IntPtr).

My question then is: How do I use CppSharp and its code transformation tools (TypeMap? Pass? What?) to achieve any of the correct translations? I could fix this as a hack, but since I interop with my C++ libraries I'd prefer to learn the right way to do this with CppSharp (learn to fish).

Thanks in advance!


Source: (StackOverflow)

C function with pointers in C#

I'm currently playing with CppSharp and I generated the bindings for the SDL2 library. It almost works, but I can't get working the event part of the library. In C, you just use the API like this

SDL_Event event;
while(SDL_WaitEvent(&event))
{
    if(e.type = SDL_QUIT)
        exit(0);
}

But in C# with the generated bindings I can't do it:

SDL.SDL_Event e = new SDL.SDL_Event();
while(SDL.SDL_WaitEvent(e))
{
    if(e.Type == (uint)SDL.SDL_EventType.SDL_QUIT)
        System.Environment.Exit(0);
}

It compiles but e.Type is always zero, which is not correct, it's like the C# object never changes internally. Is there a way to let C# pass an SDL.SDL_Event like C does.

For reference, here are the bindings (I would like to not change them, because they're generated by CppSharp):

[SuppressUnmanagedCodeSecurity]
[DllImport("SDL2", CallingConvention = global::System.Runtime.InteropServices.CallingConvention.Cdecl,EntryPoint="SDL_WaitEvent")]
internal static extern int SDL_WaitEvent(global::System.IntPtr @event);

public static int SDL_WaitEvent(global::SDL.SDL_Event @event)
{
    var ____arg0 = @event.__Instance;
    var __arg0 = new global::System.IntPtr(&____arg0);
    var __ret = __Internal.SDL_WaitEvent(__arg0);
    return __ret;
}

How can I get the event loop working in C#?

EDIT: SDL_Event generated struct

public unsafe partial struct SDL_Event
{
    [StructLayout(LayoutKind.Explicit, Size = 56)]
    public partial struct __Internal
    {
        [FieldOffset(0)]
        internal uint type;

        [FieldOffset(0)]
        internal global::SDL.SDL_CommonEvent.__Internal common;

        [FieldOffset(0)]
        internal global::SDL.SDL_WindowEvent.__Internal window;

        [FieldOffset(0)]
        internal global::SDL.SDL_KeyboardEvent.__Internal key;

        [FieldOffset(0)]
        internal global::SDL.SDL_TextEditingEvent.__Internal edit;

        [FieldOffset(0)]
        internal global::SDL.SDL_TextInputEvent.__Internal text;

        [FieldOffset(0)]
        internal global::SDL.SDL_MouseMotionEvent.__Internal motion;

        [FieldOffset(0)]
        internal global::SDL.SDL_MouseButtonEvent.__Internal button;

        [FieldOffset(0)]
        internal global::SDL.SDL_MouseWheelEvent.__Internal wheel;

        [FieldOffset(0)]
        internal global::SDL.SDL_JoyAxisEvent.__Internal jaxis;

        [FieldOffset(0)]
        internal global::SDL.SDL_JoyBallEvent.__Internal jball;

        [FieldOffset(0)]
        internal global::SDL.SDL_JoyHatEvent.__Internal jhat;

        [FieldOffset(0)]
        internal global::SDL.SDL_JoyButtonEvent.__Internal jbutton;

        [FieldOffset(0)]
        internal global::SDL.SDL_JoyDeviceEvent.__Internal jdevice;

        [FieldOffset(0)]
        internal global::SDL.SDL_ControllerAxisEvent.__Internal caxis;

        [FieldOffset(0)]
        internal global::SDL.SDL_ControllerButtonEvent.__Internal cbutton;

        [FieldOffset(0)]
        internal global::SDL.SDL_ControllerDeviceEvent.__Internal cdevice;

        [FieldOffset(0)]
        internal global::SDL.SDL_AudioDeviceEvent.__Internal adevice;

        [FieldOffset(0)]
        internal global::SDL.SDL_QuitEvent.__Internal quit;

        [FieldOffset(0)]
        internal global::SDL.SDL_UserEvent.__Internal user;

        [FieldOffset(0)]
        internal global::SDL.SDL_SysWMEvent.__Internal syswm;

        [FieldOffset(0)]
        internal global::SDL.SDL_TouchFingerEvent.__Internal tfinger;

        [FieldOffset(0)]
        internal global::SDL.SDL_MultiGestureEvent.__Internal mgesture;

        [FieldOffset(0)]
        internal global::SDL.SDL_DollarGestureEvent.__Internal dgesture;

        [FieldOffset(0)]
        internal global::SDL.SDL_DropEvent.__Internal drop;

        [FieldOffset(0)]
        internal fixed byte padding[56];

        [SuppressUnmanagedCodeSecurity]
        [DllImport("SDL", CallingConvention = global::System.Runtime.InteropServices.CallingConvention.Cdecl,
            EntryPoint="??0SDL_Event@@QEAA@AEBT0@@Z")]
        internal static extern global::System.IntPtr cctor(global::System.IntPtr instance, global::System.IntPtr _0);
    }

Source: (StackOverflow)