Вызов управляемого кода из неуправляемого и обратный вызов
Несмотря на ограничения, описанные в предыдущем разделе, есть несколько способов сотрудничества управляемого и неуправляемого кодов даже в пределах одного исходного файла. Например, приведенная ниже программа демонстрирует, что управляемый код может вызывать неуправляемый.
Заметим, что можно передать указатель на элемент данных управляемого класса в качестве параметра методу неуправляемого объекта. Это оказалось возможным благодаря объявлению указателя на управляемый объект с использованием ключевого слова _pin (закрепить). Ключевое слово _pin (закрепить) закрепляет управляемый объект в памяти, запрещая его перемещение в то время, когда неуправляемый код обрабатывает данные.
После запуска программы CallingFromManagedToUnmanaged на консоли вы увидите значения 0 и 1, это значит, что метод UnmanagedClassMethod успешно работает с переданным ему закрепленным управляемым объектом. Если из программы удалить ключевое слово _pin (закрепить), при компиляции обнаружится ошибка. В сообщении будет указано, что параметр, переданный в UnmanagedClassMethod нельзя преобразовать из int _gc * (который участвует в сборке мусора) Bint *.
//CallingFromManagedToUnmanaged.cpp fusing <mscorlib.dll> using namespace System; // использование пространства имен Система; Jpragma managed // pragma управляемый _gc class ManagedClass // класс сборщика мусора ManagedClass – управляемый класс { public: int x; }; tpragma unmanaged // pragma неуправляемый _nogc class UnmanagedClass // класс UnmanagedClass – неуправляемый класс { public: void UnmanagedClassMethod(int *px) { // px указывает на элемент данных х управляемого объекта //но этот объект закреплен, поэтому неуправляемый код // может безопасно обратиться к элементу данных х *рх = 1; // изменяет значение, чтобы доказать, // что это работало } }; ipragma managed // pragma управляемый void main(void) { ManagedClass _pin *pmcObj = new ManagedClass(); UnmanagedClass *pumcObj = new UnmanagedClass(); pmcObj › x = 0; Console::WriteLine(pmcObj › x); // до: 0 // передать элемент данных управляемого объекта // неуправляемому коду pumcObj › UnmanagedClassMethod(&pmcObj › x); Console::WriteLine(pmcObj › x); // после: 1 }
Противоположный случай рассмотрен в программе CallingFromUnmanaged-ToManaged. Обратим внимание, что неуправляемый код в главной функции main вызывает управляемую функцию ManagedFunction, которая создает экземпляр управляемого класса ManagedClass и вызывает его метод ManagedClassMethod. К сожалению, неуправляемый код в главной функции main не может непосредственно создать экземпляр класса ManagedClass, так как в неуправляемом коде невозможно обратиться напрямую ни к какому управляемому типу.
В этом можно убедиться, раскомментировав последний оператор, в котором создавался бы экземпляр класса ManagedClass. Но здесь компилятор обнаружит ошибку: в неуправляемой функции нельзя объявлять управляемый объект или указатель. Однако в данном примере мы видим, что управляемый код в функции ManagedFunction может создать экземпляр неуправляемого типа UnmanagedClass и передать его в качестве параметра в управляемый метод ManagedClassMethod. Итак, рассмотрим еще один способ взаимодействия управляемого и неуправляемого кода.
//CallingFromUnmanagedToManaged.cpp #using <mscorlib.dll> using namespace System; // использование пространства имен Система; #pragma unmanaged // pragma неуправляемый _nogc class UnmanagedClass // класс UnmanagedClass – неуправляемый класс { public: int x; }; #pragma managed // pragma управляемый _gc class ManagedClass // класс сборщика мусора ManagedClass – управляемый класс { public: void ManagedClassMethod(UnmanagedClass *pumcObject) { // pumcObject указывает на неуправляемый объект pumcObject › x =1; // изменяет значение, чтобы доказать, // что это работало } }; void ManagedFunction() { ManagedClass *pmcObj = new ManagedClass(); UnmanagedClass *pumcObj = new UnmanagedClass(); pumcObj › x = 0; Console::WriteLine(pumcObj › x); //до: О pmcObj › ManagedClassMethod(pumcObj); Console::WriteLine(pumcObj › x); //после: 1 } Ipragma unmanaged // pragma неуправляемый void main(void) { ManagedFunction(}; //вызов управляемого из неуправляемого //ManagedClass *pmcObj = new ManagedClass(); // ошибка }