Реферат по предмету "Информатика, программирование"


Семейства шрифтов в Windows

1. Семейства шрифтов в Windows
По трем израссмотренных признаков (ширина штриха, ширина символов и наличию засечек) вWindows принято выделять так называемые семейства шрифтов. Для того, что быпояснить разницу между принятыми семействами, приведем небольшую табличку,содержащую сводку характеристик разных семейств шрифтов в Windows:Семейство Ширина штриха Ширина символов Наличие засечек примеры MODERN постоянная постоянная — Courier New ROMAN переменная переменная есть Times New Roman, Antiqua, Garamond, Palatino, Bodoni SWISS переменная переменная нет Arial, Helvetica, Futura, Avantgarde, Optima, Swiss SCRIPT — — — Script, Odessa Script FWF, Decor, Jikharev, Parsek DECORATIVE — — — Windings, MusicalSymbols, Symbol DONTCARE —
Обычно ксемейству MODERN относят все шрифты фиксированной ширины. НазваниеMODERN указывает на сравнительно недавнюю историю этих шрифтов — они получилираспространение с развитием печатающей техники и компьютеров, тогда как другиевиды шрифтов возникали с XV века, когда заканчивалась эпоха готического шрифта.
В те временаначинал формироваться шрифт, похожий по своему начертанию на один из древнейшихшрифтов — римский капитальный. Это был пропорциональный шрифт с засечками инормальной контрастностью, позже он получил очень широкое распространение втипографском деле и дожил до наших дней. За свою долгую историю он многократновидоизменялся и стал родоначальником большого числа поколений шрифтов. ВWindows такие шрифты относятся к семейству ROMAN.
Реально этомусемейству соответствует очень большое число разных шрифтов, выделяемых в другихклассификационных системах. В частности, можно выделить так называемыебрусковые шрифты, обычно со слабо выраженным контрастом и засечками,перпендикулярными штрихам и имеющими примерно такую же ширину (пример — Courier); В XX веке возникли шрифты, получившие очень широкое распространение. Наиболеераспространенное название для этих шрифтов — рубленые. Эти шрифты не имеютконтраста и засечек (sans serif), в Windows им соответствует семейство SWISS.Семейство DONTCARE реально не соответствует никакой группе шрифтов. Оноиспользуется только при указании, из какого семейства надо выбирать шрифт — приэтом оно обозначает “любое семейство”.
 
1.1 Стандартныешрифты Windows
В стандартнойпоставке Windows присутствует небольшой набор шрифтов, представляющий все(определенные в Windows) семейства шрифтов. Этот набор включает в себярастровые, векторные и TrueType шрифты, информация о которых сведена внебольшую таблицу:Имя шрифта семейство кодовая таблица файл(ы) растровые шрифты System SWISS ANSI
xxxSYS.FON FixedSys DONTCARE ANSI
xxxFIX.FON Terminal MODERN OEM
xxxOEM.FON Courier MODERN ANSI
COURy.FON MS Sans Serif SWISS ANSI
SSERIFy.FON MS Serif ROMAN ANSI
SERIFy.FON Small Fonts ROMAN ANSI
SMALLy.FON Symbol DECORATIVE SYMBOL
SYMBOLy.FON векторные шрифты Modern MODERN OEM MODERN.FON Roman ROMAN OEM ROMAN.FON Script SCRIPT OEM SCRIPT.FON TrueType Arial SWISS ANSI
ARIALzz.TTF(.FOT) Courier New MODERN ANSI
COURzz.TTF(.FOT) Times New Roman ROMAN ANSI TMSRMN.TTF(.FOT) Windings DONTCARE ANSI WINDINGS.TTF(.FOT)
В этойтаблице следует внимательно рассмотреть имена файлов. В этих именах маленькимибуквами (xxx,y,zz) обозначены изменяющиеся части.
Так xxxобозначает устройство, для которого был спроектирован шрифт. Вместо этойпоследовательности реально написано CGA, EGA, VGA или 8514.
Символ yобозначает категорию устройств, к которой относится данный шрифт. Возможныезначения можно найти в таблице:Буква Соотношение сторон
Разрешающая способность X/Y (пиксел/дюйм) Устройство A 200 96/48 CGA B 133 96/72 EGA C 83 60/72 Okidata printers D 167 120/72 IBM, Epson printers E 100 96/96 VGA F 100 120/120 IBM 8514
Последовательностьzz указывает, какого типа шрифт описан в этом файле: нормальный(пустая последовательность), жирный BD, наклонный I или жирныйнаклонный BI.
 
1.2 Получение хендла шрифта
Для того, чтобы Вы могли применять шрифт в Вашей программе, Вы должны сначала получить хендлсоответствующего шрифта. Шрифт является объектом GDI, поэтому работа с нимпохожа на работу с другими объектами GDI. Как правило вы должны выполнитьследующие действия:
получитьхендл либо стандартного шрифта, либо создав «новый» шрифт
При создании«нового» шрифта создается соответствующий объект GDI, а не новый файлописания шрифта.
выбрать шрифтв контекст устройства
осуществитьвывод, используя текущий шрифт
если шрифтбыл создан, то его надо уничтожить.
Созданиешрифтов занимает некоторое время (особенно для отображения TrueType шрифтов — Windows автоматически генерирует промежуточный растровый шрифт, который ииспользуется при выводе). Если надо создавать шрифты, то это удобно делать присоздании окна или даже при запуске приложения, а уничтожать — при закрытии окнаили при завершении приложения (как и все объекты GDI, созданный шрифтуничтожается с помощью функции DeleteObject).
Если Вам надополучить хендл стандартного шрифта, то Вы можете воспользоваться функцией:
HFONT GetStockObject( nIndex );
Параметр nIndex может быть:ANSI_FIXED_FONT соответствует шрифту Courier ANSI_VAR_FONT соответствует шрифту MS Sans Serif OEM_FIXED_FONT соответствует шрифту Terminal SYSTEM_FONT соответствует шрифту System; этот шрифт используется по умолчанию SYSTEM_FIXED_FONT соответствует шрифту FixedSys; До версии Windows 3.0 системный шрифт был фиксированной ширины, он включен в Windows 3.1 для совместимости. DEVICE_DEFAULT_FONT соответствует шрифту, загруженному в устройство; для дисплея не определен

Если Вам надосоздавать собственный шрифт, то Вы можете воспользоваться одной из двухфункций:
HFONTCreateFont(
nHeight,nWidth, nEscapement, nOrientation, nWeight,
bItalic,bUnderline, bStrikeOut,
bCharSet,bOutputPrecision, bClipPrecision, bQuality, bPitchAndFamily,
lpszFacename);
или
HFONTCreateFontIndirect( lpLogFont );
Чаще применяется функция CreateFontIndirect(), получающая в качестве параметра указатель на структуру LOGFONT. Поля этой структуры совпадают с аргументами функции CreateFont().
typedefstruct tagLOGFONT {
intlfHeight;
intlfWidth;
intlfEscapement;
intlfOrientation;
intlfWeight;
BYTElfItalic;
BYTElfUnderline;
BYTElfStrikeOut;
BYTElfCharSet;
BYTElfOutPrecision;
BYTElfClipPrecision;
BYTElfQuality;
BYTElfPitchAndFamily;
BYTElfFaceName[LF_FACESIZE];
} LOGFONT;
Рассмотримназначение полей этой структуры:
lfHeight задает требуемый размер шрифта вточках (пунктах). Если значение положительно, то в высоту включаетсямежстрочный промежуток, а если отрицательно, то модуль указывает высоту символашрифта. Значение 0 указывает, что используется значение высоты по умолчанию.
lfWidth задает среднюю ширину символов впунктах. Значение 0 соответствует ширине по умолчанию.
lfEscapement задает наклон базовой линии строки вдесятых долях градуса. Для растровых шрифтов игнорируется.
lfOrientation задает ориентацию символаотносительно базовой линии в десятых долях градуса. Игнорируется для растровыхи TrueType шрифтов, для векторных используются значения: 0, 900, 1800 и 2700
lfWeight задает вес символа (жирность).Соответствует количеству закрашенных пиксел из 1000. Предусмотрены условныеобозначения для определения веса, начинающиеся на FW_... Например,нормальный текст (400) соответствует FW_NORMAL (FW_REGULAR), жирный (700)FW_BOLD.
lfItalicненулевоезначение задает наклон символов (начертание slanted). Значение 0 соответствуетобычному тексту.
lfUnderline ненулевое значение задаетподчеркивание строки текста линией. Значение 0 соответствует обычному тексту.
lfStrikeOut ненулевое значение задаетперечеркивание строки текста линией. Значение 0 соответствует обычному тексту.
lfCharSet задает кодовую таблицу, которуюдолжен поддерживать данный шрифт. Используются следующие условные обозначения:
ANSI_CHARSET кодоваятаблица ANSI
OEM_CHARSET кодоваятаблица OEM
SYMBOL_CHARSETсимволы
SHIFTJIS_CHARSETяпонская азбука
DEFAULT_CHARSETлюбая кодовая таблица.
lfOutPrecision указывает, насколько точно долженсоответствовать подбираемый шрифт указанному размеру. (Реально Вы можетезаказать растровый шрифт несуществующего размера). См. условные обозначениявида OUT_???_PRECIS в windows.h.
lpClipPrecision указывает, как должен отображатьсячастично невидимый символ. См. условные обозначения вида CLIP_???_PRECISв windows.h.
lfQuality указывает качество получаемогошрифта. Обычно используется значение PROOF_QUALITY (или DEFAULT_QUALITY). Еслиразмер растрового шрифта меньше, чем требуется, то Windows может масштабироватьшрифт. Однако при этом резко ухудшается качество, поэтому масштабирование можнозапретить, используя значение PROOF_QUALITY.
lfPitchAndFamily два младших бита задают тип шрифта — DEFAULT_PITCH (любой тип), VARIABLE_PITCH (пропорциональный) или FIXED_PITCH(моноширинный); старший байт указывает семейство, которое задается одним изследующих символов: FF_DECORATIVE, FF_DONTCARE, FF_MODERN, FF_ROMAN, FF_SCRIPT,FF_SWISS.
lfFaceName массив из LF_FACESIZE символов,содержащий заканчивающееся \0 имя шрифта. Пустое имя соответствует шрифтуустройства.
 
1.3 Основыподбора шрифтов в Windows
Когда Вывызываете функцию, создающую шрифт, Windows перебирает все имеющиеся шрифты,определяя шрифт, точнее всего соответствующий желаемому.
При подборешрифта используется система “пенальти”: для каждого из шрифтов он вычисляет“пенальти”, соответствующие отличию данного шрифта от желаемого. Шрифт сминимальным пенальти считается наиболее точно соответствующим желаемому.
Пенальтивычисляются следующим образом: для существенных параметров вводятся бальныеоценки. Если заказанный параметр соответствует шрифту, пенальти равно 0, а еслиотличается, то размер пенальти зависит от параметра. Значения пенальтиприведены в следующей таблице:параметр пенальти fCharSet 4
fPitchAndFamily: pitch
family
3
3 lfFaceName 3 lfHeight 2 lfWidth 2 lfItalic 1 lfUnderline 1 lfStrikeOut 1
В этойтаблице можно заметить несколько интересных особенностей. Например, пенальти занесоответствие кодовой таблице больше, а за не–принадлежность к семейству равнапенальти за несоответствие имени шрифта. Практически, если Вы хотитеиспользовать шрифт с конкретным именем, то Вы должны обязательно указатьправильные кодовую страницу и семейство шрифтов, иначе Windows можетиспользовать шрифт с другим именем.
 
1.4 Функциидля работы со шрифтами
После того,как Вы получили хендл шрифта, Вы можете осуществить вывод текста, используяэтот шрифт. Для этого Вы должны выбрать шрифт в контекст устройства с помощьюфункции
SelectObject(hDC, hFont );
Всепоследующие операции вывода будут использовать тот шрифт, который Вы выбрали вконтекст устройства. Если Вам надо получить информацию о загруженном шрифте, тоВы можете воспользоваться функциями:
intGetTextFace( hDC, nMaxBuffer, lpsBuffer );
intGetObject( hFont, sizeof(LOGFONT), &stLogfont );
ФункцияGetTextFace() заполняет указанный буфер именем применяемого шрифта, а функцияGetObject() позволяет заполнить структуру LOGFONT информацией о конкретномшрифте.
Более сложнымпредставляется все-таки выбор шрифта и определение характеристик вновьсоздаваемого шрифта. Это связано с тем, что в большинстве случаев Вы заранее незнаете, какие шрифты используются в данном комплекте Windows, то есть Вы должныуметь выбирать нужный шрифт из числа имеющихся в Windows.
Это можноосуществить двумя разными способами — Вы можете перебирать все шрифты и выбратьиз них нужный Вам (например создать меню, содержащее имена шрифтов), или Выможете воспользоваться функцией ChooseFont() для вызова стандартного диалогавыбора шрифта.
Сначала мыразберемся с основными правилами перебора шрифтов. В Windows для этих целей существуетдве функции:
int EnumFonts(hDC, lpszFace, lpfnEnumProc, lParam );
int EnumFontFamilies(hDC, lpszFace, lpfnEnumProc, lParam );
Обе этифункции осуществляют перебор шрифтов, которые могут быть применены на указанномустройстве, и имеющие заданное имя (значение NULL указывает на перебор всехдоступных шрифтов). Эти функции осуществляют перебор чуть-чуть различающимсяобразом.
Разницасвязана с тем, что TrueType шрифты обычно существуют в нескольких вариантах,отличающихся начертанием (жирный, наклонный и др.). Эти варианты существуют какотдельные шрифты, поэтому функция EnumFonts() перечисляет один и тот–жеTrueType шрифт несколько раз, соответственно с количеством разных начертаний.Функция EnumFontFamilies() перебирает только по одному начертанию каждогоTrueType шрифта.
Для каждогоперечисляемого шрифта вызывается функция lpfnEnumProc(), которой передаетсяструктуры типа LOGFONT и TEXTMETRIC (функция EnumFontFamilies() передаетструктуры NEWLOGFONT и NEWTEXTMETRIC, содержащие дополнительные данные), номертипа шрифта (DEVICE_FONTTYPE, RASTER_FONTTYPE или TRUETYPE_FONTTYPE) и параметрlParam, который Вы указали для функции EnumFonts() или EnumFontFamilies().
Общий видфункции, вызываемой при переборе шрифтов, следующий:
int CALLBACK _export EnumFontProc( lpLF, lpTM, nType, lParam );
int CALLBACK _export EnumFontFamProc( lpNLF, lpNTM,nType, lParam );
Параметры:
lpLF являетсядальним адресом структуры LOGFONT
lpNLF являетсядальним адресом структуры NEWLOGFONT
lpTM являетсядальним адресом структуры TEXTMETRIC
lpNTM являетсядальним адресом структуры NEWTEXTMETRIC
nType указываеттип шрифта
lParam дополнительныйпараметр, определяемый Вами.
Осуществляяперебор шрифтов, Вы можете, например, заполнить меню, содержащее имена нужныхВам шрифтов, или выбрать тот шрифт, который Вас устраивает и т.д.
Во многихслучаях удобнее, однако, не перебирать шрифты, а воспользоваться каким-либодиалогом для выбора нужного шрифта. Это можно сделать с помощью функцииChooseFont(), описанной в файле COMMDLG.H.
ФайлCOMMDLG.H содержит описания нескольких функций и структур данных, позволяющихвызывать “диалоги общего пользования” (COMMon DiaLoGs). Помимо файла COMMDLG.HВы должны включить в Ваше приложение файл COMMDLG.LIB, с помощью которогоосуществляется связывание Вашего приложения с динамической библиотекойCOMMDLG.DLL, содержащей требуемые функции.
Функция,вызывающая диалог для выбора шрифта выглядит следующим образом:
BOOL ChooseFont(lpChooseFont );
причемпараметр lpChooseFont указывает на структуру типа CHOOSEFONT:
typedefstruct tagCHOOSEFONT { /* cf */
DWORDlStructSize; // = sizeof(CHOOSEFONT)
HWND hwndOwner;
HDC hDC; //используется только для принтера
LOGFONT FAR* lpLogFont;
int iPointSize;
DWORD Flags;
COLORREF rgbColors;
LPARAM lCustData;
UINT (CALLBACK* lpfnHook)(HWND, UINT, WPARAM, LPARAM);
LPCSTR lpTemplateName;
HINSTANCE hInstance;
LPSTR lpszStyle;
UINT nFontType;
int nSizeMin;
int nSizeMax;
} CHOOSEFONT;
Вы должнызаполнить нужные поля этой структуры и вызвать функцию ChooseFont() для выборанужного шрифта. Функция возвращает результат TRUE (не 0), если шрифт былвыбран, или FALSE (0), если была нажата кнопка “Cancel”.
Заполнениеполей этой функции элементарно, рассмотреть стоит только поле Flags,описывающее характеристики диалога и выбираемого шрифта. С помощью этого поляВы можете уточнить, из какой группы Вы собираетесь выбирать шрифт:
поустройствам:
CF_PRINTERFONTSшрифты принтера (Вы должны указать hDC принтера)
CF_SCREENFONTSдисплейные шрифты
CF_BOTH все
по типамшрифтов:
CF_TTONLY толькоTrueType
CF_NOVECTORFONTSрастровые и TrueType
CF_SCALABLEONLYвекторные, TrueType и некоторые шрифты принтера
CF_WYSIWYG шрифты,используемые и дисплеем и принтером. (вместе с CF_WYSIWYG надо установитьCF_BOTH|CF_SCALABLEONLY)
по кодировке:
CF_ANSIONLY толькоANSI шрифты
CF_NOOEMFONTSвсе шрифты кроме OEM
поособенностям
CF_FIXEDPITCHONLYтолько моноширинные шрифты
CF_FORCEFONTEXISTшрифт с выбранными атрибутами должен существовать (не допускаетсяавтоматическое преобразование) по размеру
CF_LIMITSIZE установивэтот флаг Вы должны задать поля nSizeMin и nSizeMax, которые определятдопустимые размеры шрифтов.
А также Выможете несколько видоизменять диалог:
по наличиюкнопок:
CF_APPLY присутствуеткнопка “Apply” (Применить)
CF_USEHELP присутствуеткнопка “Help” (Справка)
по правиламинициализации:
CF_INITTOLOGFONTSTRUCTиспользовать данные структуры LOGFONT (указанной в CHOOSEFONT) дляинициализации диалога
повозможности выбирать параметры:
CF_EFFECTS диалогпозволит установить стили подчеркивание (underline) и перечеркивание (overstrike)
CF_NOFACESEL нельзявыбирать имя шрифта из списка
CF_NOSIMUALTIONSзапрещена имитация шрифта с помощью GDI
CF_NOSIZESEL нельзявыбирать размер шрифта
CF_NOSTYLESELнельзя выбирать стиль шрифта.
Дополнительныевозможности этой функции связаны с возможностью видоизменять сам диалог, (в томчисле самостоятельно спроектировать шаблон диалога), и функцию диалога, длявыполнения дополнительных действий.
 

2. Шрифтыв качестве ресурсов
 
2.1 Применениешрифтовых ресурсов
Сейчас мырассмотрим последнюю тему, связанную со шрифтами, а именно — созданиесобственных шрифтовых ресурсов. Ранее мы встречались с одной из разновидностейресурсов — битмапом. Тогда битмап включался в ресурс и становился доступнымприложению. Для этого мы в файле описания ресурсов включали строку вида:
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.
Добавлять илиудалять шрифты из системной таблицы удобно либо в начале и конце приложения,либо при создании и удалении главного окна приложения.
 
2.2 Созданиешрифтовых ресурсов
В этомразделе мы будем говорить только о создании собственных растровых шрифтовыхресурсов. Это связано с тем, что стандартные редакторы шрифтовых ресурсов(включаемые в SDK и компиляторы) позволяют создавать только растровые шрифты.
Для начала мыдолжны нарисовать требуемые нам шрифты с помощью какого-либо редактораресурсов. Растровые шрифты обычно размещаются в файлах с расширением .FNT (этоне шрифтовой файл, а отдельный ресурс, как, скажем, битмап). Нам можетпонадобится нарисовать несколько шрифтов разного размера, но имеющих общееначертание. Эти шрифты будут сохранены в разных .FNT файлах.
Далее мыдолжны построить шрифтовой файл .FON, содержащий наши шрифты. Этот файлявляться библиотекой ресурсов. Практически он оформлен как обычное Windowsприложение, которое содержит только ресурсы. Мы можем описать такое приложение,как приложение вообще не имеющее сегмента кода, или как библиотеку.
Так как нашабиблиотека должна содержать шрифтовые ресурсы, то мы должны задать файлописания ресурсов .RC, содержащий список нарисованных нами шрифтов, например:
1FONT fonta.fnt
2FONT fontb.fnt
3 FONTfontc.fnt
Конечно нампонадобится файл описания приложения .DEF в несколько специфичном виде:
LIBRARY
DESCRIPTION'FONTRES DISPLAY: 40-char terminal'
EXETYPEWINDOWS
STUB'WINSTUB.EXE'
DATANONE
Надо обратитьвнимание на использование слова 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. Для создания модуля не имеющего кода, нам надонаписать простейший ассемблерный файл:
_TEXTsegment byte public 'CODE'
_TEXTends
end
Этот файлописывает только один сегмент нулевой длины.
После этогомы можем приступить к построению шрифтового файла. Для этого мы сначалакомпилируем ассемблерный файл:
tasm file.asm
затем мыдолжны построить нашу библиотеку и включить в нее спроектированные ресурсы:
tlinkfile.obj,file.exe,nul,,file.def
rcfile.rc
renamefile.exe file.fon
Теперь мырасполагаем собственным шрифтовым ресурсом, который мы можем применять в нашемприложении. Еще раз надо отметить, что обязательно применение 'Borland TLINK'для построения файла, так как другие сборщики могут построить неверный модуль.
Ранее мысделали замечание о том, что мы можем строить шрифтовой файл двумя способами — как библиотеку не имеющую кода, или как обычную библиотеку. Если мы хотимстроить обычную библиотеку, то вместо ассемблерного файла нам надо написатьнебольшой файл на C:
#include
extern«C» {
intCALLBACK LibMain(
HANDLEhInstance, WORD wDataSeg, WORD cbHeapSize,LPSTR lpszCmdLine) {
// обычнофункция LibMain() разблокирует сегмент данных
// если онимеет динамический heap.
// if (cbHeapSize ) UnlockData( 0 );
// так как мывообще не имеем данных (и heap тоже)
// то можемэтого не делать.
return1;}
intCALLBACK WEP( int bSystemExit ) {
returnTRUE;}}
Этот файлсодержит две процедуры — LibMain() — которая заменяет обычный WinMain() ивызывается при инициализации библиотеки — и процедуру WEP(), которая вызываетсяпри удалении ненужной библиотеки.
В этом файленадо обратить внимание на то, что функция LibMain описана как CALLBACK (PASCALFAR), в отличие от WinMain. К сожалению, некоторые компиляторы предполагают,что она должна быть NEAR для моделей памяти с одним сегментом кода. В качествевыхода можно изменить имя, например, написать его только большими буквами.Тогда компилятор не распознает эту функцию как стандартную и не сделает ошибки,а сборщик осуществит правильное связывание, так как функция декларирована какCALLBACK (PASCAL FAR).
Втораяособенность — указание, что имена функций не должны кодироваться как C++ имена( extern «C» ). Это опять–же связано с особенностями некоторыхкомпиляторов, которые не распознают функцию WEP() (Windows Exit Procedure) какстандартную, и осуществляют для нее C++ кодирование имени — при этом сборщик неможет правильно построить задачу.
В остальномпостроение шрифтового файла не отличается от рассмотренного, конечно кромекомпиляции исходного текста, которая выполняется как для обычногоWindows-приложения:
bcc-ms -W file.c file.def
 
2.3 ОсобенностиTrueType шрифтов
Сейчас мырассмотрим некоторые особенности применения собственных TrueType шрифтов. Этиособенности связаны с тем, что TrueType шрифт представлен в совершенно инойформе, чем растровые шрифты. Если Вы с помощью какого-либо инструментальногосредства (например, FontoGrapher) создадите TrueType шрифт, то обнаружите, чтоон представлен в виде файла с расширением .TTF.
Однакоприменять .TTF файл непосредственно нельзя. Для того, что бы можно былоиспользовать TrueType шрифт надо построить промежуточный файл, обычно срасширением .FOT, который можно использовать вместо файла .FON для добавленияшрифта в таблицу ресурсов. Для построения этого файла Вы должны воспользоватьсяфункцией
BOOL CreateScalableFontResource(
nHidden,lpszResourceFile, lpszFontFile, lpszPath);
Эта функциясоздает файл с именем lpszResourceFile для доступа к .TTF файлу, заданномупараметром lpszFontFile, параметр lpszPath указывает путь до .TTF файла.Последний оставшийся параметр nHidden указывает возможность использованияшрифта другими приложениями. Если он 0, то другие приложения имеют доступ кэтому шрифту, а если 1, то доступ запрещен и этот шрифт не перечисляется припереборе шрифтов (EnumFonts(), EnumFontFamilies()).
 
2.4 Настройкаприложений
Заканчиваяразговор о шрифтах, удобно рассмотреть еще один компонент Windows — средствадля настройки приложений. Под настройкой (иногда «профилированием»)понимается задание характеристик приложения и их сохранение для использованияпри следующем запуске.
Обычно такиезадачи решаются с помощью создания конфигурационных файлов. Однако конфигурацияописывается каждой задачей по-своему, что не всегда удобно. Windows предлагаетобщий для всех приложений механизм описания их характеристик, с использованиемфайлов настройки.
Такие файлы(обычно имеющие расширение .INI) являются обычными ASCII–файлами, разделеннымина секции, начинающиеся с имени секции, заключенного в квадратные скобки. Далееследует список параметров в виде ‘параметр=значение’, каждый параметр размещаетсяв отдельной строке. В этот файл можно вставлять комментарии — строкиначинающиеся с ‘;’.
Пример взятиз файла WORKSHOP.INI:
[UserControls]
BorShade=E:\BORLANDC\WORKSHOP\BWCC.DLL
[RWS_Bitmap]
PercentLeft=50
ZoomLeft=1
ZoomRight=1
bVert=0
[RWS_Font]
PercentLeft=50
ZoomLeft=4
ZoomRight=1
bVert=1
Для работы стакими файлами Windows предоставляет набор функций, осуществляющих запись ичтение параметров:
intGetProfileInt(lpszSection, lpszEntry, nDefault);
intGetProfileString(lpszSection, lpszEntry, lpszDefault, lpsBuffer, nMaxBuffer);
BOOLWriteProfileString(lpszSection, lpszEntry, lpszString);
ПараметрlpszSection задает имя секции (скобок в имени указывать не надо), lpszEntry — имя параметра. Если мы получаем значение параметра, то можем указать значениепо умолчанию, которое возвращается, если данный параметр не найден.
С помощьюфункции GetProfileString() можно получить список имен всех параметров в секции,указав lpszEntry= NULL. При этом имена параметров секции будут скопированы вбуфер последовательно друг за другом, каждое имя будет заканчиваться 0 и послепоследнего имени будут стоять два 0.
ФункцияWriteProfileString() позволяет не только записывать параметры, но и удалять,для чего надо указать lpszString=NULL. Можно удалить целиком всю секцию, указавlpszEntry=NULL.
Все трирассмотренных функции используют файл WIN.INI. При этом имя секции частоассоциируется с именем приложения. (Поэтому в документации имя секции частоназывается именем приложения).
Конечно,часто бывает неудобно использовать общий файл настройки для всех существующихприложений (при этом, в частности, трудно организовать удаление приложений).Windows предоставляет возможность использовать собственный файл настройки (идаже несколько). Для работы с собственными файлами настройки предусмотрены ещетри функции:
intGetPrivateProfileInt( lpszSection, lpszEntry, nDefault, lpszIniFile );
intGetPrivateProfileString(
lpszSection,lpszEntry, lpszDefault, lpsBuffer, nMaxBuffer, lpszIniFile);
BOOLWritePrivateProfileString(
lpszSection,lpszEntry, lpszString, lpszIniFile);
Последнийпараметр этих функций задает имя файла настройки. Если Вы не указываете путь кфайлу, то он размещается в каталоге Windows.
 
2.5 Информациястандартных файлов настройки (win.ini и system.ini) о шрифтах и о принтере
Рассматриваянастройку приложений надо подробнее остановиться на файле WIN.INI. Этот файлсодержит большое количество характеристик, определяющих работу как самогоWindows, так и многих его приложений. Позже мы будем иногда ссылаться на этотфайл, например, при определении даты и времени.
Сейчас мырассмотрим информацию, хранимую в этом файле, касающуюся шрифтов. Самаясущественная для нас секция — [fonts]. В этой секции перечислены всешрифты, которые помещаются в системную таблицу при запуске Windows. Форматзаписей:
face name =file.fon
face name — это имя шрифта, а file.fon — имя шрифтового файла, содержащего растровый иливекторный шрифт, или file.fot — TrueType шрифт.
Пример:
[fonts]
Academy(TrueType)=ACADEMY.FOT
AcademyBold (TrueType)=ACADEMY0.FOT
Следующая секция, относящаяся к шрифтам, [FontSubstitutes], указывающая, какие шрифты, входящие в Windows 3.1 должны использоваться вместо некоторых шрифтов, входивших в Windows 3.0. Формат записей:
newname= old name
Пример:
[FontSubstitutes]
Helv=MSSans Serif
Courier=Helv
Если Выадаптируете приложение Windows 3.0 для работы в Windows 3.1, то Вам надоссылаться на эту секцию для определения имен шрифтов, которые Вы должныприменять.
Дополнительноинформация о системных шрифтах содержится в файле SYSTEM.INI, где в секции[boot] указываются системный (ANSI), терминальный (OEM) и системныйфиксированной ширины (ANSI) шрифты. Это делается с помощью параметров:
[boot]
fonts.fon=vgasys.fon
fixedfon.fon=vgafix.fon
oemfonts.fon=vgaoem.fon
Эти шрифтыиспользуются Windows при загрузке, когда системная таблица шрифтов еще неинициализирована. Кроме того некоторые шрифты, используемые DOS окном в Windowsопределены в секциях:
[boot.description]
woafont.fon=English(437)
[386Enh]
woafont=dosapp.fon
EGA80WOA.FON=EGA80WOA.FON
EGA40WOA.FON=EGA40WOA.FON
CGA80WOA.FON=CGA80WOA.FON
CGA40WOA.FON=CGA40WOA.FON
Рассмотрениестандартных файлов настройки мы продолжим, перейдя к параметрам принтера. Дляэтого мы возвращаемся к файлу WIN.INI, секция [devices]. В этой секцииперечислены все принтеры, которые были использованы инсталлированы. Каждаязапись определяет имя принтера, имя драйвера и имя выходного устройства(последовательный или параллельный порт, файл); формат записей:
printername= driver, port1 [,port2[,...]]
где printername — имя принтера, driver — имя драйвера и portN — имя выводного устройства.
Пример:
[devices]
Epson FX-80=EPSON9,FILE:,LPT1:
то есть:принтер 'Epson FX-80' обслуживается драйвером 'EPSON9.DRV' и может направлятьвывод в файл или в параллельный порт #1.
Характеристикивыводных устройств должны быть указаны еще в двух местах — в секции [ports],где перечислены имена всех разрешенных выводных устройств и заданыхарактеристики последовательных портов, и в секции [PrinterPorts], где указаныпредельные времена ожидания готовности и ошибки.
В секции[ports] записывается примерно такая информация:
[ports]
LPT1:=
LPT2:=
COM1:=9600,n,8,1
COM2:=9600,n,8,1,x
EPT:=
FILE:=
LPT1.DOS=
А в секции[PrinterPorts] записи похожи на секцию [device] с дополнительно указаннымивременами ожидания готовности и повторения для каждого устройства.
[PrinterPorts]
Epson FX-80=EPSON9,FILE:,15,45,LPT1:,15,45
С помощьювсех рассмотренных параметров описываются установленные в данный моментпринтеры, однако нас зачастую не интересуют все мыслимые принтеры, а толькоодин — тот, который подключен непосредственно сейчас. Для того, что быопределить этот принтер надо обратить внимание на секцию [windows], в которойесть параметр:
device=printer name, driver, port
Описывающийимя текущего принтера, обслуживающего его драйвера и используемое выводноеустройство. Обычно приходится пользоваться именно этой информацией.
 

3. Работас принтером
 
3.1 Получениеконтекста устройства
Теперь, когдамы научились определять характеристики принтера, мы можем перейтинепосредственно к работе с ним. Для начала нам надо получить хендл контекстаустройства, связанного с принтером. Существует две возможности сделать это:самим разобраться с файлом WIN.INI и создать контекст устройства иливоспользоваться стандартным диалогом для выбора и настройки принтера. Чащеприменяется второй способ (как более «дружественный»), однако иногдапроще все сделать самим (особенно, если Вы должны сами проверить наличие ихарактеристики принтеров — например при инсталляции программы).
Если мы хотимсами разобраться с принтером, то для создания контекста принтера мы должнывоспользоваться процедурой:
HDCCreateDC( lpszDriver, lpszDevice, lpszOutput, lpvData );
При этом мысначала должны определить имя драйвера lpszDriver, имя принтера lpszDevice иимя выводного устройства lpszOutput. Параметр lpvData мы будем устанавливать вNULL, для того, что бы произвести инициализацию по умолчанию (так как это былоопределено при инсталляции принтера или изменено через “Control Panel”).
Всю нужнуюдля создания контекста устройства информацию мы получим из параметра “device=”секции [windows]:
HDCGetPrinterDC( void ) {
charbuf[ 80 ];
char*Device, *Drive, *Output;
staticchar delimiters[]= ", ";
GetProfileString(«windows», «device», ",,,", buf, sizeof(buf)-1 );
Device=strtok( buf, "," );
Drive=strtok( NULL, delimiters );
Output=strtok( NULL, delimiters );
returnDevice && Drive && Output ?
CreateDC(Drive, Device, Output, NULL ): NULL;}
Этот способпозволяет легко получить хендл контекста текущего выбранного принтера. А еслинам желательно выбирать или настраивать принтер, то самым удобным будет способс использованием стандартного диалога (каждый драйвер принтера содержитсобственный диалог используемый для его настройки; этот диалог мы можемвызвать, обратившись к функции ExtDeviceMode драйвера — однако то–жесамое делает стандартный диалог).
Прииспользовании стандартного диалога мы должны вызвать функцию PrintDlg(...), определенную в COMMDLG.H:
#include «commdlg.h»
BOOL PrintDlg( PRINTDLG FAR* lppd);
typedefstruct tagPD {
DWORDlStructSize;
HWNDhwndOwner;
HGLOBALhDevMode;
HGLOBALhDevNames;
HDChDC;
DWORDFlags;
UINTnFromPage;
UINT nToPage;
UINT nMinPage;
UINT nMaxPage;
UINTnCopies;
HINSTANCEhInstance;
LPARAMlCustData;
UINT(CALLBACK* lpfnPrintHook)(HWND, UINT, WPARAM, LPARAM);
UINT(CALLBACK* lpfnSetupHook)(HWND, UINT, WPARAM, LPARAM);
LPCSTRlpPrintTemplateName;
LPCSTRlpSetupTemplateName;
HGLOBALhPrintTemplate;
HGLOBALhSetupTemplate;
} PRINTDLG;
Вы должнызаполнить нужные поля (обычно почти все — 0) этой структуры и вызвать функциюPrintDlg() для выбора текущего принтера и его настройки. Функция возвращаетрезультат TRUE (не 0), если контекст принтера успешно создан, или FALSE (0),если была нажата кнопка “Cancel” или возникла ошибка.
ПараметрlStructSize задает размер данной структуры, он должен быть равенsizeof(PRINTDLG), hwndOwner задает хендл окна–пользователя диалога (может быть0).
Два хендлаглобальных объектов hDevMode и hDevNames используются для начальнойинициализации диалога. Обычно они задаются 0, а функция PrintDlg() сама создаетэти блоки и указывает их хендлы. Если Вы не планируете больше обращаться кфункции PrintDlg(), то вы должны их уничтожить (с помощью функцииGlobalFree()). Однако обычно эти блоки уничтожаются только при завершении всегоприложения — так что при повторном вызове PrintDlg() в структуре PRINTDLG ужесодержаться эти хендлы и информация из этих блоков используется для повторнойинициализации диалога.
Поле hDC привызове диалога игнорируется, а после завершения может (если Вы это закажете)содержать хендл созданного контекста принтера.
Интереснорассмотреть только некоторые значения поля Flags:
PD_PRINTSETUPвместо диалога “выбор принтера” вызвать диалог “настройка принтера”.
PD_RETURNDC создатьконтекст принтера и вернуть его хендл в поле hDC
PD_RETURNIC создатьинформационный контекст принтера и вернуть его хендл в поле hDC
PD_RETURNDEFAULTне вызывать никакого диалога, просто инициализировать глобальные блоки hDevModeи hDevNames (перед таким вызовом функции PrintDlg() они должны быть равны 0)
Послеполучения хендла контекста устройства принтера мы можем перейти к выводу напринтер. Но сначала нам надо разобраться в том, как Windows организует работу спринтером.
 
3.2 Основыпечати
Когда Выполучили контекст устройства для принтера, на самом деле Вы не получили доступак самому принтеру, а только лишь к промежуточному метафайлу. Пока Вы рисуете напринтере, все нужные команды запоминаются в этом метафайле и только после того,как Вы объявите о завершении работы со страницей, Windows осуществит печатьподготовленной страницы из метафайла.
Реальныймеханизм сложнее, так как спулинг принтера может быть отключен, а, кроме того,Ваше приложение может использовать специальный метод пополосной печати, которыйзаметно усложняет внутреннюю логику печати.
Такой сложныймеханизм позволяет осуществить спулинг печати и более-менее эффективноеразделение принтера между разными приложениями.
Общиеправила, с точки зрения приложения, сводятся к следующему:
начинаяработу с принтером, Вы должны зарегистрировать собственное задание на печать.Это исключает одновременное печатание данных разными приложениями.
Далее Выдолжны заполнить страницу нужными данными и подать команду на печать этойстраницы и на переход к следующей.
Когда всестраницы напечатаны, Вы должны сказать Windows о завершении печати Вашегозадания.
В этой схемеесть несколько недостатков:
Во-первых, процесс печати даже одной страницыможет быть весьма продолжительным (до 30-60 минут) — а при такой схеме Вы неможете даже прервать процесс печати;
Во-вторых, графический образ одной страницы напринтере высокого разрешения (особенно цветном) может занимать десяткимегабайт, что достаточно жестко ограничивает возможности печати.
Для того, чтобы решить эти проблемы применяют различные приемы. Для того, что бы можно быловыполнять какую-либо иную работу одновременно с печатью, и что бы печать можнобыло прервать в любой момент, добавляют специальную функцию, называемую AbortProc(),которая вызывается автоматически во время печати для обработки сообщений и длятого, что бы работу принтера можно было прервать.
В этомслучае, помимо регистрации задания, Вы должны установить собственную AbortProcдо начала самой печати.
Для решениявторой задачи вводят специальный метод пополосной печати (banding). Вэтом случае Вы запрашиваете у принтера данные о полосе, которую надо отобразитьи заполняете эту полосу (или всю страницу — контекст устройства реальносоответствует только этой полосе). Тогда максимальный размер временного файла,содержащего образ страницы, ограничен размерами полосы.
В этом случаеВам надо иметь в виду несколько нюансов:
припополосной печати функция AbortProc() автоматически вызывается слишком редко,поэтому Вы должны сами предусмотреть вызовы этой функции с достаточнойчастотой.
ориентацияполос не обязательно горизонтальна, так как принтер может печатать как в режиме“портрет” (Portrait), так и в режиме “ландшафт” (Landscape).
Полосу дляпечати у Вас запрашивает Windows. Вы не знаете заранее ни ориентацию этойполосы, ни ее размеры. Windows формирует запрос для печатания полосы до тех пор,пока не будет напечатана вся страница.
Теперь намнадо рассмотреть непосредственно текст программы, осуществляющий печать.
 
3.3 Печатаниена принтере
Вообще дляуправления печатью достаточно только одной процедуры — Escape(), котораяиспользовалась в прежних версиях Windows.
intEscape( hDC, nEscape, cbInput, lpsInData, lpvOutput );
ПараметрnEscape указывает код выполняемой операции, параметры cbInput и lpsInDataуказывают исходные данные для операции, а lpvOutput — результат операции.Применение и форма исходных данных и результатов зависит от операции.
В версииWindows 3.1 к этой процедуре добавлен ряд вспомогательных, которые простовыполняют отдельные операции.
Сейчас мырассмотрим некоторые основные операции, необходимые для печати. Первая операциярегистрирует наше задание на печать:
Escape( hDC,STARTDOC, cbName, lpsName, NULL );
или
StartDoc(hDC, lpDocInfo );
structDOCINFO {
intcbSize;
LPSTRlpszDocName;
LPSTRlpszOutput;};
ПараметрыcbName и lpsName определяют название нашего задания. Возвращаемое значение,большее 0, указывает на успешную постановку задания в очередь, а значение 0 именьше указывает на возникшую ошибку.
Далее, еслимы хотим печатать страницу целиком, то после ее заполнения мы должны податькоманду на печать страницы:
// заполнитьстраницу
Escape( hDC,NEWFRAME, 0, NULL, NULL );
или
StartPage(hDC );
// заполнитьстраницу
EndPage( hDC);
В случаеуспешного завершения задания мы должны сообщить об этом с помощью операцииENDDOC:
Escape(hDC, ENDDOC, 0, NULL, NULL );
или
EndDoc( hDC);
Однако намможет понадобится прервать печать досрочно. Для этого мы должны разработать иустановить нашу собственную процедуру AbortProc. Предположим, что такая функциянами написана и ее имя AbortProc(). Тогда мы можем установить ее следующимспособом:
FARPROClpfnAbortProc= MakeProcInstance( (FARPROC)AbortProc, hInstance );
Escape(hDC, SETABORTPROC, 0, (LPSTR)lpfnAbortProc, NULL );
//печатаем...
FreeProcInstance(lpfnAbortProc );
или
FARPROClpfnAbortProc= MakeProcInstance( (FARPROC)AbortProc, hInstance );
SetAbortProc(hDC, (ABORTPROC)lpfnAbortProc );
//печатаем...
FreeProcInstance(lpfnAbortProc );
При этом,если наше задание будет досрочно снято с печати, то мы должны сообщить об этом(что бы задание было корректно удалено из очереди):
Escape(hDC, ABORTDOC, 0, NULL, NULL );
или
AbortDoc( hDC);
Небольшойпример (поясняющий правила разработки процедуры AbortProc):
staticBOOL bAbort;
BOOLPASCAL FAR _export AbortProc( HDC hdcPRN, short nCode ) {
MSGmsg;
while( !bAbort && PeekMessage( &msg,NULL,0,0,PM_REMOVE ) ) {
TranslateMessage(&msg );
DispatchMessage(&msg );}
return!bAbort;}
staticBOOL DoPrint( void ) {
staticchar szName[]= «Test Printing»;
FARPROClpfnAbort;
BOOLanswer= FALSE;
HDChdcPRN;
hdcPRN=GetPrinterDC(); // получение hdcPRN см. выше
lpfnAbort=MakeProcInstance( (FARPROC)AbortProc, hInstance );
Escape(hdcPRN, SETABORTPROC, 0, (LPSTR)lpfnAbort, NULL );
if( Escape( hdcPRN, STARTDOC, sizeof(szName)-1, szName, NULL ) > 0 ) {
while (!bAbort && /* есть что печатать */ ) {
//рисуем на странице
if( Escape( hdcPRN, NEWFRAME, 0,NULL,NULL )
if( bAbort ) {
Escape(hdcPRN, ABORTDOC, 0,NULL,NULL );
}else {
Escape(hdcPRN, ENDDOC, 0,NULL,NULL );
answer=TRUE;}}
FreeProcInstance((FARPROC)lpfnAbort );
DestroyDC(hdcPRN );
returnanswer;}
В этомпримере надо обратить внимание на переменную bAbort. Она может быть установленав значение TRUE для завершения печати. В данном примере досрочное завершение непредусмотрено, хотя его легко можно сделать, устанавливая эту переменную,например, в ответ на выбор пункта меню, на нажатие кнопки диалога или даже потаймеру.
Если мы будемиспользовать пополосную печать, то нам надо вместо операции NEWFRAME выполнятьсерию операций NEXTBAND до тех пор, пока полоса для печати не окажется пустой(что соответствует полностью напечатанной странице); при этом внутренний циклдля печати страниц придется несколько изменить:
...RECT rc;
...while (!bAbort && /* есть что печатать */ ) {
while( Escape(hdcPRN, NEXTBAND, 0, NULL, (LPSTR)&rc) > 0 ) {
if( IsRectEmpty( &rc ) ) goto ok_page;
// заполняемполосу или всю страницу, иногда вызывая AbortProc:
lpfnAbortProc(hdcPRN, 0 );
// Внимание!используется указатель на функцию, а не она сама!}
bAbort= TRUE;
ok_page:;}...


Не сдавайте скачаную работу преподавателю!
Данный реферат Вы можете использовать для подготовки курсовых проектов.

Поделись с друзьями, за репост + 100 мильонов к студенческой карме :

Пишем реферат самостоятельно:
! Как писать рефераты
Практические рекомендации по написанию студенческих рефератов.
! План реферата Краткий список разделов, отражающий структура и порядок работы над будующим рефератом.
! Введение реферата Вводная часть работы, в которой отражается цель и обозначается список задач.
! Заключение реферата В заключении подводятся итоги, описывается была ли достигнута поставленная цель, каковы результаты.
! Оформление рефератов Методические рекомендации по грамотному оформлению работы по ГОСТ.

Читайте также:
Виды рефератов Какими бывают рефераты по своему назначению и структуре.

Сейчас смотрят :