Графический интерфейс GDI в Microsoft Windows© Александр Фролов, Григорий ФроловТом 14, М.: Диалог-МИФИ, 1993, 288 стр. 6.1. Контекст отображения для принтераНа первый взгляд, контекст отображения для принтера получить нетрудно - достаточно вызвать функцию CreateDC , указав имя драйвера, имя устройства и имя порта вывода, к которому подключен принтер: HDC WINAPI CreateDC( LPCSTR lpszDriver, // имя драйвера LPCSTR lpszDevice, // имя устройства LPCSTR lpszOutput, // имя файла или порта вывода const void FAR* lpvInitData); // данные для инициализации Созданный при помощи функции CreateDC контекст устройства следует удалить после использования, вызвав функцию DeleteDC : BOOL WINAPI DeleteDC(HDC hdc); Как мы уже говорили, параметр lpszDriver является указателем на строку символов, содержащую имя драйвера, обслуживающего физическое устройство. Имя драйвера совпадает с именем файла *.drv, содержащего драйвер. Этот драйвер находится в системном каталоге Windows. Имя устройства lpszDevice - это название устройства. Параметр lpszOutput указывает на структуру данных типа DEVMODE, используемую при инициализации устройства вывода. Если при работе с устройством нужно использовать параметры, установленные при помощи приложения Control Panel, параметр lpszOutput следует указать как NULL. Однако как определить эти параметры? Текущий принтер описан в файле win.ini в разделе [windows]: [windows] ... ... device=HP LaserJet III,hppcl5a,LPT1: ... Вы можете получить контекст отображения для текущего принтера, указав эти параметры функции CreateDC: hdc = CreateDC("hppcl5a", "HP LaserJet III", "LPT1:", NULL); Однако к компьютеру может быть подключено несколько принтеров. Например, к порту LPT1: может быть подключен лазерный принтер, а к порту LPT2: - матричный или струйный принтер. Список подключенных принтеров, имена драйверов и портов ввода/вывода можно найти в разделе [devices] файла win.ini: [devices] Epson FX-850=EPSON9,LPT1: HP LaserJet III=hppcl5a,LPT1: Ваше приложение может получить параметры принтера, используемого по умолчанию, а также параметры всех установленных принтеров непосредственно из файла win.ini. Это можно легко сделать при помощи функции GetProfileString: int GetProfileString( LPCSTR lpszSection; // адрес раздела LPCSTR lpszEntry; // адрес элемента раздела LPCSTR lpszDefault; // адрес строки по умолчанию LPSTR lpszReturnBuffer; // адрес буфера для записи int cbReturnBuffer; // размер буфера Параметр lpszSection должен указывать на имя раздела, в нашем случае на строку "windows". Через параметр lpszEntry передается адрес текстовой строки, содержащий имя элемента раздела, в нашем случае это адрес строки "device". Если указанного элемента или раздела нет в файле win.ini, используется строка по умолчанию, адрес которой передается через параметр lpszDefault. Найденная строка (или строка по умолчанию) будет записана в буфер, адрес которого передается через параметр lpszReturnBuffer. Размер буфера должен быть указан в параметре cbReturnBuffer. Для получения контекста отображения текущего принтера обычно используется такая функция: HDC PASCAL GetPrinterDC() { char msgbuf[128]; LPSTR pch; LPSTR pchFile; LPSTR pchPort; // Определяем текущий принтер из файла win.ini if(!GetProfileString("windows", "device", "", msgbuf, sizeof(msgbuf))) return NULL; // Выполняем разбор строки для выделения имени драйвера, // имени устройства и имени порта ввода/вывода for(pch=msgbuf; *pch && *pch != ','; pch=AnsiNext(pch)); if(*pch) *pch++ = 0; // Пропускаем управляющие символы и символ табуляции while(*pch && *pch <= ' ') pch=AnsiNext(pch); pchFile = pch; while(*pch && *pch != ',' && *pch > ' ') pch = AnsiNext(pch); if(*pch) *pch++ = 0; while(*pch && (*pch <= ' ' || *pch == ',')) pch = AnsiNext(pch); pchPort = pch; while(*pch && *pch > ' ') pch = AnsiNext(pch); *pch = 0; // Возвращаем контекст отображения для принтера return CreateDC(pchFile, msgbuf, pchPort, NULL); } Приведенная выше функция способна работать с двухбайтовыми кодами символов, так как для сканирования строки используется функция AnsiNext. Ситуация, однако, усложняется при необходимости сделать выбор между одним из установленных принтеров. Хорошо спроектированное приложение должно позволять пользователю выбирать любой из установленных принтеров, а не только тот, который используется по умолчанию. В этом случае вам надо создать диалоговую панель (или меню), с помощью которой пользователь мог бы выбрать нужный принтер. Для получения списка установленных принтеров вы можете воспользоваться все той же функцией GetProfileString , указав в качестве первого параметра адрес строки "devices", а в качестве второго - значение NULL: GetProfileString("devices", NULL, "", msgbuf, sizeof(msgbuf)); В этом случае в буфер будут переписаны все строки из раздела [devices], каждая строка будет закрыта двоичным нулем, последняя строка будет закрыта двумя двоичными нулями. Однако есть еще одна задача, которую должно уметь решать ваше приложение. Как правило, для каждого принтера возможна настройка таких параметров, как размер и расположение бумаги, выбор устройства подачи бумаги, интенсивность печати и разрешающая способность и так далее. Для выполнения такой настройки ваше приложение должно вызвать функцию DeviceMode или более новую ExtDeviceMode , расположенную в драйвере нужного принтера. Заметим, что эти функции экспортируются драйвером как обычной DLL-библиотекой (драйвер принтера и есть DLL-библиотека). Для вызова одной из этих функций вы должны загрузить драйвер явным образом, вызвав функцию LoadLibrary , а затем получить адрес точки входа при помощи функции GetProcAddress . DLL-библиотеки и перечисленные выше функции мы описали в 13 томе "Библиотеки системного программиста". Все это выглядит достаточно сложно и громоздко, однако стандартное приложение Windows должно обеспечивать возможность выбора принтера для печати и возможность установки параметров для выбранного принтера. К счастью, DLL-библиотека commdlg.dll содержит функцию PrintDlg, способную решить все перечисленные выше задачи и вдобавок получить для выбранного принтера контекст отображения, который можно использовать для рисования на принтере (или печати, если вам так больше нравится). |