现象:
打印时候程序直接崩溃。调试时出现下列异常。
异常信息:
中文:System.ArgumentException : 路径中有非法字符。
英文:
System.ArgumentException' occurred in mscorlib.dll Additional information: Illegal characters in path
堆栈信息:
Stack Trace:= at System.IO.Path.CheckInvalidPathChars(String path) at System.IO.Path.Combine(String path1, String path2) at Microsoft.Internal.GDIExporter.BuildFontList(String fontdir) at Microsoft.Internal.GDIExporter.CGDIDevice.CheckFont(GlyphTypeface typeface, String name) at Microsoft.Internal.GDIExporter.CGDIRenderTarget.CreateFontW(GlyphRun pGlyphRun, Double fontSize, Double scaleY) at Microsoft.Internal.GDIExporter.CGDIRenderTarget.RenderTextThroughGDI(GlyphRun pGlyphRun, Brush pBrush) at Microsoft.Internal.GDIExporter.CGDIRenderTarget.DrawGlyphRun(Brush pBrush, GlyphRun glyphRun) at Microsoft.Internal.AlphaFlattener.BrushProxyDecomposer.Microsoft.Internal..AlphaFlattener.IProxyDrawingContext.DrawGlyphs(GlyphRun glyphrun, Geometry clip, Matrix trans, BrushProxy foreground) at Microsoft.Internal.AlphaFlattener.PrimitiveRenderer.DrawGlyphs(GlyphRun glyphrun, Rect bounds, Matrix trans, String desp) at Microsoft.Internal.AlphaFlattener.Flattener.AlphaRender(Primitive primitive, List`1 overlapping, Int32 overlapHasTransparency, Boolean disjoint, String desp) at Microsoft.Internal.AlphaFlattener.Flattener.AlphaFlatten(IProxyDrawingContext dc, Boolean disjoint) at Microsoft.Internal.AlphaFlattener.Flattener.Convert(Primitive tree, ILegacyDevice dc, Double width, Double height, Double dpix, Double dpiy, Nullable`1 quality) at Microsoft.Internal.AlphaFlattener.MetroDevice0.FlushPage(ILegacyDevice sink, Double width, Double height, Nullable`1 outputQuality) at Microsoft.Internal.AlphaFlattener.MetroToGdiConverter.FlushPage() at System.Windows.Xps.Serialization.NgcSerializationManager.EndPage() at System.Windows.Xps.Serialization.NgcFixedPageSerializer.SerializeObject(Object serializedObject) at System.Windows.Xps.Serialization.NgcDocumentPageSerializer.SerializeObject(Object serializedObject) at System.Windows.Xps.Serialization.NgcDocumentPaginatorSerializer.SerializeObject(Object serializedObject) at System.Windows.Xps.Serialization.NgcSerializationManager.SaveAsXaml(Object serializedObject) at System.Windows.Xps.XpsDocumentWriter.SaveAsXaml(Object serializedObject, Boolean isSync) at System.Windows.Xps.XpsDocumentWriter.Write(DocumentPaginator documentPaginator) at System.Windows.Controls.PrintDialog.PrintDocument(DocumentPaginator documentPaginator, String description)
原因:
在注册表 HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Fonts 中存的是字体名称及其文件位置的列表。但这些文件位置中有非法字符中有非法字符。在执行Path.Combine方法时,出现异常。
解决方案:
重新处理注册表。
代码:
public class FontsClearup { /// <summary> /// 获取系统文件位置 /// </summary> [MethodImpl(MethodImplOptions.ForwardRef), SecurityCritical, SuppressUnmanagedCodeSecurity, DllImport("shell32.dll", CharSet = CharSet.Unicode)] internal static extern int SHGetSpecialFolderPathW(IntPtr hwndOwner, StringBuilder lpszPath, int nFolder, int fCreate); /// <summary> /// 获取字体文件夹 /// </summary> /// <returns></returns> private static string GetFontDir() { var lpszPath = new StringBuilder(260); return SHGetSpecialFolderPathW(IntPtr.Zero, lpszPath, 20, 0) != 0 ? lpszPath.ToString().ToUpperInvariant() : null; } public const string FontsRegistryPath = @"HKEY_LOCAL_MACHINE\Software\Microsoft\Windows NT\CurrentVersion\Fonts"; public const string FontsLocalMachineRegistryPath = @"Software\Microsoft\Windows NT\CurrentVersion\Fonts"; /// <summary> /// 获取所有字体信息 /// </summary> /// <returns></returns> public static IEnumerable<FontInfo> ScanAllRegistryFonts() { var fontNames = new List<FontInfo>(); new RegistryPermission(RegistryPermissionAccess.Read, FontsRegistryPath).Assert(); try { var fontDirPath = GetFontDir(); using (var key = Registry.LocalMachine.OpenSubKey(FontsLocalMachineRegistryPath)) { if (key == null) { return Enumerable.Empty<FontInfo>(); } var valueNames = key.GetValueNames(); foreach (var valueName in valueNames) { var fontName = key.GetValue(valueName).ToString(); var fontInfo = new FontInfo { Name = valueName, RegistryKeyPath = key.ToString(), Value = fontName }; try { var systemFontUri = new Uri(fontName, UriKind.RelativeOrAbsolute); if (!systemFontUri.IsAbsoluteUri) { new Uri(Path.Combine(fontDirPath, fontName)); } } catch { fontInfo.IsCorrupt = true; } fontNames.Add(fontInfo); } key.Close(); key.Flush(); } } catch (Exception exception) { Console.WriteLine(exception); } finally { CodeAccessPermission.RevertAssert(); } return fontNames; } /// <summary> /// 获取所有异常字体信息 /// </summary> /// <returns></returns> public static IEnumerable<FontInfo> GetAllCorruptFonts() { var fonts = ScanAllRegistryFonts(); return fonts.Where(f => f.IsCorrupt); } /// <summary> /// 整理字体信息 /// </summary> /// <param name="p_corruptFonts"></param> public static void FixRegistryFonts(IEnumerable<FontInfo> p_corruptFonts = null) { IEnumerable<FontInfo> corruptFonts = p_corruptFonts; if (corruptFonts == null) { corruptFonts = GetAllCorruptFonts(); } new RegistryPermission(RegistryPermissionAccess.Write, FontsRegistryPath).Assert(); try { using (var key = Registry.LocalMachine.OpenSubKey(FontsLocalMachineRegistryPath, true)) { if (key == null) return; foreach (var corruptFont in corruptFonts) { if (!corruptFont.IsCorrupt) continue; var fixedFontName = RemoveInvalidCharsFormFontName(corruptFont.Value); key.SetValue(corruptFont.Name, fixedFontName, RegistryValueKind.String); } key.Close(); key.Flush(); } } catch (Exception exception) { Console.WriteLine(exception.Message); } finally { CodeAccessPermission.RevertAssert(); ScanAllRegistryFonts(); } } private static string RemoveInvalidCharsFormFontName(string fontName) { var invalidChars = Path.GetInvalidPathChars(); var fontCharList = fontName.ToCharArray().ToList(); fontCharList.RemoveAll(c => invalidChars.Contains(c)); return new string(fontCharList.ToArray()); } } public class FontInfo { public string RegistryKeyPath { get; set; } public bool IsCorrupt { get; set; } public string Name { get; set; } public string Value { get; set; } }
执行:FontsClearup.FixRegistryFonts();
其实方法的用法见注释。
参考:http://www.dnsingh.com/MyBlog/?tag=/GDIExporter.BuildFontList