E不小心

  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

现象:

  打印时候程序直接崩溃。调试时出现下列异常。

异常信息:

  中文: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

posted on 2013-07-09 21:58  E不小心  阅读(3967)  评论(0编辑  收藏  举报