PInvoke и представление параметра void** в управляемом коде - C#

Узнай цену своей работы

Формулировка задачи:

Здравствуйте! Проблема состоит в следующем: В библиотеке на CPP имеется некая функция, которая устанавливает соответствующие колбэки, а так же определена сигнатура этих колбэков, что-то вроде такого:
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;
}
Так вот вопрос в том, как сделать нечто такое на C#?:
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);
В Buffer1 я пробовал выделять память с помощью Marshal а так же с помощью GCHandle, но, на сколько я понял, просто записать в _buf ссылку не достаточно. Как правильно это делается? п.с., если интерестно, то это библиотека LibVlc. И тут я описал не все, а только то что поможет в достаточной мере раскрыть проблему.

Решение задачи: «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;
        }
    }
}

ИИ поможет Вам:


  • решить любую задачу по программированию
  • объяснить код
  • расставить комментарии в коде
  • и т.д
Попробуйте бесплатно

Оцени полезность:

9   голосов , оценка 3.667 из 5
Похожие ответы