Маршалинг данных между управляемым и неуправляемым кодом - Копирование и фиксация

ОГЛАВЛЕНИЕ


Копирование и фиксация

При выполнении маршалинга в среде CLR есть два пути развития событий: копирование и фиксация (см. статью msdn2.microsoft.com/23acw07k).

По умолчанию среда CLR создает копию, которая используется во время выполнения маршалинга. Например, если управляемый код передает строку ANSI C в неуправляемый код, среда CLR создает копию строки, преобразует ее в ANSI и передает временный указатель в неуправляемый код. Такое копирование может занимать довольно долгое время и негативно сказываться на производительности.

В некоторых случаях среда CLR может оптимизировать процесс маршалинга: она напрямую фиксирует управляемый объект в куче сборщика мусора, чтобы он (объект) не был перемещен во время выполнения вызова. Указатель на управляемый объект (или какой-то его фрагмент) передается непосредственно в неуправляемый код.

Фиксация проводится только при выполнении всех перечисленных ниже условий. Во-первых, вызов должен осуществляться из управляемого кода в машинный код, а не наоборот. Во-вторых, тип, участвующий в маршалинге, должен быть преобразуемым (или допускать преобразование при определенных условиях). В-третьих, передача не должна осуществляться по ссылке (то есть с использованием ключевых слов out и ref), и в-четвертых, вызывающая и вызываемая сторона должны находиться в одном контексте потока или в одном контейнере.

Второе правило следует оговорить особо. Преобразуемый тип — это тип, для которого есть представитель и в управляемом, и в неуправляемом коде. Преобразуемые типы никакого дополнительного преобразования во время маршалинга не требуют. Типичным примером непреобразуемого типа, допускающего преобразование в определенных условиях, является символьный тип. Изначально он не является преобразуемым, поскольку не может быть сопоставлен ни Юникоду, ни ANSI, однако, поскольку в среде CLR для символьного типа всегда используется Юникод, он становится преобразуемым, если указать [DllImportAttribute(CharSet= Unicode)] или [MarshalAsAttribute(UnmanagedType.LPWSTR)]. В следующем примере объект arg в функции PassUnicodeString может быть зафиксирован, а в функции PassAnsiString — не может.

[DllImport(@"MarshalLib.dll", CharSet = CharSet.Unicode)]
public static extern string PassUnicodeString(string arg);

[DllImport(@"MarshalLib.dll", CharSet = CharSet.Ansi)]
public static extern string PassAnsiString(string arg);