Skip to content

std::string inside of value types does not generate correct bindings for C# #1730

@mirkobraic

Description

@mirkobraic

Hello, I have a C++ class that I want to expose to C# as a value type using CS_VALUE_TYPE macro.

However, I have noticed that if my C++ class contains std::string or const char* member, the generated code is not correct and cannot build. For example, consider the following C++ code:

CS_VALUE_TYPE class EXPORT_MACRO value_type {
public:
  std::string string_member;
  const char *char_ptr_member;
};

It generates public unsafe partial struct ValueType C# structure with the following code for member variables:

public string StringMember
{
    get
    {
        var __basicStringRet0 = global::Std.BasicString<sbyte, global::Std.CharTraits<sbyte>, global::Std.Allocator<sbyte>>.__CreateInstance(__instance.string_member);
        return global::Std.BasicStringExtensions.Data(__basicStringRet0);
    }

    set
    {
        global::Std.BasicStringExtensions.__Internal.Assign(new __IntPtr(&__instance.string_member), value);
    }
}

public string CharPtrMember
{
    get
    {
        return CppSharp.Runtime.MarshalUtil.GetString(global::System.Text.Encoding.UTF8, __instance.char_ptr_member);
    }

    set
    {
        if (___instance.char_ptr_member_OwnsNativeMemory)
            Marshal.FreeHGlobal(__instance.char_ptr_member);
        ___instance.char_ptr_member_OwnsNativeMemory = true;
        if (value == null)
        {
            __instance.char_ptr_member = global::System.IntPtr.Zero;
            return;
        }
        var __bytes0 = global::System.Text.Encoding.UTF8.GetBytes(value);
        var __bytePtr0 = Marshal.AllocHGlobal(__bytes0.Length + 1);
        Marshal.Copy(__bytes0, 0, __bytePtr0, __bytes0.Length);
        Marshal.WriteByte(__bytePtr0 + __bytes0.Length, 0);
        __instance.char_ptr_member = (__IntPtr) __bytePtr0;
    }
}

StringMember setter fails with "CS0212 You can only take the address of an unfixed expression inside of a fixed statement initializer" error message, while CharPtrMember setter fails with "CS0212 The name '___instance' does not exist in the current context".

Do you know what could be the issue and how to fix it?

P.S.
The generated code works correctly if CS_VALUE_TYPE macro is omitted, but unfortunately, I need to use C# structs.
Here is an example that works:

public string StringMember
{
    get
    {
        var __basicStringRet0 = global::Std.BasicString<sbyte, global::Std.CharTraits<sbyte>, global::Std.Allocator<sbyte>>.__CreateInstance(new __IntPtr(&((__Internal*)__Instance)->string_member));
        return global::Std.BasicStringExtensions.Data(__basicStringRet0);
    }

    set
    {
        global::Std.BasicStringExtensions.__Internal.Assign(new __IntPtr(&((__Internal*)__Instance)->string_member), value);
    }
}

public string CharPtrMember
{
    get
    {
        return CppSharp.Runtime.MarshalUtil.GetString(global::System.Text.Encoding.UTF8, ((__Internal*)__Instance)->char_ptr_member);
    }

    set
    {
        if (__char_ptr_member_OwnsNativeMemory)
            Marshal.FreeHGlobal(((__Internal*)__Instance)->char_ptr_member);
        __char_ptr_member_OwnsNativeMemory = true;
        if (value == null)
        {
            ((__Internal*)__Instance)->char_ptr_member = global::System.IntPtr.Zero;
            return;
        }
        var __bytes0 = global::System.Text.Encoding.UTF8.GetBytes(value);
        var __bytePtr0 = Marshal.AllocHGlobal(__bytes0.Length + 1);
        Marshal.Copy(__bytes0, 0, __bytePtr0, __bytes0.Length);
        Marshal.WriteByte(__bytePtr0 + __bytes0.Length, 0);
        ((__Internal*)__Instance)->char_ptr_member = (__IntPtr) __bytePtr0;
    }
}

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions