Skip to content

Instantly share code, notes, and snippets.

@Sharp0802
Created March 20, 2024 12:01
Show Gist options
  • Save Sharp0802/ed24e57528db4c41b2d768c9deee81a8 to your computer and use it in GitHub Desktop.
Save Sharp0802/ed24e57528db4c41b2d768c9deee81a8 to your computer and use it in GitHub Desktop.
Interop std::string to C++ from C# with P/Invoke
#include <string>
#include <iostream>
void WriteLine(std::string str)
{
std::cout << str << std::endl << std::flush;
}
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Text;
unsafe
{
var ns = new NativeString("Hello from C++!");
WriteLine(&ns);
}
[DllImport("./main.so", EntryPoint = "_Z9WriteLineNSt7__cxx1112basic_stringIcSt11char_traitsIcESaIcEEE", ExactSpelling = true)]
static extern unsafe void WriteLine(NativeString* str);
[Serializable]
[StructLayout(LayoutKind.Sequential)]
internal struct NativeString : IDisposable
{
[StructLayout(LayoutKind.Explicit)]
private struct LocalBuffer
{
[FieldOffset(0)] public ulong Capacity;
[FieldOffset(0)] public unsafe fixed byte Buffer[16];
}
public NativeString(string str)
{
unsafe
{
_length = (ulong)Encoding.UTF8.GetByteCount(str);
_localBuffer.Capacity = (_length * 2) | 1;
_buffer = (byte*)NativeMemory.Alloc((UIntPtr)_localBuffer.Capacity);
fixed (byte* p = Encoding.UTF8.GetBytes(str))
Unsafe.CopyBlock(_buffer, p, (uint)_length);
_buffer[_length] = 0;
}
}
private unsafe byte* _buffer;
private ulong _length;
private LocalBuffer _localBuffer;
public int Length => checked((int)_length);
public static implicit operator NativeString(string str) => new(str);
public override string ToString()
{
unsafe
{
return Marshal.PtrToStringUTF8((IntPtr)_buffer)
?? throw new InvalidOperationException();
}
}
public void Dispose()
{
unsafe
{
NativeMemory.Free(_buffer);
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment