none
Gdiplus::Font construction from HFONT fails

    Question

  • Hi,
        I'm rendering text shapes on a Direct3D9 back buffer, using GetDC + ReleaseDC. Not the most efficient way, but works. The only problem is text shapes are rendered okay, but disappear after a few seconds. If I select the font once again, or change it (using a font selection dialog), it reappears for another few seconds. Here's the rendering code:

    /*** Render text shapes ***/
    while ( !m_GDITextBuffer.empty() ){
    	t_GDIDrawTextCall dgtc = m_GDITextBuffer.front();
    	HDC hdc;
    	pBackBuffer->GetDC(&hdc);
    		Gdiplus::Graphics g(hdc);
    		Gdiplus::Font graphFont( hdc, dgtc.font );
    		this->DrawText(	g, wTransform, drawShadows, dgtc.color,
    						dgtc.text, INT(dgtc.x), (INT)dgtc.y,
    						dgtc.dwWidth, dgtc.dwHeight,
    						graphFont, dgtc.keepSize,  
                                                    dgtc.staticText, dgtc.options );
    	pBackBuffer->ReleaseDC(hdc);
    	m_GDITextBuffer.pop_front();
    }
    
    Here's DrawText:

    void CGDIOverlays::DrawText(Gdiplus::Graphics &g, const t_TransformMatrix &wTransform, bool drawShadows,
    							RGB_COLOR color, const string &text, INT x, INT y, INT w, INT h,
    							const Gdiplus::Font &graphFont, BOOL keepSize, BOOL staticText, UINT options ){
    	Gdiplus::Color Color;
    	Color.SetFromCOLORREF( RGB(color.r, color.g, color.b) );
    	g.SetSmoothingMode( Gdiplus::SmoothingModeAntiAlias );
    	Gdiplus::Matrix transform;
    	if (keepSize == TRUE){
    		x = Round<const float, INT>( x * wTransform.eM11 + wTransform.eDx );
    		y = Round<const float, INT>( y * wTransform.eM22 + wTransform.eDy );
    	}
    	if (staticText == TRUE || keepSize == TRUE)
    		transform.SetElements( 1.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f );
    	else
    		transform.SetElements(	wTransform.eM11, wTransform.eM12,
    								wTransform.eM21, wTransform.eM22, wTransform.eDx, wTransform.eDy );
    	g.SetTransform( &transform );
    	Gdiplus::SolidBrush aBrush( Color );
    	USES_CONVERSION;
    
    	Gdiplus::RectF Rect( (float)x, (float)y, (float)w, (float)h );
    	SetAlignment(options);
    	m_StringFormat.SetFormatFlags( Gdiplus::StringFormatFlagsNoFitBlackBox );
    	Gdiplus::RectF mrect( (float)x, (float)y, (float)w, (float)h );
    	// Shadow
    	if (drawShadows){
    		aBrush.SetColor( m_ShadowColor );
    		mrect.X = float(x)-1;
    		g.DrawString( CA2W(text.c_str()), text.length(), &graphFont, mrect, &m_StringFormat, &aBrush);
    		mrect.Y = float(y)-1;
    		g.DrawString( CA2W(text.c_str()), text.length(), &graphFont, mrect, &m_StringFormat, &aBrush);
    		mrect.X = float(x);
    		g.DrawString( CA2W(text.c_str()), text.length(), &graphFont, mrect, &m_StringFormat, &aBrush);
    		mrect.X = float(x)+1;
    		g.DrawString( CA2W(text.c_str()), text.length(), &graphFont, mrect, &m_StringFormat, &aBrush);
    		mrect.Y = float(y);
    		g.DrawString( CA2W(text.c_str()), text.length(), &graphFont, mrect, &m_StringFormat, &aBrush);
    		mrect.Y = float(y)+1;
    		g.DrawString( CA2W(text.c_str()), text.length(), &graphFont, mrect, &m_StringFormat, &aBrush);
    		mrect.X = float(x);
    		g.DrawString( CA2W(text.c_str()), text.length(), &graphFont, mrect, &m_StringFormat, &aBrush);
    		mrect.Y = float(y);
    		g.DrawString( CA2W(text.c_str()), text.length(), &graphFont, mrect, &m_StringFormat, &aBrush);
    		aBrush.SetColor( Color );
    	}
    	// Text
    	mrect.X = (float)x; mrect.Y = (float)y;
    	Gdiplus::Status s = g.DrawString( CA2W(text.c_str()), text.length(), &graphFont, mrect, &m_StringFormat, &aBrush); //TODO: Invalid parameter. It's because sometimes graphFont == NULL
    }
    If I check the status s when text is not being displayed, it's "invalid parameter". If I check all parameters, it turns out that graphFont.nativeFont == NULL. Alright. So, I put a breakpoint on the first code block, and find that dgtc.font != NULL when I pass it to the Gdiplus::Font constructor. However, after the call to that constructor, graphFont has nativeFont == NULL and lastError == NotATrueTypeFont. What's the problem? Why does this work a few times and then it doesn't?
    Tuesday, January 26, 2010 12:47 PM

Answers

  • It was very hard to track this down, but the cause of the bug was that the HFONT was not set always. My CTextShape class had two overloads for the setFont method, one of which was legacy we forgot to delete. Sometimes the old version was called, sometimes the new one. So we stoppped using the old one and the font was always set correctly, thus the error disappeared.

     

    • Marked as answer by dario_ramos Wednesday, April 07, 2010 12:57 PM
    Wednesday, April 07, 2010 12:56 PM

All replies

  • Bump!
    Could it be because the HFONT is released (with DeleteObject or something of the sort) somewhere else? (I don't think so, but I'll check that it is set to NULL after being released). In any case... Is there a way to check if an HFONT is a valid handle to a font?
    Thursday, January 28, 2010 12:34 PM
  • It was very hard to track this down, but the cause of the bug was that the HFONT was not set always. My CTextShape class had two overloads for the setFont method, one of which was legacy we forgot to delete. Sometimes the old version was called, sometimes the new one. So we stoppped using the old one and the font was always set correctly, thus the error disappeared.

     

    • Marked as answer by dario_ramos Wednesday, April 07, 2010 12:57 PM
    Wednesday, April 07, 2010 12:56 PM