Which Hindi / Devnagari Unicode font is installed on the system?
When you view a Hindi page the characters show up in one of the fonts installed on the system. If you have "Mangal" font installed that came bundled with your Operating system you see the page in that font. The same applies when you don't have any Hindi Unicode font other than "Arial Unicode MS" font or "Raghu" font that came with your MS Office or you downloaded freely from the net respectively. How come the Browsers know which Language font is installed on your system?
Answer is simple the browser enumerates all installed fonts to find that out. One previous post Font Enumeration Application had all the functions and structures that make this possible. The code in this post derives from the code in previous post. While the previous post aimed at enumerating all fonts, store their names and the fsUsb member of the FONTSIGNATURE structure, and show the subranges supported by each font when the font was selected in the list.
Here we aim at finding the name for the first font that supports a font and stop the enumeration as soon as we got it.
Copy the code below which declare all function / constants / structures required, to a module.
Option Explicit
Public Declare Function EnumFontFamiliesEx Lib "gdi32" Alias "EnumFontFamiliesExA" ( _
ByVal hDC As Long, lpLogFont As LOGFONT, ByVal lpEnumFontProc As Long, _
ByVal lParam As Long, ByVal dw As Long) As Long
Public Const MAXSUBRANGELISTEDHERE As Integer = 90
Public Const LF_FACESIZE = 32
Public Const LF_FULLFACESIZE = 64
Public UnicodeSubRange(0 To MAXSUBRANGELISTEDHERE) As String
Public Signature() As Variant
Public FontCtr As Long
Public Type NEWTEXTMETRIC
tmHeight As Long
tmAscent As Long
tmDescent As Long
tmInternalLeading As Long
tmExternalLeading As Long
tmAveCharWidth As Long
tmMaxCharWidth As Long
tmWeight As Long
tmOverhang As Long
tmDigitizedAspectX As Long
tmDigitizedAspectY As Long
tmFirstChar As Byte
tmLastChar As Byte
tmDefaultChar As Byte
tmBreakChar As Byte
tmItalic As Byte
tmUnderlined As Byte
tmStruckOut As Byte
tmPitchAndFamily As Byte
tmCharSet As Byte
ntmFlags As Long
ntmSizeEM As Long
ntmCellHeight As Long
ntmAveWidth As Long
End Type
Public Type FONTSIGNATURE
fsUsb(4) As Long
fsCsb(2) As Long
End Type
Public Type LOGFONT
lfHeight As Long
lfWidth As Long
lfEscapement As Long
lfOrientation As Long
lfWeight As Long
lfItalic As Byte
lfUnderline As Byte
lfStrikeOut As Byte
lfCharSet As Byte
lfOutPrecision As Byte
lfClipPrecision As Byte
lfQuality As Byte
lfPitchAndFamily As Byte
lfFaceName(1 To LF_FACESIZE) As Byte
End Type
Public Type ENUMLOGFONTEX
elfLogFont As LOGFONT
elfFullName(LF_FULLFACESIZE) As Byte
elfStyle(LF_FACESIZE) As Byte
elfScript(LF_FACESIZE) As Byte
End Type
Public Type NEWTEXTMETRICEX
ntmTm As NEWTEXTMETRIC
ntmFontSig As FONTSIGNATURE
End Type
Now let's work on the form. While we are making this application specific to Hindi, it can be used for any language / Unicode subrange. Add a textbox named txtHindiFont and set its Visible Property to false. Intent for this is that it should be available for modification only to the code and that it raises an event as soon as a matching font is found.
The EnumFontFamiliesEx function takes a parameter lParam which it passes when the callback function is called. So while in the previous application we sent this value as zero, we will use it here to send the bit number associated with the language/script. You can get a complete list on this page http://msdn2.microsoft.com/en-us/library/ms776439.aspx.
Create a const initialized to "15" which is Bit associated with Devnagari script. Send this as lParam parameter. The change event of txtHindiFont pops up a message box with the font name. The name is also available to the code as text stored in txtHindiFont.
Const IDX_HINDI = 15
Private Sub Form_Load()
Dim objlogfont As LOGFONT
EnumFontFamiliesEx Form1.hDC, objlogfont, AddressOf EnumFontFamExProc, IDX_HINDI, 0
End Sub
Private Sub txtHindiFont_Change()
MsgBox "Font supporting Hindi/Devnagari installed on system is " & txtHindiFont
End Sub
That was all for the code in the form. Now lets see how the callback function EnumFontFamExProc looks like. Passing a non-zero as return value for the callback function continues the enumeration until the last font. lParam carries the Bit associated with the Unicode subrange (here devnagari) which we would be matching for, in the fonts enumerated. We would be passing a zero as soon as we find the first matching font. While a "Long" data stores 32 bits, an array of 4 longs is used to store information for all Unicode subranges. The calculation below is to find out where in the array and at which bit to look for.
Public Function EnumFontFamExProc(ByRef lpELFX As ENUMLOGFONTEX, _
ByRef lpNTME As NEWTEXTMETRICEX, ByVal lFontType As Long, _
ByVal lParam As Long) As Long
Dim p As Integer
Dim q As Integer
p = Int(lParam / 32)
q = lParam Mod 32
If q <> 31 Then
If lpNTME.ntmFontSig.fsUsb(p) And 2 ^ q Then
UpdateFontInfo (lpELFX.elfLogFont.lfFaceName)
EnumFontFamExProc = 0
Exit Function
End If
Else
If lpNTME.ntmFontSig.fsUsb(p) < 0 Then
UpdateFontInfo (lpELFX.elfLogFont.lfFaceName)
EnumFontFamExProc = 0
Exit Function
End If
End If
EnumFontFamExProc = 1
End Function
As soon as the matching font is found UpdateFontInfo function is called which adds all bytes in the array to find the facename and updates the textbox to reflect the same.
Public Function UpdateFontInfo(ByRef lfFaceName)
Dim ctr As Integer
Dim sFaceName As String
sFaceName = ""
For ctr = 1 To LF_FACESIZE
If lfFaceName(ctr) = 0 Then
Exit For
Else
sFaceName = sFaceName & Chr(lfFaceName(ctr))
End If
Next
Form1.txtHindiFont = sFaceName
End Function
Execute the application and a message box will tell you which Hindi Unicode font your machine is equipped with.


