Прямая печать из Windows
АрхивНесмотря на то, что Delphi имитирует печать в текстовом режиме, вывод на бумагу будет осуществляться с помощью стандартных средств Windows... <...> Поэтому не стоит также пытаться переключать атрибуты печати с помощью ESC-последовательностей.
С. Орлик. Секреты Delphi на примерах
В приведенной цитате из книги, написанной специалистом, в компетентности которого сомневаться не приходится, и адресованной к тому же профессиональным разработчикам, речь идет о печати без использования объекта TPrinter (с использованием процедуры AssignPrn). Тем не менее, прямая печать из Windows возможна. Но сначала разберемся: а зачем она нужна?
В стандартном диалоге Print (откройте пункт меню "Файл/Печать..." в любой Win-программе) на верхней панели справа есть маленькое незаметное окошечко "Печать в файл". Ручаюсь, вы никогда этим не пользовались - а зря. Если поставить в этом окошечке галочку, то собственно печати и не будет: вместо нее в текущем каталоге возникнет файл с расширением PRN. Он содержит последовательность кодов символов (если документ текстовый) или координаты точек (если это рисунок), перемежаемые теми самыми ESC-последовательностями для управления принтером (или вовсе без оных - если это чистый текст). Как ни странно, в Windows нет (по крайней мере, я не нашел в OSR2 Rus) никаких упоминаний, что с этим файлом делать дальше. В DOS все просто - надо послать этот файл напрямую на принтер (в устройство PRN или LPT1, что то же самое). Таким образом там как бы реализовывалась отложенная печать. А в Windows? При попытке прямой печати путем, например, запуска Norton Commander (а также его аналогов) в окне и затем печати через F5 в устройство PRN вы получите сообщение типа "Путь не найден", "Access violation" или что-то в этом роде. Короче, Windows о таком способе печати понятия не имеет. Печать из DOS-приложений ставится в общую очередь и для реализации прямой печати приходится запускать чистый сеанс DOS, что, конечно, крайне неудобно. А вообще, такая вещь может пригодиться - сама по себе процедура прямой печати занимает куда меньше ресурсов компьютера, чем запущенный Word или тем более Photoshop в совокупности со штатной программой вывода на принтер, освобождая тем самым ресурсы для других программ.
Другая возможная область применения такой процедуры - если вдруг вам взбредет в голову по какой-то причине организовать печать из своего приложения, минуя средства Windows, скажем, для ускорения вывода на матричный принтер.
Надо сказать, что, обнаружив возможность осуществления печати способом, изложенным ниже, я и сам был изумлен, ведь известно, что Windows совершенно не переносит, когда ее пытаются обойти. Так и происходит, если вы попытаетесь по привычке (как DOS) вставить в Delphi-приложение ассемблерную процедуру с использованием функций BIOS. А вот прямой вывод в порт проходит - видимо, потому, что если прерывания BIOS переопределяются, то "железо" никуда не девается и адреса портов все те же.
Порт LPT содержит три регистра: регистр данных DR = Baseaddr, регистр состояния SR = Baseaddr+1, регистр управления CR = Baseaddr+2. Для LPT1 это будут соответственно 0378h, 0379h и 037Ah. Для организации печати необходимо сигнализировать принтеру, что данные уже есть (на короткое время установить в 1 линию Strobe, то есть бит номер 0 регистра управления: CR0), затем отследить готовность принтера к приему следующих данных (линия SR6) и только потом посылать их. Полностью процедура включает еще проверку регистра состояния - в противном случае можно ожидать готовности до бесконечности, если в принтере кончилась бумага или его просто кто-то выключил. Функция prn посылает байт a на принтер и возвращает 0, если все в порядке, или значение регистра состояния, если ошибка (см. листинг).
Разумеется, Baseaddr нужно либо заменить соответствующим шестнадцатеричным числом (0378h для LPT1), либо объявить глобальную переменную (типа Word) с таким именем, принимающую соответствующее значение.
С использованием этой функции я составил небольшую программку, которая посылает PRN-файл на принтер, а в случае ошибки выводит on-top окно с сообщением и просто прерывает свою работу. Вообще-то, так не положено - правильнее будет проанализировать причину ошибки и предпринять соответствующие действия (в обращении с принтером не принято сразу сдаваться при каких-то ошибках, надо некоторое время ожидать - вдруг бумага каким-то чудом загрузится сама!). Не сомневаюсь, что грамотный читатель сможет сам довести это до ума; если возникнут вопросы - я к вашим услугам. Замечу, что функция без всяких изменений работает и в DOS-программах на языке Turbo Pascal. Кроме того, таким способом можно осуществлять обмен данными через параллельный порт.
|