Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why doesn't EM_SETTEXTMODE work?

I'm trying to use EM_SETTEXTMODE on a RichEdit control in Delphi 7.

Just create a new project, add a TRichEdit control and a TButton control and add the following code to the button's click handler:

  SendMessage(RichEdit1.Handle, WM_SETTEXT, 0, LPARAM(PChar('')));
  Button1.Caption := IntToStr(SendMessage(RichEdit1.Handle, EM_GETTEXTMODE, 0, 0));
  Button1.Caption := Button1.Caption + ' ' + IntToStr(SendMessage(RichEdit1.Handle, EM_SETTEXTMODE, TM_PLAINTEXT, 0));
  Button1.Caption := Button1.Caption + ' ' + IntToStr(SendMessage(RichEdit1.Handle, EM_GETTEXTMODE, 0, 0));

The button's caption is set to 38 0 38 after clicking on the button, meaning the text mode didn't change at all - initially it was 38 (TM_RICHTEXT or TM_SINGLELEVELUNDO or TM_MULTICODEPAGE), then SETTEXTMODE was successful (0) but even after that it is still 38.

The RichEdit's text is cleared before using EM_SETTEXTMODE as suggested by the documentation.

I've tried setting different values with EM_SETTEXTMODE and it always stays 38.

I noticed that EM_SETTEXTMODE always returns 0 (success) even if the RichEdit control contains text before calling it.

I tried using RichEdit1.Perform instead of SendMessage - no difference.

I've found several threads in various forums on this issue, and it wasn't resolved in any of them.

Any idea why isn't this working?

like image 527
jedivader Avatar asked Feb 11 '14 19:02

jedivader


1 Answers

Older Delphi versions load the RichEdit control which is located in RICHED32.DLL. Newer Delphi versions load RICHED20.DLL.

RICHED32.DLL exposes many problems, like yours. The fix is modifying comctrls.pas so that it loads RICHED20.DLL. That will most likely not be enough as there may be compatibility issues with this DLL and the VCL code. Look for the TCustomRichEdit.CreateParams() procedure, it contains the LoadLibrary call.

I tested your code in Delphi XE and there it works, so your best option is to upgrade to a more recent Delphi version.

UPDATE

I did some tests with Delphi 5 and it seems to be enough to change 2 functions. Copy Comctrls.Pas into your project and execute these modifications:

1) in TCustomRichEdit.CreateParams(), change

const
  RichEditModuleName = 'RICHED32.DLL';

into

const
  RichEditModuleName = 'RICHED20.DLL';

and

CreateSubClass(Params, 'RICHEDIT');

into

CreateSubClass(Params, 'RICHEDIT20A');

2) in the procedure TRichEditStrings.Insert(), change

if RichEdit.SelStart <> (Selection.cpMax + Length(Str)) then
      raise EOutOfResources.Create(sRichEditInsertError);

into

if RichEdit.SelStart <> (Selection.cpMax + Length(Str) - CountLineBreaks(Str)) then
      raise EOutOfResources.Create(sRichEditInsertError);

code for CountLineBreaks/PosEx:

function PosEx(const SubStr, S: string; Offset: Cardinal = 1): Integer;
var
 Tmp: PChar;

begin
 Result := 0;
 if (Offset > Cardinal(Length(S))) then exit;
 if Offset = 1 then
  Result := Pos(SubStr, S)
 else
  begin
   Tmp := StrPos(PChar(@S[Offset]), PChar(SubStr));
   if Tmp = nil then exit;
   Result := Cardinal(Tmp - PChar(@S[Offset])) + Offset;
  end;
end;


function CountLineBreaks(const S: string): Integer;
const
  LB = #13#10;
var
  P: Integer;
begin
  Result := 0;
  P := Pos(LB, S);
  while P <> 0 do
  begin
    Inc(Result);
    P := PosEx(LB, S, P + 2);
  end;
end;

Doing this in Delphi5, I get the correct result:

Delphi5

One thing to keep in mind is that RichEdit 2.0 replaces CRLF pairs with CR, so other issues may creep up. Don't shoot me if you run into problems down the road...

like image 113
whosrdaddy Avatar answered Sep 29 '22 05:09

whosrdaddy