Yoksel: Блог/2008?/07?/06?/ПечатьВWinMFC ...
SourceForge.net Logo

Home Page | Изменения / НовыеКомментарии / Справка / Помочь проекту | Вход:  Пароль:  

Блог

Печать при помощи MFC/Windows


Чтобы не забыть, на всякий случай, запишу небольшой набор сведений по сабжу.


Итак, пока не требуется гибкое управление параметрами печати, MFC справляется очень успешно. Программисту вообще ничего не нужно знать о том, как происходит печать в Windows и как реализована поддержка печати в MFC. Однако, как только появляется необходимость программно управлять рядом настроек печати (главным образом, программно выбирать принтер), так сразу приходится серьезно влезать в эту тему.

OnPreparePrinting


Печать в 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 содержат смещения этих имен относительно начала структуры. Чтобы создать DEVNAMES, сначала нужно получить требуемые имена. Сделать это можно, запросив информацию о принтере по его имени:

Сначала мы открываем принтер при помощи функции OpenPrinter, а затем запрашиваем детальную информацию о принтере при помощи функции GetPrinter. Нас интересует структура PRINTER_INFO_2. Эта структура имеет переменный размер, поэтому сначала запрашиваем требуемый объем памяти, выделяем память и запрашиваем потом уже запрашиваем данные.


Интересующие нас имена находятся в полях pPrinterName, pDriverName, pPortName. В теории pPortName может содержать несколько имен портов, разделенных запятыми. Для таких случаев я беру первый порт из списка.


Дальше просто: GlobalAllock, GlobalLock, инициализация DEVNAMES.

DEVMODE

DEVMODE – это тоже структура переменной длины. Каждый драйвер принтера может иметь специфичный для него вариант структуры DEVMODE. При этом первые поля стандартны, а после них могут идти скрытые, специфичные для драйвера поля. Поэтому нельзя взять DEVMODE от одного драйвера и подсунуть ее другому. Для получения DEVMODE можно использовать функцию DocumentProperties:


После получения DEVMODE можно ее кастомизировать под свои нужды. Например, можно установить ориентацию страницы и количество копий.

Печать

Ну вот, самое сложное позади. Осталось вывести диалог выбора принтера и создать контекст устройства. Помните, использовать DoPreparePrinting нельзя. Даже если мы инициализируем поля hDevMode и hDevNames так, как нам надо, то ничего не выйдет. В недрах DoPreparePrinting это поганое майкрософтное изделие нагло их похерит и заместит стандартными для приложения значениями. Следовательно, вывод диалога и создание DC мы должны сделать самостоятельно. Вот небольшой фрагмент процедуры OnPreparePrinting:

Естественно, предварительно нам понадобится инициализировать поля структур CPrintInfo и CPrintDialog. DoPreparePrinting делала это за нас, но, раз мы от нее отказались, инициализацию придется делать вручную. Все, дальше печать происходит как обычно.


Необходимо помнить, что созданные нами hDevNames и hDevMode должны существовать на протяжении всего процесса печати. Т.е. создать их, создать на их основе контекст устройства и сразу же удалить hDevNames и hDevMode нельзя.


Ссылок на эту страницу нет


 
Файлов нет. [Показать файлы/форму]
Комментариев нет. [Показать комментарии/форму]