diff --git a/Wox.Core/Exception/ExceptionFormatter.cs b/Wox.Core/Exception/ExceptionFormatter.cs new file mode 100644 index 0000000000..ee3095b3e2 --- /dev/null +++ b/Wox.Core/Exception/ExceptionFormatter.cs @@ -0,0 +1,206 @@ +using System; +using System.Collections.Generic; +using System.Diagnostics; +using System.Linq; +using System.Text; +using System.Xml; +using Microsoft.Win32; + +namespace Wox.Core.Exception +{ + public class ExceptionFormatter + { + public static string FormatExcpetion(object exception) + { + return CreateExceptionReport(exception); + } + + private static string CreateExceptionReport(object exceptionObject) + { + var sb = new StringBuilder(); + sb.AppendLine("## Exception"); + sb.AppendLine(); + sb.AppendLine("```"); + + var ex = exceptionObject as System.Exception; + if (ex != null) + { + var exlist = new List(); + + while (ex != null) + { + var exsb = new StringBuilder(); + exsb.Append(ex.GetType().FullName); + exsb.Append(": "); + exsb.AppendLine(ex.Message); + if (ex.Source != null) + { + exsb.Append(" Source: "); + exsb.AppendLine(ex.Source); + } + if (ex.TargetSite != null) + { + exsb.Append(" TargetAssembly: "); + exsb.AppendLine(ex.TargetSite.Module.Assembly.ToString()); + exsb.Append(" TargetModule: "); + exsb.AppendLine(ex.TargetSite.Module.ToString()); + exsb.Append(" TargetSite: "); + exsb.AppendLine(ex.TargetSite.ToString()); + } + exsb.AppendLine(ex.StackTrace); + exlist.Add(exsb); + + ex = ex.InnerException; + } + + foreach (var result in exlist.Select(o => o.ToString()).Reverse()) + { + sb.AppendLine(result); + } + sb.AppendLine("```"); + sb.AppendLine(); + } + else + { + sb.AppendLine(exceptionObject.GetType().FullName); + sb.AppendLine(new StackTrace().ToString()); + sb.AppendLine("```"); + sb.AppendLine(); + } + + sb.AppendLine("## Environment"); + sb.AppendLine(); + sb.Append("* Command Line: "); + sb.AppendLine(Environment.CommandLine); + sb.Append("* Timestamp: "); + sb.AppendLine(XmlConvert.ToString(DateTime.Now)); + sb.Append("* IntPtr Length: "); + sb.AppendLine(IntPtr.Size.ToString()); + sb.Append("* System Version: "); + sb.AppendLine(Environment.OSVersion.VersionString); + sb.Append("* CLR Version: "); + sb.AppendLine(Environment.Version.ToString()); + sb.AppendLine("* Installed .NET Framework: "); + foreach (var result in GetFrameworkVersionFromRegistry()) + { + sb.Append(" * "); + sb.AppendLine(result); + } + + sb.AppendLine(); + sb.AppendLine("## Assemblies - " + System.AppDomain.CurrentDomain.FriendlyName); + sb.AppendLine(); + foreach (var ass in System.AppDomain.CurrentDomain.GetAssemblies().OrderBy(o => o.GlobalAssemblyCache ? 100 : 0)) + { + sb.Append("* "); + sb.Append(ass.FullName); + sb.Append(" ("); + sb.Append(string.IsNullOrEmpty(ass.Location) ? "not supported" : ass.Location); + sb.AppendLine(")"); + } + + var process = System.Diagnostics.Process.GetCurrentProcess(); + sb.AppendLine(); + sb.AppendLine("## Modules - " + process.ProcessName); + sb.AppendLine(); + foreach (ProcessModule mod in process.Modules) + { + sb.Append("* "); + sb.Append(mod.FileName); + sb.Append(" ("); + sb.Append(mod.FileVersionInfo.FileDescription); + sb.Append(", "); + sb.Append(mod.FileVersionInfo.FileVersion); + sb.Append(", "); + sb.Append(mod.FileVersionInfo.ProductName); + sb.Append(", "); + sb.Append(mod.FileVersionInfo.ProductVersion); + sb.Append(", "); + sb.Append(mod.FileVersionInfo.CompanyName); + sb.Append("), "); + sb.Append(string.Format("0x{0:X16}", mod.BaseAddress.ToInt64())); + sb.AppendLine(); + } + + sb.AppendLine(); + sb.AppendLine("## Threads - " + process.Threads.Count); + sb.AppendLine(); + foreach (ProcessThread th in process.Threads) + { + sb.Append("* "); + sb.AppendLine(string.Format("{0}, {1} {2}, Started: {3}, StartAddress: 0x{4:X16}", th.Id, th.ThreadState, th.PriorityLevel, th.StartTime, th.StartAddress.ToInt64())); + } + + return sb.ToString(); + } + + // http://msdn.microsoft.com/en-us/library/hh925568%28v=vs.110%29.aspx + private static List GetFrameworkVersionFromRegistry() + { + try + { + var result = new List(); + using (RegistryKey ndpKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\")) + { + foreach (string versionKeyName in ndpKey.GetSubKeyNames()) + { + if (versionKeyName.StartsWith("v")) + { + RegistryKey versionKey = ndpKey.OpenSubKey(versionKeyName); + string name = (string)versionKey.GetValue("Version", ""); + string sp = versionKey.GetValue("SP", "").ToString(); + string install = versionKey.GetValue("Install", "").ToString(); + if (install != "") + if (sp != "" && install == "1") + result.Add(string.Format("{0} {1} SP{2}", versionKeyName, name, sp)); + else + result.Add(string.Format("{0} {1}", versionKeyName, name)); + + if (name != "") + { + continue; + } + foreach (string subKeyName in versionKey.GetSubKeyNames()) + { + RegistryKey subKey = versionKey.OpenSubKey(subKeyName); + name = (string)subKey.GetValue("Version", ""); + if (name != "") + sp = subKey.GetValue("SP", "").ToString(); + install = subKey.GetValue("Install", "").ToString(); + if (install != "") + { + if (sp != "" && install == "1") + result.Add(string.Format("{0} {1} {2} SP{3}", versionKeyName, subKeyName, name, sp)); + else if (install == "1") + result.Add(string.Format("{0} {1} {2}", versionKeyName, subKeyName, name)); + } + + } + + } + } + } + using (RegistryKey ndpKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\")) + { + int releaseKey = (int)ndpKey.GetValue("Release"); + { + if (releaseKey == 378389) + result.Add("v4.5"); + + if (releaseKey == 378675) + result.Add("v4.5.1 installed with Windows 8.1"); + + if (releaseKey == 378758) + result.Add("4.5.1 installed on Windows 8, Windows 7 SP1, or Windows Vista SP2"); + } + } + return result; + } + catch (System.Exception e) + { + return new List(); + } + + } + } +} diff --git a/Wox.Core/Plugin/PluginConfig.cs b/Wox.Core/Plugin/PluginConfig.cs index 9cc9952cf1..008d889248 100644 --- a/Wox.Core/Plugin/PluginConfig.cs +++ b/Wox.Core/Plugin/PluginConfig.cs @@ -41,6 +41,13 @@ namespace Wox.Core.Plugin private static void ParseSystemPlugins() { + string systemPluginPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), + "Wox.Plugin.SystemPlugins.dll"); + if (!File.Exists(systemPluginPath)) + { + throw new WoxCritialException("System Plugin DLL is missing."); + } + pluginMetadatas.Add(new PluginMetadata() { Name = "System Plugins", @@ -65,8 +72,15 @@ namespace Wox.Core.Plugin { if (File.Exists((Path.Combine(directory, "NeedDelete.txt")))) { - Directory.Delete(directory, true); - continue; + try + { + Directory.Delete(directory, true); + continue; + } + catch (System.Exception e) + { + Log.Error(ExceptionFormatter.FormatExcpetion(e)); + } } PluginMetadata metadata = GetPluginMetadata(directory); if (metadata != null) diff --git a/Wox.Core/Plugin/PluginManager.cs b/Wox.Core/Plugin/PluginManager.cs index cdf22a2181..0d86afe233 100644 --- a/Wox.Core/Plugin/PluginManager.cs +++ b/Wox.Core/Plugin/PluginManager.cs @@ -4,6 +4,7 @@ using System.IO; using System.Linq; using System.Reflection; using System.Threading; +using Wox.Core.Exception; using Wox.Infrastructure.Http; using Wox.Infrastructure.Logger; using Wox.Plugin; @@ -35,17 +36,19 @@ namespace Wox.Core.Plugin get { string userProfilePath = Environment.GetEnvironmentVariable("USERPROFILE"); - if (userProfilePath != null) + if (string.IsNullOrEmpty(userProfilePath)) { - return Path.Combine(Path.Combine(userProfilePath, ".Wox"), "Plugins"); + throw new WoxCritialException("Wox Can't Find Environment Variable UserProfile"); } - return string.Empty; + return Path.Combine(Path.Combine(userProfilePath, ".Wox"), "Plugins"); } } - static PluginManager() + private static void SetupPluginDirectories() { + pluginDirectories.Clear(); + pluginDirectories.Add(DefaultPluginDirectory); pluginDirectories.Add( Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Plugins")); @@ -76,6 +79,9 @@ namespace Wox.Core.Plugin /// public static void Init(IPublicAPI api) { + if (api == null) throw new WoxCritialException("api is null"); + + SetupPluginDirectories(); API = api; plugins.Clear(); diff --git a/Wox.Core/Wox.Core.csproj b/Wox.Core/Wox.Core.csproj index ce60a7f391..310f255fd7 100644 --- a/Wox.Core/Wox.Core.csproj +++ b/Wox.Core/Wox.Core.csproj @@ -49,6 +49,7 @@ + diff --git a/Wox.Infrastructure/Logger/Log.cs b/Wox.Infrastructure/Logger/Log.cs index 3860b76173..1144ac5b98 100644 --- a/Wox.Infrastructure/Logger/Log.cs +++ b/Wox.Infrastructure/Logger/Log.cs @@ -1,4 +1,5 @@ -using System.Reflection; +using System; +using System.Reflection; using log4net; namespace Wox.Infrastructure.Logger diff --git a/Wox.Test/Plugins/PluginInitTest.cs b/Wox.Test/Plugins/PluginInitTest.cs new file mode 100644 index 0000000000..8d41088874 --- /dev/null +++ b/Wox.Test/Plugins/PluginInitTest.cs @@ -0,0 +1,31 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using Moq; +using NUnit.Framework; +using Wox.Core.Exception; +using Wox.Core.Plugin; +using Wox.Plugin; + +namespace Wox.Test.Plugins +{ + + [TestFixture] + public class PluginInitTest + { + [Test] + public void CouldNotFindUserProfileTest() + { + var api = new Mock(); + Environment.SetEnvironmentVariable("USERPROFILE", ""); + Assert.Throws(typeof(WoxCritialException), () => PluginManager.Init(api.Object)); + } + + [Test] + public void PublicAPIIsNullTest() + { + Assert.Throws(typeof(WoxCritialException), () => PluginManager.Init(null)); + } + } +} diff --git a/Wox.Test/Wox.Test.csproj b/Wox.Test/Wox.Test.csproj index 5d9beedcea..95b03e737d 100644 --- a/Wox.Test/Wox.Test.csproj +++ b/Wox.Test/Wox.Test.csproj @@ -32,6 +32,9 @@ 4 + + ..\packages\Moq.4.2.1409.1722\lib\net35\Moq.dll + ..\packages\NUnit.2.6.3\lib\nunit.framework.dll @@ -44,6 +47,7 @@ + @@ -52,6 +56,10 @@ + + {B749F0DB-8E75-47DB-9E5E-265D16D0C0D2} + Wox.Core + {4FD29318-A8AB-4D8F-AA47-60BC241B8DA3} Wox.Infrastructure diff --git a/Wox.Test/packages.config b/Wox.Test/packages.config index 11e8d22bed..27bc1f3865 100644 --- a/Wox.Test/packages.config +++ b/Wox.Test/packages.config @@ -1,4 +1,5 @@  + \ No newline at end of file diff --git a/Wox/Helper/ErrorReporting/ErrorReporting.cs b/Wox/Helper/ErrorReporting/ErrorReporting.cs index 06e0eae107..a373edb4dd 100644 --- a/Wox/Helper/ErrorReporting/ErrorReporting.cs +++ b/Wox/Helper/ErrorReporting/ErrorReporting.cs @@ -8,6 +8,7 @@ using System.Windows.Forms; using System.Windows.Threading; using System.Xml; using Microsoft.Win32; +using Wox.Core.Exception; using Wox.Infrastructure.Logger; namespace Wox.Helper.ErrorReporting @@ -16,10 +17,9 @@ namespace Wox.Helper.ErrorReporting { public static void UnhandledExceptionHandle(object sender, System.UnhandledExceptionEventArgs e) { - if (System.Diagnostics.Debugger.IsAttached) return; - - string error = CreateExceptionReport("System.AppDomain.UnhandledException", e.ExceptionObject); + if (Debugger.IsAttached) return; + string error = ExceptionFormatter.FormatExcpetion(e.ExceptionObject); //e.IsTerminating is always true in most times, so try to avoid use this property //http://stackoverflow.com/questions/10982443/what-causes-the-unhandledexceptioneventargs-isterminating-flag-to-be-true-or-fal Log.Error(error); @@ -31,211 +31,22 @@ namespace Wox.Helper.ErrorReporting if (Debugger.IsAttached) return; e.Handled = true; - string error = CreateExceptionReport("System.Windows.Application.DispatcherUnhandledException", e.Exception); + string error = ExceptionFormatter.FormatExcpetion(e.Exception); Log.Error(error); TryShowErrorMessageBox(error, e.Exception); } + public static void ThreadException(object sender, System.Threading.ThreadExceptionEventArgs e) { if (Debugger.IsAttached) return; - string error = CreateExceptionReport("System.Windows.Forms.Application.ThreadException", e.Exception); + string error = ExceptionFormatter.FormatExcpetion(e.Exception); Log.Fatal(error); TryShowErrorMessageBox(error, e.Exception); } - private static string CreateExceptionReport(string ev, object exceptionObject) - { - var sb = new StringBuilder(); - sb.AppendLine("## Exception"); - sb.AppendLine(); - sb.AppendLine("```"); - - var ex = exceptionObject as Exception; - if (ex != null) - { - var exlist = new List(); - - while (ex != null) - { - var exsb = new StringBuilder(); - exsb.Append(ex.GetType().FullName); - exsb.Append(": "); - exsb.AppendLine(ex.Message); - if (ex.Source != null) - { - exsb.Append(" Source: "); - exsb.AppendLine(ex.Source); - } - if (ex.TargetSite != null) - { - exsb.Append(" TargetAssembly: "); - exsb.AppendLine(ex.TargetSite.Module.Assembly.ToString()); - exsb.Append(" TargetModule: "); - exsb.AppendLine(ex.TargetSite.Module.ToString()); - exsb.Append(" TargetSite: "); - exsb.AppendLine(ex.TargetSite.ToString()); - } - exsb.AppendLine(ex.StackTrace); - exlist.Add(exsb); - - ex = ex.InnerException; - } - - foreach (var result in exlist.Select(o => o.ToString()).Reverse()) - { - sb.AppendLine(result); - } - sb.AppendLine("```"); - sb.AppendLine(); - } - else - { - sb.AppendLine(exceptionObject.GetType().FullName); - sb.AppendLine(new StackTrace().ToString()); - sb.AppendLine("```"); - sb.AppendLine(); - } - - sb.AppendLine("## Environment"); - sb.AppendLine(); - sb.Append("* Command Line: "); - sb.AppendLine(Environment.CommandLine); - sb.Append("* Exception Handle: "); - sb.AppendLine(ev); - sb.Append("* Timestamp: "); - sb.AppendLine(XmlConvert.ToString(DateTime.Now)); - sb.Append("* IntPtr Length: "); - sb.AppendLine(IntPtr.Size.ToString()); - sb.Append("* System Version: "); - sb.AppendLine(Environment.OSVersion.VersionString); - sb.Append("* CLR Version: "); - sb.AppendLine(Environment.Version.ToString()); - sb.AppendLine("* Installed .NET Framework: "); - foreach (var result in GetFrameworkVersionFromRegistry()) - { - sb.Append(" * "); - sb.AppendLine(result); - } - - sb.AppendLine(); - sb.AppendLine("## Assemblies - " + System.AppDomain.CurrentDomain.FriendlyName); - sb.AppendLine(); - foreach (var ass in System.AppDomain.CurrentDomain.GetAssemblies().OrderBy(o => o.GlobalAssemblyCache ? 100 : 0)) - { - sb.Append("* "); - sb.Append(ass.FullName); - sb.Append(" ("); - sb.Append(SyntaxSugars.CallOrRescueDefault(() => ass.Location, "not supported")); - sb.AppendLine(")"); - } - - var process = System.Diagnostics.Process.GetCurrentProcess(); - sb.AppendLine(); - sb.AppendLine("## Modules - " + process.ProcessName); - sb.AppendLine(); - foreach (ProcessModule mod in process.Modules) - { - sb.Append("* "); - sb.Append(mod.FileName); - sb.Append(" ("); - sb.Append(mod.FileVersionInfo.FileDescription); - sb.Append(", "); - sb.Append(mod.FileVersionInfo.FileVersion); - sb.Append(", "); - sb.Append(mod.FileVersionInfo.ProductName); - sb.Append(", "); - sb.Append(mod.FileVersionInfo.ProductVersion); - sb.Append(", "); - sb.Append(mod.FileVersionInfo.CompanyName); - sb.Append("), "); - sb.Append(string.Format("0x{0:X16}", mod.BaseAddress.ToInt64())); - sb.AppendLine(); - } - - sb.AppendLine(); - sb.AppendLine("## Threads - " + process.Threads.Count); - sb.AppendLine(); - foreach (ProcessThread th in process.Threads) - { - sb.Append("* "); - sb.AppendLine(string.Format("{0}, {1} {2}, Started: {3}, StartAddress: 0x{4:X16}", th.Id, th.ThreadState, th.PriorityLevel, th.StartTime, th.StartAddress.ToInt64())); - } - - return sb.ToString(); - } - - // http://msdn.microsoft.com/en-us/library/hh925568%28v=vs.110%29.aspx - private static List GetFrameworkVersionFromRegistry() - { - try - { - var result = new List(); - using (RegistryKey ndpKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\")) - { - foreach (string versionKeyName in ndpKey.GetSubKeyNames()) - { - if (versionKeyName.StartsWith("v")) - { - RegistryKey versionKey = ndpKey.OpenSubKey(versionKeyName); - string name = (string)versionKey.GetValue("Version", ""); - string sp = versionKey.GetValue("SP", "").ToString(); - string install = versionKey.GetValue("Install", "").ToString(); - if (install != "") - if (sp != "" && install == "1") - result.Add(string.Format("{0} {1} SP{2}", versionKeyName, name, sp)); - else - result.Add(string.Format("{0} {1}", versionKeyName, name)); - - if (name != "") - { - continue; - } - foreach (string subKeyName in versionKey.GetSubKeyNames()) - { - RegistryKey subKey = versionKey.OpenSubKey(subKeyName); - name = (string)subKey.GetValue("Version", ""); - if (name != "") - sp = subKey.GetValue("SP", "").ToString(); - install = subKey.GetValue("Install", "").ToString(); - if (install != "") - { - if (sp != "" && install == "1") - result.Add(string.Format("{0} {1} {2} SP{3}", versionKeyName, subKeyName, name, sp)); - else if (install == "1") - result.Add(string.Format("{0} {1} {2}", versionKeyName, subKeyName, name)); - } - - } - - } - } - } - using (RegistryKey ndpKey = Registry.LocalMachine.OpenSubKey(@"SOFTWARE\Microsoft\NET Framework Setup\NDP\v4\Full\")) - { - int releaseKey = (int)ndpKey.GetValue("Release"); - { - if (releaseKey == 378389) - result.Add("v4.5"); - - if (releaseKey == 378675) - result.Add("v4.5.1 installed with Windows 8.1"); - - if (releaseKey == 378758) - result.Add("4.5.1 installed on Windows 8, Windows 7 SP1, or Windows Vista SP2"); - } - } - return result; - } - catch (Exception e) - { - return new List(); - } - - } - public static bool TryShowErrorMessageBox(string error, object exceptionObject) { var title = "Wox - Unhandled Exception"; @@ -271,11 +82,13 @@ namespace Wox.Helper.ErrorReporting var dialog = new WPFErrorReportingDialog(error, title, exceptionObject); dialog.ShowDialog(); } + private static void ShowWPFMessageBox(string error, string title) { System.Windows.MessageBox.Show(error, title, MessageBoxButton.OK, MessageBoxImage.Error, MessageBoxResult.OK, System.Windows.MessageBoxOptions.None); } + private static void ShowWindowsFormsMessageBox(string error, string title) { System.Windows.Forms.MessageBox.Show(error, title, MessageBoxButtons.OK,