Страницы кодировки: ликбез

Материал из TCKB 2.0
Перейти к:навигация, поиск

Для тех, кто любит во всём разбираться, ниже приведено описание трюка с подменой страниц кодировки: почему он работает, почему без него не работает, и чем всё это грозит.

Ядро систем WinNT (на котором построены собственно Windows NT, 2000, XP, 2003 и Vista) основано на 16-битном наборе символов - UTF-16 (часто называемом просто юникодом, хотя это и не совсем корректно). Все операции в системе выполняются с этими 16-битными строками, что позволяет работать в мультиязычной среде без малейших проблем. Одна программа может сочетать в себе названия кнопок и пунктов меню сразу на нескольких языках, что было невозможно при использовании 8-битных (ANSI) строк. Восемью битами можно закодировать лишь 256 различных символов - очевидно, что этого для многоязычности катастрофически мало, невозможно закодировать таким количеством символов все необходимые буквы всех языков. 16 же бит позволяют кодировать 65536 символов, и этого уже вполне достаточно.

Системы Windows прошлого поколения, основанные на ядре Win9x (версии 95, 98, ME), работали с 8-битной кодировкой, и, соответственно, все приложения создавались для работы с ней же. Для поддержки разных языков было введено понятие кодовая страница. Каждая кодовая страница определяла, какие конкретно символы будут находиться в числе тех самых 256 возможных (а точнее - 128 символов, поскольку первые 128 изначально зарезервированы стандартом под латинский алфавит, цифры, символы пунктуации и пр.). Стоит отметить, что кодовая страница - это именно поддержка символов, а не языка. То есть, если несколько языков могут использовать один и тот же набор символов, им присваивается одна общая кодовая страница. Например, у русского, украинского и белорусского языков общая кодовая страница - 1251, у английского, немецкого, французского и многих других - 1252, и т.д. В системных настройках в Win9x выбиралась кодовая страница - одна на всех - и всё работало с соответствующим набором символов.

Разумеется, с появлением WinNT все существующие разработки нельзя было просто взять и выбросить только из-за того, что они не поддерживают юникод - никто бы просто не перешёл на эту новую систему. Поэтому в WinNT решили реализовать поддержку программ, работающих с 8-битными строками. Но как это сделать? Очень просто: для каждого системного вызова делается два варианта: юникодный и ANSI. Первый работает непосредственно с системой, а второй предварительно перекодирует 8-битную строку в 16-битную, после чего передаёт эту строку юникодной версии системной функции. Кодовая страница теперь используется для этого преобразования. Понятно, что если текст, написанный в русской кодовой странице, сконвертировать в юникод, применяя какую-нибудь другую кодовую страницу, то получится абракабадра: ведь на месте русских символов окажутся символы другого языка. Вот мы и подошли, наконец, к главному вопросу: почему некоторые программы копируют в буфер белиберду.

Копирование в буфер - это обычный системный вызов. А значит, перед помещением текста в буфер система преобразовывает его в 16-битную кодировку, если это требуется. Самое главное здесь - правильно выбрать кодовую страницу. И что же делает многомудрая Windows? Она не находит ничего умнее, как взять кодовую страницу, соответствующую текущей раскладке клавиатуры! Таким образом, если в момент копирования текста включена английская раскладка, система ничтоже сумняшеся переводит текст, используя английскую кодовую страницу, которая к русскому языку не имеет ни малейшего отношения. Что оказывается при этом в буфере обмена, думаю, описывать не надо.

Что же делать? Материть Билла Гейтса - это, конечно, святое, но, увы, это не поможет. Варианта два. Первый - каждый раз перед копированием русского текста переключаться на русскую раскладку. Возможно, кому-то этот вариант подойдёт. Если же нет - остаётся второй способ: убедить Windows, что английская кодовая страница (1252) и русская (1251) - одно и то же. Именно это делает приведённая ниже замена ключа в реестре:

Windows Registry Editor Version 5.00

[HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Nls\CodePage]
"1252"="c_1251.nls"

Данный патч указывает Windows, что трансляция 8-битных строк в 16-битные в 1252 кодовой странице должна производиться с использованием файла c_1251.nls, который, как легко догадаться, описывает 1251 кодовую страницу. В результате, даже если включена английская раскладка, преобразование русскоязычной строки в 16-битный формат пройдёт корректно, и в буфере окажется правильный текст.

Казалось бы - используй этот патч и радуйся жизни. Но увы, не всё так просто. Во-первых, применив этот патч, вы лишаете себя возможности полноценно работать с оригинальной 1252 кодовой страницей. Нельзя будет системными вызовами перекодировать, например, немецкую строку из 8 бит в 16: ведь немецкий язык использует ту же самую 1252 кодовую страницу. Другая проблема: представьте, что вы создали русскоязычный текст в программе типа MS Word, не поддерживающей юникод, и при этом была включена английская раскладка. При сохранении программа пишет в файл, что кодовая страница английская. Всё работает корректно, пока этот файл используется на компьютере с переопределённой кодовой страницей. Но стоит его открыть на другом компьютере, где этот патч не был применён, весь русский текст, помеченный как английский, сразу отобразится кракозябрами - ведь на том компьютере для его преобразования будет использоваться "настоящая" 1252 кодовая страница.

Описанные здесь проблемы показывают, что, к сожалению, универсального решения не существует. Любое из них имеет как плюсы, так и минусы. И решать, какой вариант решения проблемы удобнее, каждый должен сам для себя.

Думайте сами, решайте сами
Иметь или не иметь.

© "Ирония судьбы" ;-)

Константин Власов