CppSharp
CppSharp copied to clipboard
wchar_t** or char** to string[], or alternative
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");
@tritao @ddobrev any solutions or suggestions to this
@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 any suggestions/pointers on how this should be implemented, maybe I can then do PR for this?
@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.
Maybe you should free the memory because you called Marshal.StringToHGlobalUni(s)
to avoid memory leak.