// ----------------------------------------------------
// Функции для работы с принтером
// ----------------------------------------------------
#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;
}

