Вот кусок из письма, которое я получил от Ken:
Привет, Майкл.Постоянные читатели могут вспомнить, почему я не люблю локаль потока.
Я встретился с чем-то, что, как я считаю, является багом вMultibyteToWideChar
иWideCharToMultibyte
, когда параметр кодовой страницы устанавливается вCP_THREAD_ACP
, 'язык по-умолчанию для не-Unicode приложений' - установленный в иврит. Это видно, когда используется вспомогательный макрос изatlconv.h
вродеT2WC
.
Я создал простое тестовое приложение, которое показывает неожиданные результаты на некоторых системах. Кодовая страница отCP_THREAD_ACP
получается не той же самой, чтоGetACP
. Я воспроизвёл это на двух системах с ивритом, но не на системах, где стоит традиционный китайский - одна из которым имеет полностью локализированный в традиционном китайском UI. Исходник является частью консольного проекта .NET 2003 по умолчанию.#include "stdafx.h" #include <ostream> int _tmain(int argc, _TCHAR* argv[]) { std::cout << "default code page is " << GetACP() << std::endl; std::cout << "_AtlGetConversionACP code page is " << ATL::_AtlGetConversionACP() << std::endl; CPINFOEX cpinfo = {}; GetCPInfoEx(ATL::_AtlGetConversionACP(), 0, &cpinfo); std::cout << "Thread code page is " << cpinfo.CodePage << std::endl; return 0; }Мои результаты:default code page is 1255 _AtlGetConversionACP code page is 3 Thread code page is 1252Когда моё приложение вызываетT2WC
, оно получает неверный результаты, а кодовые точки расширяются до 16-ти бит, но не конвертируются в кодовые точки иврита. Мы обходим это использованием_CONVERSION_DONT_USE_THREAD_LOCALE
, но мне любопытно, сталкивался ли кто-то ещё с этой проблемой ранее.
Спасибо за потраченное на меня время,
Ken
(Фактически, меня не так давно попросили помочь вычистить несколько плохих случаев использования локали потока в различных частях Windows в
shell32.dll
и shlwapi.dll
- наверное, скоро я за это засяду!)В любом случае, после того как Ken указал, что использование
_CONVERSION_DONT_USE_THREAD_LOCALE
решает проблему, становится довольно очевидно, что CP_THREAD_ACP
есть ни что иное, как LOCALE_IDEFAULTANSICODEPAGE
, возвращаемая GetLocaleInfo
, когда ей передают GetThreadLocale
в качестве LCID.Теперь, кодовая страница потока - довольно шаткая вещь, и не только по той причине, что заставляет меня чувствовать, как воняет локаль потока. Представьте преобразование кодовой страницы, основанное на том, что может в любой момент поменять любой код, работающей в потоке. Фу!
В самом деле, особенно противно, что ATL и MFC сделали корневое изменения в версии 7.0 в этой области (как описано здесь):
Преобразования строкФу. Я ненавижу настолько плохие изменения. И это определённо такой случай :-(
В версиях ATL до и включая ATL 3.0 в Visual C++ 6.0 строковые преобразования с использованием макросов вatlconv.h
всегда выполнялись, используя кодовую страницу ANSI системы (CP_ACP). Начиная с ATL 7.0 в Visual C++ .NET, строковые преобразования выполняются с использованием кодовой страницы ANSI текущего потока, если только не указана_CONVERSION_DONT_USE_THREAD_LOCALE
. В последнем случае используется кодовая страница ANSI системы, как и ранее.
Заметьте, что классы преобразования строк, вродеCW2AEX
, позволяют вам передавать кодовую страницу, используемую для преобразования, в их конструкторах. Если кодовая страница не указана, то класс использует ту же кодовую страницу, что и макрос.
Для дальнейшей информации см. макросы конвертации строк ATL и MFC.
Извини, Ken - эти странные различия являются результатом (плохого) дизайна. И твой обходной путь, фактически, является исправлением.
В конечном итоге, мой совет - НИКОГДА не использовать ни локаль потока, ни кодовую страницу потока, для чего бы то ни было. Никогда...
This post brought to you by װ (U+05f0, a.k.a. HEBREW LIGATURE YIDDISH DOUBLE VAV)
Комментариев нет:
Отправить комментарий
Можно использовать некоторые HTML-теги, например:
<b>Жирный</b>
<i>Курсив</i>
<a href="http://www.example.com/">Ссылка</a>
Вам необязательно регистрироваться для комментирования - для этого просто выберите из списка "Анонимный" (для анонимного комментария) или "Имя/URL" (для указания вашего имени и ссылки на сайт). Все прочие варианты потребуют от вас входа в вашу учётку.
Пожалуйста, по возможности используйте "Имя/URL" вместо "Анонимный". URL можно просто не указывать.
Ваше сообщение может быть помечено как спам спам-фильтром - не волнуйтесь, оно появится после проверки администратором.
Примечание. Отправлять комментарии могут только участники этого блога.