No Win7 algumas fontes não funcionam como no Win2K / XP

Minha pergunta é sobre como o manuseio de fontes precisa ser alterado para funcionar corretamente no Windows 7. Tenho certeza de que fiz uma suposição sobre algo que era válido antes, mas não é mais válido. Mas nem sei por onde começar a procurar! Estou rezando para que alguém possa ajudar! Aqui estão os detalhes como eu os compreendo (também publiquei esta pergunta em um fórum de desenvolvedores do Microsoft Windows, mas eles não estão respondendo):

Sim, eu estou atrasado (eu ainda escrevo código WIN32 em C simples!) Eu tenho uma DLL de 10 anos que escrevi que imita uma biblioteca I / O de tela DOS ainda mais antiga dentro da área cliente de uma janela. Escusado será dizer que só permite o uso de fontes de largura fixa. Quando alguns dos programas que usam a DLL foram movidos para o Windows 7, há uma tremulação estranha que aparece quando uma fonte TRUE TYPE de largura fixa é usada (as fontes de bitmap ainda funcionam perfeitamente). Rastreamos o problema até o fato que um único personagem escrito comExtTextOut é mais largo do que deveria ser. Eu verifiquei as medidas de três maneiras diferentes (usandoGetTextExtentPoint32 em uma cadeia de 132 caracteres e dividindo por 132, chamandoGetTextMetrics e até mesmo usandoGetCharABCWidths para todos os 256 caracteres) e todos concordam que a fonte é da mesma largura. MasExtTextOut está renderizando o retângulo de fundo um ou dois pixels mais largo que a largura da fonte. Ou então, ou está começando o background renderizando um pixel ou dois para a esquerda da posição dada nos parâmetros [Eu chamo assim:ExtTextOut( hdc, r.left, r.top, ETO_OPAQUE, &r, &ch, 1, NULL ).] E lembre-se, este código EXATO funcionou perfeitamente no Windows 2000, Windows XP e, com fontes de bitmap no Windows 7 - mas ele não funciona mais corretamente com fontes de tipo true de largura fixa no Windows 7.

Para quem não está entendendo o que eu preciso fazer: tente imaginar escrever um caractere por quadrado em um pedaço de papel milimetrado. Cada quadrado usa a mesma fonte, mas pode ter uma cor de primeiro plano e / ou de fundo diferente. eu usoTA_TOP|TA_LEFT alinhamento de texto, porque é o mais simples e qualquer alinhamento aplicado consistentemente deve funcionar para uma fonte de largura fixa.

O que estou vendo é que o ExtTextOut está emitindo um retângulo de plano de fundo maior do que eu especifiquei noRECT * parâmetro. Como o retângulo que estou fornecendo é criado a partir do tamanho relatado da fonte, isso NUNCA deve acontecer - e isso nunca aconteceu no Windows XP e anterior, e não acontece com fontes de bitmap (ou seja, .FON) no Windows 7, ou. Mas sempre acontece com fontes TrueType de largura fixa no Windows 7. Isso é com o EXACT SAME EXECUTABLE em execução no Windows 2000, Windows XP e Windows 7 (32 e 64.) Embora eu adoraria simplesmente dizer que o Windows 7 tem um bug, Estou mais inclinado a acreditar que alguma suposição fundamental que fiz sobre manipulação de fontes no Windows não é mais verdadeira (após 20 anos escrevendo software para Windows).

Mas não tenho ideia de como ou onde descobrir o que isso pode ser! Por favor, por favor me ajude!

--- alteração ---

Para qualquer pessoa interessada, consegui contornar o que estou considerando um bug - até encontrar documentação em contrário. Minha solução consiste em duas alterações na minha biblioteca:

Use o tamanho retornado deGetTextExtentPoint32() de um 'X' em vez de dados deTEXTMETRICS.Inclua oETO_CLIPPING bandeira em todosExtTextOut() chamadas.

Anteriormente, eu estava usandotmHeight+tmExternalLeading para o número de pixels entre os topos de linhas consecutivas de texto, conforme documentado. Eu descobri que o valor size.cy voltando doGetTextExtentPoint32() não era o mesmo e parecia mais preciso. O pior exemplo que encontrei foi a fonte OCRB true type. Aqui está o que eu vi no depurador para a fonte OCRB que eu criei (usando a caixa de diálogo de seleção de fontes do sistema):

ocrbtm.tmHeight          = 11
ocrbtm.tmExternalLeading =  7

ocrbsize.cy = 11

Portanto, por algum motivo que ainda não descobri, o Windows está ignorando o valor líder externo definido para a fonte OCRB. Usar o valor de tamanho em vez da TM resulta em um texto de compactação agradável e organizado, que é exatamente o que eu queria.

oETO_CLIPPING sinalizador não deve ser necessário para mim porque eu estou definindo o retângulo para exatamente as dimensões de um único caractere e usandoETO_OPAQUE para preencher o plano de fundo (e sobrescrever o conteúdo da célula anterior). Mas sem o sinalizador de recorte, um único caractere é mais largo do que o tamanho, a métrica de texto ou a largura ABC indica - pelo menos, isso é verdadeiro com base em todos a documentação que encontrei até agora.

Acredito que o problema de HEIGHT já existe há muito tempo, mas o restante era desnecessário até que executássemos nosso software no Windows 7. Estou acrescentando isso à minha pergunta para ver se alguém consegue explicar o que eu obviamente não entendo.

- alteração 2 -

1: Toda a documentação que posso encontrar diz quetmHeight+tmExternalLeading deve produzir linhas de texto simples espaçadas. Período. Mas isso nem sempre é verdade e não consigo encontrar documentação indicando como o Windows determina os valores diferentes que às vezes são retornados porGetTextExtentPoint32().

2: sob Win7 (talvez Vista)ExtTextOut começou a preencher um pouco mais de fundo do que deveria (adicionando alguns pixels extras à direita), mas apenas quando uma fonte de tipo real é selecionada. Ele faz isso mesmo se o retângulo estiverem dobro o tamanho esperado do caractere (em ambas as dimensões). DPI / Dimensionamento pode ser um fator, mas como meu sistema está definido como 100%, parece que o Windows está tendo problemas com um fator de escala 1: 1 e que parece seja um bug. O fato de que ele afeta apenas fontes true type e não bitmap (.FON) também parece descartar a escala (a menos que hajaé um bug no sistema de dimensionamento), pois o Windows deve tentar dimensionar todo o texto, não apenas parte dele. Além disso, há uma configuração em cinza (mas marcada) "Usar escala DPI do estilo do Windows XP" na caixa de diálogo "Configuração de DPI personalizada". Por último, todo este problema pode ser um resultado da minha execução sob o tema clássico do Windows em vez de um dos temas nativos do Aero ou outro Win7.

- alteração 3 -

Simplesmente chamar SetProcessDPIAware () não tem efeito sobre o problema que estou tendo. Como meu problema existe na configuração 100% DPI (escala 1: 1), se meu problemaé Relacionado a DPI, devo ter descoberto um bug na virtualização de DPI porque é assim que a Microsoft descreve o recurso:

Esse recurso funciona fornecendo métricas de sistema e elementos de interface do usuário "virtualizados" para o aplicativo, como se estivesse sendo executado em 96 DPI. Em seguida, o aplicativo é renderizado em uma superfície fora da tela de 96 DPI e o Desktop Manager do Windows dimensiona a janela do aplicativo resultante para corresponder à configuração de DPI.

Todas as minhas configurações mostram que estou em 100% de dimensionamento e, ao procurar na caixa de configurações personalizadas, isso mostra claramente que isso significa 96 DPI. Portanto, se a virtualização de DPI de 96 DPI para 96 ​​DPI não estiver funcionando para minhas fontes True Type de largura fixa, o Windows terá um problema, certo? Ou existe alguma função que eu preciso chamar (ou parar de chamar?) Para permitir que o virtualizador de DPI funcione corretamente?

Ainda não estou convencido de que o suposto problema de escala realmente tenha tanto a ver com a fonte SIZE quanto eu pensava inicialmente. Isso porque o problema está se manifestando noretângulo de fundo sendo preenchido porExtTextOut() em vez do caractere de texto sendo emitido. O retângulo de plano de fundo é ampliado um pouco quando a fonte é do tipo true. Eu também verifiquei agora que esse problema ocorre se usando o tema clássico do Windows ou o tema padrão do Windows Aero. Agora, construa um exemplo simplificado para que outras pessoas possam experimentá-lo.

- alteração 4 -

Eu criei um programa de demonstração mínimo que mostra o que estou vendo (e o que estou fazendo.) O projeto / fonte do Visual Studio 2010 pode ser baixadohttp://www.svalli.com/files/fwtt.7z - Eu intencionalmente não incluí executáveis ​​porque não quero correr o risco de espalhar malware. O programa escolheu uma fonte de largura fixa e, em seguida, grava duas grades de caracteres 5x5 na área do cliente, uma criada usando oGetTextExtentPoint32 tamanho e um usando oTEXTMETRIC tamanho conforme documentado pela Microsoft. As grades estão em um padrão quadriculado preto e branco com um caractere amarelo em vermelho escrito por último no centro para mostrar o efeito de sobreposição (você pode precisar de um utilitário de zoom para vê-lo claramente.) O programa também desenha uma string que começa com 5 X logo abaixo a grade, começando no mesmo deslocamento à esquerda, para ser usado como uma comparação para o meu método de colocar caracteres individuais (eu coincidir com a seqüência de caracteres). O menu permite alternar recorte on / off emExtTextOut e seleção de outras fontes. Existe também uma opção de linha de comandodpiaware (sensível a maiúsculas e minúsculas) que faz com que o programa chameSetProcessDPIAware() quando é iniciado, para que o efeito dessa chamada também possa ser avaliado.

Desde a criação, aprendi queExtTextOut está preenchendo o retângulo de plano de fundo correto, mas o caractere que está sendo renderizado com um plano de fundo opaco pode ser mais largo do que deveria ser e pode nem mesmo começar ondeExtTextOut foi dito para começar a desenhar! Eu disse "deve ser" porque o espaçamento de caracteres que estou terminando combina com o que recebo quando tenhoExtTextOut renderizar uma string inteira. A sobreposição pode aparentemente estar em um ou ambos os lados do retângulo dado, por exemplo, OCRB adiciona um pixel extra para os lados esquerdo e direito da célula de caractere, enquanto as outras fontes do tipo true que eu verifiquei adicionam dois pixels à direita Beira.

Eu realmente quero fazer isso da maneira "certa", mas não consigo encontrar nenhuma documentação que mostre o que estou fazendo errado ou que estou perdendo. Bem, eu provavelmente estou perdendo algo para o DPI Aware em escalas diferentes de 100%, mas por outro lado, estou apenas perplexo.

- alteração 5 -

Um pouco menos confuso ... o problema é causado pelo ClearType. Desativar o ClearType fez todas as fontes funcionarem novamente. Ligar o ClearType no XP causa o mesmo problema. Aparentemente, o ClearType pode silenciosamente (até que alguém me diga como detectá-lo) esticar os caracteres horizontalmente por alguns pixels, a fim de criar espaço para os pixels sombreados que ele adiciona para suavizar as coisas.

Está recortando a única maneira de contornar esse problema?

- alteração 6 -

Resposta parcial à minha pergunta de recorte acima: Ao criar uma nova fonte, faço agora o seguinte (no pseudo código):

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

Sem ativar o recortequase sempre funciona com os tamanhos de fonte que estou usando, embora eu tenha encontrado alguns que ainda renderizam um pixel extra à direita (ou à esquerda) da célula de caractere. Felizmente, esses parecem ser fontes gratuitas encontradas na Internet, portanto, sua qualidade geral pode estar abaixo dos padrões das fundições de fontes profissionais.

Se alguém puder encontrar uma resposta melhor, eu realmenteREALMENTE adoro ouvir isso! Até lá, acho que isso é tão bom quanto possível. Obrigado por ler até aqui!

questionAnswers(1)

yourAnswerToTheQuestion