Домашняя страница Интеграция Native кода в C# проект
Публикация
Отменить

Интеграция Native кода в C# проект

Сегодня стала очень популярной платформа .Net Framework и язык C#. На ней пишутся приложения, игры, инструменты. Однако существует много кода написанного на C++, который часто нужно использовать в C# проектах.

Это могут быть математические библиотеки, код оставшийся от прошлых проектов или другой проект, написанный на C++ для которого нужно сделать графический интерфейс.

В этой статье речь пойдет о том, как интегрировать Native код в C# проект и успешно его развивать. В качестве IDE будет использоваться Microsoft Visual Studio.

Настройка проектов

На прямую вызывать C++ код из C# нельзя. Так же нельзя подключить к C# проекту native проект. Поэтому нам понадобится дополнительная прослойка - Managed C++ проект. Этот проект создаст Managed dll, которая будет затем подключена в основное приложение. Смысл этого проекта в том, что он может содержать как managed код так unmanaged код, т.е. код на обычном C++. Более того, он может подключать обычный native проект и использовать его код.

Рассмотрим интеграцию C++ проекта в C# проект на простом примере. Создадим солюшен с Windows Forms проектом. Это будет наше приложение. Нам нужно подключить к нему native проект.

Для начала подключим его к салюшену и укажем чтобы он собирался как Static library. Это можно указать в настройках проекта.

Как уже было сказано, мы не можем напрямую использовать этот код в нашем приложении. Поэтому создадим дополнительный проект, который будет связующим звеном. Создаем его обычными средствами, как простой C++ проект.

При создании проекта указываем, чтобы его код компилировался в dll. Кроме того указываем, чтобы это был пустой проект.

После создания проекта нужно указать что это managed проект. Для этого в его настройках нужно выбрать параметр /crt. Именно этот флаг скажет компилятору, что нужно сделать managed сборку.

В этот проект можно подключать другие managed сборки. Их нужно указать в разделе Reference. В разделе Project Dependencies… выберите native проект, который мы подключили раньше.

Ну и не забудьте подключить Managed C++ проект к C# проекту через Reference. Настройка проекта завершена. Теперь вы можете написать код на Managed C++, который будет использовать С++ код напрямую. Это будет обертка управляемого кода, которую можно будет использовать в C#.

Использование native кода в Managed C++

Класс написанный на Managed C++ может напрямую использовать С++ код. Экземпляр управляемого класса может содержать указатель на не управляемый класс.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
// C++
public class Foo
{
public:
  void  Do();
}

// Managed C++
public ref FooWrapper
{
public:
      FooWrapper()
      {
           m_class = new Foo();
      }
      void Shutdown()
      {
           delete( m_class );
      }

      void Do()
      {
           m_class->Do();
      }
private:
      Foo*     m_class;
}
1
2
3
4
// C#
FooWrapper foo = new FooWrapper();
foo.Do();
foo.Shutdown();

Не забывайте следить за освобождением выделенной памяти. В неуправляемом коде управление памятью ложится на программиста.

Совет: Не стоит делать обертки для всех native классов. Значительно лучше выносить только высоко-уровневые функции, чтобы инкапсулировать всю функциональность в native коде.

Например если это библиотека, которая проводит какие то расчеты и выдает результат, то все это можно оформить в статическую функцию класса.

1
2
3
4
5
6
7
8
9
10
11
// Managed C++
public ref FooWrapper
{
public:
      static void Do()
      {
           m_class = new Foo();
           m_class->Do();
           delete( m_class );
      }
}
1
2
// C#
FooWrapper.Do();

Отладка

Одной из проблем при разработке приложений является их отладка. По умолчанию нет возможности при отладке спускаться по стеку в native код. Однако можно включить в настройках проекта опцию Enable unmanaged code debugging и при отладке можно будет остановить приложение с просматривать callstack от native кода.

Однако это приведет к некоторому снижению производительности, поэтому имеет смысл создать дополнительную build-конфигурацию и собирать ее в тот момент когда нужно дебажить native код.

Публикация защищена лицензией CC BY 4.0 .