unit RichPrint;
{* By Savva. A unit to print rich edit control content. }

interface

uses Windows, KOL, {$IFNDEF NOT_USE_PRINTER_OBJ}
     {$IFDEF USE_MHPRINTER} KOLMHPrinters {$ELSE} KOLPrinters {$ENDIF}
     ,{$ENDIF}
     RichEdit, CommDlg;

procedure FilePrint(ACaption : string;fRichEdit : PControl);
{* печать без использования объекта Printer }

{$IFNDEF NOT_USE_PRINTER_OBJ}
procedure PrintRichEdit(CONST fRichEdit : PControl;const Caption: string);
{* печать c использованием  объекта Printer }
{$ENDIF}

implementation

//*****************************************************
// печать без использования объекта Printer
// -----------------------------------------------------
// Функция FilePrint
// -----------------------------------------------------
procedure FilePrint(ACaption : string;fRichEdit : PControl);
var
  fr : FORMATRANGE;
  docInfo : TDOCINFO;
  lLastChar, lTextSize :integer ;
  pd : TPRINTDLG ;
  nRc : integer ;
  hPrintDC : HDC ;

  szErr : string;
  dwErr :DWORD ;
  //TextLenEx: TGetTextLengthEx;

begin
  // Инициализируем поля структуры PRITDLG

  ZeroMemory(@pd, sizeof(pd));
  pd.lStructSize := sizeof(TPRINTDLG);
  pd.hwndOwner   := fRichEdit.Handle;
  pd.hInstance   := HInstance;
  pd.Flags       := PD_RETURNDC or PD_NOPAGENUMS or PD_NOSELECTION or  PD_PRINTSETUP or
PD_ALLPAGES;
  pd.nFromPage   := $ffff;
  pd.nToPage     := $ffff;
  pd.nMinPage    := 0;
  pd.nMaxPage    := $ffff;
  pd.nCopies     := 1;


  // Выводим на экран диалоговую панель, предназначенную
  // для печати документа
  if PrintDlg(pd) then begin
//  if(TRUE) then begin
    hPrintDC := pd.hDC;

    // Инициализируем поля структуры FORMATRANGE
    ZeroMemory(@fr, sizeof(fr));

    // Будем печатать с использованием контекста
    // принтера, полученного от функции PrintDlg
    fr.hdc := hPrintDC;
    fr.hdcTarget:=fr.hdc;

    // Печатаем весь документ
    fr.chrg.cpMin := 0;
    fr.chrg.cpMax := -1;

    // Устанавливаем размеры страницы в TWIPS-ах
    fr.rcPage.top := 0;
    fr.rcPage.left := 0;
    fr.rcPage.right :=
      MulDiv(GetDeviceCaps(hPrintDC, PHYSICALWIDTH),
      1440, GetDeviceCaps(hPrintDC, LOGPIXELSX));

    fr.rcPage.bottom := MulDiv(GetDeviceCaps(hPrintDC,
      PHYSICALHEIGHT),1440,
      GetDeviceCaps(hPrintDC, LOGPIXELSY));
    fr.rc := fr.rcPage;

    // Оставляем поля
    if (fr.rcPage.right > 2*3*1440/4+1440) then begin
      fr.rc.left := 3*1440 div 4;
      fr.rc.right :=fr.rc.right - (fr.rc.left);
    end;
    if(fr.rcPage.bottom > 3*1440) then begin
      fr.rc.top := 1440;
      fr.rc.bottom:=fr.rc.bottom - (fr.rc.top);
    end;

    // Заполняем поля структуры DOCINFO
    ZeroMemory(@docInfo, sizeof(DOCINFO));
    docInfo.cbSize := sizeof(DOCINFO);
    docInfo.lpszOutput := nil;
    docInfo.lpszDocName := PChar(ACaption);


    // Начинаем печать документа
    nRc := StartDoc(hPrintDC, docInfo);

    // Если произошла ошибка, получаем и выводим на экран
    // код ошибки
    if (nRc < 0) then begin
      dwErr := GetLastError();

      szErr:=format( 'Print Error %ld \r\n %s', [dwErr,SysErrorMessage(dwErr)]);

      MessageBox(0, PChar(szErr),
        'Error printing', MB_OK or MB_ICONEXCLAMATION);

      DeleteDC(hPrintDC);
      exit;
    end;

    // Начинаем печать страницы
    StartPage(hPrintDC);

    lLastChar := 0;

    // Определяем длину текста
    lTextSize := fRichEdit.RE_TextSizePrecise;
    // Цикл по всем страницам документа
    while (lLastChar < lTextSize) do begin
      // Форматируем данные для принтера и печатаем их
      lLastChar := SendMessage(fRichEdit.Handle, EM_FORMATRANGE, DWORD(TRUE),
        LPARAM( @fr));

      if(lLastChar < lTextSize) then begin
        // Завершаем печать очередной страницы
        EndPage(hPrintDC);

        // Начинаем новую страницу
        StartPage(hPrintDC);
        fr.chrg.cpMin := lLastChar;
        fr.chrg.cpMax := -1;
      end;
    end;

    // Удаляем информацию, которая хранится в
    // органе управления Rich Edit
    SendMessage(fRichEdit.Handle, EM_FORMATRANGE, DWORD(TRUE), LPARAM(nil));

    // Завершаем печать страницы
    EndPage(hPrintDC);

    // Завершаем печать документа
    EndDoc(hPrintDC);

    // Удаляем контекст принтера
    DeleteDC(hPrintDC);
    end;
end;

{$IFNDEF NOT_USE_PRINTER_OBJ}
//*****************************************************
// печать c использованием  объекта Printer
procedure PrintRichEdit(CONST fRichEdit : PControl;const Caption: string);
var
  Range: TFormatRange;
  LastChar, MaxLen, LogX, LogY, OldMap: Integer;
  SaveRect: TRect;
begin
  FillChar(Range, SizeOf(TFormatRange), 0);
  Printer.Title := Caption;
  Printer.BeginDoc;
  Range.hdc := Printer.Handle;
  Range.hdcTarget := Range.hdc;
  LogX := GetDeviceCaps(Printer.Handle, LOGPIXELSX);
  LogY := GetDeviceCaps(Printer.Handle, LOGPIXELSY);

  Range.rc.right := Printer.PageWidth * 1440 div LogX;
  Range.rc.bottom := Printer.PageHeight * 1440 div LogY;
  Range.rcPage := Range.rc;
  SaveRect := Range.rc;
  LastChar := 0;
//    MaxLen := fRichEdit.Perform(WM_GETTEXTLENGTH, 0, 0);
    MaxLen := fRichEdit.RE_TextSizePrecise;
  Range.chrg.cpMax := -1;
  // ensure printer DC is in text map mode
  OldMap := SetMapMode(range.hdc, MM_TEXT);
  fRichEdit.Perform(EM_FORMATRANGE, 0, 0);    // flush buffer
    try
      repeat
        Range.rc := SaveRect;
        Range.chrg.cpMin := LastChar;
        LastChar := fRichEdit.Perform(EM_FORMATRANGE, 1, Longint(@Range));
        if (LastChar < MaxLen) and (LastChar <> -1) then Printer.NewPage;
      until (LastChar >= MaxLen) or (LastChar = -1);
      Printer.EndDoc;
    finally
      fRichEdit.Perform(EM_FORMATRANGE, 0, 0);  // flush buffer
      SetMapMode(Range.hdc, OldMap);       // restore previous map mode
    end;
end;
{$ENDIF}


end.
