Страницы

Поиск по вопросам

воскресенье, 15 декабря 2019 г.

Как передать в С++ библиотеку указатель на объект из C# и затем получить данные обратно?

#c_sharp #cpp #dll


Дело такое: Написал несколько функций на С++ и хочу их использовать в C# коде, но
не знаю как правильно объявить эти функции в C#. 

C функциями int CreateNewConverter() и void DestroyConverter(/*in*/ int id) вроде
бы понятно, но вот void Convert(int converterID, IDeckLinkVideoFrame *srcFrame, byte
**dstArray)) вызывает сомнения в правильности оформления и удобства использования в
C#, потому что у меня тут данные в библиотеку передаются и забираются через указатели.

Отмечу, что IDeckLinkVideoFrame *srcFrame это указатель на COM (Component Object
Model) объект реализующий интерфейс `IDeckLinkVideoFrame, так что, я полагаю, наверное,
можно передать его с помощью IntPtr, но я не знаю как.

Прошу помочь: укажите на ошибки, посоветуйте как правильнее, помогите решить.

H-файл: 

#ifdef DLFC_EXPORTS
#define DLFC_API __declspec(dllexport) 
#else
#define DLFC_API __declspec(dllimport) 
#endif

using namespace std;

static unordered_map Dictionary;

static int ID = 0;

extern "C" {
    DLFC_API int CreateNewConverter();

    DLFC_API void DestroyConverter( /*in*/ int id);

    DLFC_API void Convert( /*in*/  int converterID,
                           /*in*/  IDeckLinkVideoFrame *srcFrame,
                           /*out*/ byte **dstArray);
}


CPP-файл:

using namespace std;
int  CreateNewConverter() {
    ID++;
    VideoConverterARGB32* conv = new VideoConverterARGB32();
    Dictionary[ID] = conv;
    return ID;
}

void DestroyConverter(/*in*/ int id) {
    VideoConverterARGB32* conv = Dictionary[id];
    Dictionary.erase(id);
    delete conv;
}

void Convert(/*in*/  int converterID,
             /*in*/  IDeckLinkVideoFrame *srcFrame,
             /*out*/ byte **dstArray)
{
    VideoConverterARGB32* conv = Dictionary[converterID];
    conv->Convert(srcFrame, dstArray);
}    


С#:

using System.Runtime.InteropServices;
using DeckLinkAPI;

namespace AR.CaptureDevices.DeckLink {
    public class DeckLinkConverter {
        [DllImport(dllName: "DeckLinkConverter")]
        public static extern int CreateNewConverter();

        [DllImport(dllName: "DeckLinkConverter")]
        public static extern void DestroyConverter([Out] int id);

        [DllImport(dllName: "DeckLinkConverter")]
        public static extern void Convert([In]int converterID, [In] IDeckLinkVideoFrame*
srcFrame, [Out] byte** dstArray);

    }
}

    


Ответы

Ответ 1



Есть несколько вариантов. Самый простой вариант - получение ссылки List list1 = new List(); GCHandle handle1 = GCHandle.Alloc(list1); IntPtr parameter = (IntPtr) handle1; // call WinAPi and pass the parameter here // then free the handle when not needed: handle1.Free(); // back to object (in callback function): GCHandle handle2 = (GCHandle) parameter; List list2 = (handle2.Target as List); list2.Add("hello world"); Полученная ссылка для чистого массива - будет указывать на массив (скорее всего). Плюс в Marshal есть много полезностей, например: ReadByte, WriteByte, PtrToStringAnsi, StringToBSTR, Copy и другие. Ccылка http://stackoverflow.com/questions/17339928/c-sharp-how-to-convert-object-to-intptr-and-back Использование COM (ActiveX). Создаём COM-совместимый класс, и работаем в с++ как обычно работают с подобными обьектами. Если наследовать один из извесных интерфейсов - то будет совместимость с ним. "Тунели" с# сам создаёт при использовании COM-совместимых типов. Для передачи указателя на интерфейс, в Marshal есть GetComInterfaceForObject. ссылка http://www.codeproject.com/Articles/612604/Best-Practice-in-Writing-a-COM-Visible-Assembly-Cs Так же, если есть интерфейс в с++, то можно его подхватить на с# по ссылке, используя Marshal.GetTypedObjectForIUnknown. Так же можно передавать COM автоматически, для этого нужно, что б интерфейс был помечен как COM [ComVisible(true)] public interface IDeckLinkVideoFrame :IUnknown { //... } И процедура вызова с с++ была в с# обьявлена примерно так [DllImport(dllName: "DeckLinkConverter")] void Convert( [In][MarshalAs(UnmanagedType.I4)]int converterID, [In][MarshalAs(UnmanagedType.Interface)]IDeckLinkVideoFrame srcFrame, [Out][MarshalAs(UnmanagedType.LPArray)] byte **dstArray); C++-CLI. Данная модель позволяет обьеденить интерфейсы с# и с++, что то среднее что одной ногой в c# а другой в с++. https://habr.com/post/47732/

Комментариев нет:

Отправить комментарий