ID: Q98577
The information in this article applies to:
- Standard and Professional Editions of Microsoft Visual Basic programming
system for Windows, versions 2.0, 3.0
This article demonstrates how to obtain a list of available fonts for a device by calling EnumFontFamilies or EnumFonts from a DLL.
Visual Basic already provides a Fonts property for obtaining a list of available font names for a device. Microsoft recommends that you use the Fonts property instead of the function provided in this article to obtain a list of available fonts. Use the technique shown in this article only if you have encountered a bug or limitation when using the Fonts property.
To create the example shown below, you need a C compiler capable of creating Windows dynamic link libraries (DLLs), and you need to have the Visual Basic Control Development Kit (CDK) version 2.0 or 3.0. The CDK is provided with the Professional Edition of Visual Basic version 2.0 and 3.0 for Windows.
Below are the steps necessary to create a sample DLL that demonstrates using EnumFontFamilies:
1. Create a source file called FONTNAME.C and add the following code:
#include <windows.h>
#include <vbapi.h>
#include <string.h>
int FAR PASCAL _export EnumFontNames (HDC, HAD);
int FAR PASCAL _export GetNextFont (LPLOGFONT, LPNEWTEXTMETRIC,
int, LPARAM);
BOOL Win31OrGreater (VOID);
int giFontCount;
float gfVersion;
//================================================================
// Title
// EnumFontNames()
//
// Parameters
// hdc Device context for which fonts will be enumerated
// had Handle to Visual Basic string array where the
// font names will be placed.
//
// Returns
// The number of fonts enumerated.
//================================================================
int FAR PASCAL EnumFontNames (HDC hdc, HAD had)
{
giFontCount = 0;
if ( Win31OrGreater() )
//Use EnumFontFamilies under Win 3.1 and later
while (EnumFontFamilies(hdc, NULL, GetNextFont, had));
else
//Need to use EnumFonts under Win 3.0
while (EnumFonts(hdc, NULL, GetNextFont, had));
return giFontCount;
}
//================================================================
// Title
// GetNextFont()
//
// Parameters
// lplf Far pointer to LOGFONT structure
// lpntm Far pointer to NEWTEXTMETRIC structure
// FontType Type of font
// lp User-defined. In this case it holds the handle
// to a Visual Basic string array.
//
// Returns
// TRUE as a signal to enumerate the next font
// FALSE as a signal to stop enumeration
//================================================================
int FAR PASCAL GetNextFont
(
LPLOGFONT lplf,
LPNEWTEXTMETRIC lpntm,
int FontType,
LPARAM lp
)
{
static char szFirstFont[LF_FACESIZE + 1];
char szFaceName[LF_FACESIZE + 1];
int iElements, lbound;
HAD had = (HAD) lp;
LONG lBounds = VBArrayBounds(had, 1);
//Get out if there are no elements in the array
if (lBounds == AB_INVALIDINDEX)
return FALSE;
// Store the lower bound of the array for index 1
lbound = LOBOUND(lBounds);
//Get number of elements in the array
iElements = HIBOUND(lBounds) - lbound + 1;
//Initialize the vars holding the font face names
if (giFontCount == 0)
szFirstFont[0] = '\0';
szFaceName[0] = '\0';
if (giFontCount <= iElements)
{
HLSTR hlstr;
SHORT indexes[1];
//Copy the face size into a buffer so that we can ensure its
//null terminated
if ( Win31OrGreater() )
lstrcpyn((LPSTR) szFaceName, lplf->lfFaceName,
LF_FACESIZE - 1);
else
//Need to use C runtime routine fmemcpy instead of
//lstrcpyn under Win 3.0
_fmemcpy((LPVOID) szFaceName, lplf->lfFaceName,
LF_FACESIZE - 1);
szFaceName[LF_FACESIZE] = '\0';
if (giFontCount == 0)
//Store the first font retrieved. If we see this font
//again, we know we've enumerated all the fonts
lstrcpy((LPSTR) szFirstFont, szFaceName);
else if (!lstrcmp(szFirstFont, szFaceName))
//If we see the same face name again, get out and stop
//enumerating
return FALSE;
//Assume a single index array
indexes[0] = lbound + giFontCount;
//Get the VB string handle from the VB array
hlstr = VBArrayElement(had, VBArrayIndexCount(had),
indexes);
//Make sure the string handle is valid
if (HIWORD(hlstr))
{
//Add the fontname to the array
VBSetHlstr(&hlstr, (LPSTR) szFaceName, lstrlen((LPSTR)
szFaceName));
//Return and get the next font
giFontCount++;
}
return TRUE;
}
else
//Can't fit all font names into the array provided, so get
//out.
return FALSE;
}
//================================================================
// Title
// Win31OrGreater ()
//
// Returns
// TRUE if we're running under Windows 3.1 or better
// FALSE if we're running under Windows 3.0
//================================================================
BOOL Win31OrGreater ( VOID )
{
DWORD dVersion;
//Check which version of Windows we're running under
dVersion = GetVersion();
if (LOBYTE(LOWORD(dVersion)) > 3 || (LOBYTE(LOWORD(dVersion))
== 3 && HIBYTE(LOWORD(dVersion)) > 0))
return TRUE;
else
return FALSE;
}
//----------------------------------------------------------------
// Initialize library. This routine is called when the first
// client loads
// the DLL.
//----------------------------------------------------------------
int FAR PASCAL LibMain
(
HANDLE hModule,
WORD wDataSeg,
WORD cbHeapSize,
LPSTR lpszCmdLine
)
{
// Avoid warnings on unused (but required) formal parameters
wDataSeg = wDataSeg;
cbHeapSize = cbHeapSize;
lpszCmdLine = lpszCmdLine;
return 1;
}
//----------------------------------------------------------------
// WEP
//----------------------------------------------------------------
int FAR PASCAL WEP(int fSystemExit);
//----------------------------------------------------------------
// Performs cleanup tasks when the DLL is unloaded. WEP() is
// called automatically by Windows when the DLL is unloaded (no
// remaining tasks still have the DLL loaded). It is strongly
// recommended that a DLL have a WEP() function, even if it does
// nothing but returns success (1), as in this example.
//----------------------------------------------------------------
int FAR PASCAL WEP
(
int fSystemExit
)
{
// Avoid warnings on unused (but required) formal parameters
fSystemExit = fSystemExit;
return 1;
}
2. Create a module-definition file (DEF) called FONTNAME.DEF and add the
following:
LIBRARY FONTNAME
DESCRIPTION 'Example of how to enumerate all font names for
specific device'
EXETYPE WINDOWS
CODE PRELOAD MOVEABLE DISCARDABLE
DATA PRELOAD MOVEABLE SINGLE
EXPORTS
WEP @1 RESIDENTNAME
ENUMFONTNAMES @2
GETNEXTFONT @3
3. Compile FONTNAME.C from the MS-DOS command line as follows:
CL /c /ASw /W3 FONTNAME.C
4. Link the resulting FONTNAME.OBJ file as follows:
LINK /NOE /NOD
FONTNAME.OBJ+LIBENTRY.OBJ,FONTNAME.DLL,,
LIBW+SDLLCEW+VBAPI.LIB,FONTNAME.DEF;
5. Resource compile FONTNAME.DLL to make it Windows 3.0 compatible as
follows:
RC /30 FONTNAME.DLL
6. Copy FONTNAME.DLL to the \WINDOWS\SYSTEM directory.
1. Start Visual Basic or from the File menu, choose New Project (ALT, F, N)
if Visual Basic is already running. Form1 is created by default.
2. Add a list box (List1) to Form1.
3. Add the following Declare statement as one, single line to the
General Declarations section of Form1:
Declare Function EnumFontNames Lib "FONTNAME.DLL" (ByVal hDC As
Integer, FontNames() As String) As Integer
4. Add the following code to the Form_Click event of Form1:
Sub Form_Click ()
Dim i As Integer
Dim FontCount As Integer
ReDim FontNames(255) As String 'Make the array intentionally
'large to hold any number of
'font names
'For Screen fonts, pass Form1.hDC instead. If using the
'Common Dialog control, you can also pass the hDC property
'of the Common Dialog control.
FontCount = EnumFontNames(Printer.hDC, FontNames())
List1.Clear
For i = 0 To FontCount - 1
List1.AddItem FontNames(i)
Next
End Sub
5. From the Run menu, choose Start (ALT, R, S) or press the F5 key to run
the program.
6. Click Form1. The available font names for the selected printer will be
displayed in the list box.
Keywords : vbwin
Version : WINDOWS:2.0 3.0
Platform : WINDOWS
Issue type : kbinfo
Last Reviewed: October 1, 1997