Согласно этому вопросу можно беспрепятственно комбинировать управляемый и неуправляемый код с использованием C ++ / CLI. Я не совсем понимаю - разве не должно быть разделения между управляемым и неуправляемым?
Например, у меня есть InnerLibrary, который скомпилирован как нативный C ++ .dll с опубликованным заголовком, и C ++ / CLI OuterLibrary, который вызывает код из внутренней библиотеки. Будет ли сортировка? Кто это осуществит и насколько это будет дорого?
Никакого маршалинга не требуется, потому что C ++ / CLI может генерировать небезопасный код, который выполняет вызов напрямую. Взгляните на код C ++ / CLI в Reflector - он будет сильно отличаться от C #.
Это то, что C # не может сделать (по крайней мере, не без ключевого слова unsafe
и некоторых хаков с указателями), а также то, что C ++ / CLI в чистом режиме не может сделать (для по той же причине, что и C #).
Небезопасный код .NET может выполнять прямые вызовы неуправляемых функций; просто эта возможность доступна только через C ++ / CLI.
Маршалинг - это процесс передачи неуправляемых данных или вызовов в управляемый мир. Это просто, так сказать, перевод между ними.
С помощью C ++ / CLI вы можете смешивать и сопоставлять. Это означает, что если вы используете свою библиотеку напрямую, используя файл * .h и используя традиционный код C ++, она будет неуправляемой и без маршалинга. Если вы обращаетесь к этим данным с помощью классов BCL или собственного управляемого кода, вы добавляете уровень маршалинга вручную, но только при необходимости. То есть LPTSTR
необходимо будет преобразовать в управляемую строку, чтобы использовать ее как единое целое. Используя C ++ / CLI, вы можете пропустить этот шаг и придерживаться традиционного кода C ++, создавая более быстрый и гибкий код за счет отказа от безопасного, проверенного управляемого кода.
Ну, это функция, встроенная в компилятор C ++ / CLI, которая называется C ++ Interop. Как вы думаете, здесь гораздо меньше черной магии. Компилятор JIT генерирует тот же машинный код, что и ваш компилятор C ++. Все типы значений .NET имеют прямой эквивалент в C ++, поэтому преобразование не требуется. Он не автоматически обрабатывает ссылочные типы, вы должны сделать это самостоятельно. pin_ptr <>, обычно.
Все, что он на самом деле , - это вводит немного кода, который обрабатывает переход от кадра управляемого стека к кадру неуправляемого стека. Этот код помещает в стек специальный «cookie», который распознается сборщиком мусора. Это предотвращает его грубое попадание в неуправляемые фреймы и неправильную идентификацию неуправляемых указателей как объектных ссылок. В этом коде не так много всего, на сборку Release требуется около 5 наносекунд, плюс-минус.
Здесь есть два момента:
1) Управляемый / неуправляемый переход кода: каждый переход имеет фиксированную стоимость. Когда код C ++ / CLI компилируется в единую сборку, компилятор пытается сделать весь код управляемым, когда это возможно, чтобы минимизировать такие переходы. При вызове внешней неуправляемой Dll из кода C ++ / CLI такая оптимизация невозможна. Поэтому рекомендуется минимизировать такие переходы, по крайней мере, в критических по времени участках. Подробнее об этом см. Здесь: http://msdn.microsoft.com/en-us/magazine/dd315414.aspx , Производительность и расположение границы взаимодействия
2) Маршаллинг параметров. Это зависит от типа параметров. Некоторые параметры не нужно упорядочивать, например, простые типы, такие как int. Строки должны быть выстроены. Некоторые приемы, такие как закрепление указателей, позволяют предотвратить маршалинг массива простых типов.
Это зависит от типов данных.
Внутренние типы, такие как int
, double
и так далее (string
не подходит), имеют одинаковое представление как в родном, так и в управляемом коде, маршалинг не требуется. Массивы внутренних типов также размещаются одинаково (если игнорировать метаданные, которые хранит .NET, но они отделены от содержимого массива).
Типы значений, использующие явные атрибуты компоновки, где все члены являются неотъемлемыми типами, также совместимы с компоновкой памяти.
Если данные хранятся в объекте на управляемой куче, может потребоваться пиннинг (это справедливо для всех массивов).
Типы классов, с другой стороны, должны быть преобразованы/переведены туда и обратно.
Маршаллинг присутствует, но вы (т.е. программист) должны сделать это явно.
Если ваша внешняя библиотека C++CLI вызывает функцию, которая принимает System.String
/System::String^
, система типов C++ требует, чтобы вы выполнили преобразование типа перед передачей ее в функцию внутренней библиотеки, которая принимает const char*
. Вы должны выполнить преобразование самостоятельно - это и есть маршаллинг.
Microsoft поставляет нечто под названием C++ Support Library, которая предоставляет функции, помогающие взаимодействию C++ <-> C++CLI.