Одной из вещей, которые CLR может сделать очень хорошо для взаимодействия с кодом C / C ++, является распределение структур данных между управляемым и неуправляемым кодом. Поскольку строки очень важны, много работы ушло на то, чтобы как можно лучше сделать маршал строк.
В качестве дополнительного примечания вы используете void*
для объекта контекста, который создан с помощью init
и передан до write
. Поскольку вы просто возвращаете его, вы можете заменить его на IntPtr
и вообще избегать unsafe
блоков. IntPtr
всегда является размером указателя в текущей архитектуре.
Сначала давайте изменим объявление импортируемых функций. CharSet.Ansi
сообщает маршальным строкам как ANSI. Параметр ptr
становится IntPtr
[DllImport("Mandel.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public extern static IntPtr init(int width, int height);
[DllImport("Mandel.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public extern static void gen(IntPtr ptr);
[DllImport("Mandel.dll", CallingConvention = CallingConvention.Cdecl, CharSet = CharSet.Ansi)]
public extern static void write(IntPtr ptr, string path);
И оттуда вы можете выяснить, как изменить функцию для освобождения ptr
и любых других, которые вам нужно вызвать.
Использование этих функций становится намного проще и чище. Вам не нужен блок unsafe
, и вы можете передать path
непосредственно write
.
public MainWindow()
{
string path = "mypath";
InitializeComponent();
IntPtr myObj = Backend.init_obj(1920, 1080);
Backend.gen(myObj);
Backend.write(myObj, path);
}
Оригинальный комментарий, который заставил его работать:
Вместо того, чтобы пытаться создать параметр char*
самостоятельно, измените объявление так, чтобы вторым параметром был string
, и пусть среда выполнения соберет его для вас. Поскольку это строка ANSI, вы никогда не получите полную точность Unicode, но это проблема, созданная кодом C ++.