ilyachalov (ilyachalov) wrote,
ilyachalov
ilyachalov

Category:

Windows API: печать из консольной программы

Этот пост является заключительным в серии:
1. Печать через PRN из консольной программы Windows
2. С++: типы переменных в Windows API
3. C++: агрегатная инициализация структур
4. Виртуальные принтеры на примере Windows 7

Итак, не имея принтера, но при наличии хотя бы виртуальных принтеров можно попробовать написать программу печати из консольного приложения Windows с помощью набора функций Windows API (у меня — операционная система Windows 7 и компилятор среды «Visual Studio Community 2017», пишу на языке C++).

Я еще в первом посте серии ссылался на раздел на сайте компании Microsoft, посвященный функциям печати из набора Windows API:
https://docs.microsoft.com/en-us/windows/win32/printdocs/printdocs-printing

Функции Windows API, предназначенные для вывода на печать, там разбиты на несколько API (по ссылке есть схема, в которой нарисовано, как все эти API сочетаются между собой):

1) Print Document Package API (пока не могу его использовать, так как по ссылке написано, что этот API доступен с Windows 8 и для более поздних версий операционной системы);

2) Print Spooler API (самый нижний (близкий к железу) уровень, на нем построены все остальные перечисленные по ссылке API);

3) XPS Document API и Print Ticket API — специализированные API для печати документов в формате XPS;

4) GDI Print API — вариант, который я стал использовать. Про GDI (Graphics Device Interface, по-русски «интерфейс к графическим устройствам») подробнее можно почитать в соответствующей статье википедии. Если кратко, то с точки зрения разработчика это набор функций (входящий в Windows API), с помощью которых можно одним и тем же способом выводить информацию на любые устройства (дисплеи, принтеры, факсы и так далее) в одном и том же виде (принцип WYSIWYG).

В Windows GDI для работы с любым устройством нужно сначала получить так называемый контекст устройства (device context) в переменную-указатель типа HDC. Далее все функции Windows GDI для своей работы требуют эту переменную в качестве аргумента. Если не имеется контекста устройства (в нашем случае — принтера), то можно сначала получить название принтера, а затем по названию получить контекст устройства принтера с помощью функции CreateDC.

Как получить название принтера? Есть несколько способов:

1) Получить список принтеров с помощью функции EnumPrinters и дать пользователю выбрать нужный. Пример работы программы:
EnumPrinters
Текст программы: EnumPrinters.cpp

2) Показать пользователю диалоговое окно с помощью функции PrintDlg или PrintDlgEx, в котором он выберет нужный принтер. Пример работы программы:
PrintDlg
Тексты программ:
PrintDlg_listprn.cpp
PrintDlgEx_listprn.cpp

В случае функции PrintDlgEx диалоговое окно будет выглядеть по-другому, но принцип работы программы — тот же.

3) Указанные в предыдущем способе функции PrintDlg и PrintDlgEx можно запустить так (флаг PD_RETURNDEFAULT соответствующих структур PRINTDLG и PRINTDLGEX), что они не покажут на экране диалоговое окно со списком принтеров, а просто возвратят контекст устройства и название принтера по умолчанию. Тексты программ:
PrintDlg_defprn.cpp
PrintDlgEx_defprn.cpp

4) Ну и самый простой способ: получить название принтера по умолчанию с помощью функции GetDefaultPrinter. Текст программы: GetDefaultPrinter.cpp.

Схема вывода на печать из консольной программы:

1) Получаем название принтера (или сразу контекст устройства принтера и переходим к пункту 3). Например, одним из четырех указанных выше способов.

2) Получаем контекст устройства принтера с помощью функции CreateDC.

3) Используем функции Windows GDI, задавая им контекст устройства принтера в качестве параметра по следующей схеме:
    StartDoc

        StartPage

            TextOut, DrawText и им подобные функции

        EndPage

    EndDoc
4) Удаляем контекст устройства принтера с помощью функции DeleteDC.

Примеры программ:
Output_to_printer_WinGDI_1_TextOut.cpp
Output_to_printer_WinGDI_2_DrawText.cpp
Tags: Образование, Программирование
Subscribe

  • Post a new comment

    Error

    Anonymous comments are disabled in this journal

    default userpic

    Your IP address will be recorded 

  • 0 comments