У меня в одном из проектов на MS VC++ есть интерфейсная DLL с парой классов и несколькими глобальными функциями. Всего функций около пары десятков. Все крайне примитивно, используется только WinAPI и простейшие функции CRT, исключения не бросаются и не обрабатываются.
Заказчик хочет вызывать функции этой DLL из C#, но совершенно не разбирается в том, как дружить C# с C++, а я, соответственно, ничего не знаю про внутреннюю организацию C#, и некогда в нее глубоко лезть. Пока сошлись на том, что я добавлю в DLL обертки в стиле WinAPI, а они у себя сделают обертки для них.
Будет ли оптимальным способом разворачивать классы в наборы глобальных функций типа Class1_Func1, Class1_Func2 и т.д., добавляя первым параметром указатель на объект, или есть более изящный способ оформить в C# классы такой же структуры, и вызывать функции по-человечески? Например, добавить к классам абстрактные интерфейсы, сделав все функции виртуальными, оформить эти классы в стиле COM, или еще как.
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Будет ли оптимальным способом разворачивать классы в наборы глобальных функций типа Class1_Func1, Class1_Func2 и т.д., добавляя первым параметром указатель на объект,
Я бы так и сделал. Более того, я уже так пару раз интерфейсы своих плюсовых объектов оформлял для наших шарпистов. Интерфейсы не слишком развесистые, поэтому всё ручками делал. Шарписты, в свою очередь, импортировали эти функции из DLL, и оформляли в свой класс. Там тоже всё просто (но я деталей не помню)
ЕМ>Например, добавить к классам абстрактные интерфейсы, сделав все функции виртуальными, оформить эти классы в стиле COM, или еще как.
Можно, но это лишний гемор на ровном месте, имхо. Если, конечно, каких-то дальнейших перспектив нет
Re[2]: Как проще подключить C++ DLL к приложению на C#?
Здравствуйте, удусекшл, Вы писали:
ЕМ>>Например, добавить к классам абстрактные интерфейсы, сделав все функции виртуальными, оформить эти классы в стиле COM, или еще как.
У>Можно, но это лишний гемор на ровном месте, имхо. Если, конечно, каких-то дальнейших перспектив нет
Перспективы есть, но весьма скромные — может, еще пять-десять функций добавится за год-два. Это просто интерфейсная DLL для общения приложения с драйвером. Понятно, что технически проще развернуть классы в глобальные функции, но очень уж это уродливо.
Re: Как проще подключить C++ DLL к приложению на C#?
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>У меня в одном из проектов на MS VC++ есть интерфейсная DLL с парой классов и несколькими глобальными функциями. Всего функций около пары десятков. Все крайне примитивно, используется только WinAPI и простейшие функции CRT, исключения не бросаются и не обрабатываются.
ЕМ>Перспективы есть, но весьма скромные — может, еще пять-десять функций добавится за год-два. Это просто интерфейсная DLL для общения приложения с драйвером. Понятно, что технически проще развернуть классы в глобальные функции, но очень уж это уродливо.
Да вы, батенька, эстет
Re[3]: Как проще подключить C++ DLL к приложению на C#?
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Перспективы есть, но весьма скромные — может, еще пять-десять функций добавится за год-два. Это просто интерфейсная DLL для общения приложения с драйвером. Понятно, что технически проще развернуть классы в глобальные функции, но очень уж это уродливо.
Я бы обернул в COM. В С# тогда они получат авто-комплит как минимум и контекстный хелп как максимум (если только для винды)
Также тогда твою DLL можно будет автоматом использовать из всяких VBA (офиса) и питона например.
Проще всего делается через ATL, но можно и все руками.
Работы (для тебя) будет на порядок больше чем экспортировать голые функции.
Если все же экспортировать голые функции, то (им?) еще придется писать их определения на C# для вызова через P-Invoke. Не задолбают вопросами?
Я понимаю что проблемы индейцев шерифа не волнуют, но когда автокомплит есть, это все же лучше, чем когда его нет.
А вообще "леопольд, выходи" из пещеры, мир изменился
Re[2]: Как проще подключить C++ DLL к приложению на C#?
Здравствуйте, ArtDenis, Вы писали:
AD>beautiful-capi или аналог
Да там немного, меня и руками не заломает, а оберток для C# там все равно нет. Вопрос в том, есть ли относительно простой способ вызывать из C# элементарные методы классов C++ без раскидывания их по глобальным функциям.
Re[4]: Как проще подключить C++ DLL к приложению на C#?
Здравствуйте, bnk, Вы писали:
bnk>Проще всего делается через ATL, но можно и все руками.
Регистрировать в каталоге COM-серверов нужно, или из C# можно дергать DLL напрямую через DllGetClassObject?
bnk>Если все же экспортировать голые функции, то (им?) еще придется писать их определения на C# для вызова через P-Invoke. Не задолбают вопросами?
Они задолбают в любом случае (практически уже).
bnk>А вообще "леопольд, выходи" из пещеры, мир изменился
Что в свете этого следует сделать?
Re[3]: Как проще подключить C++ DLL к приложению на C#?
Здравствуйте, Евгений Музыченко, Вы писали:
AD>>beautiful-capi или аналог
ЕМ>Вопрос в том, есть ли относительно простой способ вызывать из C# элементарные методы классов C++ без раскидывания их по глобальным функциям.
Нет.
PS: Почему по глобальным-то? Правильно: по функциям, которые представляют API к классам в плоском виде. beautiful-capi сгенерирует такие функции, экспортирует из и напишет ООП-объёртку на указанном языке. Ручками это тоже сделать можно, но нужно ли?
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Да там немного, меня и руками не заломает, а оберток для C# там все равно нет. Вопрос в том, есть ли относительно простой способ вызывать из C# элементарные методы классов C++ без раскидывания их по глобальным функциям.
Есть (скорее был) C++/CLI (попытка микрософта упростить твою задачу), но сейчас пациент AFAIK скорее мертв, чем жив. Используй COM/ATL. Ленина может даже раньше закопают, чем его.
Re[5]: Как проще подключить C++ DLL к приложению на C#?
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>Регистрировать в каталоге COM-серверов нужно, или из C# можно дергать DLL напрямую через DllGetClassObject?
Регистрировать не обязательно, есть т.н. "registration-free" вариант (в manifest файле), который достаточно положить рядом с DLL. https://docs.microsoft.com/en-us/dotnet/framework/interop/registration-free-com-interop
bnk>>А вообще "леопольд, выходи" из пещеры, мир изменился
ЕМ>Что в свете этого следует сделать?
Как минимум написать Hello World на C#
Здравствуйте, Евгений Музыченко, Вы писали:
ЕМ>У меня в одном из проектов на MS VC++ есть интерфейсная DLL с парой классов и несколькими глобальными функциями. Всего функций около пары десятков. Все крайне примитивно, используется только WinAPI и простейшие функции CRT, исключения не бросаются и не обрабатываются.
ЕМ>Заказчик хочет вызывать функции этой DLL из C#, но совершенно не разбирается в том, как дружить C# с C++, а я, соответственно, ничего не знаю про внутреннюю организацию C#, и некогда в нее глубоко лезть. Пока сошлись на том, что я добавлю в DLL обертки в стиле WinAPI, а они у себя сделают обертки для них.
Есть несколко способов использовать C++ Dll в C# проекте:
1) P/Invoke
В Dll экспортируете все функции через C интерфейс и в C# проекте через DllImport используете эти функции.
Это в принципе , то что вы собираетесь делать. Неудобство здесь в том, как мне кажется, что если есть готовые классы в Dll, то их надо заворачивать в "обёртку".
2) C++/CLI
Использовать Managed C++ от Microsoft.
Здесь интерфейс пишится на стороне C# проекта. С++ классы пакуются в С++/CLI классы, С++/CLI классы используются в C# классах.
Плюсы: Можно использовать С++ классы напрямую из Dll.
Минусы: Свой специфический синтаксис C++/CLI.
3) Через СОМ интерфейс
Здесь ничего сказать не могу, не использовали.
Re: Как проще подключить C++ DLL к приложению на C#?
я приводил пример,от COMа там подсчет ссылок да реализация QueryInterface, этого достаточно для взаимодействия с .NET.
Не критики ради, а справедливости для, если так сделать, то мне кажется автокомплит не будет работать (библиотека типов не сгенерируется?). К тому же джентельмены руками QueryInterface не пишут.
И нифига так не проще по сравнению с экспортом функций, там достаточно написать __declspec(dllexport) и фсё. Два слова.
Re[3]: Как проще подключить C++ DLL к приложению на C#?
Здравствуйте, bnk, Вы писали:
bnk>Не критики ради, а справедливости для, если так сделать, то мне кажется автокомплит не будет работать (библиотека типов не сгенерируется?).
Интерфейсы руками описываются на C# (с экспортом ф-й было бы также, только писанины больше), соотв. автокомплит будет родной шарповский, ессн никаих тайп-либов не будет. Это самая простая COM-реализация, которую можно дергать из .NET.
bnk>К тому же джентельмены руками QueryInterface не пишут.
Речь шла о нескольких классах, соотв. столько же будет и интерфейсов. А судя по постам ТС думаю он лишнее в код не будет тянуть и прикручивать ATL.
bnk>И нифига так не проще по сравнению с экспортом функций, там достаточно написать __declspec(dllexport) и фсё. Два слова.
и фсё? Ну как минимум с десяток экспортов функций (судя по 1-му посту ТС), которые надо написать и в которых будет перенаправление вызова к методам классов. На создание интерфейсов из существующих классов уйдет куда меньше времени.
Если бы речь шла о кроссплатформе, то тут да — экспорт функций был бы более универсальным.
Вопрос ТС — как сделать проще, имхо проще и быстрее как я описал (ссылка на пример в посте выше).
ps: кстати если порыться в топике на который я сослался, тут
я попробовал https://github.com/mono/CppSharp , который по заголовочному файлу умеет генерить обертку на C# (порой кривовато, мож уже починили), но в целом работающая штука.
Re[4]: Как проще подключить C++ DLL к приложению на C#?
Здравствуйте, pilgrim_, Вы писали:
bnk>>Не критики ради, а справедливости для, если так сделать, то мне кажется автокомплит не будет работать (библиотека типов не сгенерируется?).
_>Интерфейсы руками описываются на C# (с экспортом ф-й было бы также, только писанины больше)
Другими словами — автокомплита из коробки не будет. Что я и сказал собственно.
bnk>>И нифига так не проще по сравнению с экспортом функций, там достаточно написать __declspec(dllexport) и фсё. Два слова.
_>Вопрос ТС — как сделать проще, имхо проще и быстрее как я описал (ссылка на пример в посте выше).
Самое простое — написать перед каждой экспортируемой функцией __declspec(dllexport) и задекларировать ее в C# для вызова через P-Invoke (две строчки)
Текста будет на порядок меньше чем с ATL/COM. Но и юзабилити этого на уровне пещерных людей. Типа так:
Если использовать ATL, то 90% кода можно "написать" с помощью визарда в студии, как поступают джентельмены.
New => Atl Project, New => Simple Object, потом просто добавить к нему методы и реализации. фсё.
Но это в десятки раз больше неочевидного кода, и просто горы синтаксического оверхеда.
Зато потом даже обезьяна сможет добавить эту библиотеку к проекту на C# кликнув мышкой на "Add Reference", и получит полный фарш с автокомплитом.
Что собственно ожидают от библиотеки нормальные люди.
Лебедю, чтобы грациозно плавать, приходится очень быстро махать лапами под водой, ничего здесь не поделаешь
Еще альтернатива — сделать промежуточную DLL-обертку на C#, в которой написать все эти корявые DllImport самому. Из которой экспортировать для C# красивые классы с методами.
Но тогда будет две DLL. Можно обернуть это в nuget пакет и опубликовать в публичном репозитории для удобства, чтобы простота использования оставалась на уровне обезьяны.
Кстати, еще один вариант — тупо переписать эту DLL написанную на C++, на C#, если она небольшая.
Функции WinAPI из C# вызываются без проблем.
Плюсую за этот вариант, несколько раз пользовался. Преимущества перед классическим pinvoke:
все описания в одном месте, нет необходимости "не забыть поправить C#" если изменил контракт на сишной стороне
гораздо прозрачнее менеджмент памяти: CLI поддерживает как managed-пулы памяти, так и native, делаем на стыке двух миров все необходимые преобразования и отпускаем память если больше не надо
енумы — опять же, см. пункт 1, описываем в одном месте (С++) и CLI выставит его на дотнетную часть, главное в отдельный namespace не забыть обернуть — иначе не увидит, global namespace оно не экспортирует
все проверки — compile time
Re[4]: Как проще подключить C++ DLL к приложению на C#?