Как проще подключить C++ DLL к приложению на C#?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 02.04.21 14:20
Оценка:
У меня в одном из проектов на MS VC++ есть интерфейсная DLL с парой классов и несколькими глобальными функциями. Всего функций около пары десятков. Все крайне примитивно, используется только WinAPI и простейшие функции CRT, исключения не бросаются и не обрабатываются.

Заказчик хочет вызывать функции этой DLL из C#, но совершенно не разбирается в том, как дружить C# с C++, а я, соответственно, ничего не знаю про внутреннюю организацию C#, и некогда в нее глубоко лезть. Пока сошлись на том, что я добавлю в DLL обертки в стиле WinAPI, а они у себя сделают обертки для них.

Будет ли оптимальным способом разворачивать классы в наборы глобальных функций типа Class1_Func1, Class1_Func2 и т.д., добавляя первым параметром указатель на объект, или есть более изящный способ оформить в C# классы такой же структуры, и вызывать функции по-человечески? Например, добавить к классам абстрактные интерфейсы, сделав все функции виртуальными, оформить эти классы в стиле COM, или еще как.
c# dll
Re: Как проще подключить C++ DLL к приложению на C#?
От: удусекшл  
Дата: 02.04.21 14:28
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Будет ли оптимальным способом разворачивать классы в наборы глобальных функций типа Class1_Func1, Class1_Func2 и т.д., добавляя первым параметром указатель на объект,


Я бы так и сделал. Более того, я уже так пару раз интерфейсы своих плюсовых объектов оформлял для наших шарпистов. Интерфейсы не слишком развесистые, поэтому всё ручками делал. Шарписты, в свою очередь, импортировали эти функции из DLL, и оформляли в свой класс. Там тоже всё просто (но я деталей не помню)


ЕМ>Например, добавить к классам абстрактные интерфейсы, сделав все функции виртуальными, оформить эти классы в стиле COM, или еще как.


Можно, но это лишний гемор на ровном месте, имхо. Если, конечно, каких-то дальнейших перспектив нет
Re[2]: Как проще подключить C++ DLL к приложению на C#?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 02.04.21 14:39
Оценка:
Здравствуйте, удусекшл, Вы писали:

ЕМ>>Например, добавить к классам абстрактные интерфейсы, сделав все функции виртуальными, оформить эти классы в стиле COM, или еще как.


У>Можно, но это лишний гемор на ровном месте, имхо. Если, конечно, каких-то дальнейших перспектив нет


Перспективы есть, но весьма скромные — может, еще пять-десять функций добавится за год-два. Это просто интерфейсная DLL для общения приложения с драйвером. Понятно, что технически проще развернуть классы в глобальные функции, но очень уж это уродливо.
Re: Как проще подключить C++ DLL к приложению на C#?
От: ArtDenis Россия  
Дата: 02.04.21 14:42
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>У меня в одном из проектов на MS VC++ есть интерфейсная DLL с парой классов и несколькими глобальными функциями. Всего функций около пары десятков. Все крайне примитивно, используется только WinAPI и простейшие функции CRT, исключения не бросаются и не обрабатываются.


beautiful-capi или аналог
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[3]: Как проще подключить C++ DLL к приложению на C#?
От: удусекшл  
Дата: 02.04.21 14:53
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:


ЕМ>Перспективы есть, но весьма скромные — может, еще пять-десять функций добавится за год-два. Это просто интерфейсная DLL для общения приложения с драйвером. Понятно, что технически проще развернуть классы в глобальные функции, но очень уж это уродливо.


Да вы, батенька, эстет
Re[3]: Как проще подключить C++ DLL к приложению на C#?
От: bnk СССР http://unmanagedvisio.com/
Дата: 02.04.21 14:53
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Перспективы есть, но весьма скромные — может, еще пять-десять функций добавится за год-два. Это просто интерфейсная DLL для общения приложения с драйвером. Понятно, что технически проще развернуть классы в глобальные функции, но очень уж это уродливо.


Я бы обернул в COM. В С# тогда они получат авто-комплит как минимум и контекстный хелп как максимум (если только для винды)
Также тогда твою DLL можно будет автоматом использовать из всяких VBA (офиса) и питона например.

Проще всего делается через ATL, но можно и все руками.
Работы (для тебя) будет на порядок больше чем экспортировать голые функции.

Если все же экспортировать голые функции, то (им?) еще придется писать их определения на C# для вызова через P-Invoke. Не задолбают вопросами?
Я понимаю что проблемы индейцев шерифа не волнуют, но когда автокомплит есть, это все же лучше, чем когда его нет.

А вообще "леопольд, выходи" из пещеры, мир изменился
Re[2]: Как проще подключить C++ DLL к приложению на C#?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 02.04.21 14:53
Оценка:
Здравствуйте, ArtDenis, Вы писали:

AD>beautiful-capi или аналог


Да там немного, меня и руками не заломает, а оберток для C# там все равно нет. Вопрос в том, есть ли относительно простой способ вызывать из C# элементарные методы классов C++ без раскидывания их по глобальным функциям.
Re[4]: Как проще подключить C++ DLL к приложению на C#?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 02.04.21 14:58
Оценка:
Здравствуйте, удусекшл, Вы писали:

У>Да вы, батенька, эстет


Дык, ёптыть!
Re[4]: Как проще подключить C++ DLL к приложению на C#?
От: Евгений Музыченко Франция https://software.muzychenko.net/ru
Дата: 02.04.21 15:03
Оценка:
Здравствуйте, bnk, Вы писали:

bnk>Проще всего делается через ATL, но можно и все руками.


Регистрировать в каталоге COM-серверов нужно, или из C# можно дергать DLL напрямую через DllGetClassObject?

bnk>Если все же экспортировать голые функции, то (им?) еще придется писать их определения на C# для вызова через P-Invoke. Не задолбают вопросами?


Они задолбают в любом случае (практически уже).

bnk>А вообще "леопольд, выходи" из пещеры, мир изменился


Что в свете этого следует сделать?
Re[3]: Как проще подключить C++ DLL к приложению на C#?
От: ArtDenis Россия  
Дата: 02.04.21 15:09
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

AD>>beautiful-capi или аналог


ЕМ>Вопрос в том, есть ли относительно простой способ вызывать из C# элементарные методы классов C++ без раскидывания их по глобальным функциям.

Нет.

PS: Почему по глобальным-то? Правильно: по функциям, которые представляют API к классам в плоском виде. beautiful-capi сгенерирует такие функции, экспортирует из и напишет ООП-объёртку на указанном языке. Ручками это тоже сделать можно, но нужно ли?
[ 🎯 Дартс-лига Уфы | 🌙 Программа для сложения астрофото ]
Re[3]: Как проще подключить C++ DLL к приложению на C#?
От: bnk СССР http://unmanagedvisio.com/
Дата: 02.04.21 15:11
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Да там немного, меня и руками не заломает, а оберток для C# там все равно нет. Вопрос в том, есть ли относительно простой способ вызывать из C# элементарные методы классов C++ без раскидывания их по глобальным функциям.


Есть (скорее был) C++/CLI (попытка микрософта упростить твою задачу), но сейчас пациент AFAIK скорее мертв, чем жив. Используй COM/ATL. Ленина может даже раньше закопают, чем его.
Re[5]: Как проще подключить C++ DLL к приложению на C#?
От: bnk СССР http://unmanagedvisio.com/
Дата: 02.04.21 15:13
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>Регистрировать в каталоге 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#
Отредактировано 02.04.2021 16:18 bnk . Предыдущая версия .
Re: Как проще подключить C++ DLL к приложению на C#?
От: Iso12  
Дата: 02.04.21 15:25
Оценка: +2
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>У меня в одном из проектов на 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#?
От: pilgrim_ Россия  
Дата: 02.04.21 15:28
Оценка:
Здравствуйте, Евгений Музыченко, Вы писали:

ЕМ>оформить эти классы в стиле COM,


Имхо так проще всего,меньше писанины и тебе и клиенту.
Вот тут
Автор: pilgrim_
Дата: 15.11.16
я приводил пример,от COMа там подсчет ссылок да реализация QueryInterface, этого достаточно для взаимодействия с .NET.
Re: Как проще подключить C++ DLL к приложению на C#?
От: AeroSun  
Дата: 02.04.21 19:01
Оценка: +1
ИМХО, не создавать велосипед с треугольными колесами и шипастым сидением, а сделать стандартно:

С++ dll --> C++/CLI dll --> C# dll

и все отлично связывается и гемор отсуствует
иначе получится очередной (opensource) c++ уродец
Отредактировано 02.04.2021 19:02 AeroSun . Предыдущая версия .
Re[2]: Как проще подключить C++ DLL к приложению на C#?
От: bnk СССР http://unmanagedvisio.com/
Дата: 02.04.21 19:07
Оценка:
Здравствуйте, pilgrim_, Вы писали:

_>Имхо так проще всего,меньше писанины и тебе и клиенту.

_>Вот тут
Автор: pilgrim_
Дата: 15.11.16
я приводил пример,от COMа там подсчет ссылок да реализация QueryInterface, этого достаточно для взаимодействия с .NET.


Не критики ради, а справедливости для, если так сделать, то мне кажется автокомплит не будет работать (библиотека типов не сгенерируется?). К тому же джентельмены руками QueryInterface не пишут.
И нифига так не проще по сравнению с экспортом функций, там достаточно написать __declspec(dllexport) и фсё. Два слова.
Re[3]: Как проще подключить C++ DLL к приложению на C#?
От: pilgrim_ Россия  
Дата: 02.04.21 19:40
Оценка:
Здравствуйте, bnk, Вы писали:

bnk>Не критики ради, а справедливости для, если так сделать, то мне кажется автокомплит не будет работать (библиотека типов не сгенерируется?).


Интерфейсы руками описываются на C# (с экспортом ф-й было бы также, только писанины больше), соотв. автокомплит будет родной шарповский, ессн никаих тайп-либов не будет. Это самая простая COM-реализация, которую можно дергать из .NET.

bnk>К тому же джентельмены руками QueryInterface не пишут.


Речь шла о нескольких классах, соотв. столько же будет и интерфейсов. А судя по постам ТС думаю он лишнее в код не будет тянуть и прикручивать ATL.

bnk>И нифига так не проще по сравнению с экспортом функций, там достаточно написать __declspec(dllexport) и фсё. Два слова.


и фсё? Ну как минимум с десяток экспортов функций (судя по 1-му посту ТС), которые надо написать и в которых будет перенаправление вызова к методам классов. На создание интерфейсов из существующих классов уйдет куда меньше времени.
Если бы речь шла о кроссплатформе, то тут да — экспорт функций был бы более универсальным.

Вопрос ТС — как сделать проще, имхо проще и быстрее как я описал (ссылка на пример в посте выше).

ps: кстати если порыться в топике на который я сослался, тут
Автор: pilgrim_
Дата: 18.11.16
я попробовал https://github.com/mono/CppSharp , который по заголовочному файлу умеет генерить обертку на C# (порой кривовато, мож уже починили), но в целом работающая штука.
Re[4]: Как проще подключить C++ DLL к приложению на C#?
От: bnk СССР http://unmanagedvisio.com/
Дата: 02.04.21 20:27
Оценка:
Здравствуйте, pilgrim_, Вы писали:

bnk>>Не критики ради, а справедливости для, если так сделать, то мне кажется автокомплит не будет работать (библиотека типов не сгенерируется?).


_>Интерфейсы руками описываются на C# (с экспортом ф-й было бы также, только писанины больше)


Другими словами — автокомплита из коробки не будет. Что я и сказал собственно.


bnk>>И нифига так не проще по сравнению с экспортом функций, там достаточно написать __declspec(dllexport) и фсё. Два слова.


_>Вопрос ТС — как сделать проще, имхо проще и быстрее как я описал (ссылка на пример в посте выше).


Самое простое — написать перед каждой экспортируемой функцией __declspec(dllexport) и задекларировать ее в C# для вызова через P-Invoke (две строчки)
Текста будет на порядок меньше чем с ATL/COM. Но и юзабилити этого на уровне пещерных людей. Типа так:

Было
// C++
void Foo() {}

// C#
void Main() {}

Стало
// C++
__declspec(dllexport) void Foo() {}

// C#
[DllImport("my.dll")]
public static extern void Foo();

void Main() {
  Foo();
}


Если использовать ATL, то 90% кода можно "написать" с помощью визарда в студии, как поступают джентельмены.
New => Atl Project, New => Simple Object, потом просто добавить к нему методы и реализации. фсё.
Но это в десятки раз больше неочевидного кода, и просто горы синтаксического оверхеда.

Зато потом даже обезьяна сможет добавить эту библиотеку к проекту на C# кликнув мышкой на "Add Reference", и получит полный фарш с автокомплитом.
Что собственно ожидают от библиотеки нормальные люди.

Лебедю, чтобы грациозно плавать, приходится очень быстро махать лапами под водой, ничего здесь не поделаешь

Еще альтернатива — сделать промежуточную DLL-обертку на C#, в которой написать все эти корявые DllImport самому. Из которой экспортировать для C# красивые классы с методами.
Но тогда будет две DLL. Можно обернуть это в nuget пакет и опубликовать в публичном репозитории для удобства, чтобы простота использования оставалась на уровне обезьяны.

Кстати, еще один вариант — тупо переписать эту DLL написанную на C++, на C#, если она небольшая.
Функции WinAPI из C# вызываются без проблем.
Отредактировано 02.04.2021 20:34 bnk . Предыдущая версия .
Re[2]: Как проще подключить C++ DLL к приложению на C#?
От: Mr.Delphist  
Дата: 07.04.21 08:37
Оценка:
Здравствуйте, AeroSun, Вы писали:

AS>С++ dll --> C++/CLI dll --> C# dll


Плюсую за этот вариант, несколько раз пользовался. Преимущества перед классическим pinvoke:

  • все описания в одном месте, нет необходимости "не забыть поправить C#" если изменил контракт на сишной стороне
  • гораздо прозрачнее менеджмент памяти: CLI поддерживает как managed-пулы памяти, так и native, делаем на стыке двух миров все необходимые преобразования и отпускаем память если больше не надо
  • енумы — опять же, см. пункт 1, описываем в одном месте (С++) и CLI выставит его на дотнетную часть, главное в отдельный namespace не забыть обернуть — иначе не увидит, global namespace оно не экспортирует
  • все проверки — compile time
  • Re[4]: Как проще подключить C++ DLL к приложению на C#?
    От: Mr.Delphist  
    Дата: 07.04.21 08:50
    Оценка: +1
    Здравствуйте, bnk, Вы писали:

    bnk>Есть (скорее был) C++/CLI (попытка микрософта упростить твою задачу), но сейчас пациент AFAIK скорее мертв, чем жив.


    Эммм... А в чём мёртвость? Жив уж 15 лет, свои задачи исполняет на все 100%.
    Подождите ...
    Wait...
    Пока на собственное сообщение не было ответов, его можно удалить.