ExceptionFormatter.cs
1 // Copyright (c) Microsoft Corporation 2 // The Microsoft Corporation 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; 6 using System.Collections.Generic; 7 using System.Globalization; 8 using System.Linq; 9 using System.Reflection; 10 using System.Text; 11 12 using Microsoft.Win32; 13 using Wox.Plugin; 14 using Wox.Plugin.Logger; 15 16 namespace Wox.Infrastructure.Exception 17 { 18 public static class ExceptionFormatter 19 { 20 public static string FormatException(System.Exception exception) 21 { 22 return CreateExceptionReport(exception); 23 } 24 25 // todo log /display line by line 26 private static string CreateExceptionReport(System.Exception ex) 27 { 28 var sb = new StringBuilder(); 29 sb.AppendLine(); 30 sb.AppendLine("## Exception"); 31 sb.AppendLine(); 32 sb.AppendLine("```"); 33 34 var exlist = new List<StringBuilder>(); 35 36 while (ex != null) 37 { 38 var exsb = new StringBuilder(); 39 exsb.Append(ex.GetType().FullName); 40 exsb.Append(": "); 41 exsb.AppendLine(ex.Message); 42 if (ex.Source != null) 43 { 44 exsb.Append(" Source: "); 45 exsb.AppendLine(ex.Source); 46 } 47 48 if (ex.TargetSite != null) 49 { 50 exsb.Append(" TargetAssembly: "); 51 exsb.AppendLine(ex.TargetSite.Module.Assembly.ToString()); 52 exsb.Append(" TargetModule: "); 53 exsb.AppendLine(ex.TargetSite.Module.ToString()); 54 exsb.Append(" TargetSite: "); 55 exsb.AppendLine(ex.TargetSite.ToString()); 56 } 57 58 exsb.AppendLine(ex.StackTrace); 59 exlist.Add(exsb); 60 61 ex = ex.InnerException; 62 } 63 64 foreach (var result in exlist.Select(o => o.ToString()).Reverse()) 65 { 66 sb.AppendLine(result); 67 } 68 69 sb.AppendLine("```"); 70 sb.AppendLine(); 71 72 sb.AppendLine("## Environment"); 73 sb.AppendLine(CultureInfo.InvariantCulture, $"* Command Line: {Environment.CommandLine}"); 74 75 // Using InvariantCulture since this is internal 76 sb.AppendLine(CultureInfo.InvariantCulture, $"* Timestamp: {DateTime.Now.ToString(CultureInfo.InvariantCulture)}"); 77 sb.AppendLine(CultureInfo.InvariantCulture, $"* Wox version: {Constant.Version}"); 78 sb.AppendLine(CultureInfo.InvariantCulture, $"* OS Version: {Environment.OSVersion.VersionString}"); 79 sb.AppendLine(CultureInfo.InvariantCulture, $"* IntPtr Length: {IntPtr.Size}"); 80 sb.AppendLine(CultureInfo.InvariantCulture, $"* x64: {Environment.Is64BitOperatingSystem}"); 81 sb.AppendLine(CultureInfo.InvariantCulture, $"* CLR Version: {Environment.Version}"); 82 sb.AppendLine(CultureInfo.InvariantCulture, $"* Installed .NET Framework: "); 83 foreach (var result in GetFrameworkVersionFromRegistry()) 84 { 85 sb.Append(" * "); 86 sb.AppendLine(result); 87 } 88 89 sb.AppendLine(); 90 sb.AppendLine("## Assemblies - " + AppDomain.CurrentDomain.FriendlyName); 91 sb.AppendLine(); 92 93 // GlobalAssemblyCache - .NET Core and .NET 5 and later: false in all cases. 94 // Source https://learn.microsoft.com/dotnet/api/system.reflection.assembly.globalassemblycache?view=net-6.0 95 foreach (var assembly in AppDomain.CurrentDomain.GetAssemblies()) 96 { 97 sb.Append("* "); 98 sb.Append(assembly.FullName); 99 sb.Append(" ("); 100 101 if (assembly.IsDynamic) 102 { 103 sb.Append("dynamic assembly doesn't has location"); 104 } 105 else if (string.IsNullOrEmpty(assembly.Location)) 106 { 107 sb.Append("location is null or empty"); 108 } 109 else 110 { 111 sb.Append(assembly.Location); 112 } 113 114 sb.AppendLine(")"); 115 } 116 117 return sb.ToString(); 118 } 119 120 // http://msdn.microsoft.com/library/hh925568%28v=vs.110%29.aspx 121 private static List<string> GetFrameworkVersionFromRegistry() 122 { 123 try 124 { 125 var result = new List<string>(); 126 using (RegistryKey ndpKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\")) 127 { 128 foreach (string versionKeyName in ndpKey.GetSubKeyNames()) 129 { 130 // Using InvariantCulture since this is internal and involves version key 131 if (versionKeyName.StartsWith('v')) 132 { 133 RegistryKey versionKey = ndpKey.OpenSubKey(versionKeyName); 134 string name = (string)versionKey.GetValue("Version", string.Empty); 135 string sp = versionKey.GetValue("SP", string.Empty).ToString(); 136 string install = versionKey.GetValue("Install", string.Empty).ToString(); 137 if (!string.IsNullOrEmpty(install)) 138 { 139 if (!string.IsNullOrEmpty(sp) && install == "1") 140 { 141 // Using InvariantCulture since this is internal 142 result.Add(string.Format(CultureInfo.InvariantCulture, "{0} {1} SP{2}", versionKeyName, name, sp)); 143 } 144 else 145 { 146 // Using InvariantCulture since this is internal 147 result.Add(string.Format(CultureInfo.InvariantCulture, "{0} {1}", versionKeyName, name)); 148 } 149 } 150 151 if (!string.IsNullOrEmpty(name)) 152 { 153 continue; 154 } 155 156 foreach (string subKeyName in versionKey.GetSubKeyNames()) 157 { 158 RegistryKey subKey = versionKey.OpenSubKey(subKeyName); 159 name = (string)subKey.GetValue("Version", string.Empty); 160 if (!string.IsNullOrEmpty(name)) 161 { 162 sp = subKey.GetValue("SP", string.Empty).ToString(); 163 } 164 165 install = subKey.GetValue("Install", string.Empty).ToString(); 166 if (!string.IsNullOrEmpty(install)) 167 { 168 if (!string.IsNullOrEmpty(sp) && install == "1") 169 { 170 // Using InvariantCulture since this is internal 171 result.Add(string.Format(CultureInfo.InvariantCulture, "{0} {1} {2} SP{3}", versionKeyName, subKeyName, name, sp)); 172 } 173 else if (install == "1") 174 { 175 // Using InvariantCulture since this is internal 176 result.Add(string.Format(CultureInfo.InvariantCulture, "{0} {1} {2}", versionKeyName, subKeyName, name)); 177 } 178 } 179 } 180 } 181 } 182 } 183 184 using (RegistryKey ndpKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\")) 185 { 186 int releaseKey = (int)ndpKey.GetValue("Release"); 187 { 188 if (releaseKey == 378389) 189 { 190 result.Add("v4.5"); 191 } 192 193 if (releaseKey == 378675) 194 { 195 result.Add("v4.5.1 installed with Windows 8.1"); 196 } 197 198 if (releaseKey == 378758) 199 { 200 result.Add("4.5.1 installed on Windows 8, Windows 7 SP1, or Windows Vista SP2"); 201 } 202 } 203 } 204 205 return result; 206 } 207 catch (System.Exception e) 208 { 209 Log.Exception("Could not get framework version from registry", e, MethodBase.GetCurrentMethod().DeclaringType); 210 return new List<string>(); 211 } 212 } 213 } 214 }