使用对EnumFontFamiliesEx的DLL调用在C#中枚举活动字体让我知道了

我的最终目标是在Windows计算机上列出所有活动字体。 例如,如果您启动写字板或Word,您将看到它们全部。 其中一些字体来自windows \ fonts文件夹,但不是全部。 有些是使用gdi32.dll调用AddFontResource(…)动态注册的。 现在,你会认为C#支持检索整个列表,如果有,请告诉我!

但是,在花了好几个小时后,常规的C#调用获取安装的系统字体只检索实际上活动的所有字体中的一些。 例如,InstalledFontCollection.Families没有找到AddFontResource添加的任何字体(它找到了wordpad中列出的大约25%的字体!)

虽然我想在C#中执行此操作,但似乎我必须使用更多gdi32.dll调用。 这样就开始了我的EnumFontFamiliesEx问题。

我已经设法让以下代码工作到我正在获得一堆字体回调。 但是,结构ENUMLOGFONTEX似乎已损坏,例如lpelfe.elfFullName通常包含几个方形字符,而不是真实姓名。 也许我在编组或结构定义中犯了一个错误,不太确定。 我尝试了很多迭代和无休止的谷歌搜索,但无济于事。

任何帮助将非常感谢。

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; } } 

}

感谢Mattias的回答。 事实certificate我有几个问题,我从其他论坛得到了一些帮助解决它们的答案。 所以这是所有人享受的最终代码。

 [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; } 

将CharSet = CharSet.Auto添加到EnumFontFamiliesEx上的DllImport属性应该可以解决问题。 就像Merlyn暗示的那样,它是ANSI / Unicode不匹配问题。

并且不要忘记释放您使用Marshal.AllocHGlobal分配的内存。