#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_mapDictionary; 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
Есть несколько вариантов. Самый простой вариант - получение ссылки Listlist1 = 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/
Комментариев нет:
Отправить комментарий