Теперь нам надо рассмотреть непосредственно текст программы, осуществляющий печать.
3.3 Печатание на принтере
Вообще для управления печатью достаточно только одной процедуры - Escape(), которая использовалась в прежних версиях Windows.
int Escape( hDC, nEscape, cbInput, lpsInData, lpvOutput );
Параметр nEscape указывает код выполняемой операции, параметры cbInput и lpsInData указывают исходные данные для операции, а lpvOutput - результат операции. Применение и форма исходных данных и результатов зависит от операции.
В версии Windows 3.1 к этой процедуре добавлен ряд вспомогательных, которые просто выполняют отдельные операции.
Сейчас мы рассмотрим некоторые основные операции, необходимые для печати. Первая операция регистрирует наше задание на печать:
Escape( hDC, STARTDOC, cbName, lpsName, NULL );
или
StartDoc( hDC, lpDocInfo );
struct DOCINFO {
int cbSize;
LPSTR lpszDocName;
LPSTR lpszOutput;};
Параметры cbName и lpsName определяют название нашего задания. Возвращаемое значение, большее 0, указывает на успешную постановку задания в очередь, а значение 0 и меньше указывает на возникшую ошибку.
Далее, если мы хотим печатать страницу целиком, то после ее заполнения мы должны подать команду на печать страницы:
// заполнить страницу
Escape( hDC, NEWFRAME, 0, NULL, NULL );
или
StartPage( hDC );
// заполнить страницу
EndPage( hDC );
В случае успешного завершения задания мы должны сообщить об этом с помощью операции ENDDOC:
Escape( hDC, ENDDOC, 0, NULL, NULL );
или
EndDoc( hDC );
Однако нам может понадобится прервать печать досрочно. Для этого мы должны разработать и установить нашу собственную процедуру AbortProc. Предположим, что такая функция нами написана и ее имя AbortProc(). Тогда мы можем установить ее следующим способом:
FARPROC lpfnAbortProc= MakeProcInstance( (FARPROC)AbortProc, hInstance );
Escape( hDC, SETABORTPROC, 0, (LPSTR)lpfnAbortProc, NULL );
// печатаем...
FreeProcInstance( lpfnAbortProc );
или
FARPROC lpfnAbortProc= MakeProcInstance( (FARPROC)AbortProc, hInstance );
SetAbortProc( hDC, (ABORTPROC)lpfnAbortProc );
// печатаем...
FreeProcInstance( lpfnAbortProc );
При этом, если наше задание будет досрочно снято с печати, то мы должны сообщить об этом (что бы задание было корректно удалено из очереди):
Escape( hDC, ABORTDOC, 0, NULL, NULL );
или
AbortDoc( hDC );
Небольшой пример (поясняющий правила разработки процедуры AbortProc):
static BOOL bAbort;
BOOL PASCAL FAR _export AbortProc( HDC hdcPRN, short nCode ) {
MSG msg;
while ( !bAbort && PeekMessage( &msg,NULL,0,0,PM_REMOVE ) ) {
TranslateMessage( &msg );
DispatchMessage( &msg );}
return !bAbort;}
static BOOL DoPrint( void ) {
static char szName[]= "Test Printing";
FARPROC lpfnAbort;
BOOL answer= FALSE;
HDC hdcPRN;
hdcPRN= GetPrinterDC(); // получение hdcPRN см. выше
lpfnAbort= MakeProcInstance( (FARPROC)AbortProc, hInstance );
Escape( hdcPRN, SETABORTPROC, 0, (LPSTR)lpfnAbort, NULL );
if ( Escape( hdcPRN, STARTDOC, sizeof(szName)-1, szName, NULL ) > 0 ) {
while ( !bAbort && /* есть что печатать */ ) {
// рисуемнастранице
if ( Escape( hdcPRN, NEWFRAME, 0,NULL,NULL ) <= 0 )bAbort= TRUE;}
if ( bAbort ) {
Escape( hdcPRN, ABORTDOC, 0,NULL,NULL );
} else {
Escape( hdcPRN, ENDDOC, 0,NULL,NULL );
answer= TRUE;}}
FreeProcInstance( (FARPROC)lpfnAbort );
DestroyDC( hdcPRN );
return answer;}
В этом примере надо обратить внимание на переменную bAbort. Она может быть установлена в значение TRUE для завершения печати. В данном примере досрочное завершение не предусмотрено, хотя его легко можно сделать, устанавливая эту переменную, например, в ответ на выбор пункта меню, на нажатие кнопки диалога или даже по таймеру.
Если мы будем использовать пополосную печать, то нам надо вместо операции NEWFRAME выполнять серию операций NEXTBAND до тех пор, пока полоса для печати не окажется пустой (что соответствует полностью напечатанной странице); при этом внутренний цикл для печати страниц придется несколько изменить:
...RECT rc;
...while ( !bAbort && /* есть что печатать */ ) {
while ( Escape(hdcPRN, NEXTBAND, 0, NULL, (LPSTR)&rc) > 0 ) {
if ( IsRectEmpty( &rc ) ) goto ok_page;
// заполняем полосу или всю страницу, иногда вызывая AbortProc:
lpfnAbortProc( hdcPRN, 0 );
// Внимание! используется указатель на функцию, а не она сама!}
bAbort= TRUE;
ok_page:;}...