Электронная библиотека книг Александра Фролова и Григория Фролова.
Shop2You.ru Создайте свой интернет-магазин
Библиотека
Братьев
Фроловых

Графический интерфейс GDI в Microsoft Windows

© Александр Фролов, Григорий Фролов
Том 14, М.: Диалог-МИФИ, 1993, 288 стр.

[Назад] [Содеожание] [Дальше]

6.4. Приложение PRNFILE

Для иллюстрации всего сказанного выше мы немного изменили приложение TEDIT, описанное в 12 томе "Библиотеки системного программиста", добавив в него возможность печати. В главном окне этого простейшего редактора текста появилась кнопка "Print", с помощью которой вы можете распечатать текст на любом установленном в системе принтере (рис. 6.5).

Рис. 6.5. Главное окно приложения PRNFILE

Исходный основного файла приложения приведен в листинге 6.1.


Листинг 6.1. Файл prnfile/prnfile.cpp


// ----------------------------------------
// Редактор текстовых файлов с возможностью печати
// ----------------------------------------

#define STRICT
#include <windows.h>
#include <commdlg.h>
#include <mem.h>
#include <string.h>
#include <stdlib.h>

// Идентификатор редактора текста
#define ID_EDIT    1

// Идентификаторы кнопок
#define ID_NEW     2
#define ID_OPEN    3
#define ID_SAVE    4
#define ID_PRINT   5
#define ID_EXIT    6

// Прототипы функций
BOOL InitApp(HINSTANCE);
LRESULT CALLBACK _export WndProc(HWND, UINT, WPARAM, LPARAM);
HFILE OpenFile(void);
HFILE OpenSaveFile(void);
int PrintFile(HWND, NPSTR, WORD);

// Имя класса окна
char const szClassName[]   = "TEditAppClass";

// Заголовок окна
char const szWindowTitle[] = "Text Editor";

// Идентификатор копии приложения
HINSTANCE hInst;

// Флаг изменений в тексте
BOOL bUpdate;

// =====================================
// Функция WinMain
// =====================================
#pragma argsused

int PASCAL
WinMain(HINSTANCE hInstance, 
   HINSTANCE hPrevInstance,
   LPSTR     lpszCmdLine, 
   int       nCmdShow)   
{
  MSG  msg;   // структура для работы с сообщениями
  HWND hwnd;  // идентификатор главного окна приложения

  // Инициализируем приложение
  if(!InitApp(hInstance))
      return FALSE;

  // Сохраняем идентификатор копии приложения
  // в глобальной переменной
  hInst = hInstance;

  // После успешной инициализации приложения создаем
  // главное окно приложения
  hwnd = CreateWindow(
    szClassName,         // имя класса окна
    szWindowTitle,       // заголовок окна
    WS_OVERLAPPEDWINDOW, // стиль окна
    CW_USEDEFAULT,       // задаем расположение и размеры
    CW_USEDEFAULT,       // окна, принятые по умолчанию
    CW_USEDEFAULT,       // 
    CW_USEDEFAULT,       // 
    0,                   // идентификатор родительского окна
    0,                   // идентификатор меню
    hInstance,           // идентификатор приложения
    NULL);               // указатель на дополнительные
                         // параметры
  // Если создать окно не удалось, завершаем приложение
  if(!hwnd)
    return FALSE;

  // Рисуем главное окно
  ShowWindow(hwnd, nCmdShow);
  UpdateWindow(hwnd);

  // Запускаем цикл обработки сообщений
  while(GetMessage(&msg, 0, 0, 0))
  {
    TranslateMessage(&msg);
    DispatchMessage(&msg);
  }
  return msg.wParam;
}

// =====================================
// Функция InitApp
// Выполняет регистрацию класса окна
// =====================================

BOOL
InitApp(HINSTANCE hInstance)
{
  ATOM aWndClass; // атом для кода возврата
  WNDCLASS wc;    // структура для регистрации
                  // класса окна

  memset(&wc, 0, sizeof(wc));

  wc.style = 0;
  wc.lpfnWndProc = (WNDPROC) WndProc;
  wc.cbClsExtra = 0;
  wc.cbWndExtra = 0;
  wc.hInstance = hInstance;
  wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
  wc.hCursor = LoadCursor(NULL, IDC_ARROW);
  wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
  wc.lpszMenuName = (LPSTR)NULL;
  wc.lpszClassName = (LPSTR)szClassName;

  // Регистрация класса
  aWndClass = RegisterClass(&wc);

  return (aWndClass != 0);
}

// =====================================
// Функция WndProc
// =====================================

LRESULT CALLBACK _export
WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
  // Идентификатор редактора текста
  static HWND hEdit;

  // Идентификаторы кнопок
  static HWND hButtNew;
  static HWND hButtOpen;
  static HWND hButtSave;
  static HWND hButtPrint;
  static HWND hButtExit;

  // Идентификаторы файлов
  static HFILE hfSrcFile, hfDstFile;

  switch (msg)
  {
    case WM_CREATE:
    {
      // Создаем редактор текста
      hEdit = CreateWindow("edit", NULL,
         WS_CHILD | WS_VISIBLE | WS_BORDER |
         WS_HSCROLL | WS_VSCROLL |
         ES_LEFT | ES_AUTOHSCROLL | ES_AUTOVSCROLL |
         ES_MULTILINE,
         0, 0, 0, 0,
         hwnd, (HMENU) ID_EDIT, hInst, NULL);

      // Устанавливаем максимальную длину
      // редактируемого текста, равную 32000 байт
      SendMessage(hEdit, EM_LIMITTEXT, 32000, 0L);

      // Сбрасываем флаг обновления текста
      bUpdate = FALSE;

      // Создаем кнопки
      hButtNew = CreateWindow("button", "New",
         WS_CHILD | WS_VISIBLE |
         BS_PUSHBUTTON,
         0, 0, 80, 20,
         hwnd, (HMENU) ID_NEW, hInst, NULL);

      hButtOpen = CreateWindow("button", "Open",
         WS_CHILD | WS_VISIBLE |
         BS_PUSHBUTTON,
         80, 0, 80, 20,
         hwnd, (HMENU) ID_OPEN, hInst, NULL);

      hButtSave = CreateWindow("button", "Save",
         WS_CHILD | WS_VISIBLE |
         BS_PUSHBUTTON,
         160, 0, 80, 20,
         hwnd, (HMENU) ID_SAVE, hInst, NULL);

      hButtPrint = CreateWindow("button", "Print",
         WS_CHILD | WS_VISIBLE |
         BS_PUSHBUTTON,
         240, 0, 80, 20,
         hwnd, (HMENU) ID_PRINT, hInst, NULL);

      hButtExit = CreateWindow("button", "Exit",
         WS_CHILD | WS_VISIBLE |
         BS_PUSHBUTTON,
         320, 0, 80, 20,
         hwnd, (HMENU) ID_EXIT, hInst, NULL);

      return 0;
    }

    case WM_SIZE:
    {
      // Устанавливаем размер органа управления
      // (текстового редактора) в соответствии
      // с размерами главного окна приложения
      MoveWindow(hEdit, 0, 20, LOWORD(lParam),
        HIWORD(lParam) - 20, TRUE);
      return 0;
    }

    // Когда главное окно приложения получает
    // фокус ввода, отдаем фокус редактору текста
    case WM_SETFOCUS:
    {
      SetFocus(hEdit);
      return 0;
    }

    case WM_COMMAND:
    {
      // Обработка извещений текстового редактора
      if(wParam == ID_EDIT)
      {
        // Ошибка
        if(HIWORD(lParam) == EN_ERRSPACE)
        {
           MessageBox(hwnd, "Мало памяти",
             szWindowTitle, MB_OK);
        }

        // Произошло изменение в редактируемом
        // тексте
        else if(HIWORD(lParam) == EN_UPDATE)
        {
           // Устанавливаем флаг обновления текста
           bUpdate = TRUE;
        }
        return 0;
      }

      // Нажата кнопка сохранения текста
      else if(wParam == ID_SAVE)
      {
        WORD wSize;
        HANDLE hTxtBuf;
        NPSTR  npTextBuffer;

        // Открываем выходной файл
        hfDstFile = OpenSaveFile();
        if(!hfDstFile) return 0;

        // Определяем размер текста
        wSize = GetWindowTextLength(hEdit);

        // Получаем идентификатор блока памяти,
        // в котором находится редактируемый текст
        hTxtBuf = 
          (HANDLE) SendMessage(hEdit, EM_GETHANDLE, 0, 0L);

        // Фиксируем блок памяти и получаем указатель
        // на него
        npTextBuffer = (NPSTR)LocalLock(hTxtBuf);

        // Записываем содержимое блока памяти в файл
        if(wSize != 
           _lwrite(hfDstFile, npTextBuffer, wSize))
        {
          // При ошибке закрываем файл и выдаем сообщение
          _lclose(hfDstFile);
          MessageBox(hwnd, "Ошибка при записи файла",
          szWindowTitle, MB_OK);
          return 0;
        }

        // Закрываем файл
        _lclose(hfDstFile);

        // Расфиксируем блок памяти
        LocalUnlock(hTxtBuf);

        // Так как файл был только что сохранен,
        // сбрасываем флаг обновления 
        bUpdate = FALSE;

        SetFocus(hEdit);
        return 0;
      }

      // Создание нового файла
      else if(wParam == ID_NEW)
      {
        // Проверяем флаг обновления
        if(bUpdate)
        {
          if(IDYES == MessageBox(hwnd,
            "Файл был изменен. Желаете сохранить?",
             szWindowTitle, MB_YESNO | MB_ICONQUESTION))
          return 0;
        }

        // Сбрасываем содержимое текстового редактора
        SetWindowText(hEdit, "\0");

        // Сбрасываем флаг обновления
        bUpdate = FALSE;

        SetFocus(hEdit);
        return 0;
      }

      // Загрузка файла для редактирования
      else if(wParam == ID_OPEN)
      {
        LPSTR lpTextBuffer;
        DWORD dwFileSize, dwCurrentPos;

        // Проверяем флаг обновления
        if(bUpdate)
        {
          if(IDYES == MessageBox(hwnd,
            "Файл был изменен. Желаете сохранить?",
            szWindowTitle, MB_YESNO | MB_ICONQUESTION))
          return 0;
        }

        // Открываем входной файл.
        hfSrcFile = OpenFile();
        if(!hfSrcFile) return 0;

        // Определяем размер файла
        dwCurrentPos = _llseek(hfSrcFile, 0L, 1);
        dwFileSize   = _llseek(hfSrcFile, 0L, 2);
        _llseek(hfSrcFile, dwCurrentPos, 0);

        // Размер файла не должен превосходить 32000 байт
        if(dwFileSize >= 32000)
        {
          _lclose(hfSrcFile);
          MessageBox(hwnd, "Размер файла больше 32000 байт",
             szWindowTitle, MB_OK);
          return 0;
        }

        // Заказываем память для загрузки файла
        lpTextBuffer = (LPSTR)malloc(32000);
        if(lpTextBuffer == NULL)
           return 0;

        // Загружаем текст из файла в буфер
        _lread(hfSrcFile, lpTextBuffer, dwFileSize);

        // Закрываем буфер двоичным нулем
        lpTextBuffer[(WORD)dwFileSize] = '\0';

        // Закрываем файл
        _lclose(hfSrcFile);

        // Переносим содержимое буфера в
        // текстовый редактор
        SetWindowText(hEdit, lpTextBuffer);

        // Освобождаем буфер
        free((void *)lpTextBuffer);

        // сбрасываем флаг обновления
        bUpdate = FALSE;

        SetFocus(hEdit);
        return 0;
      }

// ------------------------------------------
// Печать текста
// ------------------------------------------
      else if(wParam == ID_PRINT)
      {
        WORD wSize;
        HANDLE hTxtBuf;
        NPSTR  npTextBuffer;

        // Определяем размер текста
        wSize = GetWindowTextLength(hEdit);

        // Получаем идентификатор блока памяти,
        // в котором находится редактируемый текст
        hTxtBuf =
          (HANDLE) SendMessage(hEdit, EM_GETHANDLE, 0, 0L);

        // Фиксируем блок памяти и получаем указатель
        // на него
        npTextBuffer = (NPSTR)LocalLock(hTxtBuf);

        PrintFile(hwnd, npTextBuffer, wSize);

        // Расфиксируем блок памяти
        LocalUnlock(hTxtBuf);

        SetFocus(hEdit);
        return 0;
      }

      else if(wParam == ID_EXIT)
      {
         // Проверяем флаг обновления
         if(bUpdate)
         {
           if(IDYES == MessageBox(hwnd,
            "Файл был изменен. Желаете сохранить?",
            szWindowTitle, MB_YESNO | MB_ICONQUESTION))
              return 0;
         }

         // Посылаем в функцию главного окна
         // сообщение WM_CLOSE
         SendMessage(hwnd, WM_CLOSE, 0, 0L);
         return 0;
      }
      return 0;
    }

    case WM_DESTROY:
    {
      PostQuitMessage(0);
      return 0;
    }
  }
  return DefWindowProc(hwnd, msg, wParam, lParam);
}

// -------------------------------
// Функция OpenFile
// Сохранение файла
// -------------------------------

HFILE OpenFile(void)
{
  // Структура для выбора файла
  OPENFILENAME ofn;

  // Буфер для записи пути к выбранному файлу
  char szFile[256];

  // Буфер для записи имени выбранного файла
  char szFileTitle[256];

  // Фильтр расширений имени файлов
  char szFilter[256] =
    "Text Files\0*.txt;*.doc\0Any Files\0*.*\0";

  // Идентификатор открываемого файла
  HFILE hf;

  // Инициализация имени выбираемого файла
  // не нужна, поэтому создаем пустую строку
  szFile[0] = '\0';

  // Записываем нулевые значения во все поля
  // структуры, которая будет использована для
  // выбора файла
  memset(&ofn, 0, sizeof(OPENFILENAME));

  // Инициализируем нужные нам поля

  // Размер структуры
  ofn.lStructSize       = sizeof(OPENFILENAME);

  // Идентификатор окна
  ofn.hwndOwner         = NULL;

  // Адрес строки фильтра
  ofn.lpstrFilter       = szFilter;

  // Номер позиции выбора
  ofn.nFilterIndex      = 1;

  // Адрес буфера для записи пути
  // выбранного файла
  ofn.lpstrFile         = szFile;

  // Размер буфера для записи пути
  // выбранного файла
  ofn.nMaxFile          = sizeof(szFile);

  // Адрес буфера для записи имени
  // выбранного файла
  ofn.lpstrFileTitle    = szFileTitle;

  // Размер буфера для записи имени
  // выбранного файла
  ofn.nMaxFileTitle     = sizeof(szFileTitle);

  // В качестве начального каталога для
  // поиска выбираем текущий каталог
  ofn.lpstrInitialDir   = NULL;

  // Определяем режимы выбора файла
  ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST
            | OFN_HIDEREADONLY;
  // Выбираем входной файл
  if (GetOpenFileName(&ofn)) {

    // Открываем выбранный файл
    hf = _lopen(ofn.lpstrFile, OF_READ);

    // Возвращаем идентификатор файла
    return hf;
  }
  // При отказе от выбора возвращаем
  // нулевое значение
  else return 0;
}

// -------------------------------
// Функция OpenSaveFile
// Выбор файла для редактирования
// -------------------------------

HFILE OpenSaveFile(void)
{
  OPENFILENAME ofn;

  char szFile[256];
  char szFileTitle[256];
  char szFilter[256] =
     "Text Files\0*.txt\0Any Files\0*.*\0";

  HFILE hf;

  szFile[0] = '\0';
  memset(&ofn, 0, sizeof(OPENFILENAME));
  ofn.lStructSize       = sizeof(OPENFILENAME);
  ofn.hwndOwner         = NULL;
  ofn.lpstrFilter       = szFilter;
  ofn.nFilterIndex      = 1;
  ofn.lpstrFile         = szFile;
  ofn.nMaxFile          = sizeof(szFile);
  ofn.lpstrFileTitle    = szFileTitle;
  ofn.nMaxFileTitle     = sizeof(szFileTitle);
  ofn.lpstrInitialDir   = NULL;
  ofn.Flags             = OFN_HIDEREADONLY;

  // Выбираем выходной файл
  if (GetSaveFileName(&ofn)) {

    // При необходимости создаем файл
    hf = _lcreat(ofn.lpstrFile, 0);
    return hf;
  }
  else return 0;
}

Подробное описание этого файла вы найдете в 12 томе, здесь же для экономии места мы расскажем только о фрагменте, выполняющем печать.

Когда вы нажимаете кнопку "Print", соответствующий обработчик определяет размер текста, загруженного в редактор, вызывая функцию GetWindowTextLength:

wSize = GetWindowTextLength(hEdit);

Далее он получает адрес блока памяти, содержащий текст, фиксируя его:

hTxtBuf = (HANDLE) SendMessage(hEdit, EM_GETHANDLE, 0, 0L);
npTextBuffer = (NPSTR)LocalLock(hTxtBuf);

После этого вызывается функция печати PrintFile, определенная в файле print.cpp (листинг 6.2):

PrintFile(hwnd, npTextBuffer, wSize);

В качестве параметров этой функции передаются идентификатор окна приложения, адрес буфера, содержащего печатаемый текст, и размер этого буфера в байтах.

После выполнения печати буфер расфиксируется, после чего редактор текста получает фокус ввода:

LocalUnlock(hTxtBuf);
SetFocus(hEdit);
return 0;

Все функции, предназначенные для работы с принтером, мы вынесли в отдельный файл (листинг 6.2).


Листинг 6.2. Файл prnfile/print.cpp


// ----------------------------------------------------
// Функции для работы с принтером
// ----------------------------------------------------
#define STRICT
#include <windows.h>
#include <windowsx.h>
#include <commdlg.h>
#include <string.h>
#include "prnfile.hpp"

// Прототипы функций
BOOL CALLBACK _export
AbortDlgFunc(HWND hdlg, UINT msg,
   WPARAM wParam, LPARAM lParam);

BOOL CALLBACK _export AbortFunc(HDC hdc, int nCode);
HDC GetPrinterDC(HWND);

// Внешние глобальные переменные 
extern HWND hdlgAbort;
extern BOOL fAbort;

BOOL fAbort = FALSE;
HWND hdlgAbort = 0;
static PRINTDLG pd;

// ----------------------------------------------------
// Функция PrintFile
// Печать файла
// ----------------------------------------------------

BOOL PrintFile(HWND hwnd, NPSTR npBuff, WORD wSize)
{
  HDC hdc;
  int cyPage;
  int cyChar, yPos, nLength;
  int i;
  WORD wCurPos = 0;
  TEXTMETRIC tm;

  ABORTPROC lpAbortFunc;
  BOOL fDone;
  char abBuffer[256];
  DOCINFO docinfo;
  DLGPROC lpAbortDlgFunc;
  HINSTANCE hInst;
  int rc;

  // Получаем контекст устройства для принтера 
  hdc = GetPrinterDC(hwnd);

  // Определяем разрешение принтера по вертикали
  cyPage = GetDeviceCaps(hdc, VERTRES);

  // Определяем метрики текста
  GetTextMetrics(hdc, &tm);

  // Вычисляем высоту шрифта 
  cyChar = tm.tmHeight + tm.tmExternalLeading;

  // Создаем переходник для функции AbortFunc 
  hInst = GetWindowInstance(hwnd);
  lpAbortFunc =
     (ABORTPROC)MakeProcInstance((FARPROC)AbortFunc, hInst);

  // Устанавливаем функцию AbortProc
  rc = SetAbortProc(hdc, lpAbortFunc);
  if(rc <= 0)
  {
    DeleteDC(hdc);
    return FALSE;
  }

  // Создаем переходник для функции диалога
  lpAbortDlgFunc =
     (DLGPROC)MakeProcInstance((FARPROC)AbortDlgFunc, hInst);

  // Создаем диалог для отмены печати 
  hdlgAbort = CreateDialogParam (
        hInst, MAKEINTRESOURCE(IDD_ABORT),
        hwnd, lpAbortDlgFunc, NULL) ;

  if(!hdlgAbort)
  {
    FreeProcInstance((FARPROC)lpAbortFunc);
    DeleteDC(hdc);
    return FALSE;
  }

  // Отображаем созданную диалоговую панель
  ShowWindow(hdlgAbort, SW_SHOWNORMAL);
  UpdateWindow(hdlgAbort);

  // Переводим окно приложения в неактивное
  // состояние
  EnableWindow(hwnd, FALSE);

  // Заполняем структуру docinfo
  docinfo.cbSize      = sizeof(docinfo);
  docinfo.lpszDocName = NULL;
  docinfo.lpszOutput  = NULL;

  // Начинаем печать документа
  rc = StartDoc(hdc, &docinfo);
  if(rc <= 0)
  {
    DestroyWindow(hdlgAbort);
    FreeProcInstance((FARPROC)lpAbortFunc);
    FreeProcInstance((FARPROC)lpAbortDlgFunc);
    DeleteDC(hdc);
    return FALSE;
  }

  // Флаг завершения печати документа
  fDone = FALSE;

  // Цикл печати страниц документа
  while(!fDone && !fAbort)
  {
     // Начинаем печать страницы документа
     StartPage(hdc);
 
     // Начальная позиция по вертикали
     yPos = 0;

     // Цикл по строкам страницы
     while(yPos + cyChar < cyPage)
     {
        // Проверка завершения печати страницы 
        if(wCurPos > wSize)
        {
          fDone = TRUE;
          break;
        }

        i=0;
        nLength = 0;

        // Цикл по строке
        // Копируем строку в буфер abBuffer
        while((npBuff[wCurPos] != 0x0d) &&
              (wCurPos < wSize))
        {
          abBuffer[i] = npBuff[wCurPos];
          i++;
          wCurPos++;
          nLength++;
        }

        // Рисуем одну строку текста 
        TextOut(hdc, 0, yPos, abBuffer, nLength);

        // Переходим к следующей строке
        wCurPos += 2;
        yPos += cyChar ;
     }

     // Инициируем печать страницы
     rc = EndPage(hdc);
     if(rc < 0)
     {
       fAbort = TRUE;
       break;
     }
  }

  // При аварийном завершении печати вызываем
  // функцию AbortDoc, при нормальном - EndDoc
  if(fAbort)
    AbortDoc(hdc);
  else
    EndDoc(hdc);

  // Активизируем главное окно приложения
  EnableWindow(hwnd, TRUE);

  // Удаляем диалоговую панель
  DestroyWindow(hdlgAbort);

  // Освобождаем ресурсы
  FreeProcInstance((FARPROC)lpAbortFunc);
  FreeProcInstance((FARPROC)lpAbortDlgFunc);
  DeleteDC(hdc);

  return TRUE ;
}

// ----------------------------------------------------
// Функция AbortDlgFunc
// Функция диалога для диалоговой панели,
// позволяющей прервать процесс печати 
// ----------------------------------------------------
#pragma argsused

BOOL CALLBACK _export
AbortDlgFunc(HWND hdlg,
  UINT msg, WPARAM wParam, LPARAM lParam)
{
  switch(msg)
  {
    // Инициализируем флаги
    case WM_INITDIALOG:
    {
       fAbort = FALSE;
       hdlgAbort = hdlg;
       return TRUE;
    }

    case WM_COMMAND:
    {
      // Устанавливаем флаг аварийного завершения печати
      if (wParam == IDOK || wParam == IDCANCEL)
      {
        fAbort = TRUE;
        return TRUE;
      }
      return FALSE;
    }

    case WM_DESTROY:
    {
       hdlgAbort = 0;
       return FALSE;
    }
  }
  return FALSE;
}

// ----------------------------------------------------
// Функция AbortFunc
// Обеспечивает возможность работы других
// приложений во время печати 
// ----------------------------------------------------
#pragma argsused

BOOL CALLBACK _export
AbortFunc(HDC hdc, int nCode)
{
  MSG msg;

  // Второй цикл обработки сообщений
  while(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
  {
    if(!hdlgAbort || !IsDialogMessage (hdlgAbort, &msg))
    {
      TranslateMessage(&msg);
      DispatchMessage(&msg);
    }
  }

  return(!fAbort);
}

// ----------------------------------------------------
// Функция GetPrinterDC
// Выводит на экран диалоговую панель "Print",
// с помощью которой можно выбрать принтер.
// Возвращает идентификатор контекста для
// выбранного принтера
// ----------------------------------------------------

HDC GetPrinterDC(HWND hwnd)
{
  BOOL fResult;

  // Инициализируем структуру PRINTDLG
  memset(&pd, 0, sizeof(PRINTDLG));

  pd.lStructSize = sizeof(PRINTDLG);
  pd.hwndOwner   = hwnd;
  pd.Flags       = PD_RETURNDC;

  // Отображаем диалоговую панель
  fResult = PrintDlg(&pd);

  // При необходимости освобождаем память, полученную
  // функцией PrintDlg для структур DEVMODE и DEVNAMES
  if(pd.hDevMode != 0)
    GlobalFree (pd.hDevMode);

  if(pd.hDevNames != 0)
    GlobalFree (pd.hDevNames);

  // В случае успешного завершения возвращаем
  // контекст принтера
  if(fResult)
    return pd.hDC;

  else
    return 0;
}

Функция PrintFile выполняет печать файла, загруженного в текстовый редактор.

Она получает контекст печати, вызывая функцию GetPrinterDC, определенную в этом же файле. Функция GetPrinterDC выводит на экран стандартную диалоговую панель "Print", позволяющую выбрать принтер и задать параметры для выбранного принтера.

Далее определяется разрешение принтера по вертикали, метрики текста для шрифта, выбранного в контекст принтера, вычисляется высота шрифта. Вся эта информация необходима для правильного расположения строк текста на листе бумаги.

После этого функция PrintFile создает переходник для функции отмены печати и подключает последнюю, вызывая функцию SetAbortProc.

Далее создается переходник для функции диалога отмены печати, затем создается и выводится на экран диалоговая панель отмены печати. Шаблон диалоговой панели определен в файле ресурсов и содержит единственную кнопку с надписью "Cancel".

После отображения этой панели главное окно приложения переводится в неактивное состояние для передачи фокуса ввода диалоговой панели отмены печати.

Перед началом печати заполняется структура DOCINFO и вызывается функция StartDoc.

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

Перед началом печати каждой страницы вызывается функция StartPage.

Далее выполняется построчное копирование текста из буфера текстового редактора в буфер abBuffer с последующим выводом содержимого этого буфера на принтер функцией TextOut.

Печать страницы выполняется после вызова функции EndPage.

При нормальном завершении процесса печати вызывается функция EndDoc, а при аварийном - AbortDoc.

После нормального или аварийного завершения печати документа активизируется главное окно приложения, а диалоговая панель отмены печати удаляется. Вслед за этим освобождаются созданные переходники и контекст принтера.

Идентификатор диалоговой панели определен в файле prnfile.hpp (листинг 6.3).


Листинг 6.3. Файл prnfile/prnfile.hpp


#define IDD_ABORT 25

Шаблон диалоговой панели отмены печати определен в файле описания ресурсов приложения (листинг 6.4).


Листинг 6.4. Файл prnfile/prnfile.rc


#include <g:\tcwin\include\windows.h>
#include "prnfile.hpp"

IDD_ABORT DIALOG 50, 30, 89, 43
STYLE DS_MODALFRAME | WS_CAPTION | WS_SYSMENU
CAPTION "Печать..."
BEGIN
  CONTROL "Cancel", IDCANCEL, "BUTTON",
     WS_GROUP, 29, 23, 32, 14
  CTEXT   "Cancel - отмена печати",
     -1, -1, 8, 90, 8, WS_CHILD | WS_VISIBLE | WS_GROUP
END

Файл определения модуля приведен в листинге 6.5.


Листинг 6.5. Файл prnfile/prnfile.def


; =============================
; Файл определения модуля
; =============================
NAME        PRNFILE
DESCRIPTION 'Приложение PRNFILE, (C) 1994, Frolov A.V.'
EXETYPE     windows
STUB        'winstub.exe'
STACKSIZE   5120
HEAPSIZE    1024
CODE        preload moveable discardable
DATA        preload moveable multiple

[Назад] [Содеожание] [Дальше]