Чтобы не забыть, на всякий случай, запишу небольшой набор сведений по сабжу.
Итак, пока не требуется гибкое управление параметрами печати, MFC справляется очень успешно. Программисту вообще ничего не нужно знать о том, как происходит печать в Windows и как реализована поддержка печати в MFC. Однако, как только появляется необходимость программно управлять рядом настроек печати (главным образом, программно выбирать принтер), так сразу приходится серьезно влезать в эту тему.
Печать в MFC начинается с CView::OnPreparePrinting. В обязанности процедуры входит отображение диалога выбора принтера и создание DC принтера. В данную процедуру передается параметр CPrintInfo. Данная структура содержит кое-какие специфичные для MFC параметры печати и указатель на CPrintDialog. CPrintDialog является простой оберткой над виндовой структурой PRINTDLG и обеспечивает отображение того самого диалога выбора принтера.
Для отображения диалога и создания DC нам требуется просто вызвать DoPreparePrinting. DoPreparePrinting дополнительно инициализирует структуры CPrintInfo и CPrintDialog, отображает диалог и создает DC. Однако, инициализация этих структур происходит параметрами принтера по умолчанию – т.е. параметрами последнего использованного принтера. А нам нужно выбрать произвольно заданный принтер. Поэтому использовать DoPreparePrinting у нас никак не получится.
Чтобы отобразить диалог выбора принтера и создать его DC нам в обязательном порядке понадобится инициализировать для члена структуры PRINTDLG. Это hDevMode и hDevNames. hDevNames – это хендл глобального блока памяти, в котором хранится три имени, определяющих конкретный принтер: имя драйвера, имя устройства, имя порта. hDevMode – это хендл глобального блока памяти, в котором содержится специфичная для нужного принтера структура DEVMODE, модифицированная в соответствии требуемыми нам настройками печати. Рассмотрим, как создать эти хендлы.
DEVNAMES – это структура, имеющая переменный размер. Сначала идет общая часть – собственно, DEVNAMES. После общей части идут имена устройства, драйвера и порта. Поля структуры DEVNAMES содержат смещения этих имен относительно начала структуры. Чтобы создать DEVNAMES, сначала нужно получить требуемые имена. Сделать это можно, запросив информацию о принтере по его имени:
Сначала мы открываем принтер при помощи функции OpenPrinter, а затем запрашиваем детальную информацию о принтере при помощи функции GetPrinter. Нас интересует структура PRINTER_INFO_2. Эта структура имеет переменный размер, поэтому сначала запрашиваем требуемый объем памяти, выделяем память и запрашиваем потом уже запрашиваем данные.
Интересующие нас имена находятся в полях pPrinterName, pDriverName, pPortName. В теории pPortName может содержать несколько имен портов, разделенных запятыми. Для таких случаев я беру первый порт из списка.
Дальше просто: GlobalAllock, GlobalLock, инициализация DEVNAMES.
DEVMODE – это тоже структура переменной длины. Каждый драйвер принтера может иметь специфичный для него вариант структуры DEVMODE. При этом первые поля стандартны, а после них могут идти скрытые, специфичные для драйвера поля. Поэтому нельзя взять DEVMODE от одного драйвера и подсунуть ее другому. Для получения DEVMODE можно использовать функцию DocumentProperties:
После получения DEVMODE можно ее кастомизировать под свои нужды. Например, можно установить ориентацию страницы и количество копий.
Ну вот, самое сложное позади. Осталось вывести диалог выбора принтера и создать контекст устройства. Помните, использовать DoPreparePrinting нельзя. Даже если мы инициализируем поля hDevMode и hDevNames так, как нам надо, то ничего не выйдет. В недрах DoPreparePrinting это поганое майкрософтное изделие нагло их похерит и заместит стандартными для приложения значениями. Следовательно, вывод диалога и создание DC мы должны сделать самостоятельно. Вот небольшой фрагмент процедуры OnPreparePrinting:
Естественно, предварительно нам понадобится инициализировать поля структур CPrintInfo и CPrintDialog. DoPreparePrinting делала это за нас, но, раз мы от нее отказались, инициализацию придется делать вручную. Все, дальше печать происходит как обычно.
Необходимо помнить, что созданные нами hDevNames и hDevMode должны существовать на протяжении всего процесса печати. Т.е. создать их, создать на их основе контекст устройства и сразу же удалить hDevNames и hDevMode нельзя.
Ссылок на эту страницу нет