Версия для печати темы
Нажмите сюда для просмотра этой темы в оригинальном формате
Форум программистов > C/C++: Системное программирование и WinAPI > Как правильно определить кодовую страницу


Автор: vns955 1.6.2009, 19:33
Всем зрям!

Мне нужно определить текущую кодовую страницу и передать ее в setlocale(). Т.е чтоб такой код работал:

Код

   setlocale(LC_ALL, ".866");
   std::wcout.imbue(std::locale(".866"));

   wstring sStr = _T("Привет Мир");
   wcout << sStr << endl;

Это для руского языка, но если у меня например текущей будет немецкая кодовая то она должна как-то определиться из системы и быть передана в ф-ции setlocale() и imbue() и вывод на немецком должен корректно отображаться в консольном приложении. Вопрос: как правильно определить кодовую страницу которую надо подставить в упомянутые ф-ции? Использование ф-ций GetConsoleCP(), GetACP() и GetOEMCP() не увелчалось успехом. :(
Использую VS2003, стоит в настройках: Unicode character Set,   (/Zc:wchar_t),  (/Zc:forScope) в Language.

Спасибо


Автор: 586 1.6.2009, 19:54
Код
#include <stdio.h>
#include <locale.h>

int main(int argc, char* argv[])
{
   setlocale(LC_ALL, "");   // кодировка по умолчанию
   wprintf(L"Привет мир!\n");
    return 0;
}

Автор: GremlinProg 1.6.2009, 19:55
GetSystemDefaultLCID дает локаль принятую в системе
GetUserDefaultLCID дает локаль принятую для текущего пользователя

GetLocaleInfoEx - это общий метод, позволяющий извлекать разные данные локали по ее идентификатору,
например: язык, страна, страница OEM, ACP и т.п.

GetSystemDefaultLocaleName
GetUserDefaultLocaleName - тут все аналогично с первыми двумя, только вместо локали возвращается ее имя (частный случай функции GetLocaleInfo)

Автор: vns955 1.6.2009, 23:10
Пробовал подставлять то что возвращают ф-ции GetSystemDefaultLCID() и GetUserDefaultLCID() - не получилось :(

Автор: GremlinProg 1.6.2009, 23:36
Цитата(vns955 @  2.6.2009,  01:10 Найти цитируемый пост)
Пробовал подставлять то что возвращают ф-ции GetSystemDefaultLCID() и GetUserDefaultLCID() - не получилось :(

это поставлять в setlocale и не нужно,
но можно подставлять строковые: GetSystemDefaultLocaleName, GetUserDefaultLocaleName,
а GetSystemDefaultLCID() и GetUserDefaultLCID() можно подставлять в GetLocaleInfoEx, чтобы извлечь информацию

если нужна кодовая страница, как в примере, типа setlocale(LC_ALL, ".866"), то для этого есть несколько флагов к GetLocaleInfoEx:
LOCALE_IDEFAULTANSICODEPAGE - это флаг для получения ANSI-кодировки для заданной локали
LOCALE_IDEFAULTCODEPAGE  - это флаг для получения OEM-кодировки для заданной локали
только из GetLocaleInfoEx при этом вернется просто номер страницы, без точки, так что тут перед подстановкой в setlocale надо дополнительно формировать строку из этого номера (не помню только в бинарном виде или в строковом)

либо использовать просто флаг LOCALE_SENGLANGUAGE - язык локали по английски, т.е. соответственно:
для GetSystemDefaultLCID - язык, принятый в системе
для GetUserDefaultLCID - язык, принятый для пользователя

Добавлено через 14 минут и 39 секунд
Цитата(GremlinProg @  2.6.2009,  01:36 Найти цитируемый пост)
не помню только в бинарном виде или в строковом

по идее, можно и так и так, есть флаг LOCALE_RETURN_NUMBER, правда я не нашел его в http://msdn.microsoft.com/en-us/library/ms906223.aspx

Автор: GremlinProg 1.6.2009, 23:55
а, все понял, смотрел в CE, вот верная ссылка: http://msdn.microsoft.com/en-us/library/dd464799(VS.85).aspx

Автор: vns955 2.6.2009, 13:02
GetLocaleInfoEx() поддерживает минимум Windows Server 2008, а я программирую под Server 2003. Можно ли обойтись без этой ф-ции?

Автор: GremlinProg 2.6.2009, 13:31
Цитата(vns955 @  2.6.2009,  15:02 Найти цитируемый пост)
GetLocaleInfoEx() поддерживает минимум Windows Server 2008

вообще-то она даже в XP присутствует,
я ее использовал без проблем,

но если есть сомнения, используй просто GetLocaleInfo

Цитата(GetLocaleInfo @ MSDN)

Requirements
  Windows NT/2000/XP/Vista: Included in Windows Vista and later.
  Windows 95/98/Me: Unsupported.
  Header: Declared in Winnls.h; include Windows.h.
  Library: Use Kernel32.lib.


Цитата(GetLocaleInfoEx @ MSDN)

Requirements
  Windows NT/2000/XP/Vista: Included in Windows Vista and later.
  Windows 95/98/Me: Unsupported.
  Header: Declared in Winnls.h; include Windows.h.
  Library: Use Kernel32.lib.


в онлайне:

Цитата(GetLocaleInfo @ MSDN(online))

Requirements
Minimum supported client    Windows 2000 Professional
Minimum supported server    Windows 2000 Server
Header    Winnls.h (include Windows.h)
Library    Kernel32.lib
DLL    Kernel32.dll
Unicode and ANSI names    GetLocaleInfoW (Unicode) and GetLocaleInfoA (ANSI)

Цитата(GetLocaleInfoEx @ MSDN(online))

Requirements
Minimum supported client    Windows Vista
Minimum supported server    Windows Server 2008
Header    Winnls.h (include Windows.h)
Library    Kernel32.lib
DLL    Kernel32.dll


Добавлено через 2 минуты и 38 секунд
Цитата(GremlinProg @  2.6.2009,  15:31 Найти цитируемый пост)
вообще-то она даже в XP присутствует,

а, нет, перепутал
все верно - доступна только GetLocaleInfo

Автор: vns955 2.6.2009, 15:41
Ну я пробовал использовать GetLocaleInfo() с флагом LOCALE_IDEFAULTCODEPAGE, она вернула 850. Я это значение подставил в setlocale() только с точкой т.е ".850" и то же самое :(.  Мне кажется что не этом дело - пробовал я различные значения, нужно наверное копать в другую сторону.

Автор: GremlinProg 2.6.2009, 17:08
Цитата(vns955 @  2.6.2009,  17:41 Найти цитируемый пост)
Ну я пробовал использовать GetLocaleInfo() с флагом LOCALE_IDEFAULTCODEPAGE, она вернула 850. Я это значение подставил в setlocale() только с точкой т.е ".850" и то же самое

как так-то?
Код

    int buffer    = 0;
    ::GetLocaleInfo(
        ::GetUserDefaultLCID(),
        LOCALE_RETURN_NUMBER | LOCALE_IDEFAULTANSICODEPAGE,
        (LPTSTR)&buffer,
        sizeof(buffer)
    );

Код

buffer == 1251

Код

    int buffer    = 0;
    ::GetLocaleInfo(
        ::GetUserDefaultLCID(),
        LOCALE_RETURN_NUMBER | LOCALE_IDEFAULTCODEPAGE,
        (LPTSTR)&buffer,
        sizeof(buffer)
    );

Код

buffer == 866

Автор: GremlinProg 2.6.2009, 17:26
уэльский:
Код

    int oem = 0,ansi = 0;
    LCID lcid    = MAKELCID( MAKELANGID(LANG_WELSH,SUBLANG_WELSH_UNITED_KINGDOM), SORT_DEFAULT);
    ::GetLocaleInfo(lcid,LOCALE_RETURN_NUMBER | LOCALE_IDEFAULTANSICODEPAGE,(LPTSTR)&ansi,sizeof(ansi));
    ::GetLocaleInfo(lcid,LOCALE_RETURN_NUMBER | LOCALE_IDEFAULTCODEPAGE,(LPTSTR)&oem,sizeof(oem));

Код

oem = 850
ansi = 1252

чешский:
Код

    int oem = 0,ansi = 0;
    LCID lcid    = MAKELCID( MAKELANGID(LANG_CZECH,SUBLANG_CZECH_CZECH_REPUBLIC), SORT_DEFAULT);
    ::GetLocaleInfo(lcid,LOCALE_RETURN_NUMBER | LOCALE_IDEFAULTANSICODEPAGE,(LPTSTR)&ansi,sizeof(ansi));
    ::GetLocaleInfo(lcid,LOCALE_RETURN_NUMBER | LOCALE_IDEFAULTCODEPAGE,(LPTSTR)&oem,sizeof(oem));

Код

oem = 852
ansi = 1250


Автор: vns955 2.6.2009, 17:31
Ну да, именно так если использовать такие ф-ции как у Вас, но я юзал GetSystemDefaultLCID() для затравки, поэтому получил другие значения, но это ничего не меняет - все равно не выводит правильно :(

Автор: GremlinProg 2.6.2009, 17:44
с GetSystemDefaultLCID аналогично (у меня они равны)

vns955, я так полагаю, у тебя просто операционка на русскую локаль не настроена (смотри панель управления, язык и рег. стандарты и т.д.)

Автор: vns955 2.6.2009, 19:29
Проблема не в том чтоб русские символы выводить а чтоб правильно выводить другие, вот такой код неправильно выводит немецкие символы:

Код

   setlocale(LC_ALL, ".850");
   std::wcout.imbue(std::locale(".850"));
    //SetConsoleCP(lcid);

   wstring sStr = _T("Qualitätsprüfung");
   wcout << sStr.c_str() << endl;

Немецкий в системе установлен, установлено чтоб использавать этот язык для не юникод символов. Far и Total Commander корректно отображает немецкие папки - русские нет, а если я установлю по-умолчанию русский - будет наоборот. Так вот мне надо чтоб моя прога работала так же :(

Автор: GremlinProg 2.6.2009, 19:58
Цитата(vns955 @  2.6.2009,  21:29 Найти цитируемый пост)
 вот такой код неправильно выводит немецкие символы

перед setlocale попробуй поставить SetThreadLocale( lcid )

Автор: vns955 3.6.2009, 12:46
Не работает :(. А Вы так делали и работало?

Автор: GremlinProg 3.6.2009, 12:58
нет, не пробовал,
просто это единственная функция в API, которая позволяет сменить  языковые стандарты в текщем потоке

как еще один вариант - поэкспериментировать с CharToOem, совместно с SetThreadLocale
не очень удобно, но надо хотя бы один рабочий вариант иметь (и мне кажется, тут локаль CRT желательно вообще не использовать, т.е. без setlocale, только API, чтобы не мешали они друг-другу)

Добавлено через 1 минуту и 29 секунд
по крайней мере до получения каких-либо вменяемых результатов

Powered by Invision Power Board (http://www.invisionboard.com)
© Invision Power Services (http://www.invisionpower.com)