Справочник функций

Ваш аккаунт

Войти через: 
Забыли пароль?
Регистрация
Информацию о новых материалах можно получать и без регистрации:

Почтовая рассылка

Подписчиков: -1
Последний выпуск: 19.06.2015

Неправильное отображение строк в commctrl'ах

30K
14 сентября 2007 года
red f0x
5 / / 14.09.2007
Здравствуйте, господа.

Такой занятный вопрос: есть приложение написанное на чистом WinAPI без примеси всяких MFC. Язык - С (IDE - MSVC 8). На самом деле, это фронт-энд к cli-тулзе.

Наш гуёвый фронт-энд создаёт пайп, пускает второй процесс, подсовывая ему вместо дескрипторов stdout, stdin дескрипторы на свой пайп. (Используются CreateProcess(), CreatePipe(), но думаю, это роли никакой не играет). Далее, дочерний процесс что-то пишет в свой stdout, мы это читает через наш пайп. Потом считав всё, начинаем отпарсенный уже в фронт-энде вывод дочерёнка распихивать по строкам ListView. Строки гоняем обычными RTL'евыми str*cpy(), т.к. они у нас все на английском и без какого-либо намёка на мультибайтовость.
В ListView всё, что в структурах записано обычными латинскими символами отображается самыми настоящими китайскими иероглифами. Но менюшки, тултипы для тубаров, одним словом, всё, что из файла ресурсов, отображается файно на чистом английском, как и задумано.

Суть в том, что если верить отладчику, то строки на всём пути от дочернего процесса и до ListView выглядят так, как надо (было бы странно, если бы они не выглядели нормально). А в ListView их почему-то не по-детски передёргивает на китайский. Причём передёргиваются даже цифры состоящие более чем из одного числа.

Сам не могу что-то так сходу сообразить. Может кто знает, что за грабль?

На скрине видно, что получается на следующем примере:
данные по ListView загоняем из массива типа
 
Код:
typedef struct tagPROCINFO {
    unsigned long pid;
    unsigned long ppid;         /* parent process's ID */
    signed long priority;
    unsigned long usage;
    unsigned long tc;           /* threads count */
    char name [MAX_NAME];
    char wtitle [MAX_TITLE];    /* window title */
} PROCINFO pin [MAX_PROCNR];


При том, что pin [0] = { 0, 0, 0, 0, "[System Process]", NULL } (поля структуры по очерёдности следования соответствуют колонкам в ListView). Для второго процесса pid и приоритет тоже состоят из одной цифры - отображаются нормально, далее с третьей строки в колонках "pid" и "приоритет" тоже начинается ХЗ что.

Это приложение пока ещё очень полуфабрикат, но такие косяки с отображением уже сильно смущают.

Заранее 10х.
30K
15 сентября 2007 года
red f0x
5 / / 14.09.2007
Итак, попробую ответить себе сам.

Путём некоторых более подробных поисков и лазаний по таблице символов было установлено следующее:

На самом деле, это тот самый момент, когда удобство юзера оборачивается кошмаром программера :)

Если определён деф _UNICODE, то строки интерпретируются либо как последовательности широких символов (2 байта), или если определён деф _MBCS - как мльтибайтовые последовательности. Очевидно, умные дядьки в MS, в отличие от меня не умного, предвидели это и потому в качестве слоя совместимости следует использовать вместо хедеров wchar.h || string.h хедер tchar.h. Вместо привычного char* str || char str[] - _TCHAR* str || _TCHAR str[] соответственно. Соотв вместо рутин str*() || _wcs*() следует использовать функции _tcs*(), которые являются "заглушками" и отображаются на правильные и наиболее уместные функции - str*() || _wcs*() || _mbs*() в зависимости от того, определены или нет _MBCS || _UNICODE.

Т.е., нативными типами (char) лучше не пользоваться из соображений совместимости. Можно пренебречь совместимостью и пользоваться только ANSI-строками, но при это автоматически становится практически нереальной поддержка национальных языков с письменностью на не латинской основе. В т.ч. русского в UNICODE.
Моя ошибка в том, что был определён _UNICODE, но все строки в тексте - ANSI'шные, а не широкие, как должны были бы быть, пока дело не доходит до отображения в commctrl'ах, всё нормально, но именно из-за такой путаницы (commctrl'ы "исходят" из того, что строки - в UNICODE, в то время, как на самом деле они - ANSI'шные) происходит неправильное отображение. (Снова, заглушки переопределяются на <ИМЯ_ФУНКЦИИ>W, вместо <ИМЯ_ФУНКЦИИ>A, как для ANSI-строк).

Символы берутся не как таковые as is, а как коды символов в UNICODE.
Чтобы наши строки были отображены, как иероглифы, необходимо, чтобы значения двухвухбайтовой последовательности (16-битное слово) находились в диапазоне 0х4Е00-0хFA2D (это диапазон, отведённый под собственно иероглифы, но есть ещё слоговое письмо, как в японском, например). Вот и вся арифметика.

Придётся переписывать ту чась, что работает со строками. Немного неприятно, но не смертельно.

Если ваше приложение изначально не должно поддерживать национальные языки, просто смело делайте #undef _UNICODE, #undef _MBCS и пользуйтесь нативным char* + str*().

Строки на английском в скомпилированном файле ресурсов тоже оказались в UNICODE.
355
15 сентября 2007 года
&lt;SCORP&gt;
786 / / 21.10.2006
а лучше просто настройки проекта правильно поставить ;)
кстати, проблемы с юникодом -- самые распространённые грабли с 8-ой судией :)
Реклама на сайте | Обмен ссылками | Ссылки | Экспорт (RSS) | Контакты
Добавить статью | Добавить исходник | Добавить хостинг-провайдера | Добавить сайт в каталог