Определите интерфейс на C ++, который должен быть реализован на C # и C ++
Вопрос
У меня есть интерфейс, который я определил на C ++, который теперь необходимо реализовать на C #.Каков наилучший способ сделать это?Я вообще не хочу использовать COM в своем определении интерфейса.Способ, которым я решил это прямо сейчас, заключается в том, чтобы иметь два определения интерфейса, одно на C ++ и одно на C #.Затем я предоставляю интерфейсы C # в качестве COM-сервера.Это было мое приложение, которое написано на C ++ и может вызывать C #.Могу ли я в любом случае избежать необходимости определять свою реализацию как на C ++, так и на C #?
Решение
Если вы готовы использовать C ++ / CLI для вашего управляемого кода вместо C #, то вы можете просто использовать собственное определение интерфейса C ++ непосредственно через заголовочный файл.Насколько легко это будет, будет зависеть от того, что именно есть в вашем интерфейсе - простейший случай - это то, что вы могли бы использовать из C.
Взгляните на Маркуса Хига Эксперт C ++/ CLI:.NET для программистов на Visual C ++, за много полезной информации о смешивании родного и управляемого C ++ в .NET.
Другие советы
Глоток это отличный инструмент для переноса классов C ++ на другие языки, такие как C #.
Почему вы не хотите использовать COM?
Это было бы моим предложением.COM-взаимодействие действительно хорошо работало для меня, и я использовал COM-объекты и интерфейсы в C # (просто ссылаюсь на COM-объект, и вызываемая во время выполнения оболочка создается автоматически).Аналогично, пометка класса C # как "Register для COM-взаимодействия" сработала наоборот.
Напишите интерфейс на C ++ и используйте макросы, чтобы сделать его похожим на стандартный заголовочный файл cpp в UNIX и на файл IDL в Windows (если это не сработает, вы всегда можете написать скрипт на python / ruby для генерации IDL из заголовочного файла C ++).
Скомпилируйте IDL для создания typelib.Используйте импортер TypeLib, чтобы сгенерировать определения интерфейса для C # и реализовать интерфейсы там.
Напишите интерфейс на IDL и используйте инструмент для компиляции интерфейса на целевой язык.Вы могли бы найти указания на это, изучив CORBA, который был связан с межъязыковым взаимодействием.
/Аллан
Другой подход заключается в использовании "плоского" API в стиле C.С таким же успехом вы могли бы использовать extern "C"
для предотвращения случайной перегрузки.Используйте файл DEF для явного присвоения имен экспортируемым функциям, поэтому они определенно никак не оформлены (функции C ++ "оформлены" кодировкой типов параметров в таблице экспорта).
На x86 остерегайтесь соглашений о вызовах.Вероятно, это делается для того, чтобы явно заявить об использовании __stdcall
или __cdecl
.Поскольку P /Invoke в основном используется для вызова API-интерфейсов Windows, по умолчанию используется StdCall , но C и C ++ по умолчанию используют cdecl, поскольку это поддерживает varargs .
Недавно я обновил COM-интерфейс IRapiStream
в плоском интерфейсе C, поскольку .NET, казалось, пытался преобразовать IStream в хранилище, что завершилось неудачей с ошибкой STG_E_UNIMPLEMENTEDFUNCTION
.
Вы не упоминаете, какую версию .NET вы используете, но кое-что, что сработало для меня при использовании Visual Studio .NET 2003, - это предоставление тонкой оболочки C # вокруг упрощенной реализации реального класса C ++:
public __gc class MyClass_Net {
public:
MyClass_Net()
:native_ptr_(new MyClass())
{
}
~MyClass_Net()
{
delete native_ptr_;
}
private:
MyClass __nogc *native_ptr_;
};
Очевидно, что там было бы предпочтительнее использовать Boost shared_ptr, но я никогда не мог заставить их хорошо играть с V.NET 2003...
Методы просто перенаправляют к базовым методам C ++ через указатель.Возможно, придется преобразовать аргументы метода.Например, для вызова метода C ++, который принимает строку, метод C #, вероятно, должен принимать System.String (System::String в управляемом C ++).Для этого вам пришлось бы использовать System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi() .
Одна приятная особенность этого подхода заключается в том, что, поскольку управляемый C ++ - это язык .NET, вы можете предоставлять средства доступа как свойства (__property).Вы даже можете выставлять атрибуты, очень похожие на C #.