PInvoke и представление параметра void** в управляемом коде - C#
Формулировка задачи:
Здравствуйте!
Проблема состоит в следующем:
В библиотеке на CPP имеется некая функция, которая устанавливает соответствующие колбэки, а так же определена сигнатура этих колбэков, что-то вроде такого:
На С++ тело колбэка должно выглядеть следующим образом:
Так вот вопрос в том, как сделать нечто такое на C#?:
Сейчас это выглядит следующим образом:
В Buffer1 я пробовал выделять память с помощью Marshal а так же с помощью GCHandle, но, на сколько я понял, просто записать в _buf ссылку не достаточно.
Как правильно это делается?
п.с., если интерестно, то это библиотека LibVlc. И тут я описал не все, а только то что поможет в достаточной мере раскрыть проблему.
typedef void *(*lock)(void **buf); extern "C" __declspec ( dllexport ) void set_callbacks(lock _lock);
unsigned char * pixels; //инициализируется где-то в коде, и является массивом определенного размера
........
void *lock(void **buf)
{
*buf = pixels;
return NULL;
}void **buf *buf = pixels;
public static class myLib
{
[DllImport("Library.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void set_callbacks(lock_cb _lock);
public delegate IntPtr lock_cb(ref IntPtr _buf);
}
.....
static IntPtr cbLock(ref IntPtr _buf)
{
_buf= Buffer1; //Buffer1 это IntPtr в котором находится ссылка на область памяти в неуправляемой куче
return IntPtr.Zero;
}
.....
myLib.set_callbacks(cbLock);Решение задачи: «PInvoke и представление параметра void** в управляемом коде»
textual
Листинг программы
using System;
using System.Linq;
using System.Runtime.InteropServices;
namespace ConsoleApplication1 {
static class Program {
[DllImport(@"Library.dll", EntryPoint = @"set_callbacks", CallingConvention = CallingConvention.Cdecl)]
public static extern void SetCallback(CallbackHandler _lock);
[UnmanagedFunctionPointer(CallingConvention.Cdecl)]
public delegate IntPtr CallbackHandler(IntPtr data);
static void Main() {
SetCallback(Callback);
TEST();
_currentCallbackHandle.Free();
}
static IntPtr Callback(IntPtr buf) {
var arr = ToByteArray(buf);
var flat = Flatten(arr);
_currentCallbackHandle = GCHandle.Alloc(flat, GCHandleType.Pinned); // !!
return _currentCallbackHandle.AddrOfPinnedObject();
}
// TEST
static GCHandle _currentCallbackHandle;
[DllImport(@"Library.dll", CallingConvention = CallingConvention.Cdecl)]
public static extern void TEST();
static byte[][] ToByteArray(IntPtr buf) {
var l1p = new IntPtr[2];
Marshal.Copy(buf, l1p, 0, l1p.Length);
var arr = new byte[2][];
for (int k = 0; k < arr.Length; k++)
Marshal.Copy(l1p[k], arr[k] = new byte[4], 0, arr[k].Length);
return arr;
}
static byte[] Flatten(byte[][] arr) {
var result = new byte[arr.Sum(t => t.Length)];
for (int i = 0, c = 0; i < arr.Length; i++) {
arr[i].CopyTo(result, c);
c += arr[i].Length;
}
return result;
}
}
}