Search code examples
visual-studio-2010unicodefontsmfcrichedit

Mfc Font binding and Rich Edit Control RICHEDIT50W does not display Unicode Properly


Latest update:

Well, I found a culprit of some sort. I changed the control to RichEdit20W from the 50W and it displays the Hangul (Korean) now. I did not have to change any other code except for the init, added AfxInitRichEdit2(), and commented out the LoadLibrary(L"MsftEdit.dll"). The AfxInitRichEdit5() is not available for VS2010. All things being equal and Rich Edit 4.1 has been available since VS2005, it should have worked. I can't upgrade to VS2015 right now so I'm stuck. I'm going to offer a bounty though for anybody who can make the Hangul work with 50W and VS2010.


I have a dilemma that I can't seem to solve.

I have an mfc Unicode app that uses CEdit and CRicheditCtrl.
The Rich Edit is 50W loaded from MsftEdit.dll and verified with Spy++
that the class name is RICHEDIT50W.

My problem:

I'm using the same Font Courier New for both the CEdit and CRichEditCtrl.

As a test, I used some of the Hangul symbols to see the output for both
controls.

CEdit outputs ᄀᄁᄂᄃᄄᄅᄆᄇᄈ
while the
CRichEditCtrl outputs a box for each character, like there is no glyph for it.

If they are using the same font, shouldn't I see the same output characters?

I think that font-binding is not a problem, both have the same default font.

Can anybody solve this riddle ?

Thanks in advance!

Note that this happens with some other character sets as well, not just Hangul


Update

I looked at the VS2010 WordPad example, it uses CRichEditView but it
provides wrappers to access the embedded CRichEditCtrl.

I thought I could glean some info but I can't see how they are doing the
Rich Edit control calls.

This is how I am generating the font's for both controls.
But, I'm showing specifically the Rich Edit part.

The doc's say that Font binding should handle switching from the default
font to the font at the current insertion point.

I am doing insertion mostly at the end using
ctrl.SetSel(-1,-1);
ctrl.ReplaceSel( str );

And, according to the doc's, this should change to the correct font as needed,
if other than the default font.

In the WordPad sample, if I paste in the Hangul text, the font switches to
Gulim.

Here is my code:

LOGFONT lf;
int pitch = 10;
memset(&lf, 0, sizeof(LOGFONT));

HDC hdc = ::GetDC(NULL);
lf.lfHeight = -MulDiv( pitch, GetDeviceCaps(hdc, LOGPIXELSY), 72);
lf.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
lstrcpy(lf.lfFaceName, _T("Courier New") );
lf.lfWeight = FW_NORMAL;
lf.lfCharSet = ANSI_CHARSET;  // English, but use DEFAULT_CHARSET if not
lf.lfQuality = DEFAULT_QUALITY;


if ( !m_Font.CreateFontIndirect(&lf) )
{   // Ours didn't work, create a system default fixed font
    // ( Ignore, example for post only. Never gets called though )
    //memset(&lf, 0, sizeof(LOGFONT));
    //::GetObject(GetStockObject(ANSI_FIXED_FONT), sizeof(LOGFONT), &lf);
    //m_Font.CreateFontIndirect(&lf);
}


// Save the generated Font LOGFONT 
m_lf = lf;

// Set the default Font CHARFORMAT2
memset( &m_cfDefaultFont, 0, sizeof(m_cfDefaultFont) );
m_cfDefaultFont.cbSize = sizeof(m_cfDefaultFont);
m_cfDefaultFont.dwMask = CFM_CHARSET | CFM_FACE | CFM_WEIGHT ;
m_cfDefaultFont.bCharSet = m_lf.lfCharSet;
lstrcpy( m_cfDefaultFont.szFaceName, m_lf.lfFaceName );
m_cfDefaultFont.wWeight = m_lf.lfWeight;

// Finally set the font in the controls
m_RichEdit.SetFont( &m_Font );

// Same effect as m_RichEdit.SetFont()
//m_RichEdit.SendMessage(EM_SETCHARFORMAT, SCF_ALL, &m_cfDefaultFont);

// This displays nothing but 'box' glyphs
m_RichEdit.SetWindowTextW(_T("ᄃᄄᄅᄆᄇᄈᄉᄊᄋᄌᄍᄎ"));

Update 2

This is how I initialize the Rich Edit in the app.
And shows the usage of 50W in a dialog control.

-- winapp.cpp
BOOL CMyApp::InitInstance()
{
    // ...... //

    CString strRichEdit = _T("Msftedit.dll");
    m_hMsfteditDll = AfxLoadLibrary( strRichEdit );
    if ( m_hMsfteditDll == NULL )
    {
        CString str;
        str.Format(_T("Error: Cannot find Rich Edit component %s"), strRichEdit );
        AfxMessageBox(str);
        return FALSE;
    }
    return TRUE;
}
int CRegexFormatApp::ExitInstance() 
{
    if ( m_hMsfteditDll != NULL )
        AfxFreeLibrary( m_hMsfteditDll );
    return CWinAppEx::ExitInstance();
}

// =========================

-- .rc 
CONTROL         "",IDC_RICH_EDIT,"RICHEDIT50W",WS_VSCROLL | WS_HSCROLL,40,15,148,28

-- Dlg.h
CRichEditCtrl m_RichEdit;

-- Dlg.cpp
void Dlg::DoDataExchange(CDataExchange* pDX)
{
    CDialogEx::DoDataExchange(pDX);
    DDX_Control(pDX, IDC_RICH_EDIT, m_RichEdit); // Use .rc setting to Create/Attach
}

BOOL Dlg::OnInitDialog()
{
    CDialogEx::OnInitDialog();
    CreateAndSetRichFont();  // Code shown above
    m_RichEdit.SetWindowTextW( ... );
}

Solution

  • This code should work in a Unicode project:

    BOOL CMyApp::InitInstance()
    {
        CWinApp::InitInstance();
        LoadLibrary(L"MsftEdit.dll");
        ...
    }
    
    BOOL CMyDialog::OnInitDialog()
    {
        CDialog::OnInitDialog();
    
        static CRichEditCtrl redit;
        CWnd *wnd = &redit;
        wnd->Create(MSFTEDIT_CLASS, L"ᄃᄄᄅᄆᄇᄈᄉᄊᄋᄌᄍᄎ",
                WS_CHILD | WS_VISIBLE, CRect(0,0,300,300), this, 1001, 0);
        ...
        //redit is not to be mixed up with controls created in dialog editor.
    }
    

    Edit ----------------

    NONCLIENTMETRICS info = { sizeof(info) };
    SystemParametersInfo(SPI_GETNONCLIENTMETRICS, sizeof(info), &info, 0);
    LOGFONT logfont = info.lfMessageFont;
    
    //CClientDC has automatic cleanup, use it instead of GetDC
    CClientDC dc(this);
    logfont.lfHeight = -MulDiv(abs(logfont.lfHeight), dc.GetDeviceCaps(LOGPIXELSY), 76);
    
    CFont font;
    font.CreateFontIndirect(&logfont);
    m_RichEdit.SetFont(&font);
    
    m_RichEdit.SetWindowText(L"ᄃᄄᄅᄆᄇᄈᄉᄊᄋᄌᄍᄎ");
    
    m_RichEdit.SetSel(1, 1);
    
    CString test = L"(Test, ελληνικά)";
    
    //Test to make sure we can see Unicode text
    AfxMessageBox(test);
    m_RichEdit.ReplaceSel(test);
    
    //optional:
    //get default CHARFORMAT
    CHARFORMAT2 charFormat;
    //m_RichEdit.GetSelectionCharFormat(charFormat);
    m_RichEdit.GetDefaultCharFormat(charFormat);