Enumerating active fonts in C # using a DLL call in EnumFontFamiliesEx has me schtumped

My ultimate goal is to list all active fonts on a Windows computer. For example, if you run WordPad or Word, you will see all of them. Some of these fonts come from the windows \ fonts folder, but not for everyone. Some of them are dynamically registered by calling gdi32.dll AddFontResource (...). Now you would think that C # had support for retrieving the whole list, and if so, let me know please!

However, after spending many hours doing this, regular C # calls to install installed system fonts retrieve only some of all existing fonts. For example, InstalledFontCollection.Families does not find any of the fonts added using AddFontResource (it finds about 25% of the fonts listed in the text box!)

While I want to do this in C #, it seems I need to use some more calls to gdi32.dll. So my problem began with EnumFontFamiliesEx.

I managed to get the following code that works to such an extent that I get a bunch of callbacks with fonts. However, the ENUMLOGFONTEX structure seems to be corrupted, and for example, lpelfe.elfFullName usually contains a pair of square characters, rather than a real name. Perhaps I was mistaken in sorting or defining the structure, not quite sure. I tried a lot of iterations and an endless google search, but to no avail.

Any help would be greatly appreciated.

using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.Windows.Media; using System.Runtime.InteropServices; using Microsoft.Win32; namespace FontRetriever { public partial class TestForm : Form { [DllImport("gdi32.dll")] static extern int EnumFontFamiliesEx(IntPtr hdc, [In] IntPtr pLogfont, EnumFontExDelegate lpEnumFontFamExProc, IntPtr lParam, uint dwFlags); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public class LOGFONT { public int lfHeight; public int lfWidth; public int lfEscapement; public int lfOrientation; public FontWeight lfWeight; [MarshalAs(UnmanagedType.U1)] public bool lfItalic; [MarshalAs(UnmanagedType.U1)] public bool lfUnderline; [MarshalAs(UnmanagedType.U1)] public bool lfStrikeOut; public FontCharSet lfCharSet; public FontPrecision lfOutPrecision; public FontClipPrecision lfClipPrecision; public FontQuality lfQuality; public FontPitchAndFamily lfPitchAndFamily; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string lfFaceName; } public enum FontWeight : int { FW_DONTCARE = 0, FW_THIN = 100, FW_EXTRALIGHT = 200, FW_LIGHT = 300, FW_NORMAL = 400, FW_MEDIUM = 500, FW_SEMIBOLD = 600, FW_BOLD = 700, FW_EXTRABOLD = 800, FW_HEAVY = 900, } public enum FontCharSet : byte { ANSI_CHARSET = 0, DEFAULT_CHARSET = 1, SYMBOL_CHARSET = 2, SHIFTJIS_CHARSET = 128, HANGEUL_CHARSET = 129, HANGUL_CHARSET = 129, GB2312_CHARSET = 134, CHINESEBIG5_CHARSET = 136, OEM_CHARSET = 255, JOHAB_CHARSET = 130, HEBREW_CHARSET = 177, ARABIC_CHARSET = 178, GREEK_CHARSET = 161, TURKISH_CHARSET = 162, VIETNAMESE_CHARSET = 163, THAI_CHARSET = 222, EASTEUROPE_CHARSET = 238, RUSSIAN_CHARSET = 204, MAC_CHARSET = 77, BALTIC_CHARSET = 186, } public enum FontPrecision : byte { OUT_DEFAULT_PRECIS = 0, OUT_STRING_PRECIS = 1, OUT_CHARACTER_PRECIS = 2, OUT_STROKE_PRECIS = 3, OUT_TT_PRECIS = 4, OUT_DEVICE_PRECIS = 5, OUT_RASTER_PRECIS = 6, OUT_TT_ONLY_PRECIS = 7, OUT_OUTLINE_PRECIS = 8, OUT_SCREEN_OUTLINE_PRECIS = 9, OUT_PS_ONLY_PRECIS = 10, } public enum FontClipPrecision : byte { CLIP_DEFAULT_PRECIS = 0, CLIP_CHARACTER_PRECIS = 1, CLIP_STROKE_PRECIS = 2, CLIP_MASK = 0xf, CLIP_LH_ANGLES = (1 << 4), CLIP_TT_ALWAYS = (2 << 4), CLIP_DFA_DISABLE = (4 << 4), CLIP_EMBEDDED = (8 << 4), } public enum FontQuality : byte { DEFAULT_QUALITY = 0, DRAFT_QUALITY = 1, PROOF_QUALITY = 2, NONANTIALIASED_QUALITY = 3, ANTIALIASED_QUALITY = 4, CLEARTYPE_QUALITY = 5, CLEARTYPE_NATURAL_QUALITY = 6, } [Flags] public enum FontPitchAndFamily : byte { DEFAULT_PITCH = 0, FIXED_PITCH = 1, VARIABLE_PITCH = 2, FF_DONTCARE = (0 << 4), FF_ROMAN = (1 << 4), FF_SWISS = (2 << 4), FF_MODERN = (3 << 4), FF_SCRIPT = (4 << 4), FF_DECORATIVE = (5 << 4), } [StructLayout(LayoutKind.Sequential)] public class NEWTEXTMETRICEX { //public const int LF_FACESIZE = 32; public int tmHeight; public int tmAscent; public int tmDescent; public int tmInternalLeading; public int tmExternalLeading; public int tmAveCharWidth; public int tmMaxCharWidth; public int tmWeight; public int tmOverhang; public int tmDigitizedAspectX; public int tmDigitizedAspectY; public char tmFirstChar; public char tmLastChar; public char tmDefaultChar; public char tmBreakChar; public byte tmItalic; public byte tmUnderlined; public byte tmStruckOut; public byte tmPitchAndFamily; public byte tmCharSet; } private const byte DEFAULT_CHARSET = 1; private const byte SHIFTJIS_CHARSET = 128; private const byte JOHAB_CHARSET = 130; private const byte EASTEUROPE_CHARSET = 238; private const byte DEFAULT_PITCH = 0; private const byte FIXED_PITCH = 1; private const byte VARIABLE_PITCH = 2; private const byte FF_DONTCARE = (0 << 4); private const byte FF_ROMAN = (1 << 4); private const byte FF_SWISS = (2 << 4); private const byte FF_MODERN = (3 << 4); private const byte FF_SCRIPT = (4 << 4); private const byte FF_DECORATIVE = (5 << 4); public TestForm() { InitializeComponent(); } private int cnt = 0; private void TestForm_Load(object sender, EventArgs e) { LOGFONT lf = CreateLogFont(""); IntPtr plogFont = Marshal.AllocHGlobal(Marshal.SizeOf(lf)); Marshal.StructureToPtr(lf, plogFont, true); int ret = 0; try { Graphics G = pictureBox1.CreateGraphics(); IntPtr P = G.GetHdc(); del1 = new EnumFontExDelegate(callback1); ret = EnumFontFamiliesEx(P, plogFont, del1, IntPtr.Zero, 0); System.Diagnostics.Trace.WriteLine("EnumFontFamiliesEx = " + ret.ToString()); } catch { System.Diagnostics.Trace.WriteLine("Exception"); } } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct ENUMLOGFONTEX { public LOGFONT elfLogFont; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] public string elfFullName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string elfStyle; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string elfScript; } public delegate int EnumFontExDelegate(ref ENUMLOGFONTEX lpelfe, IntPtr lpntme, int FontType, int lParam); public EnumFontExDelegate del1; public int callback1(ref ENUMLOGFONTEX lpelfe, IntPtr lpntme, int FontType, int lParam) { try { ++cnt; Font F = Font.FromLogFont(lpelfe.elfLogFont); Console.WriteLine(F.Name + " " + lpelfe.elfFullName); } catch { System.Diagnostics.Trace.WriteLine("What happened?"); } return cnt; } public static LOGFONT CreateLogFont(string fontname) { LOGFONT lf = new LOGFONT(); lf.lfHeight = 0; lf.lfWidth = 0; lf.lfEscapement = 0; lf.lfOrientation = 0; lf.lfWeight = 0; lf.lfItalic = false; lf.lfUnderline = false; lf.lfStrikeOut = false; lf.lfCharSet = FontCharSet.DEFAULT_CHARSET; lf.lfOutPrecision = 0; lf.lfClipPrecision = 0; lf.lfQuality = 0; lf.lfPitchAndFamily = FontPitchAndFamily.FF_DONTCARE; lf.lfFaceName = ""; return lf; } } 

}

+3
c # callback fonts dll gdi
source share
2 answers

Thanks for Mattias's answer. It turned out that I had several questions, and I received answers to other forums that helped solve them. So here is the final code for everyone.

 [DllImport("gdi32.dll", CharSet = CharSet.Auto)] static extern int EnumFontFamiliesEx(IntPtr hdc, [In] IntPtr pLogfont, EnumFontExDelegate lpEnumFontFamExProc, IntPtr lParam, uint dwFlags); [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public class LOGFONT { public int lfHeight; public int lfWidth; public int lfEscapement; public int lfOrientation; public FontWeight lfWeight; [MarshalAs(UnmanagedType.U1)] public bool lfItalic; [MarshalAs(UnmanagedType.U1)] public bool lfUnderline; [MarshalAs(UnmanagedType.U1)] public bool lfStrikeOut; public FontCharSet lfCharSet; public FontPrecision lfOutPrecision; public FontClipPrecision lfClipPrecision; public FontQuality lfQuality; public FontPitchAndFamily lfPitchAndFamily; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string lfFaceName; } public enum FontWeight : int { FW_DONTCARE = 0, FW_THIN = 100, FW_EXTRALIGHT = 200, FW_LIGHT = 300, FW_NORMAL = 400, FW_MEDIUM = 500, FW_SEMIBOLD = 600, FW_BOLD = 700, FW_EXTRABOLD = 800, FW_HEAVY = 900, } public enum FontCharSet : byte { ANSI_CHARSET = 0, DEFAULT_CHARSET = 1, SYMBOL_CHARSET = 2, SHIFTJIS_CHARSET = 128, HANGEUL_CHARSET = 129, HANGUL_CHARSET = 129, GB2312_CHARSET = 134, CHINESEBIG5_CHARSET = 136, OEM_CHARSET = 255, JOHAB_CHARSET = 130, HEBREW_CHARSET = 177, ARABIC_CHARSET = 178, GREEK_CHARSET = 161, TURKISH_CHARSET = 162, VIETNAMESE_CHARSET = 163, THAI_CHARSET = 222, EASTEUROPE_CHARSET = 238, RUSSIAN_CHARSET = 204, MAC_CHARSET = 77, BALTIC_CHARSET = 186, } public enum FontPrecision : byte { OUT_DEFAULT_PRECIS = 0, OUT_STRING_PRECIS = 1, OUT_CHARACTER_PRECIS = 2, OUT_STROKE_PRECIS = 3, OUT_TT_PRECIS = 4, OUT_DEVICE_PRECIS = 5, OUT_RASTER_PRECIS = 6, OUT_TT_ONLY_PRECIS = 7, OUT_OUTLINE_PRECIS = 8, OUT_SCREEN_OUTLINE_PRECIS = 9, OUT_PS_ONLY_PRECIS = 10, } public enum FontClipPrecision : byte { CLIP_DEFAULT_PRECIS = 0, CLIP_CHARACTER_PRECIS = 1, CLIP_STROKE_PRECIS = 2, CLIP_MASK = 0xf, CLIP_LH_ANGLES = (1 << 4), CLIP_TT_ALWAYS = (2 << 4), CLIP_DFA_DISABLE = (4 << 4), CLIP_EMBEDDED = (8 << 4), } public enum FontQuality : byte { DEFAULT_QUALITY = 0, DRAFT_QUALITY = 1, PROOF_QUALITY = 2, NONANTIALIASED_QUALITY = 3, ANTIALIASED_QUALITY = 4, CLEARTYPE_QUALITY = 5, CLEARTYPE_NATURAL_QUALITY = 6, } [Flags] public enum FontPitchAndFamily : byte { DEFAULT_PITCH = 0, FIXED_PITCH = 1, VARIABLE_PITCH = 2, FF_DONTCARE = (0 << 4), FF_ROMAN = (1 << 4), FF_SWISS = (2 << 4), FF_MODERN = (3 << 4), FF_SCRIPT = (4 << 4), FF_DECORATIVE = (5 << 4), } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct NEWTEXTMETRIC { public int tmHeight; public int tmAscent; public int tmDescent; public int tmInternalLeading; public int tmExternalLeading; public int tmAveCharWidth; public int tmMaxCharWidth; public int tmWeight; public int tmOverhang; public int tmDigitizedAspectX; public int tmDigitizedAspectY; public char tmFirstChar; public char tmLastChar; public char tmDefaultChar; public char tmBreakChar; public byte tmItalic; public byte tmUnderlined; public byte tmStruckOut; public byte tmPitchAndFamily; public byte tmCharSet; int ntmFlags; int ntmSizeEM; int ntmCellHeight; int ntmAvgWidth; } public struct FONTSIGNATURE { [MarshalAs(UnmanagedType.ByValArray)] int[] fsUsb; [MarshalAs(UnmanagedType.ByValArray)] int[] fsCsb; } public struct NEWTEXTMETRICEX { NEWTEXTMETRIC ntmTm; FONTSIGNATURE ntmFontSig; } [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)] public struct ENUMLOGFONTEX { public LOGFONT elfLogFont; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 64)] public string elfFullName; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string elfStyle; [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32)] public string elfScript; } private const byte DEFAULT_CHARSET = 1; private const byte SHIFTJIS_CHARSET = 128; private const byte JOHAB_CHARSET = 130; private const byte EASTEUROPE_CHARSET = 238; private const byte DEFAULT_PITCH = 0; private const byte FIXED_PITCH = 1; private const byte VARIABLE_PITCH = 2; private const byte FF_DONTCARE = (0 << 4); private const byte FF_ROMAN = (1 << 4); private const byte FF_SWISS = (2 << 4); private const byte FF_MODERN = (3 << 4); private const byte FF_SCRIPT = (4 << 4); private const byte FF_DECORATIVE = (5 << 4); … private void TestForm_Load(object sender, EventArgs e) { LOGFONT lf = CreateLogFont(""); IntPtr plogFont = Marshal.AllocHGlobal(Marshal.SizeOf(lf)); Marshal.StructureToPtr(lf, plogFont, true); int ret = 0; try { Graphics G = pictureBox1.CreateGraphics(); IntPtr P = G.GetHdc(); del1 = new EnumFontExDelegate(callback1); ret = EnumFontFamiliesEx(P, plogFont, del1, IntPtr.Zero, 0); System.Diagnostics.Trace.WriteLine("EnumFontFamiliesEx = " + ret.ToString()); G.ReleaseHdc(P); } catch { System.Diagnostics.Trace.WriteLine("Error!"); } finally { Marshal.DestroyStructure(plogFont, typeof(LOGFONT)); } } public delegate int EnumFontExDelegate(ref ENUMLOGFONTEX lpelfe, ref NEWTEXTMETRICEX lpntme, int FontType, int lParam); public EnumFontExDelegate del1; public int callback1(ref ENUMLOGFONTEX lpelfe, ref NEWTEXTMETRICEX lpntme, int FontType, int lParam) { try { // Do something cool } catch (Exception e) { System.Diagnostics.Trace.WriteLine(e.ToString()); } return cnt; } public static LOGFONT CreateLogFont(string fontname) { LOGFONT lf = new LOGFONT(); lf.lfHeight = 0; lf.lfWidth = 0; lf.lfEscapement = 0; lf.lfOrientation = 0; lf.lfWeight = 0; lf.lfItalic = false; lf.lfUnderline = false; lf.lfStrikeOut = false; lf.lfCharSet = FontCharSet.DEFAULT_CHARSET; lf.lfOutPrecision = 0; lf.lfClipPrecision = 0; lf.lfQuality = 0; lf.lfPitchAndFamily = FontPitchAndFamily.FF_DONTCARE; lf.lfFaceName = ""; return lf; } 
+4
source share

Adding CharSet = CharSet.Auto to your DllImport attribute in EnumFontFamiliesEx should take care of the problem. As Merlin hints, this is an ANSI / Unicode mismatch problem.

And don't forget to free the memory that you allocated with Marshal.AllocHGlobal.

-one
source share

All Articles