На этом шаге мы приведем программу, реализующую указанное преобразование.
Тип wchar_t - это native-тип символа по таблице Юникода. Этот тип данного отличается от типа char тем, что символ кодируется двумя байтами, а не одним. Класс String тоже создает строку из Юникод-символов, однако по своему определению относится к managed-типу.
Преобразование, которое мы рассматриваем, фактически переводит Юникод-строку из состояния managed в состояние native. А в этом состоянии со строкой уже можно работать, применяя обычный указатель *. Юникод-тексты можно вводить в файлы и читать из них соответственно функциями fputws() и fgetws.
Текст программы приведен ниже, а результат - на рисунке 1.
// 214_1.cpp: главный файл проекта. #include "stdafx.h" #include <stdio.h> //для printf() #include <conio.h> //для _getch() #include <vcclr.h> //для PtrToStringChars() using namespace System; using namespace System::Runtime::InteropServices; #pragma unmanaged void NativeTakesAString(const wchar_t* p) { printf("(native) recieved '%S'\n", p); } #pragma managed void main() { String^ s = gcnew String("test string"); pin_ptr<const wchar_t> str = PtrToStringChars(s); // метод размещает s в управляемой куче и выдает // native-указатель типа _const_Char_ptr на // размещенный объект. Этот указатель с помощью оператора // [cli::]pin_ptr<cv_qualifier type> var = ^initializer; // преобразуется в тип const wchar_t. // Здесь: // cv_qualifier - квалификатор const или квалификатор volatile. // Квалификатор volatile показывает, что поле может // модифицироваться многочисленными средами, выполняющимися в // данный момент, и все изменения данного поля будут // присутствовать в этом поле. Указатель типа pin_ptr по // умолчанию имеет квалификатор volatile, поэтому в операторе // применен квалификатор const, чтобы объект в куче не изменял // своего значения, а не только место расположения. // initializer - это ссылочный тип данного: элемент // managed-массива или любого другого объекта, которому // вы назначаете native-указатель. // Метод PtrToStringChars() как раз и выдает такой указатель: // native-указатель в управляемой (managed) куче. // type - тип initializer'а. В нашем случае это wchar_t // var - это имя pin_ptr указателя. В нашем случае это // str. Т.е. str - это уже native-указатель String в // управляемой куче. Console::WriteLine("(managed) passing string to native func..."); // вывод сообщения из managed-функции NativeTakesAString( str ); // вызов native-функции, которая выдаст native-сообщение _getch(); }
Рис.1. Результат преобразования Юникод-строки в native-строку
Здесь применен указатель pin_ptr (указатель от зашкаливания, как определяют его авторы). Это внутренний указатель, который оберегает объект (на который он указывает) от какого-либо перемещения в управляемой куче (памяти, с которой работает режим CLR): значение указателя не изменяется средой CLR. Такое условие необходимо при передаче адреса managed-объекта native-функции, потому что этот адрес не должен меняться во время вызова native-функции.
На следующем шаге мы приведем пример программы, выполняющей преобразование строки wchar_t в строку String^.