CppSharp icon indicating copy to clipboard operation
CppSharp copied to clipboard

wchar_t** or char** to string[], or alternative

Open jlerasmus opened this issue 3 years ago • 5 comments

Hi all,

Please refer to detail below. I would like to know how can I generate a C# string[] parameter for a wchar_t** parameter in the C header.

Alternatively, how can I call/pass a string[] array to the char** parameter in the generated C# code.

Header
uint add_many_items(const wchar_t* name, const wchar_t** items);
Generated code
  • Extern definition
    [SuppressUnmanagedCodeSecurity, DllImport("lib-test.so", EntryPoint = "add_many_items", CallingConvention = __CallingConvention.Cdecl)]
    internal static extern uint AddManyItems([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(CppSharp.Runtime.UTF32Marshaller))] string name, char** items);
    
  • Method
    public static uint AddManyItems(string name, char** items)
    {
        var __ret = __Internal.AddManyItems(name, items);
        return __ret;
    }
    
Intended usage
string[] items = { "item-1", "item-2" };
AddManyItems("list-a", items);
Used settings
var options = driver.Options;
options.GeneratorKind = GeneratorKind.CSharp;
options.GenerationOutputMode = GenerationOutputMode.FilePerUnit;

var parserOptions = driver.ParserOptions;
parserOptions.TargetTriple = "aarch64-linux-gnu"; // Target linux generation (which uses UTTF32 for strings)
parserOptions.MicrosoftMode = false;
parserOptions.Verbose = true;
parserOptions.LanguageVersion = CppSharp.Parser.LanguageVersion.CPP17;
parserOptions.AddIncludeDirs(@"..\..\..\..\..\deepstream-services-library\src");

jlerasmus avatar Sep 29 '21 09:09 jlerasmus

@tritao @ddobrev any solutions or suggestions to this

jlerasmus avatar Oct 13 '21 16:10 jlerasmus

@jlerasmus we can map wchar_t** to string[] but we just haven't got to it yet. In case you need it quickly, you can contact our priority support.

ddobrev avatar Oct 14 '21 11:10 ddobrev

@ddobrev any suggestions/pointers on how this should be implemented, maybe I can then do PR for this?

jlerasmus avatar Oct 14 '21 11:10 jlerasmus

@jlerasmus I've been thinking as a general CppSharp solution, we need to refactor the generator so C-based pointers are wrapped as say a CPointer<> class, which could provide helper methods to help deal with these cases. We can't know the semantics just from looking at the code, so I think that's the best approach, to help the user call the code as intended originally.

CPointer could have methods like GetArray(length), GetNullTerminatedString(), and maybe even implicit/explicit conversions too taking arrays.

That's likely too much work for you to do though, if you want to take it then we could help.

But if you're just looking for a quick solution then you can either write a type map (a bit more work) or just write an extension method that you compile with your generated bindings.

AddManyItems(string name, string[] items)
{
 unsafe 
 {
    // Iterate through the array items and marshal the strings to a IntPtr[]
    // Use Marshal.StringToHGlobalUni or similar here. 
    // Check https://github.com/mono/CppSharp/blob/main/src/Generator/Types/Std/Stdlib.CSharp.cs#L118
    IntPtr[] strings = items.Select((s) => Marshal.StringToHGlobalUni(s)).ToArray();
    char*[] ptrs = strings.Select((s) => (char*)s.ToPointer());
    fixed (char** arr = &ptrs)
    {
      __Internal.AddManyItems(name, arr);
    }
    // Call Marshal.FreeHGlobal on ptrs items
  }
}

Just out of the top of my head, but that should be the gist of it.

tritao avatar Oct 14 '21 12:10 tritao

Maybe you should free the memory because you called Marshal.StringToHGlobalUni(s) to avoid memory leak.

weiyinfu avatar Aug 11 '22 00:08 weiyinfu