We have an application that displays information in a scrolling RichEdit control, always displaying the latest, i.e. the bottom lines. For this purpose we add new lines at the bottom, place the SelStart at the end, to move the caret there, and ask the RichEdit to show the current position of the caret.
This works fine with the old version of the application, but fails to scroll to the end with the new version compiled with Delphi XE. Same code (mostly), same machine, different Delphi. Digging a little bit I found that it still works though when the RichEdit has the focus, which is unlikely to happen (not the default).
Between D2007 and D2009 the code snippet used to scroll the caret into view
Perform(Messages.EM_SCROLLCARET, 0, 0); // Scroll to caret
ceased to work for a RichEdit control when the RichEdit does not have the focus.
Because the same code works with D2007 and, on the same machine, does not work anymore with D2009 and above, one would easily put the blame on Embarcadero, not on Microsoft.
In fact, that would be blaming the messenger; Embarcadero basically did not change their code, but merely went from linking the RichEdit 1.0 compatibility module to the 2.0 one
Up to D2007:
RichEditModuleName = 'RICHED32.DLL';
D2009 and up:
RichEditModuleName = 'RICHED20.DLL';
The bug (I’m sure they could call it a feature) lies with Microsoft. And if you try with the newest Richedit 4.1, you get the same problem.
There is a workaround though, and that’s where Embarcadero could have made good on the promise of the VCL to isolate the developers from the quirks of the Windows API. Making sure that the RichEdit does not hide the selection allows EM_SCROLLCARET to perform as expected.
But according to Murphy’s Law, the default is HideSelection := True….
procedure ScrollToEnd(ARichEdit: TRichEdit); var isSelectionHidden: Boolean; begin with ARichEdit do begin SelStart := Perform(Messages.EM_LINEINDEX, Lines.Count, 0);//Set caret at end isSelectionHidden := HideSelection; try HideSelection := False; Perform(Messages.EM_SCROLLCARET, 0, 0); // Scroll to caret finally HideSelection := isSelectionHidden; end; end; end;