вторник, 14 декабря 2010 г.

Почему я считаю, что локаль потока действительно воняет

Это перевод Why I think the thread locale really stinks. Автор: Майкл Каплан.

Я не люблю локаль потока (thread locale).

Да, GetThreadLocale и SetThreadLocale являются двумя из многих NLS функций, которыми владеет команда GIFT.

И да, если вы посмотрите на функции, которыми мы владеем, как если бы они были нашими детьми, то нам следовало бы любить их всех.

В таком случае я думаю, что из меня никудышный родитель (если вы помните, я также считаю, что SetLocaleInfo - тоже отстой).

Во-первых, тут есть странные зависимости между USER32 и SHELL32, которые, вероятно, должны использовать локаль пользователя, но вместо этого они используют локаль потока и откатываются к системной локали, если что-то пойдёт не так.

Во-вторых, вот печальная история в GetThreadLocale:
Возвращаемое значение
Функция возвращает системную локаль пользователя по умолчанию.

Примечания
Когда создаётся поток, он использует системную локаль пользователя по умолчанию. Система читает эту настройку из реестра, когда система стартует. Эта настройка может быть изменена в дальнейшем, используя соответствующий апплет Панели управления.
Поскольку она всегда возвращает локаль потока, которая начинает свою жизнь как локаль прользователя (установленная в региональных настройках), но может потом быть изменена вызовом SetThreadLocale, получается что обе части текста звучат довольно паршиво.

В-третьих, есть ещё худшая история в SetThreadLocale:
Возвращаемое значение
Если функция успешна, то она возвращает не нулевое значение.

Если функция заканчивается неудачно, то возвращаемое значение - ноль. Чтобы получить дополнительную информацию об ошибке, вызовите GetLastError.

Примечания
Когда создаётся поток, он использует системную локаль пользователя по умолчанию. Система читает эту настройку из реестра, когда система стартует. Эта настройка может быть изменена в дальнейшем, используя соответствующий апплет Панели управления.

Функция SetThreadLocale влияет на выбор ресурсов, которые определены с помощью LANGUAGE. Это влияет на такие функции как CreateDialog, DialogBox, LoadMenu, LoadString и FindResource, а также устанавливает кодовую страницу за CP_THREAD_ACP, но не влияет на FindResourceEx.

Windows 2000/XP: не используйте SetThreadLocale для выбора языка UI. Чтобы выбрать нужный вариант ресурса, определённый с конкретным LANGUAGE, используйте FindResourceEx.
С чего бы мне начать? Функция должна возвращать LCID при успехе - предыдущую локаль потока!, а не просто BOOL. Т.е. быть такой же, как, скажем, SetWindowLong. Ох, ну и ладно, не думаю, что это прям уж конец мира.

И снова тут есть этот глупый текст про 'системную локаль пользователя по умолчанию', которая является зверем, не обнаруженным в природе. Указание, что она читается из реестра при старте системе - враньё. Она основывается на локали пользователя. Всегда.

Затем тут идёт текст про то, как функция влияет на загрузку ресурсов - и предупрежение не использовать эту функциональность в Win2000 и выше. Поскольку она не поддерживается в Win9x, на самом деле этот текст говорит: "годится только для NT 3.1, 3.5x и 4.0". Другими словами, это предупреждение про то, что функция не полезна на современных платформах, если только вы не хотите запутать Оболочку и подсистему User странными способами. Хотя прямо это не говорится.

В-четвёртых, факт невероятной сложности загрузки ресурсов частично обусловлен этой сомнительной функциональностью. Результат не основан на локали пользователя, и не основан, по существу, на локали потока, пока вы её не измените. И в последнем случае он неожиданно будет основан на локали потока. Если только он не основан на языке UI - чему он вообще-то и должен быть равен. Я клянусь, что вам нужны шаман и доски для спиритических сеансов, чтобы узнать, какие ресурсы загружаются, если вы начнете играться с различными региональными настройками - что, в основном, происходит из-за этой странной настройки, которая колеблется между языком интерфейса пользователя и локалью пользователя: локали потока.

Старые платформы ещё хуже - там используется именно системная локаль, за исключением случаев, когда вы меняете локаль потока (даже хотя локаль потока изначально устанавливается в локаль пользователя). Я думаю, что это почти то же самое, как и в Win2000 и выше, только локаль системы заменена языком UI.

Это, кстати, (теперь, когда я об этом подумал) является первым разумным объяснением странного поведения Visual Basic <= 6.0, когда в IDE локаль пользователя является языком для загрузки ресурсов, даже хотя в скомпилированном приолжении это работать не будет - VB устанавливал локаль потока в локаль пользователя и запутывал этим миллионы VB программистов с этим никогда-ранее-полностью-не-объяснённым поведением. Боже.

В любом случае, мы документируем, что разработчики должны использовать LOCALE_USER_DEFAULT, а не GetThreadLocale, когда они пытаются уважать пользовательские настройки.

Если вы спросите меня, то мы должны рассматривать каждое место, где сейчас используется локаль потока, как баг, который нужно исправить, а не как старое поведение, с которым нужно смириться. Мы и так медленно ломали поведение в каждой новой версии, даже не объясняя почему, поскольку оно и так было неверным, так почему бы просто не остановиться и не перестать использовать эту подлую функциональность?

В конце концов, локаль потока - отстой!

This post brought to you by "ײ" (U+05f2, HEBREW LIGATURE YIDDISH DOUBLE YOD)

Комментариев нет:

Отправить комментарий

Можно использовать некоторые HTML-теги, например:

<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>

Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку (поддерживается OpenID).

Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.

Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.