Microsoft KB Archive/98577

= INFO: Example of calling EnumFontFamilies from a DLL =

Article ID: 98577

Article Last Modified on 12/12/2003

-

APPLIES TO


 * Microsoft Visual Basic 2.0 Standard Edition
 * Microsoft Visual Basic 3.0 Professional Edition
 * Microsoft Visual Basic 2.0 Professional Edition
 * Microsoft Visual Basic 3.0 Professional Edition

-



This article was previously published under Q98577





SUMMARY
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.



MORE INFORMATION
Below are the steps necessary to create a sample DLL that demonstrates using EnumFontFamilies:

STEP ONE: Create Example .DLL File
  Create a source file called FONTNAME.C and add the following code: #include      #include       #include       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; }                         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   Compile FONTNAME.C from the MS-DOS command line as follows: CL /c /ASw /W3 FONTNAME.C   Link the resulting FONTNAME.OBJ file as follows: LINK /NOE /NOD FONTNAME.OBJ+LIBENTRY.OBJ,FONTNAME.DLL,, LIBW+SDLLCEW+VBAPI.LIB,FONTNAME.DEF;   Resource compile FONTNAME.DLL to make it Windows 3.0 compatible as follows: RC /30 FONTNAME.DLL </li> Copy FONTNAME.DLL to the \WINDOWS\SYSTEM directory.</li></ol>

STEP TWO: Create Visual Basic Sample Program
<ol> 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.</li> Add a list box (List1) to Form1.</li>  Add the following Declare statement as one, single line to the General Declarations section of Form1: Declare Function EnumFontNames Lib &quot;FONTNAME.DLL&quot; (ByVal hDC As        Integer, FontNames As String) As Integer </li>  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 </li> From the Run menu, choose Start (ALT, R, S) or press the F5 key to run the program.</li> Click Form1. The available font names for the selected printer will be displayed in the list box.</li></ol>

Keywords: kbinfo KB98577

-

[mailto:TECHNET@MICROSOFT.COM Send feedback to Microsoft]

© Microsoft Corporation. All rights reserved.