{ Существует проблема совместимости при вызове оригинального метода RichEdit.Print под NT 4.0. Исключительная ситуация EDivByZero происходит из-за того, что свойство Printer.Handle вне блока BeginDoc/EndDoc под NT 4.0 возвращает дескриптор информационного контекста (Information Context - IC) вместо дескриптора контекста устройства (Device Context - DC). EM_FORMATRANGE пытается использовать этот IC вместо реального DC принтера, вызывая этим исключительную ситуацию. Если свойство Handle акцептуется ПОСЛЕ BeginDoc, дескриптор контекста устройства возвращает истину, что и было мною исправлено в коде. Я оставил на том же месте в коде оригинальное месторасположение вызова BeginDoc, при этом сделав соответствующий комментарий для указания на внесенные изменения. } procedure TCustomRichEdit.Print(const Caption: string); var Range: TFormatRange; LastChar, MaxLen, LogX, LogY: Integer; begin FillChar(Range, SizeOf(TFormatRange), 0); with Printer, Range do begin LogX := GetDeviceCaps(Handle, LOGPIXELSX); LogY := GetDeviceCaps(Handle, LOGPIXELSY); // Спозиционированный вызов BeginDoc для обеспечения // совместимости под NT 4.0 и Win95 BeginDoc; hdc := Handle; hdcTarget := hdc; if IsRectEmpty(PageRect) then begin rc.right := PageWidth * 1440 div LogX; rc.bottom := PageHeight * 1440 div LogY; end else begin rc.left := PageRect.Left * 1440 div LogX; rc.top := PageRect.Top * 1440 div LogY; rc.right := PageRect.Right * 1440 div LogX; rc.bottom := PageRect.Bottom * 1440 div LogY; end; rcPage := rc; Title := Caption; // Оригинальная позиция BeginDoc { BeginDoc; } LastChar := 0; MaxLen := GetTextLen; chrg.cpMax := -1; repeat chrg.cpMin := LastChar; LastChar := SendMessage(Self.Handle, EM_FORMATRANGE, 1, Longint(@Range)); if (LastChar < MaxLen) and (LastChar <> -1) then NewPage; until (LastChar >= MaxLen) or (LastChar = -1); EndDoc; end; SendMessage(Handle, EM_FORMATRANGE, 0, 0); end; |
unit PrtRichU; interface uses SysUtils, Windows, Classes, ComCtrls, RichEdit, Printers; procedure PrintRichEdit(const Caption: string; const RichEdt: TRichEdit); implementation procedure PrintRichEdit(const Caption: string; const RichEdt: TRichEdit); var Range: TFormatRange; LastChar, MaxLen, LogX, LogY, OldMap: Integer; begin FillChar(Range, SizeOf(TFormatRange), 0); with Printer, Range do begin BeginDoc; hdc := Handle; hdcTarget := hdc; LogX := GetDeviceCaps(Handle, LOGPIXELSX); LogY := GetDeviceCaps(Handle, LOGPIXELSY); if IsRectEmpty(RichEdt.PageRect) then begin rc.right := PageWidth * 1440 div LogX; rc.bottom := PageHeight * 1440 div LogY; end else begin rc.left := RichEdt.PageRect.Left * 1440 div LogX; rc.top := RichEdt.PageRect.Top * 1440 div LogY; rc.right := RichEdt.PageRect.Right * 1440 div LogX; rc.bottom := RichEdt.PageRect.Bottom * 1440 div LogY; end; rcPage := rc; Title := Caption; LastChar := 0; MaxLen := RichEdt.GetTextLen; chrg.cpMax := -1; OldMap := SetMapMode(hdc, MM_TEXT); SendMessage(RichEdt.Handle, EM_FORMATRANGE, 0, 0); try repeat chrg.cpMin := LastChar; LastChar := SendMessage(RichEdt.Handle, EM_FORMATRANGE, 1, Longint(@Range)); if (LastChar < MaxLen) and (LastChar <> -1) then NewPage; until (LastChar >= MaxLen) or (LastChar = -1); EndDoc; finally SendMessage(RichEdt.Handle, EM_FORMATRANGE, 0, 0); SetMapMode(hdc, OldMap); end; end; end; end. |