Смекни!
smekni.com

Семейства шрифтов в Windows (стр. 4 из 5)

Пример:

[fonts]

Academy (TrueType)=ACADEMY.FOT

Academy Bold (TrueType)=ACADEMY0.FOT

Следующаясекция, относящаясякшрифтам, [FontSubstitutes], указывающая, какиешрифты, входящиев Windows 3.1 должныиспользоватьсявместонекоторыхшрифтов, входившихв Windows 3.0. Форматзаписей:

new name= old name

Пример:

[FontSubstitutes]

Helv=MS Sans 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]. В этой секции перечислены все принтеры, которые были использованы инсталлированы. Каждая запись определяет имя принтера, имя драйвера и имя выходного устройства (последовательный или параллельный порт, файл); формат записей:

printer name= driver, port1 [,port2[,...]]

где printer name - имя принтера, driver - имя драйвера и portN - имя выводного устройства.

Пример:

[devices]

EpsonFX-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]

EpsonFX-80=EPSON9,FILE:,15,45,LPT1:,15,45

С помощью всех рассмотренных параметров описываются установленные в данный момент принтеры, однако нас зачастую не интересуют все мыслимые принтеры, а только один - тот, который подключен непосредственно сейчас. Для того, что бы определить этот принтер надо обратить внимание на секцию [windows], в которой есть параметр:

device= printer name, driver, port

Описывающий имя текущего принтера, обслуживающего его драйвера и используемое выводное устройство. Обычно приходится пользоваться именно этой информацией.

3. Работа с принтером

3.1 Получение контекста устройства

Теперь, когда мы научились определять характеристики принтера, мы можем перейти непосредственно к работе с ним. Для начала нам надо получить хендл контекста устройства, связанного с принтером. Существует две возможности сделать это: самим разобраться с файлом WIN.INI и создать контекст устройства или воспользоваться стандартным диалогом для выбора и настройки принтера. Чаще применяется второй способ (как более "дружественный"), однако иногда проще все сделать самим (особенно, если Вы должны сами проверить наличие и характеристики принтеров - например при инсталляции программы).

Если мы хотим сами разобраться с принтером, то для создания контекста принтера мы должны воспользоваться процедурой:

HDC CreateDC( lpszDriver, lpszDevice, lpszOutput, lpvData );

При этом мы сначала должны определить имя драйвера lpszDriver, имя принтера lpszDevice и имя выводного устройства lpszOutput. Параметр lpvData мы будем устанавливать в NULL, для того, что бы произвести инициализацию по умолчанию (так как это было определено при инсталляции принтера или изменено через “Control Panel”).

Всю нужную для создания контекста устройства информацию мы получим из параметра “device=” секции [windows]:

HDC GetPrinterDC( void ) {

char buf[ 80 ];

char *Device, *Drive, *Output;

static char delimiters[]= ", ";

GetProfileString( "windows", "device", ",,,", buf, sizeof(buf)-1 );

Device= strtok( buf, "," );

Drive= strtok( NULL, delimiters );

Output= strtok( NULL, delimiters );

return Device && Drive && Output ?

CreateDC( Drive, Device, Output, NULL ) : NULL;}

Этот способ позволяет легко получить хендл контекста текущего выбранного принтера. А если нам желательно выбирать или настраивать принтер, то самым удобным будет способ с использованием стандартного диалога (каждый драйвер принтера содержит собственный диалог используемый для его настройки; этот диалог мы можем вызвать, обратившись к функции ExtDeviceMode драйвера - однако то–же самое делает стандартный диалог).

При использовании стандартного диалога мы должны вызвать функцию PrintDlg(...), определенную в COMMDLG.H:

#include "commdlg.h"

BOOLPrintDlg( PRINTDLGFAR* lppd );

typedef struct tagPD {

DWORD lStructSize;

HWND hwndOwner;

HGLOBAL hDevMode;

HGLOBAL hDevNames;

HDC hDC;

DWORD Flags;

UINT nFromPage;

UINT nToPage;

UINT nMinPage;

UINT nMaxPage;

UINT nCopies;

HINSTANCE hInstance;

LPARAM lCustData;

UINT (CALLBACK* lpfnPrintHook)(HWND, UINT, WPARAM, LPARAM);

UINT (CALLBACK* lpfnSetupHook)(HWND, UINT, WPARAM, LPARAM);

LPCSTR lpPrintTemplateName;

LPCSTR lpSetupTemplateName;

HGLOBAL hPrintTemplate;

HGLOBAL hSetupTemplate;

} 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 формирует запрос для печатания полосы до тех пор, пока не будет напечатана вся страница.