1 // Licensed to the .NET Foundation under one or more agreements. 2 // The .NET Foundation licenses this file to you under the MIT license. 3 // See the LICENSE file in the project root for more information. 4 5 using System.Diagnostics; 6 using System.IO; 7 using System.Runtime.InteropServices; 8 9 namespace System.Drawing 10 { 11 public static partial class SystemFonts 12 { 13 public static Font CaptionFont 14 { 15 get 16 { 17 Font captionFont = null; 18 19 var data = new NativeMethods.NONCLIENTMETRICS(); 20 bool result = UnsafeNativeMethods.SystemParametersInfo(NativeMethods.SPI_GETNONCLIENTMETRICS, data.cbSize, data, 0); 21 22 if (result) 23 { 24 captionFont = GetFontFromData(data.lfCaptionFont); 25 } 26 27 captionFont.SetSystemFontName(nameof(CaptionFont)); 28 return captionFont; 29 } 30 } 31 32 public static Font SmallCaptionFont 33 { 34 get 35 { 36 Font smcaptionFont = null; 37 38 var data = new NativeMethods.NONCLIENTMETRICS(); 39 bool result = UnsafeNativeMethods.SystemParametersInfo(NativeMethods.SPI_GETNONCLIENTMETRICS, data.cbSize, data, 0); 40 41 if (result) 42 { 43 smcaptionFont = GetFontFromData(data.lfSmCaptionFont); 44 } 45 46 smcaptionFont.SetSystemFontName(nameof(SmallCaptionFont)); 47 return smcaptionFont; 48 } 49 } 50 51 public static Font MenuFont 52 { 53 get 54 { 55 Font menuFont = null; 56 57 var data = new NativeMethods.NONCLIENTMETRICS(); 58 bool result = UnsafeNativeMethods.SystemParametersInfo(NativeMethods.SPI_GETNONCLIENTMETRICS, data.cbSize, data, 0); 59 60 if (result) 61 { 62 menuFont = GetFontFromData(data.lfMenuFont); 63 } 64 65 menuFont.SetSystemFontName(nameof(MenuFont)); 66 return menuFont; 67 } 68 } 69 70 public static Font StatusFont 71 { 72 get 73 { 74 Font statusFont = null; 75 76 var data = new NativeMethods.NONCLIENTMETRICS(); 77 bool result = UnsafeNativeMethods.SystemParametersInfo(NativeMethods.SPI_GETNONCLIENTMETRICS, data.cbSize, data, 0); 78 79 if (result) 80 { 81 statusFont = GetFontFromData(data.lfStatusFont); 82 } 83 84 statusFont.SetSystemFontName(nameof(StatusFont)); 85 return statusFont; 86 } 87 } 88 89 public static Font MessageBoxFont 90 { 91 get 92 { 93 Font messageBoxFont = null; 94 95 var data = new NativeMethods.NONCLIENTMETRICS(); 96 bool result = UnsafeNativeMethods.SystemParametersInfo(NativeMethods.SPI_GETNONCLIENTMETRICS, data.cbSize, data, 0); 97 98 if (result) 99 { 100 messageBoxFont = GetFontFromData(data.lfMessageFont); 101 } 102 103 messageBoxFont.SetSystemFontName(nameof(MessageBoxFont)); 104 return messageBoxFont; 105 } 106 } 107 IsCriticalFontException(Exception ex)108 private static bool IsCriticalFontException(Exception ex) 109 { 110 return !( 111 // In any of these cases we'll handle the exception. 112 ex is ExternalException || 113 ex is ArgumentException || 114 ex is OutOfMemoryException || // GDI+ throws this one for many reasons other than actual OOM. 115 ex is InvalidOperationException || 116 ex is NotImplementedException || 117 ex is FileNotFoundException); 118 } 119 120 public static Font IconTitleFont 121 { 122 get 123 { 124 Font iconTitleFont = null; 125 126 var itfont = new SafeNativeMethods.LOGFONT(); 127 bool result = UnsafeNativeMethods.SystemParametersInfo(NativeMethods.SPI_GETICONTITLELOGFONT, Marshal.SizeOf(itfont), itfont, 0); 128 129 if (result) 130 { 131 iconTitleFont = GetFontFromData(itfont); 132 } 133 134 iconTitleFont.SetSystemFontName(nameof(IconTitleFont)); 135 return iconTitleFont; 136 } 137 } 138 139 public static Font DefaultFont 140 { 141 get 142 { 143 Font defaultFont = null; 144 145 // For Arabic systems, always return Tahoma 8. 146 bool systemDefaultLCIDIsArabic = (UnsafeNativeMethods.GetSystemDefaultLCID() & 0x3ff) == 0x0001; 147 if (systemDefaultLCIDIsArabic) 148 { 149 try 150 { 151 defaultFont = new Font("Tahoma", 8); 152 } 153 catch (Exception ex) when (!IsCriticalFontException(ex)) { } 154 } 155 156 // First try DEFAULT_GUI. 157 if (defaultFont == null) 158 { 159 IntPtr handle = UnsafeNativeMethods.GetStockObject(NativeMethods.DEFAULT_GUI_FONT); 160 try 161 { 162 using (Font fontInWorldUnits = Font.FromHfont(handle)) 163 { 164 defaultFont = FontInPoints(fontInWorldUnits); 165 } 166 } 167 catch (ArgumentException) 168 { 169 } 170 } 171 172 // If DEFAULT_GUI didn't work, try Tahoma. 173 if (defaultFont == null) 174 { 175 try 176 { 177 defaultFont = new Font("Tahoma", 8); 178 } 179 catch (ArgumentException) 180 { 181 } 182 } 183 184 // Use GenericSansSerif as a last resort - this will always work. 185 if (defaultFont == null) 186 { 187 defaultFont = new Font(FontFamily.GenericSansSerif, 8); 188 } 189 190 if (defaultFont.Unit != GraphicsUnit.Point) 191 { 192 defaultFont = FontInPoints(defaultFont); 193 } 194 195 Debug.Assert(defaultFont != null, "defaultFont wasn't set."); 196 197 defaultFont.SetSystemFontName(nameof(DefaultFont)); 198 return defaultFont; 199 } 200 } 201 202 public static Font DialogFont 203 { 204 get 205 { 206 Font dialogFont = null; 207 208 if ((UnsafeNativeMethods.GetSystemDefaultLCID() & 0x3ff) == 0x0011) 209 { 210 // Always return DefaultFont for Japanese cultures. 211 dialogFont = DefaultFont; 212 } 213 else 214 { 215 try 216 { 217 // Use MS Shell Dlg 2, 8pt for anything other than than Japanese. 218 dialogFont = new Font("MS Shell Dlg 2", 8); 219 } 220 catch (ArgumentException) 221 { 222 } 223 } 224 225 if (dialogFont == null) 226 { 227 dialogFont = DefaultFont; 228 } 229 else if (dialogFont.Unit != GraphicsUnit.Point) 230 { 231 dialogFont = FontInPoints(dialogFont); 232 } 233 234 // For Japanese cultures, SystemFonts.DefaultFont returns a new Font object every time it is invoked. 235 // So for Japanese we return the DefaultFont with its SystemFontName set to DialogFont. 236 dialogFont.SetSystemFontName(nameof(DialogFont)); 237 return dialogFont; 238 } 239 } 240 FontInPoints(Font font)241 private static Font FontInPoints(Font font) 242 { 243 return new Font(font.FontFamily, font.SizeInPoints, font.Style, GraphicsUnit.Point, font.GdiCharSet, font.GdiVerticalFont); 244 } 245 GetFontFromData(SafeNativeMethods.LOGFONT logFont)246 private static Font GetFontFromData(SafeNativeMethods.LOGFONT logFont) 247 { 248 if (logFont == null) 249 { 250 return null; 251 } 252 253 Font font = null; 254 try 255 { 256 font = Font.FromLogFont(logFont); 257 } 258 catch (Exception ex) when (!IsCriticalFontException(ex)) { } 259 260 return 261 font == null ? DefaultFont : 262 font.Unit != GraphicsUnit.Point ? FontInPoints(font) : 263 font; 264 } 265 } 266 } 267