Сейчас мы рассмотрим последнюю тему, связанную со шрифтами, а именно - создание собственных шрифтовых ресурсов. Ранее мы встречались с одной из разновидностей ресурсов - битмапом. Тогда битмап включался в ресурс и становился доступным приложению. Для этого мы в файле описания ресурсов включали строку вида:
name BITMAP “file.bmp”
По аналогии хочется поступить также и со шрифтом, тем более, что существует такой вид ресурсов - FONT. Однако этот метод не работает. Это связано с тем, что все шрифты в Windows доступны всем приложениям. В этом случае включать шрифт в приложение становиться невозможным - так как в момент его завершения шрифт может использоваться другим приложением. Поэтому шрифтовые ресурсы в Windows оформляются в виде отдельных файлов.
Так как шрифты доступны всем приложениям, то мы сначала должны включить свой шрифт в системную таблицу шрифтов. При этом шрифт становится доступным всем приложениям Windows (в том числе и нашему). Теперь мы можем вызвать функцию CreateFont() или CreateFontIndirect() для получения хендла шрифта, а в конце работы, после уничтожения созданного шрифта, мы должны удалить его из системной таблицы.
В некоторых случаях может быть удобным добавление шрифта в список шрифтов, автоматически попадающих в системную таблицу при запуске Windows. Для этого Вы должны добавить строку в файл WIN.INI, секция [fonts] (как это делается - позже, когда будем рассматривать настройку приложений). При этом все последующие запуски Windows будет автоматически добавлять Ваш шрифт в системную таблицу. Однако в текущем сеансе этого автоматически не происходит, так что Вы должны сами добавить его в таблицу.
Для включения шрифта в системную таблицу надо воспользоваться функцией:
int AddFontResource( lpszFileName );
возвращаемое значение указывает число шрифтов, добавленных в системную таблицу из этого файла, значение 0 указывает на ошибку.
Обычно шрифтовые файлы имеют расширение .FON; Такой файл может содержать несколько шрифтов с общим именем, но разными размерами символов. Windows будет использовать шрифт того размера, который наиболее точно подходит к запрашиваемому.
Если добавленный шрифт не предназначен строго для внутреннего использования, то Вы должны послать всем приложениям сообщение о смене шрифта:
SendMessage( HWND_BROADCAST, WM_FONTCHANGE, 0, 0L );
Для удаления шрифта из системной таблицы Вы должны воспользоваться функцией
BOOL RemoveFontResource( lpszFileName );
Как и при добавлении шрифта, если этот шрифт может применяться другими приложениями, то Вы должны послать сообщение WM_FONTCHANGE.
Добавлять или удалять шрифты из системной таблицы удобно либо в начале и конце приложения, либо при создании и удалении главного окна приложения.
Создание шрифтовых ресурсов
В этом разделе мы будем говорить только о создании собственных растровых шрифтовых ресурсов. Это связано с тем, что стандартные редакторы шрифтовых ресурсов (включаемые в SDK и компиляторы) позволяют создавать только растровые шрифты.
Для начала мы должны нарисовать требуемые нам шрифты с помощью какого-либо редактора ресурсов. Растровые шрифты обычно размещаются в файлах с расширением .FNT (это не шрифтовой файл, а отдельный ресурс, как, скажем, битмап). Нам может понадобится нарисовать несколько шрифтов разного размера, но имеющих общее начертание. Эти шрифты будут сохранены в разных .FNT файлах.
Далее мы должны построить шрифтовой файл .FON, содержащий наши шрифты. Этот файл являться библиотекой ресурсов. Практически он оформлен как обычное Windows приложение, которое содержит только ресурсы. Мы можем описать такое приложение, как приложение вообще не имеющее сегмента кода, или как библиотеку.
Так как наша библиотека должна содержать шрифтовые ресурсы, то мы должны задать файл описания ресурсов .RC, содержащий список нарисованных нами шрифтов, например:
1 FONT fonta.fnt
2 FONT fontb.fnt
3 FONT fontc.fnt
Конечно нам понадобится файл описания приложения .DEF в несколько специфичном виде:
LIBRARY
DESCRIPTION 'FONTRES DISPLAY : 40-char terminal'
EXETYPE WINDOWS
STUB 'WINSTUB.EXE'
DATA NONE
Надо обратить внимание на использование слова LIBRARY, вместо NAME, для указания того, что это не обычное приложение, а библиотека. Далее мы должны указать, что наша библиотека не имеет данных 'DATA NONE' и составить описание нашего шрифта. Для этого мы должны в DESCRIPTION указать строку специального формата:
DESCRIPTION 'FONTRES aspect,logpixelsx,logpixelsy : comment'
DESCRIPTION 'FONTRES DEVICESPECIFIC device : comment'
DESCRIPTION 'FONTRES DISPLAY : comment'
Здесь представлены три разных формата таких описаний. Первый формат указывает характеристики устройства, для которого разработан шрифт; значения характеристик можно найти, получив информацию о контексте устройства, или из таблички со сводкой системных шрифтов, приведенной выше.
Второй формат задает шрифт, созданный для конкретного устройства. Параметр device задает имя устройства, для которого шрифт спроектирован, например: IBM 8514. Третий формат указывает, что шрифт спроектирован для дисплея.
Далее мы должны построить библиотеку ресурсов. Как уже говорилось, это можно сделать двумя способами - создав приложение не имеющее кода или создав приложение, являющееся разделяемой библиотекой.
Если мы хотим описать приложение не имеющее кода, то нам будет удобнее воспользоваться компиляторами Borland, так как построители задач других фирм часто, встретив сегмент нулевой длины, предполагают длину 65536. Для создания модуля не имеющего кода, нам надо написать простейший ассемблерный файл:
_TEXT segment byte public 'CODE'
_TEXT ends
end
Этот файл описывает только один сегмент нулевой длины.
После этого мы можем приступить к построению шрифтового файла. Для этого мы сначала компилируем ассемблерный файл:
tasm file.asm
затем мы должны построить нашу библиотеку и включить в нее спроектированные ресурсы:
tlink file.obj,file.exe,nul,,file.def
rc file.rc
rename file.exe file.fon
Теперь мы располагаем собственным шрифтовым ресурсом, который мы можем применять в нашем приложении. Еще раз надо отметить, что обязательно применение 'Borland TLINK' для построения файла, так как другие сборщики могут построить неверный модуль.
Ранее мы сделали замечание о том, что мы можем строить шрифтовой файл двумя способами - как библиотеку не имеющую кода, или как обычную библиотеку. Если мы хотим строить обычную библиотеку, то вместо ассемблерного файла нам надо написать небольшой файл на C:
#include <windows.h>
extern "C" {
int CALLBACK LibMain(
HANDLE hInstance, WORD wDataSeg, WORD cbHeapSize,LPSTR lpszCmdLine) {
// обычно функция LibMain() разблокирует сегмент данных
// если он имеет динамический heap.
// if ( cbHeapSize ) UnlockData( 0 );
// так как мы вообще не имеем данных (и heap тоже)
// то можем этого не делать.
return 1;}
int CALLBACK WEP( int bSystemExit ) {
return TRUE;}}
Этот файл содержит две процедуры - LibMain() - которая заменяет обычный WinMain() и вызывается при инициализации библиотеки - и процедуру WEP(), которая вызывается при удалении ненужной библиотеки.
В этом файле надо обратить внимание на то, что функция LibMain описана как CALLBACK (PASCAL FAR), в отличие от WinMain. К сожалению, некоторые компиляторы предполагают, что она должна быть NEAR для моделей памяти с одним сегментом кода. В качестве выхода можно изменить имя, например, написать его только большими буквами. Тогда компилятор не распознает эту функцию как стандартную и не сделает ошибки, а сборщик осуществит правильное связывание, так как функция декларирована как CALLBACK (PASCAL FAR).
Вторая особенность - указание, что имена функций не должны кодироваться как C++ имена ( extern "C" ). Это опять–же связано с особенностями некоторых компиляторов, которые не распознают функцию WEP() (Windows Exit Procedure) как стандартную, и осуществляют для нее C++ кодирование имени - при этом сборщик не может правильно построить задачу.
В остальном построение шрифтового файла не отличается от рассмотренного, конечно кроме компиляции исходного текста, которая выполняется как для обычного Windows-приложения:
bcc -ms -W file.c file.def
Дата: 2019-07-25, просмотров: 251.