/ src / modules / launcher / Wox.Infrastructure / Exception / ExceptionFormatter.cs
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  }