В Win7 некоторые шрифты не работают так же, как в Win2K / XP

Мой вопрос о том, как нужно изменить обработку шрифтов для корректной работы в Windows 7. Я уверен, что я сделал предположение о том, что раньше было допустимо, но больше не действует. Но я даже не знаю, с чего начать! Я молюсь, чтобы кто-то мог помочь! Вот детали, которые я понимаю (я также разместил этот вопрос на форуме разработчиков Microsoft Windows, но они не отвечают):

Да, я отстал (черт возьми, я все еще пишу код WIN32 на простом C!) У меня есть 10-летняя DLL, которую я написал, которая имитирует еще более старую библиотеку ввода-вывода для экрана DOS в клиентской области окна. Излишне говорить, что он позволяет использовать только шрифты фиксированной ширины. Когда некоторые программы, использующие DLL, были перенесены в Windows 7, при использовании шрифта TRUE TYPE фиксированной ширины появляется странное мерцание (растровые шрифты по-прежнему работают отлично.) Мы отследили проблему до факта что один символ, написанный сExtTextOut шире, чем должно быть. Я проверил измерения тремя различными способами (используяGetTextExtentPoint32 на строке из 132 символов и делится на 132, вызываяGetTextMetrics и даже с помощьюGetCharABCWidths для всех 256 символов) и все они согласны с тем, что шрифт имеет одинаковую ширину. НоExtTextOut визуализирует фоновый прямоугольник на один или два пикселя шире, чем ширина шрифта. Либо чем, либо он начинает фон, отрисовывая пиксель или два слева от позиции, заданной в параметрах [Я называю это так:ExtTextOut( hdc, r.left, r.top, ETO_OPAQUE, &r, &ch, 1, NULL ).] И помните, этот EXACT-код отлично работал в Windows 2000, Windows XP и с растровыми шрифтами в Windows 7 - но он больше не работает правильно с шрифтами истинного типа фиксированной ширины в Windows 7.

Для тех, кто не понимает, что мне нужно делать: попытайтесь представить, как пишется один символ на квадрат на листе миллиметровки. Каждый квадрат использует один и тот же шрифт, но может иметь различный цвет переднего плана и / или фона. я используюTA_TOP|TA_LEFT выравнивание текста, потому что это самое простое и любое последовательно применяемое выравнивание должно работать для шрифта фиксированной ширины.

Я вижу, что ExtTextOut испускает фоновый прямоугольник большего размера, чем я указал вRECT * параметр. Поскольку предоставленный мною прямоугольник создается из сообщенного размера шрифта, это НИКОГДА не должно происходить - и это никогда не происходило в Windows XP и более ранних версиях и не происходит с растровыми (т.е. .FON) шрифтами в Windows 7, или. Но это ВСЕГДА происходит со шрифтами TrueType фиксированной ширины под Windows 7. Это с ТОЧНЫМ ЖЕ ИСПОЛНИТЕЛЬНЫМ, работающим в Windows 2000, Windows XP и Windows 7 (32 и 64). Хотя я хотел бы просто сказать, что в Windows 7 есть ошибка, Я более склонен полагать, что некоторые фундаментальные предположения, которые я сделал относительно обработки шрифтов в Windows, больше не верны (после 20 лет написания программного обеспечения для Windows).

Но я понятия не имею, как или где узнать, что это может быть! Пожалуйста, ПОЖАЛУЙСТА, помогите мне!

--- поправка ---

Для тех, кто заинтересован, мне удалось обойти то, что я считаю багом, пока не найду документацию об обратном. Мой обходной путь состоит из двух изменений в моей библиотеке:

Используйте размер, возвращенный изGetTextExtentPoint32() «Х» вместо данных изTEXTMETRICS.ВключитьETO_CLIPPING флаг во всехExtTextOut() звонки.

Ранее я использовалtmHeight+tmExternalLeading для количества пикселей между вершинами последовательных строк текста, как задокументировано. Я обнаружил, что значение size.cy возвращается изGetTextExtentPoint32() не то же самое и казалось более точным. Худшим примером, который я нашел, был шрифт OCRB True Type. Вот что я увидел в отладчике для шрифта OCRB, который я создал (используя диалог выбора системного шрифта):

ocrbtm.tmHeight          = 11
ocrbtm.tmExternalLeading =  7

ocrbsize.cy = 11

Поэтому, по какой-то причине, которую мне еще предстоит выяснить, Windows игнорирует внешнее ведущее значение, определенное для шрифта OCRB. Использование значения размера вместо ТМ приводит к хорошему, аккуратному, плотно упакованному тексту, чего я и хотел.

ETO_CLIPPING флаг не должен быть мне необходим, потому что я устанавливаю прямоугольник точно в размеры одного символа и используюETO_OPAQUE чтобы заполнить фон (и перезаписать содержимое предыдущей ячейки). Но без флага отсечения один символ шире, чем указали бы размер, метрика текста или ширина ABC - по крайней мере, это верно для всех документация, которую я нашел до сих пор.

Я считаю, что проблема HEIGHT существовала долгое время, но остальное было ненужным, пока мы не запустили наше программное обеспечение под Windows 7. Я добавляю это к своему вопросу, чтобы посмотреть, сможет ли кто-нибудь объяснить то, что я, очевидно, не понимаю.

- поправка 2 -

1: Вся документация, которую я могу найти, говорит, чтоtmHeight+tmExternalLeading должен производить одинарные строки текста. Период. Но это не всегда так, и я не могу найти документацию, указывающую, как Windows определяет различные значения, которые иногда возвращаютсяGetTextExtentPoint32().

2: под Win7 (возможно, Vista)ExtTextOut начал заливать немного больше фона, чем нужно (добавив пару дополнительных пикселей справа), но только когда выбран шрифт истинного типа. Это делает это, даже если прямоугольникдвойной ожидаемый размер символа (в обоих измерениях). DPI / Scaling может быть фактором, но поскольку моя система настроена на 100%, может показаться, что в Windows возникают проблемы с коэффициентом масштабирования 1: 1, и это может показаться быть ошибкой Тот факт, что он влияет только на настоящие шрифты, а не на растровые (.FON) шрифты, также исключает масштабирование (если нетявляется ошибка в системе масштабирования), поскольку Windows должна пытаться масштабировать весь текст, а не только его часть. Кроме того, в диалоговом окне «Пользовательские настройки DPI» есть серый параметр (но отмечен флажок) «Использовать масштабирование DPI в стиле Windows XP». Наконец, вся эта проблема может быть результатом моего запуска под темой Windows Classic вместо одной из Aero или других собственных тем Win7.

- поправка 3 -

Простой вызов SetProcessDPIAware () не влияет на мою проблему. Так как моя проблема существует при настройке 100% DPI (масштаб 1: 1), если моя проблемаявляется Связанный с DPI, значит, я обнаружил ошибку в виртуализации DPI, потому что Microsoft так описывает эту функцию:

Эта функция работает, предоставляя приложению «виртуализированные» системные метрики и элементы пользовательского интерфейса, как если бы оно работало с разрешением 96 DPI. Затем приложение выполняет рендеринг на экранную поверхность с разрешением 96 точек на дюйм, и диспетчер Windows рабочего стола масштабирует получающееся окно приложения в соответствии с настройкой DPI.

Все мои настройки показывают, что я на 100% масштабируюсь, и просмотр в окне пользовательских настроек ясно показывает, что означает 96 DPI. Итак, если виртуализация DPI с 96 DPI на 96 DPI не работает для моих шрифтов с истинным шрифтом фиксированной ширины, то проблема в Windows, не так ли? Или есть какая-то функция, которую мне нужно вызвать (или прекратить звонить?), Чтобы позволить виртуализатору DPI работать правильно?

Я до сих пор не уверен, что предполагаемая проблема масштабирования на самом деле имеет такое же отношение к размеру шрифта, как я изначально думал. Это потому, что проблема проявляется вфоновый прямоугольник заполняетсяExtTextOut() вместо испускаемого текстового символа. Фоновый прямоугольник немного увеличивается, когда шрифт имеет истинный тип. Теперь я также убедился, что эта проблема возникает независимо от того, используется ли классическая тема Windows или стандартная тема Windows Aero. Теперь создайте упрощенный пример, чтобы другие могли поэкспериментировать с ним.

- поправка 4 -

Я создал минимальную демонстрационную программу, которая показывает, что я вижу (и что я делаю). Проект / источник Visual Studio 2010 можно загрузить сhttp://www.svalli.com/files/fwtt.7z - Я специально не включал исполняемые файлы, потому что не хочу рисковать распространением вредоносного ПО. В программе вы выбираете шрифт фиксированной ширины, а затем записывает две сетки символов 5x5 в клиентскую область, одна из которых создана с использованиемGetTextExtentPoint32 размер и один с помощьюTEXTMETRIC размер, задокументированный Microsoft. Сетки выполнены в черно-белом шахматном порядке с желтым на красном символом, который написан последним в центре, чтобы показать эффект перекрытия (вам может понадобиться утилита масштабирования, чтобы ясно увидеть его.) Программа также рисует строку, начинающуюся с 5 X чуть ниже сетка, начинающаяся с того же левого смещения, которая будет использоваться в качестве сравнения для моего метода размещения отдельных символов (я сопоставляю строку.) Меню позволяет включать / выключать обрезку вExtTextOut и выбор других шрифтов. Также есть опция командной строкиdpiaware (с учетом регистра), который вызывает программуSetProcessDPIAware() когда он запускается, так что эффект этого вызова также может быть оценен.

Создав это, я узнал, чтоExtTextOut заполняет правильный прямоугольник фона, но символ, отображаемый с непрозрачным фоном, может быть шире, чем должен быть, и может даже не начинаться сExtTextOut было сказано начать рисовать! Я сказал «должно быть», потому что расстояние между персонажами совпадает с тем, что я получаю, когда имеюExtTextOut сделать всю строку По-видимому, перекрытие может быть на одной или обеих сторонах данного прямоугольника, например, OCRB добавляет дополнительный пиксель на левую и правую стороны ячейки символа, в то время как другие проверенные шрифты истинного типа добавляют два пикселя справа край.

Я действительно хочу сделать это "правильным" способом, но я не могу найти документацию, которая показывает, что я делаю неправильно или отсутствует. Ну, я, вероятно, что-то упускаю для DPI Aware в масштабах, отличных от 100%, но в остальном я просто сбит с толку.

- поправка 5 -

Чуть менее сбит с толку ... проблема вызвана ClearType. Отключение ClearType заставило все шрифты работать снова. Включение ClearType под XP вызывает ту же проблему. Очевидно, ClearType может молча (пока кто-нибудь не подскажет мне, как его обнаружить) растянуть символы по горизонтали на пару пикселей, чтобы освободить место для затененных пикселей, которые оно добавляет, чтобы сгладить объекты.

Является ли отсечение единственным способом решения этой проблемы?

- поправка 6 -

Частичный ответ на мой заданный выше вопрос: при создании нового шрифта я теперь делаю следующее (в псевдокоде):

CreateFontIndirect
SelectFont
GetTextMetrics
if( (tmPitchAndFamily & TMPF_TRUETYPE) && Win6.x or above )
   if( SystemParametersInfo( SPI_GETCLEARTYPE ) )
        lfQuality = NONANTIALIASED_QUALITY
        DeleteObject( font )
        CreateFontIndirect

Без включения отсечения этопочти всегда работает с размерами шрифтов, которые я использую, хотя я нашел несколько, которые по-прежнему отображают дополнительный пиксель справа (или слева) от ячейки символа. К счастью, это бесплатные шрифты, найденные в Интернете, поэтому их общее качество может быть ниже стандартов профессиональных шрифтовых компаний.

Если кто-нибудь сможет найти лучший ответ, я бы действительноДЕЙСТВИТЕЛЬНО люблю это слышать! До тех пор, я думаю, это так хорошо, как это получится. Спасибо за чтение этого далеко!

Ответы на вопрос(1)

Ваш ответ на вопрос