Roboto font issues in MFC based application - mfc

I have old MFC based application. Recently we moved from Trébuchent to Roboto font. From that time onwards on some machines we are finding weird characters in the application.
I am using the CreateFontIndirect function to create the font. The IDE that I am using is Visual studio 2008.
This issue is not affecting the entire application. It is only affecting a few places.
I have observed a pattern in those junk characters. Is appears that it is adding 2 to every ASCII value. For example: if I want to display ABCD it is showing CDEF.
Please help me out in finding this. Thanks in Advance.
Here is my code sample :
void Render (CDC *pDC)
{
CString strText;
CFont *pFont = GetLocalFontStore()->LoadFont(_T("Roboto"), (int)(26 *fSizeFactor) , FW_EXTRABOLD, false, false);
COLORREF txtColor =RGB(255,0,0);
CRect rcTobeDrawn = CRect( (CPoint(177,172)), (CPoint(636,215)));
strText = _T(“This is my string”);
CFont *pOldfont = pDC->SelectObject(pFont);
COLORREF oldTxtColor = pDC->SetTextColor(txtColor);
int oldBkMode = pDC->SetBkMode(TRANSPARENT);
pDC->DrawText(strText, rcTobeDrawn, DT_CENTER|DT_NOCLIP|DT_VCENTER);
pDC->SelectObject(pOldfont);
pDC->SetBkMode(oldBkMode);
pDC->SetTextColor(oldTxtColor);
}
CFont* CLocalFontStore::LoadFont(CString strFaceName,int height,int weight/*=FW_REGULAR*/,
bool bUnderLine/*=false*/,bool bItalics/* = false*/, BYTE charSet /*= DEFAULT_CHARSET*/,bool bHeightFlag/* = false*/)
{
if(m_nCharSet == -1)
m_nCharSet = GetCharset();
LOGFONT lf;
CFont* pFont = NULL;
CString strFontText;
memset(&lf, 0, sizeof(LOGFONT));
swprintf_s(lf.lfFaceName,GetCommonLobby()->GetSupportedFontName(strFaceName));
double d72DPIHeight = (STANDARD_DPI * (float)height) / 72.0;
lf.lfHeight = (long) (d72DPIHeight < 0.0 ? ceil(d72DPIHeight - 0.5) : floor(d72DPIHeight + 0.5));
lf.lfWeight = weight >0 ? weight : FW_DONTCARE;
lf.lfUnderline = bUnderLine ? true :false;
lf.lfItalic = bItalics;
lf.lfCharSet = m_nCharSet;
strFontText.Format(_T("%s~%d~%d~%d~%d~%d"), lf.lfFaceName, lf.lfHeight, lf.lfWeight, lf.lfUnderline, lf.lfItalic, m_nCharSet);
if(m_FontMap.size() != 0)
pFont = GetFont(strFontText);
if(pFont == NULL)
{
HFONT hFont = GetIFontStore()->LoadFont(strFaceName, height, weight, bUnderLine, bItalics, charSet,bHeightFlag);
if(hFont != NULL)
{
pFont = new CFont;
pFont->Attach(hFont);
m_FontMap[strFontText] = pFont;
}
}
return pFont;
}
CFont* CLocalFontStore::LoadFont(CString strFaceName,int height,int weight/*=FW_REGULAR*/,
bool bUnderLine/*=false*/,bool bItalics/* = false*/, BYTE charSet /*= DEFAULT_CHARSET*/,bool bHeightFlag/* = false*/)
{
if(m_nCharSet == -1)
m_nCharSet = GetCharset();
LOGFONT lf;
CFont* pFont = NULL;
CString strFontText;
memset(&lf, 0, sizeof(LOGFONT));
swprintf_s(lf.lfFaceName,GetCommonLobby()->GetSupportedFontName(strFaceName));
double d72DPIHeight = (STANDARD_DPI * (float)height) / 72.0;
lf.lfHeight = (long) (d72DPIHeight < 0.0 ? ceil(d72DPIHeight - 0.5) : floor(d72DPIHeight + 0.5));
lf.lfWeight = weight >0 ? weight : FW_DONTCARE;
lf.lfUnderline = bUnderLine ? true :false;
lf.lfItalic = bItalics;
lf.lfCharSet = m_nCharSet;
strFontText.Format(_T("%s~%d~%d~%d~%d~%d"), lf.lfFaceName, lf.lfHeight, lf.lfWeight, lf.lfUnderline, lf.lfItalic, m_nCharSet);
if(m_FontMap.size() != 0)
pFont = GetFont(strFontText);
if(pFont == NULL)
{
HFONT hFont = GetIFontStore()->LoadFont(strFaceName, height, weight, bUnderLine, bItalics, charSet,bHeightFlag);
if(hFont != NULL)
{
pFont = new CFont;
pFont->Attach(hFont);
m_FontMap[strFontText] = pFont;
}
}
return pFont;
}
HFONT CFontStore::LoadPointFont(CString strFaceName,int height,int weight/*=FW_REGULAR*/,
bool bUnderLine/*=false*/,bool bItalics/* = false*/, BYTE charSet /*= DEFAULT_CHARSET*/,bool bHeightFlag/* = false*/, bool bIsEnglish/* = false*/)
{
LOGFONT lf;
CString strFontText;
memset(&lf, 0, sizeof(LOGFONT));
if (!_tcsicmp(strFaceName, _T("Small Fonts")))
{
_stprintf(lf.lfFaceName, strFaceName);
}
else
{
_stprintf(lf.lfFaceName,GetCommonLobby()->GetSupportedFontName(strFaceName));
}
double d72DPIHeight = (STANDARD_DPI * (float)height) / 72.0;
lf.lfHeight = (long) (d72DPIHeight < 0.0 ? ceil(d72DPIHeight - 0.5) : floor(d72DPIHeight + 0.5));
lf.lfWeight = weight >0 ? weight : FW_DONTCARE;
lf.lfUnderline = bUnderLine ? true :false;
lf.lfItalic = bItalics;
lf.lfCharSet = GetCharset();
if(!bIsEnglish)
{
ChangeFont(lf, 10);
}
strFontText.Format(_T("%s~%d~%d~%d~%d~%d"),lf.lfFaceName,lf.lfHeight,lf.lfWeight,lf.lfUnderline,lf.lfItalic, GetCharset());
HFONT hFont = NULL;
if(m_FontMap.size() != 0)
{
hFont = GetFont(strFontText);
}
if(hFont == NULL)
{
lf.lfHeight = -lf.lfHeight;
HFONT hf = CreateFontIndirect(&lf);
if(NULL != hf)
{
hFont = hf;
m_FontMap[strFontText] = hFont;
}
}
return hFont;
}

Related

DrawText Refresh Problem - Text Disappears

I'm using Objective Grid and wanted to have a grid cell control that can show an icon and text. So I took RogueWave's example (https://rwkbp.makekb.com/entry/466/) and modified it as below.
Initially the text renders correctly, but if I do anything in the grid that refreshes the relevant cell, the text disappears. If I update the whole grid, or even refresh the cell by dragging it off screen and back again, the text reappears - until it disappears again. Seems like a paint or InvalidateRect problem - but I can't figure out how to fix it. Any ideas?
Thanks!
//------------------------------------------------------------------------------
void CGXIconControl::Draw(CDC* pDC, CRect rect, ROWCOL nRow, ROWCOL nCol, const CGXStyle& style, const CGXStyle* pStandardStyle)
//------------------------------------------------------------------------------
{
BOOL b;
ASSERT(pDC != NULL && pDC->IsKindOf(RUNTIME_CLASS(CDC)));
// ASSERTION-> Invalid Device Context ->END
ASSERT(nRow <= Grid()->GetRowCount() && nCol <= Grid()->GetColCount());
// ASSERTION-> Cell coordinates out of range ->END
ASSERT_VALID(pDC);
DrawBackground(pDC, rect, style);
pDC->SetBkMode(TRANSPARENT);
if (rect.right <= rect.left || rect.Width() <= 1 || rect.Height() <= 1)
{
return;
}
CString str = style.GetIncludeValue() ? style.GetValue() : _T("");
CString sTxtBefore = _T("");
CString sTxtAfter = _T("");
int nHAlign = style.GetHorizontalAlignment();
int nVAlign = style.GetVerticalAlignment();
// Save these value to restore them when done drawing
COLORREF crOldTextColor = pDC->GetTextColor();
COLORREF crOldBkColor = pDC->GetBkColor();
if (!style.GetEnabled())
{
pDC->SetTextColor(::GetSysColor(COLOR_GRAYTEXT));
}
CBrush Brush;
Brush.CreateSolidBrush(style.GetEnabled() ? ::GetSysColor(COLOR_WINDOWTEXT) : ::GetSysColor(COLOR_GRAYTEXT));
LOGBRUSH lBrush = { 0 };
Brush.GetLogBrush(&lBrush);
CBrush* pOldBrush = (CBrush*)pDC->SelectStockObject(NULL_BRUSH);
CPen linePen;
linePen.CreatePen(PS_SOLID, 1, &lBrush);
CPen* pOldPen = pDC->SelectObject(&linePen);
// Set font bold if necessary
CFont* pCurfont = pDC->GetCurrentFont();
LOGFONT lf;
CFont font;
if (pCurfont)
{
pCurfont->GetLogFont(&lf);
}
if (style.GetFont().GetBold())
{
lf.lfWeight = FW_BOLD;
}
font.CreateFontIndirect(&lf);
CFont* pOldFont = pDC->SelectObject(&font);
int nIcoStart = str.Find(_T("#ICO"));
if (nIcoStart == -1)
{
// We didn't find an icon indicator, so just draw the text
pDC->DrawText(str, rect, DT_SINGLELINE|nHAlign|nVAlign);
}
else
{
sTxtBefore = str.Left(nIcoStart);
CSize szBefore = pDC->GetTextExtent(sTxtBefore);
int nIconEnd = str.Find(_T(")"), nIcoStart);
CString strIDResource = str.Mid(nIcoStart + 5, nIconEnd - (nIcoStart + 5));
UINT nIDResource = _ttoi(strIDResource);
// Load the highest bit-depth available
HICON hIcon = NULL;
hIcon = LoadResourceIcon(nIDResource, m_nIconSize, m_nIconSize, 32);
hIcon == NULL ? LoadResourceIcon(nIDResource, m_nIconSize, m_nIconSize, 24) : NULL;
hIcon == NULL ? LoadResourceIcon(nIDResource, m_nIconSize, m_nIconSize, 16) : NULL;
hIcon == NULL ? LoadResourceIcon(nIDResource, m_nIconSize, m_nIconSize, 8) : NULL;
sTxtAfter = str.Right(str.GetLength() - nIconEnd - 1);
CSize szAfter = pDC->GetTextExtent(sTxtAfter);
CRect rectCell = CGXControl::GetCellRect(nRow, nCol, rect, &style);
CRect rectBefore = rectCell;
CRect rectAfter = rectCell;
int nTotalWidth = szBefore.cx + m_nIconSize + szAfter.cx;
// Calculate positions
int nTop, nLeft;
switch (nHAlign)
{
case DT_LEFT:
{
rectBefore.right = rectBefore.left + szBefore.cx;
nLeft = rectBefore.right;
rectAfter.left = nLeft + m_nIconSize;
rectAfter.right = rectAfter.left + szAfter.cx;
} break;
case DT_CENTER:
{
rectBefore.left = (rectCell.right - rectCell.Width() / 2) - nTotalWidth / 2;
rectBefore.right = rectBefore.left + szBefore.cx;
nLeft = rectBefore.right;
rectAfter.left = nLeft + m_nIconSize;
rectAfter.right = rectAfter.left + szAfter.cx;
} break;
case DT_RIGHT:
{
// Work from the right
rectAfter.right = rectCell.right;
rectAfter.left = rectAfter.right - szAfter.cx;
nLeft = rectAfter.left - m_nIconSize;
rectBefore.right = nLeft;
rectBefore.left = rectBefore.right - szBefore.cx;
} break;
}
switch (nVAlign)
{
case DT_TOP:
nTop = rectCell.top;
break;
case DT_VCENTER:
nTop = rectCell.top + (rectCell.Height() / 2 - m_nIconSize / 2);
break;
case DT_BOTTOM:
nTop = rectCell.bottom - m_nIconSize;
break;
}
if (!sTxtBefore.IsEmpty())
{
pDC->DrawText(sTxtBefore, rectBefore, DT_SINGLELINE|nHAlign|nVAlign);
}
b = ::DrawIconEx(pDC->m_hDC, nLeft, nTop, hIcon, m_nIconSize, m_nIconSize, 0, NULL, DI_NORMAL);
b = ::DestroyIcon(hIcon);
if (!sTxtAfter.IsEmpty())
{
pDC->DrawText(sTxtAfter, rectAfter, DT_SINGLELINE|nHAlign|nVAlign);
}
}
// Reset original values
pDC->SetTextColor(crOldTextColor);
pDC->SetBkColor(crOldBkColor);
pDC->SelectObject(pOldBrush);
pDC->SelectObject(pOldPen);
pDC->SelectObject(pOldFont);
// Child Controls: spin-buttons, hotspot, combobox btn, ...
CGXControl::Draw(pDC, rect, nRow, nCol, style, pStandardStyle);
}

Does CMFCStatusBar::SetPaneIcon supports alpha icon?

My App setup icons for panes in status bar (class CMFCStatusBar). There is only one method for this task - CMFCStatusBar::SetPaneIcon(). But if icon have alpha channel this method loads wrong image (on black background).
I looked into the source code and I saw that CMFCStatusBar uses internal HIMAGELISTs for every panes. All this HIMAGELIST creates with flag ILC_MASK | ILC_COLORDDB, not ILC_COLOR32 or ILC_COLOR24.
This is a bug!
So, is there a way to use the icons with alpha channel in CMFCStatusBar panes?
Example:
HICON hIcon = ::LoadImage(hModule, MAKEINTRESOURCE(nIconID), IMAGE_ICON, 16, 16, LR_DEFAULTCOLOR);
m_StatusBar.SetPaneIcon(m_StatusBar.CommandToIndex(ID_INDICATOR_1), hIcon);
Microsoft developed the CMFC classes (Feature Pack) from the BCG toolkit. If you compare the CMFCStatusBar::SetPaneIcon() method with the BCG method from the same class, you’ll notice a few subtle differences.
BCG defines its method with a flag for alpha blend. The method looks like:
void CBCGPStatusBar::SetPaneIcon (int nIndex, HBITMAP hBmp,
COLORREF clrTransparent, BOOL bUpdate, BOOL bAlphaBlend/* = FALSE*/)
The CMFC equivalent removes the ‘bAlphaBlend’ flag.
Comparing the method code, you’ll see that BCG uses the following code that has been removed from the CMFC version:
DWORD dwFlags = ILC_MASK | ILC_COLORDDB;
if (bAlphaBlend)
{
dwFlags = ILC_COLOR32;
}
pSBP->hImage = ::ImageList_Create (pSBP->cxIcon, pSBP->cyIcon, dwFlags, 1, 0);
I’m not sure why the CMFC version differs so much (Microsoft may have a valid reason), but, I’ve included the BCG version below. I would study the BCG version and possibly create your own ‘SetPaneIcon’ method from that code (at your own risk).
void CBCGPStatusBar::SetPaneIcon (int nIndex, HBITMAP hBmp,
COLORREF clrTransparent, BOOL bUpdate, BOOL bAlphaBlend/* = FALSE*/)
{
ASSERT_VALID(this);
CBCGStatusBarPaneInfo* pSBP = _GetPanePtr(nIndex);
if (pSBP == NULL)
{
ASSERT (FALSE);
return;
}
// Disable animation (if exist):
SetPaneAnimation (nIndex, NULL, 0, FALSE);
if (hBmp == NULL)
{
if (pSBP->hImage != NULL)
{
::ImageList_Destroy (pSBP->hImage);
}
pSBP->hImage = NULL;
if (bUpdate)
{
InvalidatePaneContent (nIndex);
}
return;
}
BITMAP bitmap;
::GetObject (hBmp, sizeof (BITMAP), &bitmap);
if (pSBP->hImage == NULL)
{
pSBP->cxIcon = bitmap.bmWidth;
pSBP->cyIcon = bitmap.bmHeight;
DWORD dwFlags = ILC_MASK | ILC_COLORDDB;
if (bAlphaBlend)
{
dwFlags = ILC_COLOR32;
}
pSBP->hImage = ::ImageList_Create (pSBP->cxIcon, pSBP->cyIcon, dwFlags, 1, 0);
RecalcLayout ();
}
else
{
ASSERT (pSBP->cxIcon == bitmap.bmWidth);
ASSERT (pSBP->cyIcon == bitmap.bmHeight);
::ImageList_Remove (pSBP->hImage, 0);
}
//---------------------------------------------------------
// Because ImageList_AddMasked changes the original bitmap,
// we need to create a copy:
//---------------------------------------------------------
HBITMAP hbmpCopy = (HBITMAP) ::CopyImage (hBmp, IMAGE_BITMAP, 0, 0, 0);
if (bAlphaBlend)
{
::ImageList_Add (pSBP->hImage, hbmpCopy, NULL);
}
else
{
::ImageList_AddMasked (pSBP->hImage, hbmpCopy, clrTransparent);
}
::DeleteObject (hbmpCopy);
if (bUpdate)
{
InvalidatePaneContent (nIndex);
}
}
My solution, based in rrirower code.
CMFCStatusBarPaneInfo* CMyStatusBar::GetPane(int nIndex) const {
if (nIndex == 255 && m_nCount < 255) {
// Special case for the simple pane
for (int i = 0; i < m_nCount; i++)
{
CMFCStatusBarPaneInfo* pSBP = GetPane(i);
ENSURE(pSBP != NULL);
if (pSBP->nStyle & SBPS_STRETCH) {
return pSBP;
}
}
}
if (nIndex < 0 || nIndex >= m_nCount) {
return NULL;
}
if (m_pData == NULL) {
ASSERT(FALSE);
return NULL;
}
return((CMFCStatusBarPaneInfo*)m_pData) + nIndex;
}
void CMyStatusBar::SetPaneIcon(int nIndex, HICON hIcon, BOOL bUpdate /*= TRUE*/)
{
ASSERT_VALID(this);
CMFCStatusBarPaneInfo* pSBP = GetPane(nIndex);
if (pSBP == NULL)
{
ASSERT(FALSE);
return;
}
// Disable animation(if exist):
SetPaneAnimation(nIndex, NULL, 0, FALSE);
if (hIcon == NULL)
{
if (pSBP->hImage != NULL)
{
::ImageList_Destroy(pSBP->hImage);
}
pSBP->hImage = NULL;
if (bUpdate)
{
InvalidatePaneContent(nIndex);
}
return;
}
ICONINFO iconInfo;
::GetIconInfo(hIcon, &iconInfo);
BITMAP bitmap;
::GetObject(iconInfo.hbmColor, sizeof(BITMAP), &bitmap);
::DeleteObject(iconInfo.hbmColor);
::DeleteObject(iconInfo.hbmMask);
if (pSBP->hImage == NULL)
{
pSBP->cxIcon = bitmap.bmWidth;
pSBP->cyIcon = bitmap.bmHeight;
pSBP->hImage = ::ImageList_Create(pSBP->cxIcon, pSBP->cyIcon, ILC_COLOR32 | ILC_MASK, 1, 0);
::ImageList_AddIcon(pSBP->hImage, hIcon);
RecalcLayout();
}
else
{
ASSERT(pSBP->cxIcon == bitmap.bmWidth);
ASSERT(pSBP->cyIcon == bitmap.bmHeight);
::ImageList_ReplaceIcon(pSBP->hImage, 0, hIcon);
}
if (bUpdate)
{
InvalidatePaneContent(nIndex);
}
}

How to render CRichEditCtrl on CDC with transparent backgorund ? (MFC)

I need help with rendering CRichEditCtrl content with transparent background on graphical context which is displayed on screen and printed as well.
Now I have following code, which is working good except transparency issues:
CRichEditCtrl ctrl; // my CRichEditCtrl
CDC *dc; // - my graphical context
dc->SetBkMode(TRANSPARENT);
dc->DPtoHIMETRIC(&targetSize);
CRect cHiMetricRect( 0, 0, origSize.cx*factor,origSize.cy*factor);
CRect cTwipsRect( 0, 0, (TWIPS_INCH * targetSize.cx + HIMETRIC_INCH / 2) / HIMETRIC_INCH, (TWIPS_INCH * targetSize.cy + HIMETRIC_INCH / 2) / HIMETRIC_INCH);
CMetaFileDC metaFile;
metaFile.CreateEnhanced( dc, NULL, cHiMetricRect, NULL );
metaFile.SetBkMode(TRANSPARENT);
metaFile.SetAttribDC( dc->m_hDC );
FORMATRANGE stFR;
stFR.hdcTarget = stFR.hdc = metaFile.m_hDC;
stFR.rcPage = stFR.rc = cTwipsRect;
stFR.chrg.cpMin = 0;
stFR.chrg.cpMax = -1;
ctrl.FormatRange( &stFR, TRUE);
ctrl.FormatRange( NULL, TRUE);
HENHMETAFILE hMetaFile = metaFile.CloseEnhanced();
dc->PlayMetaFile(hMetaFile,&cr);
DeleteEnhMetaFile(hMetaFile);
I need to render this text with transparency because there are already things drawn on my DC.
I tried to search web for any help about metafiles and transparency but found nothing adequate. I will be thankful for any kind of help.
I'm not very sure about MetaFiles, but I've done something similar with EMFs with straight WinAPI which does work -- call EnumEnhMetaFile instead of PlayMetaFile, like:
BOOL bFirstTime = TRUE;
EnumEnhMetaFile(hDC, m_hEmf, (ENHMFENUMPROC)EmfEnumProc_Play_TranspBackground, &bFirstTime, &rc);
where the EnumProc is defined as
int CALLBACK EmfEnumProc_Play_TranspBackground(HDC hDC, LPHANDLETABLE lpHTable, LPENHMETARECORD lpEMFR, int nObj, LPARAM lpData)
{ BOOL bOK;
if (lpEMFR->iType == EMR_SETBKMODE)
{ EMRSETBKMODE* lpEMRBkMode = (EMRSETBKMODE*) lpEMFR;
if (lpEMRBkMode->iMode == OPAQUE)
{ EMRSETBKMODE EmrBkMode;
EmrBkMode.emr.iType = EMR_SETBKMODE;
EmrBkMode.emr.nSize = (sizeof(EmrBkMode) % 4 == 0 ? sizeof(EmrBkMode) : (((sizeof(EmrBkMode) / 4) + 1) * 4));
EmrBkMode.iMode = TRANSPARENT;
bOK = PlayEnhMetaFileRecord(hDC, lpHTable, (LPENHMETARECORD)&EmrBkMode, (UINT)nObj);
return bOK;
}
}
bOK = PlayEnhMetaFileRecord(hDC, lpHTable, lpEMFR, (UINT)nObj);
if (lpEMFR->iType == EMR_HEADER)
{ BOOL* pbFirstTime = (BOOL*)lpData;
if (*pbFirstTime)
{ EMRSETBKMODE EmrBkMode;
EmrBkMode.emr.iType = EMR_SETBKMODE;
EmrBkMode.emr.nSize = (sizeof(EmrBkMode) % 4 == 0 ? sizeof(EmrBkMode) : (((sizeof(EmrBkMode) / 4) + 1) * 4));
EmrBkMode.iMode = TRANSPARENT;
PlayEnhMetaFileRecord(hDC, lpHTable, (LPENHMETARECORD)&EmrBkMode, (UINT)nObj);
*pbFirstTime = FALSE;
}
}
return bOK;
}
I used EnumEnhMetaFile function:
EnumEnhMetaFile(dc->m_hDC, hMetaFile, myMetafileProc, NULL, rect );
Then I used callback procedure that retrives each record of metafile:
int metafileProc( HDC hDC, HANDLETABLE *lpHTable, const ENHMETARECORD *lpEMFR, int nObj, LPARAM lpData) {
if ( lpEMFR->iType == EMR_EXTTEXTOUTW ) {
COLORREF_STRUCT *c = (COLORREF_STRUCT *)&(lastBgColor);
EMR_EXTTEXTOUTW_STRUCT *s = (EMR_EXTTEXTOUTW_STRUCT *)lpEMFR;
s->textStruct.options = 0x00;
if ( bgColorFlag ) {
bgColorFlag = false;
renderRect( hDC, s->textStruct.rect, c );
}
PlayEnhMetaFileRecord( hDC, lpHTable, lpEMFR, nObj );
} else if ( lpEMFR->iType == EMR_SETBKCOLOR ) {
BYTE *ptr = (BYTE*)lpEMFR;
COLORREF temp = *((COLORREF*)(ptr+8));
if ( temp != 0xFFFFFF ) {
lastBgColor = temp;
bgColorFlag = true;
}
}
return 1;
}
where renderRect( hDC, s->textStruct.rect, c ) is function which draws transparent background in c color. I have to zero options flag for text becouse there was different behaviour in Windows XP and Windows 7 and 8 - after that everything works ok. Thanks for help. Best regards.

GetCharWidth32 and Point Size issue

Currently I have the following function to attempt to get the character widths for specific characters in a string. It returns the same values for a font regardless of point size. I know this is in logical units. What multiplier do I need to take into account to get it out of logical units and into pixels?
Thanks!
double Utils::GetFormattedCharWidth(char theChar, Gdiplus::Font* pFont, RectF& rectArc, Graphics& graphics)
{
double textWidth = 0;
HDC hdc = NULL;
DWORD outLine = 0; //= GetLastError();
hdc = graphics.GetHDC();
outLine = GetLastError();
LPINT lpBuffer = new int;
/*ABC *abc = new ABC[256];
for(int iCon = 0; iCon < 256; iCon++)
{
(&abc[iCon])->abcA = 0;
(&abc[iCon])->abcB = 0;
(&abc[iCon])->abcC = 0;
}*/
DWORD dSize = 0;
SetMapMode(hdc,MM_TEXT);
HGDIOBJ hOldFont = SelectObject(hdc, pFont);
outLine = GetLastError();
//outLine = GetLastError();
//DWORD d = GetGlyphOutline(hdc, theChar, GGO_METRICS, lpg, dSize, lpvBuffer, LPM);
DWORD d = GetCharWidth32(hdc, theChar, theChar, lpBuffer);
//lpABC = (LPABC)GlobalAllocPtr( GHND, 256*sizeof(ABC) );
//d = GetCharABCWidthsA(hdc, 0, 255, abc);
outLine = GetLastError();
//DWORD d = GetCharABCWidthsA(hdc, theChar, theChar, abc);
int iExtraSpacing = GetTextCharacterExtra(hdc);
outLine = GetLastError();
graphics.ReleaseHDC(hdc);
textWidth = (double)(*lpBuffer) ;
//delete abc;
delete lpBuffer;
graphics.ReleaseHDC(hdc);
return textWidth + iExtraSpacing;
}
New code for Mark using Measure String.
double Utils::GetFormattedCharWidth(char theChar, Gdiplus::Font* pFont, RectF& rectArc, Graphics& graphics)
{
double textWidth = 0;
char charBuff[4];
memset(&charBuff, 0, 4);
charBuff[0] = theChar;
RectF rectTemp;
WCHAR* pChar = (WCHAR*)charBuff;
graphics.MeasureString(pChar, 1, pFont, rectArc, &rectTemp);
textWidth = rectTemp.Width;
return textWidth;
}
You're trying to select a GDI+ Font into a GDI DC. I'm pretty sure that's not going to work. You need a GDI handle to the font.

Trying to make VMR-9 MixerBitmap & GDI work

I'm attempting to overlay a bitmap on some video. I create a bitmap in memory, then I call SelectObject to select it into a memoryDC, so I can perform a DrawText operation on it.
I'm not getting any results on screen at all - can anyone suggest why?
thanks
HRESULT MyGraph::MixTextOverVMR9(LPCTSTR szText)
{
// create a bitmap object using GDI, render the text to it accordingly
// then Sets the bitmap as an alpha bitmap to the VMR9, so that it can be overlayed.
HRESULT hr = S_OK;
CBitmap bmpMem;
CFont font;
LOGFONT logicfont;
CRect rcText;
CRect rcVideo;
VMR9AlphaBitmap alphaBmp;
HWND hWnd = this->GetFirstRendererWindow();
COLORREF clrText = RGB(255, 255, 0);
COLORREF clrBlack = RGB(0,0,0);
HDC hdcHwnd = NULL;
CDC dcMem;
LONG lWidth;
LONG lHeight;
if( ! m_spVideoRenderer.p )
return E_NOINTERFACE;
if( !m_spWindowlessCtrl.p )
return E_NOINTERFACE;
if( ! m_spIMixerBmp9.p )
{
m_spIMixerBmp9 = m_spVideoRenderer;
if( ! m_spIMixerBmp9.p )
return E_NOINTERFACE;
}
// create the font..
LPCTSTR sFont = _T("Times New Roman");
memset(&logicfont, 0, sizeof(LOGFONT));
logicfont.lfHeight = 42;
logicfont.lfWidth = 20;
logicfont.lfStrikeOut = 0;
logicfont.lfUnderline = 0;
logicfont.lfItalic = FALSE;
logicfont.lfWeight = FW_NORMAL;
logicfont.lfEscapement = 0;
logicfont.lfCharSet = ANSI_CHARSET;
logicfont.lfQuality = ANTIALIASED_QUALITY;
logicfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
wcscpy_s( &logicfont.lfFaceName[0], wcslen(sFont)*2, sFont );
font.CreateFontIndirectW(&logicfont);
// create a compatible memDC from the video window's HDC
if( hWnd == NULL )
return E_FAIL;
hdcHwnd = GetDC(hWnd);
dcMem = CreateCompatibleDC(hdcHwnd);
// get the required bitmap metrics from the MediaBuffer
if( ! SUCCEEDED(m_spWindowlessCtrl->GetNativeVideoSize(&lWidth, &lHeight, NULL, NULL)) )
return E_FAIL;
// create a bitmap for the text
bmpMem.CreateCompatibleBitmap(dcMem.m_hDC, lWidth, lHeight);
SelectBitmap (dcMem.m_hDC, bmpMem);
SetBkMode (dcMem.m_hDC, TRANSPARENT);
SetTextColor (dcMem.m_hDC, clrText);
SelectFont (dcMem.m_hDC, font.m_hFont);
// draw the text
DrawTextW(dcMem.m_hDC, szText, wcslen(szText), rcText, DT_CALCRECT | DT_NOPREFIX );
DrawTextW(dcMem.m_hDC, szText, wcslen(szText), rcText, DT_NOPREFIX );
// Set the alpha bitmap on the VMR9 renderer
memset(&alphaBmp, 0, sizeof(VMR9AlphaBitmap));
alphaBmp.rDest.left = 0;
alphaBmp.rDest.top = 0.5;
alphaBmp.rDest.right = 0.5;
alphaBmp.rDest.bottom = 1;
alphaBmp.dwFlags = VMR9AlphaBitmap_hDC;
alphaBmp.hdc = dcMem.m_hDC;
alphaBmp.pDDS = NULL;
alphaBmp.rSrc = rcText; // rect to copy from the source image
alphaBmp.fAlpha = 0.5f; // transparency value (1.0 is opaque, 0.0 is transparent)
alphaBmp.clrSrcKey = clrText;
// alphaBmp.dwFilterMode = MixerPref9_AnisotropicFiltering;
hr = m_spIMixerBmp9->SetAlphaBitmap(&alphaBmp);
DeleteDC(hdcHwnd);
dcMem.DeleteDC();
bmpMem.DeleteObject();
font.DeleteObject();
return hr;
}
I got this one solved, so if anyone else needs to know how it's done...
HRESULT MyGraph::MixTextOverVMR9(LPCTSTR szText)
{
// create a bitmap object using GDI, render the text to it accordingly
// then Sets the bitmap as an alpha bitmap to the VMR9, so that it can be overlayed.
HRESULT hr = S_OK;
CBitmap bmpMem;
CFont font;
LOGFONT logicfont;
CRect rcText;
CRect rcVideo;
VMR9AlphaBitmap alphaBmp;
HWND hWnd = this->GetFirstRendererWindow();
COLORREF clrText = RGB(255, 255, 0);
COLORREF clrBlack = RGB(0,0,0);
HDC hdcHwnd = NULL;
CDC dcMem;
LONG lWidth;
LONG lHeight;
if( ! m_spVideoRenderer.p )
return E_NOINTERFACE;
if( !m_spWindowlessCtrl.p )
return E_NOINTERFACE;
if( ! m_spIMixerBmp9.p )
{
m_spIMixerBmp9 = m_spVideoRenderer;
if( ! m_spIMixerBmp9.p )
return E_NOINTERFACE;
}
// create the font..
LPCTSTR sFont = _T("Impact");
memset(&logicfont, 0, sizeof(LOGFONT));
logicfont.lfHeight = 24;
//logicfont.lfWidth = 24;
logicfont.lfStrikeOut = 0;
logicfont.lfUnderline = 0;
logicfont.lfItalic = FALSE;
logicfont.lfWeight = FW_NORMAL;
logicfont.lfEscapement = 0;
logicfont.lfCharSet = ANSI_CHARSET;
logicfont.lfQuality = ANTIALIASED_QUALITY;
logicfont.lfPitchAndFamily = DEFAULT_PITCH | FF_DONTCARE;
wcscpy_s( &logicfont.lfFaceName[0], wcslen(sFont)*2, sFont );
font.CreateFontIndirectW(&logicfont);
// create a compatible memDC from the video window's HDC
if( hWnd == NULL )
return E_FAIL;
hdcHwnd = GetDC(hWnd);
dcMem = CreateCompatibleDC(hdcHwnd);
// get the required bitmap metrics from the MediaBuffer
if( ! SUCCEEDED(m_spWindowlessCtrl->GetNativeVideoSize(&lWidth, &lHeight, NULL, NULL)) )
return E_FAIL;
// create a bitmap for the text
bmpMem.CreateCompatibleBitmap(dcMem.m_hDC, lWidth, lHeight);
SelectBitmap (dcMem.m_hDC, bmpMem);
SetBkColor (dcMem.m_hDC, clrBlack);
SetBkMode (dcMem.m_hDC, TRANSPARENT);
SetTextColor (dcMem.m_hDC, clrText);
SelectFont (dcMem.m_hDC, font.m_hFont);
// draw the text
DrawTextW(dcMem.m_hDC, szText, wcslen(szText), rcText, DT_CALCRECT | DT_NOPREFIX );
DrawTextW(dcMem.m_hDC, szText, wcslen(szText), rcText, DT_NOPREFIX );
// Set the alpha bitmap on the VMR9 renderer
memset(&alphaBmp, 0, sizeof(VMR9AlphaBitmap));
// top left
alphaBmp.rDest.left = 0.0f + EDGE_BUFFER;
alphaBmp.rDest.top = 0.0f + EDGE_BUFFER;
alphaBmp.rDest.right = ((float)rcText.right / (float) lWidth) + EDGE_BUFFER;
alphaBmp.rDest.bottom = ((float)rcText.bottom / (float)lHeight) + EDGE_BUFFER;
// top right
alphaBmp.rDest.left = 1.0f - ( (float)rcText.right / (float)lWidth)- EDGE_BUFFER;
alphaBmp.rDest.top = 0.0f + EDGE_BUFFER;
alphaBmp.rDest.right = 1.0f - EDGE_BUFFER;
alphaBmp.rDest.bottom = ((float)rcText.bottom / (float)lHeight) + EDGE_BUFFER;
/*
// bottom left
alphaBmp.rDest.left = 0.0f + EDGE_BUFFER;
alphaBmp.rDest.top = 1.0f - ((float)rcText.bottom / (float)lHeight) - EDGE_BUFFER;
alphaBmp.rDest.right = ((float)rcText.right / (float) lWidth) + EDGE_BUFFER;
alphaBmp.rDest.bottom = 1.0f - EDGE_BUFFER;
*/
/*
// bottom right
alphaBmp.rDest.left = 1.0f - ( (float)rcText.right / (float)lWidth)- EDGE_BUFFER;
alphaBmp.rDest.top = (float)(lHeight - rcText.bottom) / (float)lHeight - EDGE_BUFFER;
alphaBmp.rDest.right = 1.0f - EDGE_BUFFER;
alphaBmp.rDest.bottom = 1.0f - EDGE_BUFFER;
*/
alphaBmp.dwFlags = VMR9AlphaBitmap_hDC | VMRBITMAP_SRCCOLORKEY;
alphaBmp.hdc = dcMem.m_hDC;
alphaBmp.pDDS = NULL;
alphaBmp.rSrc = rcText; // rect to copy from the source image
alphaBmp.fAlpha = 0.3f; // transparency value (1.0 is opaque, 0.0 is transparent)
alphaBmp.clrSrcKey = clrBlack;
alphaBmp.dwFilterMode = MixerPref9_PointFiltering;
hr = m_spIMixerBmp9->SetAlphaBitmap(&alphaBmp);
DeleteDC(hdcHwnd);
dcMem.DeleteDC();
bmpMem.DeleteObject();
font.DeleteObject();
return hr;
}