Hi Rik!
Thanks for this.
We have several separate RTF parts printed in columns (the first scenario you mentioned). Each note is a separate TRichMemo control, and we print them side-by-side in a grid layout - 3 columns per row, 2 rows per (usually Landscape) page. We call PrintRichMemoToRect() separately for each note, passing different rectangles for each column position (e.g., column 0 at X=343, column 1 at X=2209, column 2 at X=4075). We do NOT have one RTF document with actual column formatting.
I've implemented your approach exactly as you described:
// Convert pixels to twips using printer DPI
function PixelsToTwips(Pixels: Integer; DPI: Integer): Integer;
const
CTwipsPerInch = 1440;
begin
Result := MulDiv(Pixels, CTwipsPerInch, DPI);
end;
// In the printing function:
RectTwips.Left := PixelsToTwips(ARect.Left, LogPixelsX);
RectTwips.Top := PixelsToTwips(ARect.Top, LogPixelsY);
RectTwips.Right := PixelsToTwips(ARect.Right, LogPixelsX);
RectTwips.Bottom := PixelsToTwips(ARect.Bottom, LogPixelsY);
// Set rc = rcPage as rvk does
FormatRange.rcPage := RectTwips;
FormatRange.rc := RectTwips;
// Call EM_FORMATRANGE
LastChar := SendMessage(RichMemo.Handle, EM_FORMATRANGE, 1, LPARAM(@FormatRange));
// Flush buffer
SendMessage(RichMemo.Handle, EM_FORMATRANGE, 0, 0);[code=pascal]
[/code]
Unfortunately, despite using your exact approach, the text still renders incorrectly:
Column 0 (first note): Text aligns slightly to the left
Column 1 (second note): Text renders far to the LEFT of where it should be, overlapping column 0
Column 2 (third note): Text renders even further LEFT, overlapping column 1
It's as if EM_FORMATRANGE is ignoring the rc.Left coordinate entirely and always rendering at some fixed position regardless of what rectangle we pass.
From my debug log for a 3-column print:Column 0: Input Rect (pixels): L=343, T=2420, R=2179, B=4261
Converted Rect (twips): L=662, T=5808, R=4085, B=10226
rc = rcPage = (662,5808,4085,10226) twips
Result: Text renders slightly to the left
Column 1: Input Rect (pixels): L=2415, T=2420, R=4251, B=4261
Converted Rect (twips): L=4528, T=5808, R=7971, B=10226
rc = rcPage = (4528,5808,7971,10226) twips
Result: Text renders FAR LEFT (overlaps column 0)
Column 2: Input Rect (pixels): L=4477, T=2420, R=6313, B=4261
Converted Rect (twips): L=8394, T=5808, R=11837, B=10226
rc = rcPage = (8394,5808,11837,10226) twips
Result: Text renders EVEN FURTHER LEFT (overlaps column 1)
Printer DPI: X=768, Y=0 (falls back to 600)
Tests We've Tried:
- Setting rc = rcPage (your approach) - no effect
Setting rc to full page area (0,0,PageWidth,PageHeight) - no effect, text still renders at same wrong positions
Various pixel offsets and adjustments - no improvement
Using SetViewportOrgEx with PHYSICALOFFSETX - made it worse
Creating temporary invisible RichEdit controls positioned at print coordinates - caused access violation crash
The critical finding:
When we tested setting rc to the full page area instead of the column-specific rectangle, the text rendered at exactly the same wrong positions. This would seem to prove that EM_FORMATRANGE is completely ignoring the rc parameter we pass to it.
Questions:
- Could this be a printer driver quirk? Note that our Y DPI returns 0 (we fall back to 600). Could this indicate a driver issue (Epson ET-4850 Series) that's also affecting EM_FORMATRANGE? I've tried using the standard Microsoft "Print to PDF" driver as well, and the displacements are even more to the left.
Are we missing something about the DC state? Do we need to set any specific DC properties before calling EM_FORMATRANGE?
Could the on-screen RichEdit control's window position be interfering? The TRichMemo controls are visible on-screen at various positions. Could EM_FORMATRANGE be using the window's screen position instead of the rc we provide?
Does your approach work with landscape orientation? We're printing in landscape mode with a 3x2 grid.