title: How to make TRichEdit behave like WordPad on Windows 7 when changing font for certain non-text characters?
body: <p>With the help of <code>Sertac Akyuz</code>, it seems the direct reason is related to the charset of <code>\bullet</code>: In my localized Windows, the <code>\bullet</code> input by typing Alt(0149) always gets <code>\fcharset134</code>, and attempts to change its font through <code>EM_SETCHARFORMAT</code> always fail (well, the color, size, style can indeed be changed but not font family name).</p>
  
  <p>The simplest workaround is therefore to first reset the charset and then change the font. </p>
  
  <p>Note: RichEdit <strong>(version >= 4.1)</strong> should be used! </p>
  
  <p>Note: RichEdit versions can be found at MSDN's <a href="http://msdn.microsoft.com/en-us/library/windows/desktop/bb787873%28v=vs.85%29.aspx" rel="nofollow noreferrer"> About Rich Edit Controls</a>, Murray Sargent's MSDN Blog <a href="http://blogs.msdn.com/b/murrays/archive/2011/10/17/824003.aspx" rel="nofollow noreferrer">RichEdit versions</a> and <a href="http://blogs.msdn.com/b/murrays/archive/2009/09/05/richedit-versions-update-to-7-0.aspx" rel="nofollow noreferrer">RichEdit Versions Update to 7.0</a>. The latter pages mentioned RichEdit versions higher than 4.1. As a test, I copied the RICHED20.DLL shiped with Office 2010 together with the application to Windows 2000, and everything works like a charm!</p>
  
  <pre><code>procedure TMainForm.ButtonFontClick(Sender: TObject);
  var
    format: TCharFormat2;
  begin
    if dlgFontCdxTxt.Execute then
    begin
      FillChar(format, sizeof(format), 0);
      format.cbSize:= Sizeof(format);
      format.dwMask:= CFM_CHARSET;
      format.bCharSet := 1; // or 0;
      redtTextBlock.Perform(EM_SETCHARFORMAT, SCF_SELECTION, Integer(@format));
  
      FillChar(format, sizeof(format), 0);
      format.cbSize:= Sizeof(format);
      format.dwMask:= CFM_FACE;
      StrPLCopy(format.szFaceName, dlgFontCdxTxt.Font.Name, High(format.szFaceName));
      redtTextBlock.Perform(EM_SETCHARFORMAT, SCF_SELECTION, Integer(@format));
    end;
    redtTextBlock.SetFocus;
  end;
  </code></pre>
  
  <p>==================================================</p>
  
  <p>According to <a href="http://en.wikipedia.org/wiki/WordPad" rel="nofollow noreferrer">Wikipedia</a>, <code>WordPad</code> used Microsoft's <code>RichEdit</code> control, versions 1.0, 2.0 and 3.0 in Windows 95, 98 and Windows 2000, respectively. In Windows XP SP1 and later, WordPad uses RichEdit 4.1, including Windows 7. </p>
  
  <p>Say a rtf document, being edited in WordPad, contains a non-text character Alt(0149), <code>the bullet dot •</code>. (Or U+2022)</p>
  
  <p>In Windows 2000 SP4 or XP SP2, the font of that bullet dot can only take the default font of WordPad. That is to say, one cannot change font for that bullet dot interactively in WordPad. </p>
  
  <p>However, in Windows 7 SP1, one could change its font by <code>first changing to "Arial Unicode MS"</code>, and then to any desired font unlimited times. </p>
  
  <p><img src="https://i.stack.imgur.com/hDokb.png" alt="Wordpad_1">
  <img src="https://i.stack.imgur.com/xQAEf.png" alt="WordPad_2">
  <img src="https://i.stack.imgur.com/5oJQo.png" alt="WordPad_3"></p>
  
  <p>Furthermore, WordPad document created using WordPad in Windows 7 that contains different fonts of the dot can be opened and viewed correctly in WordPad in Windows 2000 or XP.</p>
  
  <p>The TRichEdit (Delphi XE, Windows 7) can also open and view the WordPad document created using WordPad in Windows 7 correctly by <code>TRichEdit.Lines.LoadFromFile</code>.</p>
  
  <p><img src="https://i.stack.imgur.com/JY51Z.png" alt="TRichEdit_1"></p>
  
  <p>Interactively, the TRichEdit (Delphi XE, Windows 7) allows <code>the bullet dot</code>'s font to be changed to "Arial Unicode MS". However, one cannot go further to change to other fonts interactively in TRichEdit.
  <img src="https://i.stack.imgur.com/xxsg2.png" alt="TRichEdit_2">
  <img src="https://i.stack.imgur.com/7NBoB.png" alt="TRichEdit_3">
  <img src="https://i.stack.imgur.com/VDMkX.png" alt="TRichEdit_4"></p>
  
  <p>I am therefore wondering (1) the reason of the different behavior of WordPad in Windows 7, and (2) whether it is possible to make TRichEdit behave alike?</p>
  
  <p>PS: One may need type Alt(0149) several times to get the dot in WordPad. Typing 2022 and Alt+x always works, as suggested <a href="http://us.generation-nt.com/answer/alt-plusxxx-keystroke-dont-make-through-my-richedit-control-help-26070432.html?page=2" rel="nofollow noreferrer">here</a>. </p>
  
  <p>PS: One need to "activate" the fonts in WordPad as mentioned in the answer of <a href="https://stackoverflow.com/questions/11300277/why-tfontdialog-gives-less-fonts-than-screen-fonts">Why TFontDialog gives less fonts than Screen.Fonts?</a></p>
  
  <p>PS: One can always change the dot to different fonts in Word.</p>
  
  <h3>sample.rtf (paste into a plain text file and then change the extension to rtf to use)</h3>
  
  <pre><code>{\rtf1\ansi\ansicpg936\deff0\deflang1033\deflangfe2052{\fonttbl{\f0\fswiss\fprq2\fcharset134 Arial Unicode MS;}{\f1\fnil\fcharset0 Arial Unicode MS;}{\f2\froman\fprq2\fcharset0 Times New Roman;}{\f3\fscript\fprq2\fcharset0 Comic Sans MS;}{\f4\fnil\fcharset0 Comic Sans MS;}{\f5\fmodern\fprq1\fcharset0 Consolas;}{\f6\fnil\fcharset0 Consolas;}{\f7\fmodern\fprq1\fcharset0 Lucida Console;}{\f8\fnil\fcharset0 Lucida Console;}{\f9\froman\fprq2\fcharset2 Symbol;}{\f10\froman\fprq2\fcharset0 Symbol;}{\f11\fnil\fcharset134 \'cb\'ce\'cc\'e5;}}
  {\*\generator Msftedit 5.41.21.2510;}\viewkind4\uc1\pard\nowidctlpar\sa200\sl276\slmult1\lang2052\f0\fs22 Arial sample text \lang1033\f1\bullet\f2\par
  \b\f3 Comic sample text \f4\bullet\f2\par
  \b0\f5 Consolas sample text \f6\bullet\f2\par
  \f7 Lucida sample text \f8\bullet\f2\par
  \pard\nowidctlpar\qj\lang2052\f9 symbl sample text \lang1033\f10\u149?\kerning2\fs21\par
  \pard\sa200\sl276\slmult1\lang2052\kerning0\f11\fs22\par
  }
  </code></pre>
  
  <h3>uMainForm.dfm to view the format of the lines of TRichEdit</h3>
  
  <pre><code>object MainForm: TMainForm
    Left = 0
    Top = 0
    Caption = 'MainForm'
    ClientHeight = 362
    ClientWidth = 637
    Color = clBtnFace
    Font.Charset = DEFAULT_CHARSET
    Font.Color = clWindowText
    Font.Height = -11
    Font.Name = 'Tahoma'
    Font.Style = []
    OldCreateOrder = False
    OnCreate = FormCreate
    PixelsPerInch = 96
    TextHeight = 13
    object pnlBtn: TPanel
      Left = 0
      Top = 0
      Width = 637
      Height = 57
      Align = alTop
      Caption = 'pnlBtn'
      TabOrder = 0
      object Button1: TButton
        Left = 240
        Top = 14
        Width = 137
        Height = 31
        Caption = 'Analyze Rich Edit'
        TabOrder = 0
        OnClick = Button1Click
      end
    end
    object pnlClient: TPanel
      Left = 0
      Top = 57
      Width = 637
      Height = 305
      Align = alClient
      Caption = 'pnlClient'
      TabOrder = 1
      object redtTextBlock: TRichEdit
        Left = 1
        Top = 1
        Width = 225
        Height = 303
        Align = alLeft
        Font.Charset = GB2312_CHARSET
        Font.Color = clWindowText
        Font.Height = -11
        Font.Name = 'Tahoma'
        Font.Style = []
        Lines.Strings = (
          'redt1')
        ParentFont = False
        TabOrder = 0
      end
      object mmo1: TMemo
        Left = 226
        Top = 1
        Width = 410
        Height = 303
        Align = alClient
        Lines.Strings = (
          'mmo1')
        TabOrder = 1
      end
    end
    object Button2: TButton
      Left = 36
      Top = 14
      Width = 171
      Height = 31
      Caption = 'Font...'
      TabOrder = 2
      OnClick = Button2Click
    end
    object dlgFontCdxTxt: TFontDialog
      Font.Charset = DEFAULT_CHARSET
      Font.Color = clWindowText
      Font.Height = -11
      Font.Name = 'Tahoma'
      Font.Style = []
      Left = 480
      Top = 16
    end
  end
  </code></pre>
  
  <h3>uMainForm.pas to view the format of the lines of TRichEdit</h3>
  
  <pre><code>unit uMainForm;
  
  interface
  
  uses
    Contnrs,
    Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
    Dialogs, StdCtrls, ComCtrls, ExtCtrls;
  
  type
  
    TCdxmlStyle = class
    public
      FontName: string;
      Str: string;
    end;
  
    TCdxmlText = class
    public
      Styles: TObjectList;
      constructor Create;
    end;
  
    TMainForm = class(TForm)
      redtTextBlock: TRichEdit;
      mmo1: TMemo;
      pnlBtn: TPanel;
      pnlClient: TPanel;
      Button1: TButton;
      Button2: TButton;
      dlgFontCdxTxt: TFontDialog;
      procedure Button1Click(Sender: TObject);
      procedure Button2Click(Sender: TObject);
      procedure FormCreate(Sender: TObject);
    private
      { Private declarations }
      procedure TestLoadFromFile;
      procedure AnalyzeRichEdit;
    public
      { Public declarations }
    end;
  
  var
    MainForm: TMainForm;
  
  implementation
  
  {$R *.dfm}
  
  uses
    RichEdit, StrUtils;
  
  { TCdxmlText }
  
  constructor TCdxmlText.Create;
  begin
    Styles := TObjectList.Create;
  end;
  
  var
    l_HiddenRichEdit: TRichEdit;
  
  { TMainForm }
  
  procedure TMainForm.FormCreate(Sender: TObject);
  begin
    TestLoadFromFile;
    AnalyzeRichEdit;
  end;
  
  procedure TMainForm.Button2Click(Sender: TObject);
  var
    format: TCharFormat2;
  begin
    if dlgFontCdxTxt.Execute then
    begin
      FillChar(format, sizeof(format), 0);
      format.cbSize:= Sizeof(format);
      format.dwMask:= CFM_FACE;
  
      StrPLCopy(format.szFaceName, dlgFontCdxTxt.Font.Name, High(format.szFaceName));
  
      redtTextBlock.Perform(EM_SETCHARFORMAT, SCF_SELECTION, Integer(@format));
    end;
    redtTextBlock.SetFocus;
  end;
  
  procedure TMainForm.Button1Click(Sender: TObject);
  begin
    AnalyzeRichEdit;
  end;
  
  procedure TMainForm.TestLoadFromFile;
  begin
    redtTextBlock.Clear;
  
    redtTextBlock.Lines.LoadFromFile('sample.rtf');
  end;
  
  procedure TMainForm.AnalyzeRichEdit;
  var
    l_MemStream: TMemoryStream;
    l_Format: TCharFormat2;
  
    I, J: Integer;
    l_CdxmlStyle, l_CdxmlStyleWorker: TCdxmlStyle;
    l_StyleFont: string;
  
    l_CdxmlText: TCdxmlText;
  begin
    l_CdxmlStyle := nil;
    l_CdxmlStyleWorker := nil;
  
    mmo1.Clear;
  
    l_MemStream := TMemoryStream.Create;
    redtTextBlock.Lines.SaveToStream(l_MemStream);
    l_MemStream.Seek(0, soFromBeginning);
    l_HiddenRichEdit.Lines.LoadFromStream(l_MemStream);
  
    l_CdxmlText := TCdxmlText.Create;
    for I := 0 to Length(TrimRight(l_HiddenRichEdit.Text)) - 1 do
    begin
      l_CdxmlStyleWorker := TCdxmlStyle.Create;
  
      FillChar(l_Format, sizeof(l_Format), 0);
      l_Format.cbSize:= Sizeof(l_Format);
      l_Format.dwMask:= CFM_FACE;
  
      l_HiddenRichEdit.SelStart := I;
      l_HiddenRichEdit.SelLength := 1;
      l_HiddenRichEdit.Perform(EM_GETCHARFORMAT, SCF_SELECTION, Integer(@l_Format));
  
      l_CdxmlStyleWorker.FontName := l_Format.szFaceName;
  
      l_CdxmlStyleWorker.Str := AnsiReplaceStr(l_HiddenRichEdit.SelText, #13, #13#10);
  
      if l_CdxmlStyle = nil then
      begin
        l_CdxmlText.Styles.Add(l_CdxmlStyleWorker);
        l_CdxmlStyle := l_CdxmlStyleWorker;
      end
      else if (l_CdxmlStyleWorker.FontName  &lt;&gt; l_CdxmlStyle.FontName ) then
      begin
        l_CdxmlText.Styles.Add(l_CdxmlStyleWorker);
        l_CdxmlStyle := l_CdxmlStyleWorker;
      end
      else
      begin
        l_CdxmlStyle.Str := l_CdxmlStyle.Str + l_CdxmlStyleWorker.Str;
      end;
    end;
  
    for I := 0 to l_CdxmlText.Styles.Count - 1 do
    begin
      l_CdxmlStyle := TCdxmlStyle(l_CdxmlText.Styles[I]);
      mmo1.Lines.Add(l_CdxmlStyle.Str + ':' + l_CdxmlStyle.FontName);
    end;
  end;
  
  initialization
  
    l_HiddenRichEdit := TRichEdit.CreateParented(HWND_MESSAGE);
  
  end.
  </code></pre>