Mfc Font binding and Rich Edit Control RICHEDIT50W does not display Unicode Properly - visual-studio-2010

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( ... );
}

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);

Related

How do I make a combobox show a tab control like VS' when setting a color?

I mean this control:
When you click on this, instead of regular options, a tab control with the colors is displayed. How can I do this? is this a owner-draw combobox or something else? I'm aware on how draw text, rectangles, images, etc with a owner-draw combobox but I don't know how add controls over there. I have no code to show yet because I have no idea how do that. I've tried something like call CreateWindow() in WM_DRAWITEM using the values from DRAWITEMSTRUCT.rcItem but I can't make a control inside the groupbox's client area, the button gets behind the control.
Looks like you are looking for CBN_DROPDOWN.
Sent when the list box of a combo box is about to be made visible. The
parent window of the combo box receives this notification code through
the WM_COMMAND message.
Some code:
HWND hWndComboBox = CreateWindow(
WC_COMBOBOX,
TEXT(""),
WS_CHILD | WS_VISIBLE | CBS_DROPDOWNLIST,
10, 20, 70, 17,
hWnd, (HMENU)IDB_COMBOX, hInstance, NULL);
...
case WM_COMMAND:
{
int wmId = LOWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDB_COMBOX:
{
switch (HIWORD(wParam))
{
case CBN_DROPDOWN:
{
CHOOSECOLOR cc; // common dialog box structure
static COLORREF acrCustClr[16]; // array of custom colors
static DWORD rgbCurrent; // initial color selection
// Initialize CHOOSECOLOR
ZeroMemory(&cc, sizeof(cc));
cc.lStructSize = sizeof(cc);
cc.hwndOwner = hWnd;
cc.lpCustColors = (LPDWORD)acrCustClr;
cc.rgbResult = rgbCurrent;
cc.Flags = CC_FULLOPEN | CC_RGBINIT;
ChooseColor(&cc);
}
break;
...
Debug:

Can I make a property sheet without resource script?

I'd like to add controls to a property sheet without resource script, rather using pure code.
The reason for this I'd like to create a property sheet(mimicking C#'s property grid), calling C routines/WINAPI, from another language, binary-compatible to C; but I'd like to define everything with code, without need of a resource script. Is this possible or the way to go is write my own property-sheet-like, with underlying CreateWindow*() calls? (different approaches to do this are welcome, I'm new to WINAPI) which I suppose property sheet use behind the scenes
Found the solution! I found this post from Raymond Chen where he shows how do that.
the main code goes like this:
BOOL FakeMessageBox(HWND hwnd, LPCWSTR pszMessage, LPCWSTR pszTitle)
{
BOOL fSuccess = FALSE;
HDC hdc = GetDC(NULL);
if (hdc) {
NONCLIENTMETRICSW ncm = { sizeof(ncm) };
if (SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, 0, &ncm, 0)) {
DialogTemplate tmp;
// Write out the extended dialog template header
tmp.Write<WORD>(1); // dialog version
tmp.Write<WORD>(0xFFFF); // extended dialog template
tmp.Write<DWORD>(0); // help ID
tmp.Write<DWORD>(0); // extended style
tmp.Write<DWORD>(WS_CAPTION | WS_SYSMENU | DS_SETFONT | DS_MODALFRAME);
tmp.Write<WORD>(2); // number of controls
tmp.Write<WORD>(32); // X
tmp.Write<WORD>(32); // Y
tmp.Write<WORD>(200); // width
tmp.Write<WORD>(80); // height
tmp.WriteString(L""); // no menu
tmp.WriteString(L""); // default dialog class
tmp.WriteString(pszTitle); // title
// Next comes the font description.
// See text for discussion of fancy formula.
if (ncm.lfMessageFont.lfHeight < 0) {
ncm.lfMessageFont.lfHeight = -MulDiv(ncm.lfMessageFont.lfHeight,
72, GetDeviceCaps(hdc, LOGPIXELSY));
}
tmp.Write<WORD>((WORD)ncm.lfMessageFont.lfHeight); // point
tmp.Write<WORD>((WORD)ncm.lfMessageFont.lfWeight); // weight
tmp.Write<BYTE>(ncm.lfMessageFont.lfItalic); // Italic
tmp.Write<BYTE>(ncm.lfMessageFont.lfCharSet); // CharSet
tmp.WriteString(ncm.lfMessageFont.lfFaceName);
// Then come the two controls. First is the static text.
tmp.AlignToDword();
tmp.Write<DWORD>(0); // help id
tmp.Write<DWORD>(0); // window extended style
tmp.Write<DWORD>(WS_CHILD | WS_VISIBLE); // style
tmp.Write<WORD>(7); // x
tmp.Write<WORD>(7); // y
tmp.Write<WORD>(200-14); // width
tmp.Write<WORD>(80-7-14-7); // height
tmp.Write<DWORD>(-1); // control ID
tmp.Write<DWORD>(0x0082FFFF); // static
tmp.WriteString(pszMessage); // text
tmp.Write<WORD>(0); // no extra data
// Second control is the OK button.
tmp.AlignToDword();
tmp.Write<DWORD>(0); // help id
tmp.Write<DWORD>(0); // window extended style
tmp.Write<DWORD>(WS_CHILD | WS_VISIBLE |
WS_GROUP | WS_TABSTOP | BS_DEFPUSHBUTTON); // style
tmp.Write<WORD>(75); // x
tmp.Write<WORD>(80-7-14); // y
tmp.Write<WORD>(50); // width
tmp.Write<WORD>(14); // height
tmp.Write<DWORD>(IDCANCEL); // control ID
tmp.Write<DWORD>(0x0080FFFF); // static
tmp.WriteString(L"OK"); // text
tmp.Write<WORD>(0); // no extra data
// Template is ready - go display it.
fSuccess = DialogBoxIndirect(g_hinst, tmp.Template(),
hwnd, DlgProc) >= 0;
}
ReleaseDC(NULL, hdc); // fixed 11 May
}
return fSuccess;
}

CListCtrl set font style to bold

I want to change font of any cell of CListCtrl control to bold. Can any one tell how to do it for CList Ctrl.
I have already done this for a CTreeCtrl, like this
pTC->SetItemState(hItemCur, TVIS_BOLD, TVIS_BOLD);
do we have something similar for CListCtrl?
Thanks in advance.
If you can use CMFCListCtrl (VS2008 SP1 and up), you can derive a class from it and override OnGetCellFont. From there you return your bold font (you can create your own or return AFX_GLOBAL_DATA::fontBold):
HFONT CMyListCtrl::OnGetCellFont( int nRow, int nColumn, DWORD dwData /*= 0*/ )
{
if (UseBoldFont(/* params */))
{
return GetGlobalData()->fontBold;
}
return NULL;
}
If you have to stick to plain old CListCtrl, the easiest way would be to use Custom Draw, where you can tweak the drawing process to your own needs. Don't confuse it with Owner Draw, where you have to do all the drawing yourself.
Here's an article explaining the basics of using Custom Draw with CListCtrl.
Add
ON_NOTIFY_REFLECT(NM_CUSTOMDRAW, OnCustomdraw)
to your message map.
Now you can simply modify items as you wish in this function. In here you can change the align, font, background-color, text-color, [...], and you can set items to bold -> example. The best way IMO, is to either store a pointer to a struct, class or simply a flag in the LPARAM of the item(s) in the control. This function works for both CListCtrl and CTreeCtrl.
Here is an example with flags:
enum ColorFlags
{
F_COLOR_BLACK = 0x1,
F_COLOR_WHITE = 0x2
//and more...
};
enum CustomColors
{
COLOR_BLACK = RGB(0, 0, 0),
COLOR_WHITE = RGB(255, 255, 255)
};
afx_msg
void CMyListCtrl::OnCustomdraw(NMHDR *pNMHDR, LRESULT *pResult)
{
NMLVCUSTOMDRAW *pDraw = reinterpret_cast<NMLVCUSTOMDRAW*>(pNMHDR);
switch (pDraw->nmcd.dwDrawStage)
{
case CDDS_PREPAINT:
*pResult = CDRF_NOTIFYITEMDRAW; //Do not forget this...
break;
case CDDS_ITEMPREPAINT:
{
switch (pDraw->nmcd.lItemlParam) //Extract color from flags
{
case F_COLOR_BLACK:
{
pDraw->clrText = COLOR_BLACK;
} break;
case F_COLOR_WHITE:
{
pDraw->clrText = COLOR_WHITE;
} break;
default:
break;
} //switch
} break;
} //switch
}

ttf Text wont show up in SDL

No matter what i try i cant get my text to load into a texture in SDL 2.0 using SDL_ttf.
Here is my textToTexture code
void sdlapp::textToTexture(string text, SDL_Color textColor,SDL_Texture* textTexture)
{
//free prevoius texture in textTexture if texture exists
if (textTexture != nullptr || NULL)
{
SDL_DestroyTexture(textTexture);
}
SDL_Surface* textSurface = TTF_RenderText_Solid(m_font, text.c_str(), textColor);
textTexture = SDL_CreateTextureFromSurface(m_renderer, textSurface);
//free surface
SDL_FreeSurface(textSurface);
}
And then here is me loading the texture and text
bool sdlapp::loadMedia()
{
bool success = true;
//load media here
//load font
m_font = TTF_OpenFont("Fonts/MotorwerkOblique.ttf", 28);
//load text
SDL_Color textColor = { 0x255, 0x255, 0x235 };
textToTexture("im a texture thing", textColor, m_font_texture);
return success;
}
And then this is the code i am using to render it
void sdlapp::render()
{
//clear the screen
SDL_RenderClear(m_renderer);
//do render stuff here
SDL_Rect rect= { 32, 64, 128, 32 };
SDL_RenderCopy(m_renderer, m_font_texture, NULL, NULL);
//update the screen to the current render
SDL_RenderPresent(m_renderer);
}
Does anyone know what i am doing wrong?
Thanks in Advance, JustinWeq.
textToTexture renders the text with SDL_ttf, the resulting SDL_Texture address is then assigned to a variable called textTexture. Problem is, textTexture is a local variable pointing to the same address as m_font_texture. They're not the same variable, they're different variables poiting to the same place, thus you're not changing any callee variables.
For clarification on pointers, I'd recommend seeing question 4.8 of the C-FAQ
I'd make textToTexture return the new texture address, and don't bother freeing resources that are not managed by it (m_font_texture belongs to sdlapp, it should be managed by it).

Custom titles for Windows 7 Jump List Recent items

Quickie question: I'm toying with some of the new taskbar APIs in Windows 7 and have gotten Recent Items on my Apps jumplist to show up, but I would like to display them under a different title than the filename (most files my app will be opening will have very similar names). I don't see any way to do that with the IShellItem interface, though. Would I have to use custom categories and IShellLinks to accomplish this?
For reference, my current code looks like this:
void AddRecentApp(const wchar_t* path, const wchar_t* title /* Can I even use this? */ ) {
HRESULT hres;
hres = CoInitialize(NULL);
IShellItem* recentItem;
hres = SHCreateItemFromParsingName(path, NULL, IID_PPV_ARGS(&recentItem));
if(SUCCEEDED(hres)) {
SHARDAPPIDINFO recentItemInfo;
recentItemInfo.pszAppID = MY_APP_USER_MODEL_ID;
recentItemInfo.psi = recentItem;
SHAddToRecentDocs(SHARD_APPIDINFO, &recentItemInfo);
recentItem->Release();
}
}
Figured it out. IShellItems are just a representation of a file, so they only will provide that file's information (no custom title, etc.) An IShellLink is essentially a shortcut, and is much more flexible in terms of display and actions taken when launched, so are more appropriate in this situation. Here's my new code:
void AddRecentApp(const wchar_t* path, const wchar_t* title) {
HRESULT hres;
hres = CoInitialize(NULL);
// Shell links give us more control over how the item is displayed and run
IShellLink* shell_link;
hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&shell_link));
if(SUCCEEDED(hres)) {
// Set up the basic link properties
shell_link->SetPath(path);
shell_link->SetArguments(L"--some-command-line-here"); // command line to execute when item is opened here!
shell_link->SetDescription(title); // This is what shows in the tooltip
shell_link->SetIconLocation(L"/path/to/desired/icon", 0); // can be an icon file or binary
// Open up the links property store and change the title
IPropertyStore* prop_store;
hres = shell_link->QueryInterface(IID_PPV_ARGS(&prop_store));
if(SUCCEEDED(hres)) {
PROPVARIANT pv;
InitPropVariantFromString(title, &pv);
// Set the title property.
prop_store->SetValue(PKEY_Title, pv); // THIS is where the displayed title is actually set
PropVariantClear(&pv);
// Save the changes we made to the property store
prop_store->Commit();
prop_store->Release();
}
// The link must persist in the file system somewhere, save it here.
IPersistFile* persist_file;
hres = shell_link->QueryInterface(IID_PPV_ARGS(&persist_file));
if(SUCCEEDED(hres)) {
hres = persist_file->Save(L"/link/save/directory", TRUE);
persist_file->Release();
}
// Add the link to the recent documents list
SHARDAPPIDINFOLINK app_id_info_link;
app_id_info_link.pszAppID = MY_APP_USER_MODEL_ID;
app_id_info_link.psl = shell_link;
SHAddToRecentDocs(SHARD_APPIDINFOLINK, &app_id_info_link);
shell_link->Release();
}
}

Resources