-
Notifications
You must be signed in to change notification settings - Fork 541
std::string inside of value types does not generate correct bindings for C# #1730
Description
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;
}
}