INFO: Example of calling EnumFontFamilies from a DLL

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

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

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.

STEP TWO: Create Visual Basic Sample Program

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