How to Display UNICODE Characters in a CListCtrl or a CEdit

The question: How can I display special characters (such as ∞ and Φ …) in a list control/edit box has come up a few times in the Codeguru Visual C++ Programming forum. There was a particular post that made me think of a simple way to display those characters. That being said I, built a small, dialog-based application that illustrates this in a very simple manner (or this is what I like to think).

These are the steps to follow to have the same behavior reproduced in your projects:

  1. Create a file (using Notepad) with all the special characters you need to display. For the character ∞, for example, just press “Alt” and 236 on the numpad. For the character Φ, press “Alt” and 237, and so on. For a list of all the special characters, please see an ASCII table. All of them are listed under the “Extended ASCII Codes” section. Give this file a name (I named it Unicode.txt, but it can be whatever you think is suitable) and save it with “Unicode” encoding (File, Save As.). See the screenshot below for the encoding type:
  2. Create a dialog-based application with the following remarks:
    1. Make sure you have added _UNICODE in: Project->Settings->C/C++->General->Preprocessor definitions.
    2. Add wWinMainCRTStartup in: Project->Settings->Link->Category: Output->Entry-point symbol.
    3. Make sure that these settings are in the “Release” version as well. The pictures below show only the “Debug” build settings!
    4. For both these options, please see the following screenshots:

    5. Add a CListCtrl REPORT style and a CEdit box to your dialog using resource editor and, with the help of the class wizard, add member variables of type CListCtrl/CEdit to the newly added controls. Name the variable for the CListCtrl m_list and the variable for the CEdit m_edit. Add a protected member variable of type CFont to your dialog. Name this variable CFont m_font.
    6. Now, create two protected functions, one called SetControlsFont (to create and apply the UNICODE font to the controls) and another one called SetControlsText (to read the UNICODE characters from the file and display these characters into the created controls).
    7. The function SetControlsFont creates and applies the UNICODE font to the controls.
    8. void CUnicodeDlg::SetControlsFont()
      {
         // create UNICODE Font and apply it to the controls.
         CDC *pDC = GetDC();
      
         // create UNICODE font
         LOGFONT lf;
         memset(&lf, 0, sizeof(lf));
         lf.lfHeight =
            MulDiv(20, ::GetDeviceCaps(pDC->m_hDC,
                   LOGPIXELSY), 72);
         lf.lfWeight = FW_NORMAL;
         lf.lfOutPrecision = OUT_TT_ONLY_PRECIS;
         wcscpy(lf.lfFaceName, _T("Lucida Sans Unicode"));
         m_font.CreateFontIndirect(&lf);
      
         // apply the font to the controls
         m_list.SetFont(&m_font);
         m_edit.SetFont(&m_font);
      
         // release the device context.
         ReleaseDC(pDC);
      }
      
    9. The function SetControlsText reads the characters from the file and sets the text into the controls. The usage of the function is pretty basic: the first argument is the filename, the second and the third are the controls where to display the text. In your case, m_list and m_edit. For the usage of this function, please see the example shown below in OnInitDialog.
    10. void CUnicodeDlg::SetControlsText(LPCTSTR lpszFileName,
           CListCtrl &list, CEdit &edit)
      {
      
         CFile file;
      
         // open the file and read the Unicode characters
         // input file has to be encoded with UTF-16 little
         // endian
         // if the file was saved as described above this
         // condition is already fulfilled
         TRY
         {
            file.Open(lpszFileName, CFile::modeRead);
            CString strText;
            UINT nRes = file.Read(strText.GetBuffer(1024),
                                  1024);
            strText.ReleaseBuffer(nRes / 2);
      
            // test to see whether the file is UNICODE
            if(strText.GetAt(0) == 0xFEFF)
            {
               // insert a column in the list control
               list.InsertColumn(0, _T("Unicode characters"),
                                 LVCFMT_LEFT, 300);
      
               // display characters in the list control
               list.InsertItem(0, strText);
      
               // display characters in the edit control
               edit.SetWindowText(strText);
      
               // close file
               file.Close();
            }
            else
               AfxMessageBox(_T("The file is not UNICODE."));
         }
         CATCH(CFileException, e)
         {
            e->ReportError();
         }
         END_CATCH
      }
      
    11. All you have to do now is call these two functions from your CDialog’s OnInitDialog and you’re all set:
    12. BOOL CUnicodeDlg::OnInitDialog()
      {
         CDialog::OnInitDialog();
      
         // Add "About..." menu item to system menu.
      
         // IDM_ABOUTBOX must be in the system command range.
         ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
         ASSERT(IDM_ABOUTBOX < 0xF000);
      
         CMenu* pSysMenu = GetSystemMenu(FALSE);
         if (pSysMenu != NULL)
         {
            CString strAboutMenu;
            strAboutMenu.LoadString(IDS_ABOUTBOX);
            if (!strAboutMenu.IsEmpty())
            {
               pSysMenu->AppendMenu(MF_SEPARATOR);
               pSysMenu->AppendMenu(MF_STRING,
                  IDM_ABOUTBOX, strAboutMenu);
            }
         }
      
         // Set the icon for this dialog. The framework does
         // this automatically when the application's main
         // window is not a dialog.
         SetIcon(m_hIcon, TRUE);     // Set big icon
         SetIcon(m_hIcon, FALSE);    // Set small icon
      
         // TODO: Add extra initialization here
      
         // set controls font
         SetControlsFont();
      
         // fill the controls
         SetControlsText(_T("unicode.txt"), m_list, m_edit);
      
         return TRUE;    // return TRUE unless you set the
                         // focus to a control
      }
      

This is an article where you can find a more detailed discussion about UTF-16 and UNICODE. The article also shows a class that deals with reading/writing from/to a UNICODE file. The credits for this article go to Jeffrey Walton.

That’s it. Pretty easy, right? Compile and run it. Enjoy!

More by Author

Get the Free Newsletter!

Subscribe to Developer Insider for top news, trends & analysis

Must Read