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];
Неправильное отображение строк в commctrl'ах
Такой занятный вопрос: есть приложение написанное на чистом WinAPI без примеси всяких MFC. Язык - С (IDE - MSVC 8). На самом деле, это фронт-энд к cli-тулзе.
Наш гуёвый фронт-энд создаёт пайп, пускает второй процесс, подсовывая ему вместо дескрипторов stdout, stdin дескрипторы на свой пайп. (Используются CreateProcess(), CreatePipe(), но думаю, это роли никакой не играет). Далее, дочерний процесс что-то пишет в свой stdout, мы это читает через наш пайп. Потом считав всё, начинаем отпарсенный уже в фронт-энде вывод дочерёнка распихивать по строкам ListView. Строки гоняем обычными RTL'евыми str*cpy(), т.к. они у нас все на английском и без какого-либо намёка на мультибайтовость.
В ListView всё, что в структурах записано обычными латинскими символами отображается самыми настоящими китайскими иероглифами. Но менюшки, тултипы для тубаров, одним словом, всё, что из файла ресурсов, отображается файно на чистом английском, как и задумано.
Суть в том, что если верить отладчику, то строки на всём пути от дочернего процесса и до ListView выглядят так, как надо (было бы странно, если бы они не выглядели нормально). А в ListView их почему-то не по-детски передёргивает на китайский. Причём передёргиваются даже цифры состоящие более чем из одного числа.
Сам не могу что-то так сходу сообразить. Может кто знает, что за грабль?
На скрине видно, что получается на следующем примере:
данные по ListView загоняем из массива типа
Код:
При том, что pin [0] = { 0, 0, 0, 0, "[System Process]", NULL } (поля структуры по очерёдности следования соответствуют колонкам в ListView). Для второго процесса pid и приоритет тоже состоят из одной цифры - отображаются нормально, далее с третьей строки в колонках "pid" и "приоритет" тоже начинается ХЗ что.
Это приложение пока ещё очень полуфабрикат, но такие косяки с отображением уже сильно смущают.
Заранее 10х.
Путём некоторых более подробных поисков и лазаний по таблице символов было установлено следующее:
На самом деле, это тот самый момент, когда удобство юзера оборачивается кошмаром программера :)
Если определён деф _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.
кстати, проблемы с юникодом -- самые распространённые грабли с 8-ой судией :)