Many times, a particular font needs to be used in an applications due to inhouse graphics designer’s font choice. In order for the application to use the fonts, the font needs to be installed using the installer. Too many fonts on the user machine may slow the system down considerably.
You can actually get away without installing the font: GDI and GDI+ each provide two ways for you, as a programmer, to add a font for an application to use without installing it. I’ll show you how in this article!
GDI’s AddFontResourceEx and AddFontMemResourceEx
AddFontResourceEx
Let me first talk about GDI’s two functions for adding fonts to application for use. I’ll then talk about GDI+’s own functions. You can use AddFontResourceEx to add a physical font file for the application to use.
int AddFontResourceEx( LPCTSTR lpszFilename, // font file name DWORD fl, // font characteristics PVOID pdv // reserved );
Here is an example on how to use AddFontResourceEx.
CString szFontFile = "D:\\SkiCargo.ttf"; int nResults = AddFontResourceEx( m_szFontFile, // font file name FR_PRIVATE, // font characteristics NULL);
To use the font you’ve added, just specify its name in the CreateFont or CreateFontIndirect function like any other installed font. To know the name of the font, just right click on the ttf extension file in the Windows Explorer and select “Open” and you will see its actual name. Or you can use the TTF and TTC class which I wrote. to know its font name
Note: The font filename(“SkiCargo.ttf”) in this article is actually its font name, “SkiCargo”, this is usually not the case! To be on the safe side, use the right click method or TTF and TTC class, I just mentioned, to find out its name!
CClientDC dc(this); dc.SetBkMode(TRANSPARENT); LOGFONT lf; memset(&lf, 0, sizeof(lf)); lf.lfHeight = -MulDiv(24, pDC->GetDeviceCaps(LOGPIXELSY), 72); lf.lfWeight = FW_NORMAL; lf.lfOutPrecision = OUT_TT_ONLY_PRECIS; wcscpy_s(lf.lfFaceName, L"SkiCargo"); // create and select it CFont newFont; if (!newFont.CreateFontIndirect(&lf)) return; CFont* pOldFont = dc.SelectObject(&newFont); // use a path to record how the text was drawn wchar_t buf[] = _T("The quick brown fox jumps over the lazy dog!"); dc.TextOut( 10, 10, buf, wcslen(buf)); // Put back the old font dc.SelectObject(pOldFont);
You must remember to call RemoveFontResourceEx before the application exits. You should note that the parameters must be the same as the ones that you fed into AddFontResourceEx!
BOOL RemoveFontResourceEx( LPCTSTR lpFileName, // name of font file DWORD fl, // font characteristics PVOID pdv // Reserved. );
CString szFontFile = "D:\\SkiCargo.ttf"; BOOL b = RemoveFontResourceEx( m_szFontFile, // name of font file FR_PRIVATE, // font characteristics NULL // Reserved. );
AddFontMemResourceEx
If our font is in a resource dll, cabinet file or archival compressed file, you can extract it into the memory and then use AddFontMemResourceEx to read it from the memory.
HANDLE AddFontMemResourceEx( PVOID pbFont, // font resource DWORD cbFont, // number of bytes in font resource PVOID pdv, // Reserved. Must be 0. DWORD *pcFonts // number of fonts installed );
Here is an example on how to use AddFontMemResourceEx on a font file embedded in the resource.
HINSTANCE hResInstance = AfxGetResourceHandle( ); HRSRC res = FindResource(hResInstance, MAKEINTRESOURCE(IDR_MYFONT),L"BINARY"); if (res) { HGLOBAL mem = LoadResource(hResInstance, res); void *data = LockResource(mem); size_t len = SizeofResource(hResInstance, res); DWORD nFonts; m_fonthandle = AddFontMemResourceEx( data, // font resource len, // number of bytes in font resource NULL, // Reserved. Must be 0. &nFonts // number of fonts installed ); if(m_fonthandle==0) { MessageBox(L"Font add fails", L"Error"); } }
To use the font you have added, please refer to the previous AddFontResourceEx example. They are the same. Just use it like any other installed font. You should call RemoveFontMemResourceEx before the application exits. When the process goes away, the system will unload the fonts, even if you don’t call RemoveFontMemResourceEx. Note: The parameters must be the same as the ones you feed into AddFontResourceEx!
BOOL RemoveFontMemResourceEx( HANDLE fh // handle to the font resource );
if(m_fonthandle) { BOOL b = RemoveFontMemResourceEx(m_fonthandle); if(b==0) { MessageBox(L"Font remove fails", L"Error"); } }
GDI+’s PrivateFontCollection::AddFontFile and PrivateFontCollection::AddMemoryFont
PrivateFontCollection’s AddFontFile
For GDI+, you can use its PrivateFontCollection class member, AddFontFile to add a physical font file.
Status AddFontFile(const WCHAR* filename);
Here is how to use AddFontFile to add a font file.
Gdiplus::PrivateFontCollection m_fontcollection; //... CString szFontFile = szExePath + L"SkiCargo.ttf"; Gdiplus::Status nResults = m_fontcollection.AddFontFile(szFontFile);
Here is how to use the font we have just added to PrivateFontCollection object, m_fontcollection.
// When painting the text FontFamily fontFamily; int nNumFound=0; m_fontcollection.GetFamilies(1,&fontFamily,&nNumFound); if(nNumFound>0) { Font font(&fontFamily,28,FontStyleRegular,UnitPixel); StringFormat strformat; wchar_t buf[] = L"The quick brown fox jumps over the lazy dog!"; graphics.DrawString(buf,wcslen(buf),&font,PointF(10.0f,10.0f),&strformat,&brush); }
Note: unlike the GDI’s AddFontResourceEx and AddFontMemResourceEx, there is no RemoveFontFile for AddFontFile. All added fonts will be removed by PrivateFontCollection’s destructor.
PrivateFontCollection’s AddMemoryFont
For GDI+, you can use its PrivateFontCollection class member, AddMemoryFont to add a font in memory.
Status AddMemoryFont(const VOID *memory, INT length);
Here is how to use AddMemoryFont on a font file embedded in the resource. Similar to AddFontFile, there is no RemoveMemoryFont to call. Everything will be taken care of by PrivateFontCollection’s destructor.
HINSTANCE hResInstance = AfxGetResourceHandle( ); HRSRC res = FindResource(hResInstance, MAKEINTRESOURCE(IDR_MYFONT),L"BINARY"); if (res) { HGLOBAL mem = LoadResource(hResInstance, res); void *data = LockResource(mem); size_t len = SizeofResource(hResInstance, res); Gdiplus::Status nResults = m_fontcollection.AddMemoryFont(data,len); if(nResults!=Gdiplus::Ok) { MessageBox(L"Font add fails", L"Error"); } }
As to how to use the font you have just added to PrivateFontCollection object, m_fontcollection, please refer to the previous AddFontFile example, they are the same.