diff --git a/Deploy/Installer/Installer.iss b/Deploy/Installer/Installer.iss index 21f08fd913..253572eef3 100644 --- a/Deploy/Installer/Installer.iss +++ b/Deploy/Installer/Installer.iss @@ -29,11 +29,13 @@ Name: english; MessagesFile: compiler:Default.isl Type: files; Name: "{commonstartup}\{#MyAppName}.lnk" [Tasks] -Name: desktopicon; Description: {cm:CreateDesktopIcon}; GroupDescription: {cm:AdditionalIcons}; Flags: unchecked +Name: desktopicon; Description: {cm:CreateDesktopIcon}; GroupDescription: {cm:AdditionalIcons}; Name: startupfolder; Description: Startup with Windows; [Files] -Source: {#MyAppPath}\*; DestDir: {app}; Flags: ignoreversion recursesubdirs +Source: {#MyAppPath}\*; Excludes: Plugins\*,Themes\*; DestDir: {app}; Flags: ignoreversion recursesubdirs +Source: {#MyAppPath}\Plugins\*; DestDir: {%USERPROFILE}\.Wox\Plugins; Flags: ignoreversion recursesubdirs +Source: {#MyAppPath}\Themes\*; DestDir: {%USERPROFILE}\.Wox\Themes; Flags: ignoreversion recursesubdirs [Icons] Name: {group}\{#MyAppName}; Filename: {app}\{#MyAppExeName} @@ -42,4 +44,10 @@ Name: {userdesktop}\{#MyAppName}; Filename: {app}\{#MyAppExeName}; Tasks: deskto Name: {userstartup}\{#MyAppName}; Filename: {app}\{#MyAppExeName}; Tasks: startupfolder [Run] -Filename: {app}\{#MyAppExeName}; Description: {cm:LaunchProgram,{#MyAppName}}; Flags: nowait postinstall skipifsilent +Filename: {app}\{#MyAppExeName}; Description: {cm:LaunchProgram,{#MyAppName}}; Flags: nowait postinstall skipifsilent unchecked + +[UninstallDelete] +Type: filesandordirs; Name: "{%USERPROFILE}\.Wox" + +[UninstallRun] +Filename: {sys}\taskkill.exe; Parameters: "/f /im Wox.exe"; Flags: skipifdoesntexist runhidden diff --git a/Plugins/Wox.Plugin.PluginManagement/Main.cs b/Plugins/Wox.Plugin.PluginManagement/Main.cs index 960a2c328c..a2153610d7 100644 --- a/Plugins/Wox.Plugin.PluginManagement/Main.cs +++ b/Plugins/Wox.Plugin.PluginManagement/Main.cs @@ -197,7 +197,7 @@ namespace Wox.Plugin.PluginManagement private List ListUnInstalledPlugins(Query query) { List results = new List(); - List allInstalledPlugins = ParseThirdPartyPlugins(); + List allInstalledPlugins = ParseUserPlugins(); if (query.ActionParameters.Count > 1) { string pluginName = query.ActionParameters[1]; @@ -235,7 +235,7 @@ namespace Wox.Plugin.PluginManagement private List ListInstalledPlugins() { List results = new List(); - foreach (PluginMetadata plugin in ParseThirdPartyPlugins()) + foreach (PluginMetadata plugin in ParseUserPlugins()) { results.Add(new Result() { @@ -247,7 +247,7 @@ namespace Wox.Plugin.PluginManagement return results; } - private static List ParseThirdPartyPlugins() + private static List ParseUserPlugins() { List pluginMetadatas = new List(); if (!Directory.Exists(PluginPath)) @@ -276,7 +276,7 @@ namespace Wox.Plugin.PluginManagement try { metadata = JsonConvert.DeserializeObject(File.ReadAllText(configPath)); - metadata.PluginType = PluginType.ThirdParty; + metadata.PluginType = PluginType.User; metadata.PluginDirectory = pluginDirectory; } catch (Exception) 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/Exception/WoxCritialException.cs b/Wox.Core/Exception/WoxCritialException.cs new file mode 100644 index 0000000000..76aea3dea6 --- /dev/null +++ b/Wox.Core/Exception/WoxCritialException.cs @@ -0,0 +1,17 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Wox.Core.Exception +{ + /// + /// Represent exceptions that wox can't handle and MUST close running Wox. + /// + public class WoxCritialException : WoxException + { + public WoxCritialException(string msg) : base(msg) + { + } + } +} diff --git a/Wox.Core/Exception/WoxException.cs b/Wox.Core/Exception/WoxException.cs new file mode 100644 index 0000000000..a5df7a3d34 --- /dev/null +++ b/Wox.Core/Exception/WoxException.cs @@ -0,0 +1,14 @@ +namespace Wox.Core.Exception +{ + /// + /// Base Wox Exceptions + /// + public class WoxException : System.Exception + { + public WoxException(string msg) + : base(msg) + { + + } + } +} diff --git a/Wox.Infrastructure/Exceptions/WoxHttpException.cs b/Wox.Core/Exception/WoxHttpException.cs similarity index 51% rename from Wox.Infrastructure/Exceptions/WoxHttpException.cs rename to Wox.Core/Exception/WoxHttpException.cs index 026d1d8ab9..55e3431a0e 100644 --- a/Wox.Infrastructure/Exceptions/WoxHttpException.cs +++ b/Wox.Core/Exception/WoxHttpException.cs @@ -1,9 +1,4 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; - -namespace Wox.Infrastructure.Exceptions +namespace Wox.Core.Exception { public class WoxHttpException :WoxException { diff --git a/Wox.Infrastructure/Exceptions/WoxJsonRPCException.cs b/Wox.Core/Exception/WoxJsonRPCException.cs similarity index 78% rename from Wox.Infrastructure/Exceptions/WoxJsonRPCException.cs rename to Wox.Core/Exception/WoxJsonRPCException.cs index 0e984a3e6f..d3c0bfb0da 100644 --- a/Wox.Infrastructure/Exceptions/WoxJsonRPCException.cs +++ b/Wox.Core/Exception/WoxJsonRPCException.cs @@ -1,4 +1,4 @@ -namespace Wox.Infrastructure.Exceptions +namespace Wox.Core.Exception { public class WoxJsonRPCException : WoxException { diff --git a/Wox.Core/Plugin/CSharpPluginLoader.cs b/Wox.Core/Plugin/CSharpPluginLoader.cs index 9cfdc56734..5910a6bebf 100644 --- a/Wox.Core/Plugin/CSharpPluginLoader.cs +++ b/Wox.Core/Plugin/CSharpPluginLoader.cs @@ -44,7 +44,7 @@ namespace Wox.Core.Plugin plugins.Add(pair); } } - catch (Exception e) + catch (System.Exception e) { Log.Error(string.Format("Couldn't load plugin {0}: {1}", metadata.Name, e.Message)); #if (DEBUG) diff --git a/Wox.Core/Plugin/JsonRPCPlugin.cs b/Wox.Core/Plugin/JsonRPCPlugin.cs index 1b878dfce3..fd0514af36 100644 --- a/Wox.Core/Plugin/JsonRPCPlugin.cs +++ b/Wox.Core/Plugin/JsonRPCPlugin.cs @@ -4,8 +4,8 @@ using System.Diagnostics; using System.IO; using System.Reflection; using System.Threading; +using System.Windows.Forms; using Newtonsoft.Json; -using Wox.Infrastructure.Exceptions; using Wox.Infrastructure.Logger; using Wox.Plugin; @@ -72,9 +72,8 @@ namespace Wox.Core.Plugin } return results; } - catch (Exception e) + catch (System.Exception e) { - ErrorReporting.TryShowErrorMessageBox(e.Message, e); Log.Error(e.Message); } } @@ -83,14 +82,14 @@ namespace Wox.Core.Plugin private void ExecuteWoxAPI(string method, object[] parameters) { - MethodInfo methodInfo = App.Window.GetType().GetMethod(method); - if (methodInfo != null) + MethodInfo methodInfo = PluginManager.API.GetType().GetMethod(method); + if (methodInfo != null) { try { - methodInfo.Invoke(App.Window, parameters); + methodInfo.Invoke(PluginManager.API, parameters); } - catch (Exception) + catch (System.Exception) { #if (DEBUG) { @@ -132,7 +131,7 @@ namespace Wox.Core.Plugin string result = reader.ReadToEnd(); if (result.StartsWith("DEBUG:")) { - System.Windows.Forms.MessageBox.Show(new Form { TopMost = true }, result.Substring(6)); + MessageBox.Show(new Form { TopMost = true }, result.Substring(6)); return ""; } if (string.IsNullOrEmpty(result)) @@ -142,7 +141,8 @@ namespace Wox.Core.Plugin string error = errorReader.ReadToEnd(); if (!string.IsNullOrEmpty(error)) { - ErrorReporting.TryShowErrorMessageBox(error, new WoxJsonRPCException(error)); + //todo: + // ErrorReporting.TryShowErrorMessageBox(error, new WoxJsonRPCException(error)); } } } diff --git a/Wox.Core/Plugin/JsonRPCPluginLoader.cs b/Wox.Core/Plugin/JsonRPCPluginLoader.cs index 234da6a25d..0bf35979c9 100644 --- a/Wox.Core/Plugin/JsonRPCPluginLoader.cs +++ b/Wox.Core/Plugin/JsonRPCPluginLoader.cs @@ -13,7 +13,7 @@ namespace Wox.Core.Plugin return jsonRPCPluginMetadatas.Select(metadata => new PluginPair() { - Plugin = jsonRPCPlugin, + Plugin = new T(), //every JsonRPC plugin should has its own plugin instance Metadata = metadata }).ToList(); } diff --git a/Wox.Core/Plugin/PluginConfig.cs b/Wox.Core/Plugin/PluginConfig.cs index 0359ef6483..008d889248 100644 --- a/Wox.Core/Plugin/PluginConfig.cs +++ b/Wox.Core/Plugin/PluginConfig.cs @@ -4,7 +4,7 @@ using System.IO; using System.Linq; using System.Reflection; using Newtonsoft.Json; -using Wox.Infrastructure.Exceptions; +using Wox.Core.Exception; using Wox.Infrastructure.Logger; using Wox.Infrastructure.Storage.UserSettings; using Wox.Plugin; @@ -28,7 +28,7 @@ namespace Wox.Core.Plugin ParseSystemPlugins(); foreach (string pluginDirectory in pluginDirectories) { - ParseThirdPartyPlugins(pluginDirectory); + ParseUserPlugins(pluginDirectory); } if (PluginManager.DebuggerMode != null) @@ -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", @@ -56,16 +63,24 @@ namespace Wox.Core.Plugin }); } - private static void ParseThirdPartyPlugins(string pluginDirectory) + private static void ParseUserPlugins(string pluginDirectory) { + if (!Directory.Exists(pluginDirectory)) return; string[] directories = Directory.GetDirectories(pluginDirectory); foreach (string directory in directories) { 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) @@ -88,10 +103,10 @@ namespace Wox.Core.Plugin try { metadata = JsonConvert.DeserializeObject(File.ReadAllText(configPath)); - metadata.PluginType = PluginType.ThirdParty; + metadata.PluginType = PluginType.User; metadata.PluginDirectory = pluginDirectory; } - catch (Exception) + catch (System.Exception) { string error = string.Format("Parse plugin config {0} failed: json format is not valid", configPath); Log.Warn(error); @@ -138,4 +153,4 @@ namespace Wox.Core.Plugin return metadata; } } -} +} \ No newline at end of file diff --git a/Wox/Helper/PluginInstaller.cs b/Wox.Core/Plugin/PluginInstaller.cs similarity index 87% rename from Wox/Helper/PluginInstaller.cs rename to Wox.Core/Plugin/PluginInstaller.cs index ed66f5eb24..25e7d3b3c1 100644 --- a/Wox/Helper/PluginInstaller.cs +++ b/Wox.Core/Plugin/PluginInstaller.cs @@ -1,18 +1,17 @@ using System; using System.Diagnostics; using System.IO; -using System.Linq; using System.Windows; +using System.Windows.Forms; using ICSharpCode.SharpZipLib.Zip; using Newtonsoft.Json; -using Wox.Core.Plugin; using Wox.Plugin; -namespace Wox.Helper +namespace Wox.Core.Plugin { - public class PluginInstaller + internal class PluginInstaller { - public static void Install(string path) + internal static void Install(string path) { if (File.Exists(path)) { @@ -37,11 +36,7 @@ namespace Wox.Helper return; } - string pluginFolerPath = Path.Combine(Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath), "Plugins"); - if (!Directory.Exists(pluginFolerPath)) - { - Directory.CreateDirectory(pluginFolerPath); - } + string pluginFolerPath = PluginManager.DefaultPluginDirectory; string newPluginName = plugin.Name .Replace("/", "_") @@ -66,9 +61,9 @@ namespace Wox.Helper plugin.Name, existingPlugin.Metadata.Version, plugin.Version, plugin.Author); } - MessageBoxResult result = MessageBox.Show(content, "Install plugin", - MessageBoxButton.YesNo, MessageBoxImage.Question); - if (result == MessageBoxResult.Yes) + DialogResult result = MessageBox.Show(content, "Install plugin", MessageBoxButtons.YesNo, + MessageBoxIcon.Question); + if (result == DialogResult.Yes) { if (existingPlugin != null && Directory.Exists(existingPlugin.Metadata.PluginDirectory)) { @@ -88,7 +83,7 @@ namespace Wox.Helper // Plugins.Init(); //} if (MessageBox.Show("You have installed plugin " + plugin.Name + " successfully.\r\n Restart Wox to take effect?", "Install plugin", - MessageBoxButton.YesNo, MessageBoxImage.Question) == MessageBoxResult.Yes) + MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes) { ProcessStartInfo Info = new ProcessStartInfo(); Info.Arguments = "/C ping 127.0.0.1 -n 1 && \"" + @@ -97,7 +92,7 @@ namespace Wox.Helper Info.CreateNoWindow = true; Info.FileName = "cmd.exe"; Process.Start(Info); - App.Window.CloseApp(); + PluginManager.API.CloseApp(); } } } @@ -116,15 +111,15 @@ namespace Wox.Helper try { metadata = JsonConvert.DeserializeObject(File.ReadAllText(configPath)); - metadata.PluginType = PluginType.ThirdParty; + metadata.PluginType = PluginType.User; metadata.PluginDirectory = pluginDirectory; } - catch (Exception) + catch (System.Exception) { string error = string.Format("Parse plugin config {0} failed: json format is not valid", configPath); #if (DEBUG) { - throw new Exception(error); + throw new System.Exception(error); } #endif return null; @@ -137,7 +132,7 @@ namespace Wox.Helper metadata.Language); #if (DEBUG) { - throw new Exception(error); + throw new System.Exception(error); } #endif return null; @@ -148,7 +143,7 @@ namespace Wox.Helper metadata.ExecuteFilePath); #if (DEBUG) { - throw new Exception(error); + throw new System.Exception(error); } #endif return null; diff --git a/Wox.Core/Plugin/PluginManager.cs b/Wox.Core/Plugin/PluginManager.cs index 91af115ba8..0d86afe233 100644 --- a/Wox.Core/Plugin/PluginManager.cs +++ b/Wox.Core/Plugin/PluginManager.cs @@ -4,7 +4,9 @@ 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; namespace Wox.Core.Plugin @@ -15,21 +17,43 @@ namespace Wox.Core.Plugin public static class PluginManager { public static String DebuggerMode { get; private set; } + public static IPublicAPI API { get; private set; } + private static List plugins = new List(); - + /// /// Directories that will hold Wox plugin directory /// private static List pluginDirectories = new List(); - static PluginManager() + + /// + /// Default plugin directory + /// new plugin will be installed to this directory + /// + public static string DefaultPluginDirectory { + get + { + string userProfilePath = Environment.GetEnvironmentVariable("USERPROFILE"); + if (string.IsNullOrEmpty(userProfilePath)) + { + throw new WoxCritialException("Wox Can't Find Environment Variable UserProfile"); + } + + return Path.Combine(Path.Combine(userProfilePath, ".Wox"), "Plugins"); + } + } + + private static void SetupPluginDirectories() + { + pluginDirectories.Clear(); + + pluginDirectories.Add(DefaultPluginDirectory); pluginDirectories.Add( Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Plugins")); - pluginDirectories.Add( - Path.Combine(Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Personal), ".Wox"),"Plugins")); - MakesurePluginDirectoriesExist(); + MakesurePluginDirectoriesExist(); } private static void MakesurePluginDirectoriesExist() @@ -38,7 +62,14 @@ namespace Wox.Core.Plugin { if (!Directory.Exists(pluginDirectory)) { - Directory.CreateDirectory(pluginDirectory); + try + { + Directory.CreateDirectory(pluginDirectory); + } + catch (System.Exception e) + { + Log.Error(e.Message); + } } } } @@ -46,8 +77,12 @@ namespace Wox.Core.Plugin /// /// Load and init all Wox plugins /// - public static void Init() + public static void Init(IPublicAPI api) { + if (api == null) throw new WoxCritialException("api is null"); + + SetupPluginDirectories(); + API = api; plugins.Clear(); List pluginMetadatas = PluginConfig.Parse(pluginDirectories); @@ -61,11 +96,21 @@ namespace Wox.Core.Plugin { CurrentPluginMetadata = pair.Metadata, Proxy = HttpProxy.Instance, - API = App.Window + API = API })); } } + public static void InstallPlugin(string path) + { + PluginInstaller.Install(path); + } + + public static void Query(Query query) + { + QueryDispatcher.QueryDispatcher.Dispatch(query); + } + public static List AllPlugins { get @@ -74,11 +119,11 @@ namespace Wox.Core.Plugin } } - public static bool HitThirdpartyKeyword(Query query) + public static bool IsUserPluginQuery(Query query) { if (string.IsNullOrEmpty(query.ActionName)) return false; - return plugins.Any(o => o.Metadata.PluginType == PluginType.ThirdParty && o.Metadata.ActionKeyword == query.ActionName); + return plugins.Any(o => o.Metadata.PluginType == PluginType.User && o.Metadata.ActionKeyword == query.ActionName); } public static void ActivatePluginDebugger(string path) diff --git a/Wox.Core/Plugin/QueryDispatcher/IQueryDispatcher.cs b/Wox.Core/Plugin/QueryDispatcher/IQueryDispatcher.cs new file mode 100644 index 0000000000..c5312a0332 --- /dev/null +++ b/Wox.Core/Plugin/QueryDispatcher/IQueryDispatcher.cs @@ -0,0 +1,7 @@ +namespace Wox.Core.Plugin.QueryDispatcher +{ + internal interface IQueryDispatcher + { + void Dispatch(Wox.Plugin.Query query); + } +} diff --git a/Wox.Core/Plugin/QueryDispatcher/QueryDispatcher.cs b/Wox.Core/Plugin/QueryDispatcher/QueryDispatcher.cs new file mode 100644 index 0000000000..0e0eb62fb9 --- /dev/null +++ b/Wox.Core/Plugin/QueryDispatcher/QueryDispatcher.cs @@ -0,0 +1,21 @@ + +namespace Wox.Core.Plugin.QueryDispatcher +{ + internal static class QueryDispatcher + { + private static IQueryDispatcher pluginCmd = new UserPluginQueryDispatcher(); + private static IQueryDispatcher systemCmd = new SystemPluginQueryDispatcher(); + + public static void Dispatch(Wox.Plugin.Query query) + { + if (PluginManager.IsUserPluginQuery(query)) + { + pluginCmd.Dispatch(query); + } + else + { + systemCmd.Dispatch(query); + } + } + } +} diff --git a/Wox/Commands/SystemCommand.cs b/Wox.Core/Plugin/QueryDispatcher/SystemPluginQueryDispatcher.cs similarity index 71% rename from Wox/Commands/SystemCommand.cs rename to Wox.Core/Plugin/QueryDispatcher/SystemPluginQueryDispatcher.cs index d1ca9eb4fc..a20aa8ebf7 100644 --- a/Wox/Commands/SystemCommand.cs +++ b/Wox.Core/Plugin/QueryDispatcher/SystemPluginQueryDispatcher.cs @@ -1,20 +1,17 @@ -using System; -using System.Collections.Generic; +using System.Collections.Generic; using System.Linq; -using System.Text; using System.Threading; -using Wox.Core.Plugin; using Wox.Infrastructure.Storage.UserSettings; using Wox.Plugin; using Wox.Plugin.SystemPlugins; -namespace Wox.Commands +namespace Wox.Core.Plugin.QueryDispatcher { - public class SystemCommand : BaseCommand + public class SystemPluginQueryDispatcher : IQueryDispatcher { private IEnumerable allSytemPlugins = PluginManager.AllPlugins.Where(o => o.Metadata.PluginType == PluginType.System); - public override void Dispatch(Query query) + public void Dispatch(Query query) { var queryPlugins = allSytemPlugins; if (UserSettingStorage.Instance.WebSearches.Exists(o => o.ActionWord == query.ActionName && o.Enabled)) @@ -22,7 +19,7 @@ namespace Wox.Commands //websearch mode queryPlugins = new List() { - allSytemPlugins.First(o => ((ISystemPlugin)o.Plugin).ID == "565B73353DBF4806919830B9202EE3BF") + allSytemPlugins.First(o => o.Metadata.ID == "565B73353DBF4806919830B9202EE3BF") }; } @@ -34,7 +31,7 @@ namespace Wox.Commands List results = pair1.Plugin.Query(query); results.ForEach(o => { o.AutoAjustScore = true; }); - App.Window.PushResults(query, pair1.Metadata, results); + PluginManager.API.PushResults(query, pair1.Metadata, results); }); } } diff --git a/Wox/Commands/PluginCommand.cs b/Wox.Core/Plugin/QueryDispatcher/UserPluginQueryDispatcher.cs similarity index 54% rename from Wox/Commands/PluginCommand.cs rename to Wox.Core/Plugin/QueryDispatcher/UserPluginQueryDispatcher.cs index d233f766b9..3b96d2c3a8 100644 --- a/Wox/Commands/PluginCommand.cs +++ b/Wox.Core/Plugin/QueryDispatcher/UserPluginQueryDispatcher.cs @@ -2,26 +2,24 @@ using System.Collections.Generic; using System.Linq; using System.Threading; -using Wox.Core.Plugin; -using Wox.Helper; using Wox.Infrastructure.Logger; using Wox.Infrastructure.Storage.UserSettings; using Wox.Plugin; -namespace Wox.Commands +namespace Wox.Core.Plugin.QueryDispatcher { - public class PluginCommand : BaseCommand + public class UserPluginQueryDispatcher : IQueryDispatcher { - public override void Dispatch(Query query) + public void Dispatch(Query query) { - PluginPair thirdPlugin = PluginManager.AllPlugins.FirstOrDefault(o => o.Metadata.ActionKeyword == query.ActionName); - if (thirdPlugin != null && !string.IsNullOrEmpty(thirdPlugin.Metadata.ActionKeyword)) + PluginPair userPlugin = PluginManager.AllPlugins.FirstOrDefault(o => o.Metadata.ActionKeyword == query.ActionName); + if (userPlugin != null && !string.IsNullOrEmpty(userPlugin.Metadata.ActionKeyword)) { - var customizedPluginConfig = UserSettingStorage.Instance.CustomizedPluginConfigs.FirstOrDefault(o => o.ID == thirdPlugin.Metadata.ID); + var customizedPluginConfig = UserSettingStorage.Instance.CustomizedPluginConfigs.FirstOrDefault(o => o.ID == userPlugin.Metadata.ID); if (customizedPluginConfig != null && customizedPluginConfig.Disabled) { //need to stop the loading animation - UpdateResultView(null); + PluginManager.API.StopLoadingBar(); return; } @@ -29,12 +27,12 @@ namespace Wox.Commands { try { - List results = thirdPlugin.Plugin.Query(query) ?? new List(); - App.Window.PushResults(query,thirdPlugin.Metadata,results); + List results = userPlugin.Plugin.Query(query) ?? new List(); + PluginManager.API.PushResults(query,userPlugin.Metadata,results); } - catch (Exception queryException) + catch (System.Exception queryException) { - Log.Error(string.Format("Plugin {0} query failed: {1}", thirdPlugin.Metadata.Name, + Log.Error(string.Format("Plugin {0} query failed: {1}", userPlugin.Metadata.Name, queryException.Message)); #if (DEBUG) { diff --git a/Wox.Core/README.md b/Wox.Core/README.md new file mode 100644 index 0000000000..2c191d0856 --- /dev/null +++ b/Wox.Core/README.md @@ -0,0 +1,5 @@ +What does Wox.Core do? +===== + +* Handle Query +* Loading Plugins (including system plugin and user plugin) \ No newline at end of file diff --git a/Wox.Core/README.txt b/Wox.Core/README.txt deleted file mode 100644 index 3cd91680db..0000000000 --- a/Wox.Core/README.txt +++ /dev/null @@ -1,4 +0,0 @@ -What does Wox.Core do? - -* Handle Query -* Loading Plugins \ No newline at end of file diff --git a/Wox.Core/Wox.Core.csproj b/Wox.Core/Wox.Core.csproj index 34f0938d78..310f255fd7 100644 --- a/Wox.Core/Wox.Core.csproj +++ b/Wox.Core/Wox.Core.csproj @@ -18,7 +18,7 @@ true full false - bin\Debug\ + ..\Output\Debug\ DEBUG;TRACE prompt 4 @@ -32,18 +32,33 @@ 4 + + False + ..\packages\SharpZipLib.0.86.0\lib\20\ICSharpCode.SharpZipLib.dll + False ..\packages\Newtonsoft.Json.6.0.7\lib\net35\Newtonsoft.Json.dll + + + + + + + + + + + @@ -55,7 +70,7 @@ - + diff --git a/Wox.Core/packages.config b/Wox.Core/packages.config index 4185726464..6311fc40d5 100644 --- a/Wox.Core/packages.config +++ b/Wox.Core/packages.config @@ -1,4 +1,5 @@  + \ No newline at end of file diff --git a/Wox.Infrastructure/ChineseToPinYin.cs b/Wox.Infrastructure/ChineseToPinYin.cs deleted file mode 100644 index 1f59d7c282..0000000000 --- a/Wox.Infrastructure/ChineseToPinYin.cs +++ /dev/null @@ -1,15 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Text; - -namespace Wox.Infrastructure -{ - public static class ChineseToPinYin - { - [Obsolete] - public static string ToPinYin(string txt) - { - return txt.Unidecode(); - } - } -} diff --git a/Wox.Infrastructure/Exceptions/WoxException.cs b/Wox.Infrastructure/Exceptions/WoxException.cs deleted file mode 100644 index 581f36edb7..0000000000 --- a/Wox.Infrastructure/Exceptions/WoxException.cs +++ /dev/null @@ -1,13 +0,0 @@ -using System; - -namespace Wox.Infrastructure.Exceptions -{ - public class WoxException : Exception - { - public WoxException(string msg) - : base(msg) - { - - } - } -} 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.Infrastructure/Storage/BaseStorage.cs b/Wox.Infrastructure/Storage/BaseStorage.cs index d899cb6908..c72bf63c35 100644 --- a/Wox.Infrastructure/Storage/BaseStorage.cs +++ b/Wox.Infrastructure/Storage/BaseStorage.cs @@ -10,18 +10,35 @@ using Newtonsoft.Json; namespace Wox.Infrastructure.Storage { [Serializable] - public abstract class BaseStorage : IStorage where T : class,IStorage,new() + public abstract class BaseStorage : IStorage where T : class,IStorage, new() { - private readonly string configFolder = Path.Combine(Path.GetDirectoryName(Application.ExecutablePath), "Config"); + private string configFolder; + + private string ConfigFolder + { + get + { + if (string.IsNullOrEmpty(configFolder)) + { + string userProfilePath = Environment.GetEnvironmentVariable("USERPROFILE"); + if (userProfilePath == null) + { + throw new ArgumentException("Environment variable USERPROFILE is empty"); + } + configFolder = Path.Combine(Path.Combine(userProfilePath, ".Wox"), "Config"); + } + return configFolder; + } + } protected string ConfigPath { get { - return Path.Combine(configFolder, ConfigName + FileSuffix); + return Path.Combine(ConfigFolder, ConfigName + FileSuffix); } } - + protected abstract string FileSuffix { get; } protected abstract string ConfigName { get; } @@ -72,9 +89,9 @@ namespace Wox.Infrastructure.Storage { if (!File.Exists(ConfigPath)) { - if (!Directory.Exists(configFolder)) + if (!Directory.Exists(ConfigFolder)) { - Directory.CreateDirectory(configFolder); + Directory.CreateDirectory(ConfigFolder); } File.Create(ConfigPath).Close(); } diff --git a/Wox.Infrastructure/Storage/UserSettings/UserSettingStorage.cs b/Wox.Infrastructure/Storage/UserSettings/UserSettingStorage.cs index 229e100a2a..beb156a4fd 100644 --- a/Wox.Infrastructure/Storage/UserSettings/UserSettingStorage.cs +++ b/Wox.Infrastructure/Storage/UserSettings/UserSettingStorage.cs @@ -174,7 +174,15 @@ namespace Wox.Infrastructure.Storage.UserSettings if (string.IsNullOrEmpty(storage.ProgramSuffixes)) { storage.ProgramSuffixes = "lnk;exe;appref-ms;bat"; - } + } + if (storage.QueryBoxFont == null) + { + storage.QueryBoxFont = FontFamily.GenericSansSerif.Name; + } + if (storage.ResultItemFont == null) + { + storage.ResultItemFont = FontFamily.GenericSansSerif.Name; + } } } diff --git a/Wox.Infrastructure/Wox.Infrastructure.csproj b/Wox.Infrastructure/Wox.Infrastructure.csproj index c50978f96d..7c84bf829c 100644 --- a/Wox.Infrastructure/Wox.Infrastructure.csproj +++ b/Wox.Infrastructure/Wox.Infrastructure.csproj @@ -56,9 +56,6 @@ - - - @@ -67,21 +64,18 @@ + + + + - - - - - - - diff --git a/Wox.Plugin.SystemPlugins/ControlPanel/ControlPanelItem.cs b/Wox.Plugin.SystemPlugins/ControlPanel/ControlPanelItem.cs index 6d76e269a0..5781fa2910 100644 --- a/Wox.Plugin.SystemPlugins/ControlPanel/ControlPanelItem.cs +++ b/Wox.Plugin.SystemPlugins/ControlPanel/ControlPanelItem.cs @@ -22,4 +22,4 @@ namespace Wox.Plugin.SystemPlugins.ControlPanel GUID = newGUID; } } -} +} \ No newline at end of file diff --git a/Wox.Plugin.SystemPlugins/Program/ProgramSetting.xaml b/Wox.Plugin.SystemPlugins/Program/ProgramSetting.xaml index ded91a25c2..6f00f4cd5c 100644 --- a/Wox.Plugin.SystemPlugins/Program/ProgramSetting.xaml +++ b/Wox.Plugin.SystemPlugins/Program/ProgramSetting.xaml @@ -4,6 +4,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:infrastructure="clr-namespace:Wox.Infrastructure;assembly=Wox.Infrastructure" + xmlns:program="clr-namespace:Wox.Plugin.SystemPlugins.Program" mc:Ignorable="d" d:DesignHeight="300" d:DesignWidth="600"> @@ -26,7 +27,7 @@ - + diff --git a/Wox.Infrastructure/StringEmptyConverter.cs b/Wox.Plugin.SystemPlugins/Program/StringEmptyConverter.cs similarity index 87% rename from Wox.Infrastructure/StringEmptyConverter.cs rename to Wox.Plugin.SystemPlugins/Program/StringEmptyConverter.cs index f553695737..c2d5366306 100644 --- a/Wox.Infrastructure/StringEmptyConverter.cs +++ b/Wox.Plugin.SystemPlugins/Program/StringEmptyConverter.cs @@ -1,11 +1,8 @@ using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Windows.Data; using System.Windows.Markup; -namespace Wox.Infrastructure +namespace Wox.Plugin.SystemPlugins.Program { public class StringEmptyConverter : MarkupExtension, IValueConverter { diff --git a/Wox.Plugin.SystemPlugins/ThirdpartyPluginIndicator.cs b/Wox.Plugin.SystemPlugins/UserPluginIndicator.cs similarity index 97% rename from Wox.Plugin.SystemPlugins/ThirdpartyPluginIndicator.cs rename to Wox.Plugin.SystemPlugins/UserPluginIndicator.cs index 31e3ab0acf..cc1d492a3b 100644 --- a/Wox.Plugin.SystemPlugins/ThirdpartyPluginIndicator.cs +++ b/Wox.Plugin.SystemPlugins/UserPluginIndicator.cs @@ -8,7 +8,7 @@ using Wox.Infrastructure.Storage.UserSettings; namespace Wox.Plugin.SystemPlugins { - public class ThirdpartyPluginIndicator : BaseSystemPlugin + public class UserPluginIndicator : BaseSystemPlugin { private List allPlugins = new List(); private PluginInitContext context; diff --git a/Wox.Plugin.SystemPlugins/Wox.Plugin.SystemPlugins.csproj b/Wox.Plugin.SystemPlugins/Wox.Plugin.SystemPlugins.csproj index 7fb13e044d..75604f9377 100644 --- a/Wox.Plugin.SystemPlugins/Wox.Plugin.SystemPlugins.csproj +++ b/Wox.Plugin.SystemPlugins/Wox.Plugin.SystemPlugins.csproj @@ -86,6 +86,7 @@ ProgramSuffixes.xaml + @@ -102,7 +103,7 @@ - + diff --git a/Wox.Plugin/IPublicAPI.cs b/Wox.Plugin/IPublicAPI.cs index 64ff13ab08..5ae94e0a40 100644 --- a/Wox.Plugin/IPublicAPI.cs +++ b/Wox.Plugin/IPublicAPI.cs @@ -6,7 +6,12 @@ namespace Wox.Plugin { public interface IPublicAPI { - + /// + /// Push result to query window + /// + /// + /// + /// void PushResults(Query query,PluginMetadata plugin, List results); bool ShellRun(string cmd, bool runAsAdministrator = false); diff --git a/Wox.Plugin/PluginType.cs b/Wox.Plugin/PluginType.cs index a36cc50b27..b8ffc6e124 100644 --- a/Wox.Plugin/PluginType.cs +++ b/Wox.Plugin/PluginType.cs @@ -8,6 +8,6 @@ namespace Wox.Plugin public enum PluginType { System, - ThirdParty + User } -} +} \ No newline at end of file diff --git a/Wox.Plugin/README.md b/Wox.Plugin/README.md new file mode 100644 index 0000000000..1d5c7394da --- /dev/null +++ b/Wox.Plugin/README.md @@ -0,0 +1,5 @@ +What does Wox.Plugin do? +==== + +* Define base objects and interfaces for plugins +* Plugin Author who making C# plugin should reference this DLL via nuget \ No newline at end of file diff --git a/Wox.Plugin/Wox.Plugin.csproj b/Wox.Plugin/Wox.Plugin.csproj index abc3493ebb..d915ddd7bc 100644 --- a/Wox.Plugin/Wox.Plugin.csproj +++ b/Wox.Plugin/Wox.Plugin.csproj @@ -59,6 +59,9 @@ + + +