En Win7 algunas fuentes no funcionan como lo hicieron en Win2K / XP

Mi pregunta es acerca de cómo se debe cambiar el manejo de la fuente para que funcione correctamente en Windows 7. Estoy seguro de que he asumido algo que antes era válido, pero ya no es válido. ¡Pero ni siquiera sé por dónde empezar a buscar! ¡Estoy rezando para que alguien pueda ayudar! Aquí están los detalles tal como los entiendo (también publiqué esta pregunta en un foro de desarrolladores de Microsoft Windows, pero no están respondiendo):

Sí, estoy atrasado (¡diablos, todavía escribo el código WIN32 en C simple!) Tengo una DLL de 10 años que escribí que imita una biblioteca de E / S de la pantalla de DOS aún más antigua dentro del área del cliente de una ventana. No hace falta decir que solo permite el uso de fuentes de ancho fijo. Cuando algunos de los programas que usan la DLL se han movido a Windows 7, hay un parpadeo extraño que aparece cuando se usa una fuente de TIPO VERDADERO de ancho fijo (las fuentes de mapa de bits aún funcionan perfectamente). Hemos rastreado el problema hasta el hecho que un solo personaje escrito conExtTextOut es más ancho de lo que debería ser. He comprobado las medidas de tres maneras diferentes (utilizandoGetTextExtentPoint32 en una cadena de 132 caracteres y dividiendo por 132, llamandoGetTextMetrics e incluso utilizandoGetCharABCWidths para los 256 caracteres) y todos están de acuerdo en que la fuente es del mismo ancho. PeroExtTextOut representa el rectángulo de fondo uno o dos píxeles más ancho que el ancho de la fuente. O bien, o está empezando el fondo, mostrando un píxel o dos a la izquierda de la posición dada en los parámetros [lo llamo así:ExtTextOut( hdc, r.left, r.top, ETO_OPAQUE, &r, &ch, 1, NULL ).] Y recuerde, este código EXACTO funcionó perfectamente en Windows 2000, Windows XP y, con las fuentes de mapa de bits en Windows 7, pero ya no funciona correctamente con las fuentes de tipo verdadero de ancho fijo en Windows 7.

Para cualquier persona que no esté comprendiendo lo que necesito hacer: intente imaginar escribir un carácter por cuadrado en una hoja de papel cuadriculado. Cada cuadrado usa la misma fuente, pero puede tener un color de fondo y / o de primer plano diferente. yo sueloTA_TOP|TA_LEFT alineación de texto, porque es la más simple y cualquier alineación aplicada de manera consistente debería funcionar para una fuente de ancho fijo.

Lo que estoy viendo es que ExtTextOut está emitiendo un rectángulo de fondo más grande de lo que he especificado en elRECT * parámetro. Dado que el rectángulo que estoy proporcionando se crea a partir del tamaño informado de la fuente, esto NUNCA debería suceder, y nunca sucedió en Windows XP y versiones anteriores, y no ocurre con las fuentes de mapa de bits (es decir, .FON) en Windows 7, ya sea. Pero SIEMPRE sucede con fuentes TrueType de ancho fijo en Windows 7. Esto es con el EXECUTABLE EXACT MAME ejecutado en Windows 2000, Windows XP y Windows 7 (32 y 64.) Aunque me encantaría decir simplemente que Windows 7 tiene un error, Estoy más inclinado a creer que una suposición fundamental que he hecho sobre el manejo de fuentes en Windows ya no es cierta (después de 20 años de escribir software para Windows).

¡Pero no tengo idea de cómo o dónde descubrir qué podría ser eso! Por favor, por favor ayúdame!

--- enmienda ---

Para cualquier persona interesada, me las arreglé para solucionar lo que considero un error, hasta que encuentre documentación que indique lo contrario. Mi solución consiste en dos cambios a mi biblioteca:

Usa el tamaño devuelto deGetTextExtentPoint32() de una 'X' en lugar de datos deTEXTMETRICS.Incluir laETO_CLIPPING bandera en todoExtTextOut() llamadas

Anteriormente, estaba usandotmHeight+tmExternalLeading para el número de píxeles entre la parte superior de las filas de texto consecutivas, como se documenta. Descubrí que el valor size.cy regresa de laGetTextExtentPoint32() no era lo mismo y parecía más preciso. El peor ejemplo que encontré fue la fuente de tipo verdadero OCRB. Esto es lo que vi en el depurador para la fuente OCRB que había creado (usando el diálogo de selección de fuente del sistema):

ocrbtm.tmHeight          = 11
ocrbtm.tmExternalLeading =  7

ocrbsize.cy = 11

Entonces, por alguna razón que aún no he descubierto, Windows está ignorando el valor principal externo definido para la fuente OCRB. Usar el valor de tamaño en lugar de la TM da como resultado un texto ordenado, ordenado y ordenado, que es justo lo que quería.

losETO_CLIPPING La bandera no debería ser necesaria para mí porque estoy configurando el rectángulo exactamente a las dimensiones de un solo carácter y utilizandoETO_OPAQUE para completar el fondo (y sobrescribir el contenido de la celda anterior). Pero sin el indicador de recorte, un solo carácter es más ancho que el tamaño, la métrica del texto o el ancho ABC indicaría, al menos, eso es cierto basado en todos La documentación que he encontrado hasta ahora.

Creo que el problema de ALTURA ha existido durante mucho tiempo, pero el resto fue innecesario hasta que ejecutamos nuestro software en Windows 7. Lo agregué a mi pregunta para ver si alguien puede explicar lo que obviamente no entiendo.

- enmienda 2 -

1: Toda la documentación que puedo encontrar dice quetmHeight+tmExternalLeading Debe producir líneas de texto espaciadas a un solo espacio. Período. Pero eso no siempre es cierto y no puedo encontrar documentación que indique cómo Windows determina los diferentes valores que algunas veces devuelvenGetTextExtentPoint32().

2: bajo Win7 (tal vez Vista)ExtTextOut comenzó a rellenar un poco más de fondo de lo que debería (agregando un par de píxeles adicionales a la derecha), pero solo cuando se selecciona una fuente de tipo verdadero. Lo hace incluso si el rectángulo esdoble el tamaño esperado del carácter (en AMBAS dimensiones). DPI / Escalado puede ser un factor, pero como mi sistema está configurado al 100%, parece que Windows está teniendo problemas con un factor de escala 1: 1 y eso parece ser un insecto El hecho de que solo afecte las fuentes de tipo verdadero y no de mapa de bits (.FON) también parece descartar la escala (a menos que hayaes un error en el sistema de escalado), ya que Windows debería intentar escalar todo el texto, no solo parte de él. Además, hay una configuración en gris (pero marcada) "Usar escala de DPI del estilo de Windows XP" en el cuadro de diálogo "Configuración de PPP personalizada". Por último, todo este problema puede ser el resultado de mi ejecución bajo el tema de Windows Classic en lugar de uno de los temas nativos de Aero u otros Win7.

- enmienda 3 -

El simple hecho de llamar a SetProcessDPIAware () no tiene ningún efecto en el problema que tengo. Dado que mi problema existe en la configuración de 100% de ppp (escala 1: 1), si mi problemaes Relacionado con DPI, entonces debo haber descubierto un error en la virtualización de DPI porque así es como Microsoft describe la característica:

Esta característica funciona al proporcionar métricas del sistema "virtualizadas" y elementos de UI a la aplicación, como si se estuviera ejecutando a 96 DPI. La aplicación luego se presenta en una superficie fuera de la pantalla de 96 ppp, y el Administrador de escritorio de Windows ajusta la escala de la ventana resultante para que coincida con la configuración de ppp.

Todas mis configuraciones muestran que estoy a una escala del 100%, y mirar en el cuadro de configuraciones personalizadas muestra claramente que significa 96 ppp. Entonces, si la virtualización de DPI de 96 DPI a 96 DPI no funciona para mis fuentes de tipo verdadero de ancho fijo, entonces Windows tiene un problema, ¿verdad? ¿O hay alguna función a la que necesito llamar (o dejar de llamar?) Para permitir que el virtualizador de DPI funcione correctamente?

Todavía no estoy convencido de que el supuesto problema de escala en realidad tenga tanto que ver con la fuente SIZE como pensé originalmente. Eso es porque el problema se está manifestando en elrectángulo de fondo siendo llenado porExtTextOut() En lugar del carácter de texto que se emite. El rectángulo de fondo se amplía un poco cuando la fuente es de tipo verdadero. Ahora también he verificado que este problema ocurre si se usa el tema Clásico de Windows o el tema Aero estándar de Windows. Ahora para construir un ejemplo simplificado para que otros puedan experimentar con él.

- enmienda 4 -

He creado un programa de demostración mínimo que muestra lo que estoy viendo (y lo que estoy haciendo). El proyecto / fuente de Visual Studio 2010 se puede descargar desdehttp://www.svalli.com/files/fwtt.7z - Intencionalmente no incluí ejecutables porque no quiero correr el riesgo de propagar malware. El programa tiene que elegir una fuente de ancho fijo y luego escribir dos cuadrículas de 5x5 en el área del cliente, una creada con laGetTextExtentPoint32 tamaño y uno usando elTEXTMETRIC tamaño documentado por Microsoft. Las cuadrículas están en un patrón de tablero de ajedrez en blanco y negro con un carácter amarillo sobre rojo escrito en el centro para mostrar el efecto de superposición (es posible que necesite una utilidad de zoom para verlo claramente). El programa también dibuja una cadena que comienza con 5 X justo debajo La cuadrícula, que comienza en el mismo desplazamiento a la izquierda, se usará como una comparación para mi método de colocar caracteres individuales (coincido con la cadena). El menú permite activar / desactivar el recorte enExtTextOut y selección de otras fuentes. También hay una opción de línea de comandosdpiaware (distingue entre mayúsculas y minúsculas) que hace que el programa llameSetProcessDPIAware() cuando se inicia, para que también se pueda evaluar el efecto de esa llamada.

De crear esto he aprendido queExtTextOut está rellenando el rectángulo de fondo correcto, pero el carácter que se representa con un fondo opaco puede ser más ancho de lo que debería y ni siquiera comenzar dondeExtTextOut Se le dijo que comenzara a dibujar! Dije "debería ser" porque el espaciado de caracteres con el que estoy terminando coincide con lo que obtengo cuando tengoExtTextOut hacer una cadena entera. Aparentemente, la superposición puede estar en uno o en ambos lados del rectángulo dado, por ejemplo, OCRB agrega un píxel adicional a los lados izquierdo y derecho de la celda de caracteres, mientras que las otras fuentes de tipo verdadero que he verificado agregan dos píxeles a la derecha borde.

Realmente quiero hacer esto de la manera "correcta", pero no puedo encontrar ninguna documentación que muestre lo que estoy haciendo mal o me falta. Bueno, probablemente me esté faltando algo para DPI Aware en escalas distintas al 100%, pero por lo demás, estoy desconcertado.

- enmienda 5 -

Un poco menos desconcertado ... el problema es causado por ClearType. Al desactivar ClearType, todas las fuentes funcionaron de nuevo. Activar ClearType en XP causa el mismo problema. Al parecer, ClearType puede silenciar (hasta que alguien me diga cómo detectarlo) estirar los caracteres horizontalmente en un par de píxeles para hacer espacio para los píxeles sombreados que agrega para suavizar las cosas.

¿Es el recorte la única manera de evitar este problema?

- enmienda 6 -

Respuesta parcial a mi pregunta de recorte anterior: al crear una nueva fuente, ahora hago lo siguiente (en pseudo código):

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

Sin habilitar el recorte de estecasi Siempre funciona con los tamaños de fuente que estoy usando, aunque he encontrado algunos que aún representan un píxel adicional a la derecha (o izquierda) de la celda de caracteres. Afortunadamente, estas parecen ser fuentes gratuitas que se encuentran en Internet, por lo que su calidad general podría estar por debajo de los estándares de las fundiciones de fuentes profesionales.

Si alguien puede encontrar una mejor respuesta, yo realmente,DE VERDAD Me encanta escucharlo! Hasta entonces, creo que esto es tan bueno como será posible. ¡Gracias por leer hasta aquí!

Respuestas a la pregunta(1)

Su respuesta a la pregunta