mirror of
https://github.com/microsoft/PowerToys.git
synced 2026-04-06 11:16:51 +02:00
Merge branch 'json-rpc'
This commit is contained in:
@@ -2,7 +2,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Python.Runtime;
|
||||
using Wox.Helper;
|
||||
using Wox.Infrastructure.Storage.UserSettings;
|
||||
using Wox.Plugin;
|
||||
@@ -12,43 +11,25 @@ namespace Wox.Commands
|
||||
{
|
||||
public class PluginCommand : BaseCommand
|
||||
{
|
||||
private string currentPythonModulePath = string.Empty;
|
||||
private IntPtr GIL;
|
||||
|
||||
public override void Dispatch(Query q)
|
||||
public override void Dispatch(Query query)
|
||||
{
|
||||
PluginPair thirdPlugin = Plugins.AllPlugins.FirstOrDefault(o => o.Metadata.ActionKeyword == q.ActionName);
|
||||
PluginPair thirdPlugin = Plugins.AllPlugins.FirstOrDefault(o => o.Metadata.ActionKeyword == query.ActionName);
|
||||
if (thirdPlugin != null && !string.IsNullOrEmpty(thirdPlugin.Metadata.ActionKeyword))
|
||||
{
|
||||
var customizedPluginConfig = UserSettingStorage.Instance.CustomizedPluginConfigs.FirstOrDefault(o => o.ID == thirdPlugin.Metadata.ID);
|
||||
if (customizedPluginConfig != null && customizedPluginConfig.Disabled)
|
||||
{
|
||||
//need to stop the loading animation
|
||||
UpdateResultView(null);
|
||||
return;
|
||||
}
|
||||
|
||||
if (thirdPlugin.Metadata.Language == AllowedLanguage.Python)
|
||||
{
|
||||
SwitchPythonEnv(thirdPlugin);
|
||||
}
|
||||
ThreadPool.QueueUserWorkItem(t =>
|
||||
{
|
||||
try
|
||||
{
|
||||
thirdPlugin.InitContext.PushResults = (qu, r) =>
|
||||
{
|
||||
if (r != null)
|
||||
{
|
||||
r.ForEach(o =>
|
||||
{
|
||||
o.PluginDirectory = thirdPlugin.Metadata.PluginDirecotry;
|
||||
o.OriginQuery = qu;
|
||||
});
|
||||
UpdateResultView(r);
|
||||
}
|
||||
};
|
||||
List<Result> results = thirdPlugin.Plugin.Query(q) ?? new List<Result>();
|
||||
thirdPlugin.InitContext.PushResults(q, results);
|
||||
List<Result> results = thirdPlugin.Plugin.Query(query) ?? new List<Result>();
|
||||
App.Window.PushResults(query,thirdPlugin.Metadata,results);
|
||||
}
|
||||
catch (Exception queryException)
|
||||
{
|
||||
@@ -63,24 +44,5 @@ namespace Wox.Commands
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void SwitchPythonEnv(PluginPair thirdPlugin)
|
||||
{
|
||||
if (currentPythonModulePath != thirdPlugin.Metadata.PluginDirecotry)
|
||||
{
|
||||
currentPythonModulePath = thirdPlugin.Metadata.PluginDirecotry;
|
||||
|
||||
if (GIL != IntPtr.Zero)
|
||||
{
|
||||
Runtime.PyEval_RestoreThread(GIL);
|
||||
PythonEngine.Shutdown();
|
||||
}
|
||||
PythonEngine.Initialize();
|
||||
IntPtr pyStrPtr = Runtime.PyString_FromString(thirdPlugin.Metadata.PluginDirecotry);
|
||||
IntPtr sysDotPath = Runtime.PySys_GetObject("path");
|
||||
Runtime.PyList_Append(sysDotPath, pyStrPtr);
|
||||
GIL = PythonEngine.BeginAllowThreads();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -19,19 +19,10 @@ namespace Wox.Commands
|
||||
|
||||
ThreadPool.QueueUserWorkItem(state =>
|
||||
{
|
||||
pair1.InitContext.PushResults = (q, r) =>
|
||||
{
|
||||
foreach (Result result in r)
|
||||
{
|
||||
result.PluginDirectory = pair1.Metadata.PluginDirecotry;
|
||||
result.OriginQuery = q;
|
||||
result.AutoAjustScore = true;
|
||||
}
|
||||
UpdateResultView(r);
|
||||
};
|
||||
|
||||
List<Result> results = pair1.Plugin.Query(query);
|
||||
pair1.InitContext.PushResults(query, results);
|
||||
results.ForEach(o=> { o.AutoAjustScore = true; });
|
||||
|
||||
App.Window.PushResults(query,pair1.Metadata,results);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,230 +1,32 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Windows;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using Wox.Helper;
|
||||
|
||||
namespace Wox.Converters
|
||||
{
|
||||
public class ImagePathConverter : IMultiValueConverter
|
||||
{
|
||||
private static readonly Dictionary<string, object> imageCache = new Dictionary<string, object>();
|
||||
|
||||
private static readonly List<string> imageExts = new List<string>
|
||||
{
|
||||
".png",
|
||||
".jpg",
|
||||
".jpeg",
|
||||
".gif",
|
||||
".bmp",
|
||||
".tiff",
|
||||
".ico"
|
||||
};
|
||||
|
||||
private static readonly List<string> selfExts = new List<string>
|
||||
{
|
||||
".exe",
|
||||
".lnk",
|
||||
".ani",
|
||||
".cur",
|
||||
".sln",
|
||||
".appref-ms"
|
||||
};
|
||||
|
||||
private static ImageSource GetIcon(string fileName)
|
||||
{
|
||||
Icon icon = GetFileIcon(fileName);
|
||||
if (icon == null) icon = Icon.ExtractAssociatedIcon(fileName);
|
||||
|
||||
if (icon != null)
|
||||
{
|
||||
return System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon(icon.Handle,
|
||||
new Int32Rect(0, 0, icon.Width, icon.Height), BitmapSizeOptions.FromEmptyOptions());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
|
||||
{
|
||||
object img;
|
||||
if (values[0] == null) return null;
|
||||
|
||||
string path = values[0].ToString();
|
||||
if (path.StartsWith("data:", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
return new BitmapImage(new Uri(path));
|
||||
}
|
||||
|
||||
string relativePath = values[0].ToString();
|
||||
string pluginDirectory = values[1].ToString();
|
||||
string fullPath = Path.Combine(pluginDirectory, path);
|
||||
string ext = Path.GetExtension(path).ToLower();
|
||||
if (imageCache.ContainsKey(fullPath))
|
||||
{
|
||||
return imageCache[fullPath];
|
||||
}
|
||||
if (!selfExts.Contains(ext) && imageCache.ContainsKey(ext))
|
||||
{
|
||||
return imageCache[ext];
|
||||
}
|
||||
string fullPath = Path.Combine(pluginDirectory, relativePath);
|
||||
|
||||
string resolvedPath = string.Empty;
|
||||
if (!string.IsNullOrEmpty(path) && path.Contains(":\\") && File.Exists(path))
|
||||
if (relativePath.StartsWith("data:", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
resolvedPath = path;
|
||||
return new BitmapImage(new Uri(relativePath));
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(path) && File.Exists(fullPath))
|
||||
{
|
||||
resolvedPath = fullPath;
|
||||
}
|
||||
string extn = Path.GetExtension(resolvedPath).ToLower();
|
||||
|
||||
var cacheKey = fullPath;
|
||||
if (selfExts.Contains(extn))
|
||||
{
|
||||
img = GetIcon(resolvedPath);
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(resolvedPath) && imageExts.Contains(ext) && File.Exists(resolvedPath))
|
||||
{
|
||||
img = new BitmapImage(new Uri(resolvedPath));
|
||||
}
|
||||
else
|
||||
{
|
||||
img = GetIcon(resolvedPath);
|
||||
if (!selfExts.Contains(ext)) cacheKey = ext;
|
||||
}
|
||||
|
||||
if (img != null)
|
||||
{
|
||||
imageCache.Add(cacheKey, img);
|
||||
}
|
||||
|
||||
return img;
|
||||
return ImageLoader.Load(fullPath);
|
||||
}
|
||||
|
||||
public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
// http://blogs.msdn.com/b/oldnewthing/archive/2011/01/27/10120844.aspx
|
||||
public static Icon GetFileIcon(string name)
|
||||
{
|
||||
SHFILEINFO shfi = new SHFILEINFO();
|
||||
uint flags = SHGFI_SYSICONINDEX;
|
||||
|
||||
IntPtr himl = SHGetFileInfo(name,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
ref shfi,
|
||||
(uint) Marshal.SizeOf(shfi),
|
||||
flags);
|
||||
|
||||
if (himl != IntPtr.Zero)
|
||||
{
|
||||
IntPtr hIcon = ImageList_GetIcon(himl, shfi.iIcon, ILD_NORMAL);
|
||||
var icon = (Icon) Icon.FromHandle(hIcon).Clone();
|
||||
DestroyIcon(hIcon);
|
||||
return icon;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
[DllImport("comctl32.dll", SetLastError = true)]
|
||||
private static extern IntPtr ImageList_GetIcon(IntPtr himl, int i, uint flags);
|
||||
|
||||
private const int MAX_PATH = 256;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct SHITEMID
|
||||
{
|
||||
public ushort cb;
|
||||
[MarshalAs(UnmanagedType.LPArray)] public byte[] abID;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct ITEMIDLIST
|
||||
{
|
||||
public SHITEMID mkid;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct BROWSEINFO
|
||||
{
|
||||
public IntPtr hwndOwner;
|
||||
public IntPtr pidlRoot;
|
||||
public IntPtr pszDisplayName;
|
||||
[MarshalAs(UnmanagedType.LPTStr)] public string lpszTitle;
|
||||
public uint ulFlags;
|
||||
public IntPtr lpfn;
|
||||
public int lParam;
|
||||
public IntPtr iImage;
|
||||
}
|
||||
|
||||
// Browsing for directory.
|
||||
private const uint BIF_RETURNONLYFSDIRS = 0x0001;
|
||||
private const uint BIF_DONTGOBELOWDOMAIN = 0x0002;
|
||||
private const uint BIF_STATUSTEXT = 0x0004;
|
||||
private const uint BIF_RETURNFSANCESTORS = 0x0008;
|
||||
private const uint BIF_EDITBOX = 0x0010;
|
||||
private const uint BIF_VALIDATE = 0x0020;
|
||||
private const uint BIF_NEWDIALOGSTYLE = 0x0040;
|
||||
private const uint BIF_USENEWUI = (BIF_NEWDIALOGSTYLE | BIF_EDITBOX);
|
||||
private const uint BIF_BROWSEINCLUDEURLS = 0x0080;
|
||||
private const uint BIF_BROWSEFORCOMPUTER = 0x1000;
|
||||
private const uint BIF_BROWSEFORPRINTER = 0x2000;
|
||||
private const uint BIF_BROWSEINCLUDEFILES = 0x4000;
|
||||
private const uint BIF_SHAREABLE = 0x8000;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct SHFILEINFO
|
||||
{
|
||||
public const int NAMESIZE = 80;
|
||||
public IntPtr hIcon;
|
||||
public int iIcon;
|
||||
public uint dwAttributes;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)] public string szDisplayName;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = NAMESIZE)] public string szTypeName;
|
||||
};
|
||||
|
||||
private const uint SHGFI_ICON = 0x000000100; // get icon
|
||||
private const uint SHGFI_DISPLAYNAME = 0x000000200; // get display name
|
||||
private const uint SHGFI_TYPENAME = 0x000000400; // get type name
|
||||
private const uint SHGFI_ATTRIBUTES = 0x000000800; // get attributes
|
||||
private const uint SHGFI_ICONLOCATION = 0x000001000; // get icon location
|
||||
private const uint SHGFI_EXETYPE = 0x000002000; // return exe type
|
||||
private const uint SHGFI_SYSICONINDEX = 0x000004000; // get system icon index
|
||||
private const uint SHGFI_LINKOVERLAY = 0x000008000; // put a link overlay on icon
|
||||
private const uint SHGFI_SELECTED = 0x000010000; // show icon in selected state
|
||||
private const uint SHGFI_ATTR_SPECIFIED = 0x000020000; // get only specified attributes
|
||||
private const uint SHGFI_LARGEICON = 0x000000000; // get large icon
|
||||
private const uint SHGFI_SMALLICON = 0x000000001; // get small icon
|
||||
private const uint SHGFI_OPENICON = 0x000000002; // get open icon
|
||||
private const uint SHGFI_SHELLICONSIZE = 0x000000004; // get shell size icon
|
||||
private const uint SHGFI_PIDL = 0x000000008; // pszPath is a pidl
|
||||
private const uint SHGFI_USEFILEATTRIBUTES = 0x000000010; // use passed dwFileAttribute
|
||||
private const uint SHGFI_ADDOVERLAYS = 0x000000020; // apply the appropriate overlays
|
||||
private const uint SHGFI_OVERLAYINDEX = 0x000000040; // Get the index of the overlay
|
||||
|
||||
private const uint FILE_ATTRIBUTE_DIRECTORY = 0x00000010;
|
||||
private const uint FILE_ATTRIBUTE_NORMAL = 0x00000080;
|
||||
private const uint ILD_NORMAL = 0x00000000;
|
||||
|
||||
[DllImport("Shell32.dll")]
|
||||
private static extern IntPtr SHGetFileInfo(
|
||||
string pszPath,
|
||||
uint dwFileAttributes,
|
||||
ref SHFILEINFO psfi,
|
||||
uint cbFileInfo,
|
||||
uint uFlags
|
||||
);
|
||||
|
||||
[DllImport("User32.dll")]
|
||||
private static extern int DestroyIcon(IntPtr hIcon);
|
||||
}
|
||||
}
|
||||
217
Wox/Helper/ImageLoader.cs
Normal file
217
Wox/Helper/ImageLoader.cs
Normal file
@@ -0,0 +1,217 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Drawing;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
|
||||
namespace Wox.Helper
|
||||
{
|
||||
public class ImageLoader
|
||||
{
|
||||
private static readonly Dictionary<string, ImageSource> imageCache = new Dictionary<string, ImageSource>();
|
||||
private static object locker = new object();
|
||||
|
||||
private static readonly List<string> imageExts = new List<string>
|
||||
{
|
||||
".png",
|
||||
".jpg",
|
||||
".jpeg",
|
||||
".gif",
|
||||
".bmp",
|
||||
".tiff",
|
||||
".ico"
|
||||
};
|
||||
|
||||
private static readonly List<string> selfExts = new List<string>
|
||||
{
|
||||
".exe",
|
||||
".lnk",
|
||||
".ani",
|
||||
".cur",
|
||||
".sln",
|
||||
".appref-ms"
|
||||
};
|
||||
|
||||
private static ImageSource GetIcon(string fileName)
|
||||
{
|
||||
Icon icon = GetFileIcon(fileName);
|
||||
if (icon == null) icon = Icon.ExtractAssociatedIcon(fileName);
|
||||
|
||||
if (icon != null)
|
||||
{
|
||||
return System.Windows.Interop.Imaging.CreateBitmapSourceFromHIcon(icon.Handle,
|
||||
new Int32Rect(0, 0, icon.Width, icon.Height), BitmapSizeOptions.FromEmptyOptions());
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public static ImageSource Load(string path)
|
||||
{
|
||||
ImageSource img = null;
|
||||
if (path == null) return null;
|
||||
if (imageCache.ContainsKey(path))
|
||||
{
|
||||
return imageCache[path];
|
||||
}
|
||||
|
||||
string ext = Path.GetExtension(path).ToLower();
|
||||
string resolvedPath = string.Empty;
|
||||
if (!string.IsNullOrEmpty(path) && path.Contains(":\\") && File.Exists(path))
|
||||
{
|
||||
resolvedPath = path;
|
||||
}
|
||||
|
||||
if (selfExts.Contains(ext))
|
||||
{
|
||||
img = GetIcon(resolvedPath);
|
||||
}
|
||||
else if (!string.IsNullOrEmpty(resolvedPath) && imageExts.Contains(ext) && File.Exists(resolvedPath))
|
||||
{
|
||||
img = new BitmapImage(new Uri(resolvedPath));
|
||||
}
|
||||
|
||||
if (img != null)
|
||||
{
|
||||
if (!imageCache.ContainsKey(path))
|
||||
{
|
||||
lock (locker)
|
||||
{
|
||||
if (!imageCache.ContainsKey(path))
|
||||
{
|
||||
imageCache.Add(path, img);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return img;
|
||||
}
|
||||
|
||||
// http://blogs.msdn.com/b/oldnewthing/archive/2011/01/27/10120844.aspx
|
||||
private static Icon GetFileIcon(string name)
|
||||
{
|
||||
SHFILEINFO shfi = new SHFILEINFO();
|
||||
uint flags = SHGFI_SYSICONINDEX;
|
||||
|
||||
IntPtr himl = SHGetFileInfo(name,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
ref shfi,
|
||||
(uint)Marshal.SizeOf(shfi),
|
||||
flags);
|
||||
|
||||
if (himl != IntPtr.Zero)
|
||||
{
|
||||
IntPtr hIcon = ImageList_GetIcon(himl, shfi.iIcon, ILD_NORMAL);
|
||||
var icon = (Icon)Icon.FromHandle(hIcon).Clone();
|
||||
DestroyIcon(hIcon);
|
||||
return icon;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
[DllImport("comctl32.dll", SetLastError = true)]
|
||||
private static extern IntPtr ImageList_GetIcon(IntPtr himl, int i, uint flags);
|
||||
|
||||
private const int MAX_PATH = 256;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct SHITEMID
|
||||
{
|
||||
public ushort cb;
|
||||
[MarshalAs(UnmanagedType.LPArray)]
|
||||
public byte[] abID;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct ITEMIDLIST
|
||||
{
|
||||
public SHITEMID mkid;
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct BROWSEINFO
|
||||
{
|
||||
public IntPtr hwndOwner;
|
||||
public IntPtr pidlRoot;
|
||||
public IntPtr pszDisplayName;
|
||||
[MarshalAs(UnmanagedType.LPTStr)]
|
||||
public string lpszTitle;
|
||||
public uint ulFlags;
|
||||
public IntPtr lpfn;
|
||||
public int lParam;
|
||||
public IntPtr iImage;
|
||||
}
|
||||
|
||||
// Browsing for directory.
|
||||
private const uint BIF_RETURNONLYFSDIRS = 0x0001;
|
||||
private const uint BIF_DONTGOBELOWDOMAIN = 0x0002;
|
||||
private const uint BIF_STATUSTEXT = 0x0004;
|
||||
private const uint BIF_RETURNFSANCESTORS = 0x0008;
|
||||
private const uint BIF_EDITBOX = 0x0010;
|
||||
private const uint BIF_VALIDATE = 0x0020;
|
||||
private const uint BIF_NEWDIALOGSTYLE = 0x0040;
|
||||
private const uint BIF_USENEWUI = (BIF_NEWDIALOGSTYLE | BIF_EDITBOX);
|
||||
private const uint BIF_BROWSEINCLUDEURLS = 0x0080;
|
||||
private const uint BIF_BROWSEFORCOMPUTER = 0x1000;
|
||||
private const uint BIF_BROWSEFORPRINTER = 0x2000;
|
||||
private const uint BIF_BROWSEINCLUDEFILES = 0x4000;
|
||||
private const uint BIF_SHAREABLE = 0x8000;
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
private struct SHFILEINFO
|
||||
{
|
||||
public const int NAMESIZE = 80;
|
||||
public IntPtr hIcon;
|
||||
public int iIcon;
|
||||
public uint dwAttributes;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = MAX_PATH)]
|
||||
public string szDisplayName;
|
||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = NAMESIZE)]
|
||||
public string szTypeName;
|
||||
};
|
||||
|
||||
private const uint SHGFI_ICON = 0x000000100; // get icon
|
||||
private const uint SHGFI_DISPLAYNAME = 0x000000200; // get display name
|
||||
private const uint SHGFI_TYPENAME = 0x000000400; // get type name
|
||||
private const uint SHGFI_ATTRIBUTES = 0x000000800; // get attributes
|
||||
private const uint SHGFI_ICONLOCATION = 0x000001000; // get icon location
|
||||
private const uint SHGFI_EXETYPE = 0x000002000; // return exe type
|
||||
private const uint SHGFI_SYSICONINDEX = 0x000004000; // get system icon index
|
||||
private const uint SHGFI_LINKOVERLAY = 0x000008000; // put a link overlay on icon
|
||||
private const uint SHGFI_SELECTED = 0x000010000; // show icon in selected state
|
||||
private const uint SHGFI_ATTR_SPECIFIED = 0x000020000; // get only specified attributes
|
||||
private const uint SHGFI_LARGEICON = 0x000000000; // get large icon
|
||||
private const uint SHGFI_SMALLICON = 0x000000001; // get small icon
|
||||
private const uint SHGFI_OPENICON = 0x000000002; // get open icon
|
||||
private const uint SHGFI_SHELLICONSIZE = 0x000000004; // get shell size icon
|
||||
private const uint SHGFI_PIDL = 0x000000008; // pszPath is a pidl
|
||||
private const uint SHGFI_USEFILEATTRIBUTES = 0x000000010; // use passed dwFileAttribute
|
||||
private const uint SHGFI_ADDOVERLAYS = 0x000000020; // apply the appropriate overlays
|
||||
private const uint SHGFI_OVERLAYINDEX = 0x000000040; // Get the index of the overlay
|
||||
|
||||
private const uint FILE_ATTRIBUTE_DIRECTORY = 0x00000010;
|
||||
private const uint FILE_ATTRIBUTE_NORMAL = 0x00000080;
|
||||
private const uint ILD_NORMAL = 0x00000000;
|
||||
|
||||
[DllImport("Shell32.dll")]
|
||||
private static extern IntPtr SHGetFileInfo(
|
||||
string pszPath,
|
||||
uint dwFileAttributes,
|
||||
ref SHFILEINFO psfi,
|
||||
uint cbFileInfo,
|
||||
uint uFlags
|
||||
);
|
||||
|
||||
[DllImport("User32.dll")]
|
||||
private static extern int DestroyIcon(IntPtr hIcon);
|
||||
}
|
||||
|
||||
}
|
||||
77
Wox/JsonRPC/JsonPRCModel.cs
Normal file
77
Wox/JsonRPC/JsonPRCModel.cs
Normal file
@@ -0,0 +1,77 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Wox.Plugin;
|
||||
|
||||
namespace Wox.JsonRPC
|
||||
{
|
||||
public class JsonRPCErrorModel
|
||||
{
|
||||
public int Code { get; set; }
|
||||
|
||||
public string Message { get; set; }
|
||||
|
||||
public string Data { get; set; }
|
||||
}
|
||||
|
||||
public class JsonRPCModelBase
|
||||
{
|
||||
public int Id { get; set; }
|
||||
|
||||
public string JsonRPC { get; set; }
|
||||
}
|
||||
|
||||
public class JsonRPCResponseModel : JsonRPCModelBase
|
||||
{
|
||||
public string Result { get; set; }
|
||||
|
||||
public JsonRPCErrorModel Error { get; set; }
|
||||
}
|
||||
|
||||
public class JsonRPCQueryResponseModel : JsonRPCResponseModel
|
||||
{
|
||||
public new List<JsonRPCResult> Result { get; set; }
|
||||
}
|
||||
|
||||
public class JsonRPCRequestModel : JsonRPCModelBase
|
||||
{
|
||||
public string Method { get; set; }
|
||||
|
||||
public object[] Parameters { get; set; }
|
||||
|
||||
public bool DontHideAfterAction { get; set; }
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
if (Parameters != null && Parameters.Length > 0)
|
||||
{
|
||||
string parameters = Parameters.Aggregate("[", (current, o) => current + (GetParamterByType(o) + ","));
|
||||
parameters = parameters.Substring(0, parameters.Length - 1) + "]";
|
||||
return string.Format(@"{{\""method\"":\""{0}\"",\""parameters\"":{1}}}", Method, parameters);
|
||||
}
|
||||
|
||||
return string.Format(@"{{\""method\"":\""{0}\"",\""parameters\"":[]}}",Method);
|
||||
}
|
||||
|
||||
private string GetParamterByType(object paramter)
|
||||
{
|
||||
if (paramter is string)
|
||||
{
|
||||
return string.Format(@"\""{0}\""", paramter);
|
||||
}
|
||||
if (paramter is int || paramter is float || paramter is double)
|
||||
{
|
||||
return string.Format(@"{0}", paramter);
|
||||
}
|
||||
if (paramter is bool)
|
||||
{
|
||||
return string.Format(@"{0}", paramter.ToString().ToLower());
|
||||
}
|
||||
return paramter.ToString();
|
||||
}
|
||||
}
|
||||
|
||||
public class JsonRPCResult : Result
|
||||
{
|
||||
public JsonRPCRequestModel JsonRPCAction { get; set; }
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
132
Wox/PluginLoader/BasePlugin.cs
Normal file
132
Wox/PluginLoader/BasePlugin.cs
Normal file
@@ -0,0 +1,132 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Newtonsoft.Json;
|
||||
using Wox.JsonRPC;
|
||||
using Wox.Plugin;
|
||||
|
||||
namespace Wox.PluginLoader
|
||||
{
|
||||
public abstract class BasePlugin : IPlugin
|
||||
{
|
||||
protected PluginInitContext context;
|
||||
|
||||
public abstract string SupportedLanguage { get; }
|
||||
|
||||
protected abstract string ExecuteQuery(Query query);
|
||||
protected abstract string ExecuteAction(JsonRPCRequestModel rpcRequest);
|
||||
|
||||
public List<Result> Query(Query query)
|
||||
{
|
||||
string output = ExecuteQuery(query);
|
||||
if (!string.IsNullOrEmpty(output))
|
||||
{
|
||||
try
|
||||
{
|
||||
List<Result> results = new List<Result>();
|
||||
|
||||
JsonRPCQueryResponseModel queryResponseModel = JsonConvert.DeserializeObject<JsonRPCQueryResponseModel>(output);
|
||||
foreach (JsonRPCResult result in queryResponseModel.Result)
|
||||
{
|
||||
JsonRPCResult result1 = result;
|
||||
result.Action = (c) =>
|
||||
{
|
||||
if (!string.IsNullOrEmpty(result1.JsonRPCAction.Method))
|
||||
{
|
||||
if (result1.JsonRPCAction.Method.StartsWith("Wox."))
|
||||
{
|
||||
ExecuteWoxAPI(result1.JsonRPCAction.Method.Substring(4), result1.JsonRPCAction.Parameters);
|
||||
}
|
||||
else
|
||||
{
|
||||
ThreadPool.QueueUserWorkItem(state =>
|
||||
{
|
||||
string actionReponse = ExecuteAction(result1.JsonRPCAction);
|
||||
JsonRPCRequestModel jsonRpcRequestModel = JsonConvert.DeserializeObject<JsonRPCRequestModel>(actionReponse);
|
||||
if (jsonRpcRequestModel != null
|
||||
&& string.IsNullOrEmpty(jsonRpcRequestModel.Method)
|
||||
&& jsonRpcRequestModel.Method.StartsWith("Wox."))
|
||||
{
|
||||
ExecuteWoxAPI(jsonRpcRequestModel.Method.Substring(4), jsonRpcRequestModel.Parameters);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
return !result1.JsonRPCAction.DontHideAfterAction;
|
||||
};
|
||||
results.Add(result);
|
||||
}
|
||||
return results;
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private void ExecuteWoxAPI(string method, object[] parameters)
|
||||
{
|
||||
MethodInfo methodInfo = App.Window.GetType().GetMethod(method);
|
||||
if (methodInfo != null)
|
||||
{
|
||||
try
|
||||
{
|
||||
methodInfo.Invoke(App.Window, parameters);
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
#if (DEBUG)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Execute external program and return the output
|
||||
/// </summary>
|
||||
/// <param name="fileName"></param>
|
||||
/// <param name="arguments"></param>
|
||||
/// <returns></returns>
|
||||
protected string Execute(string fileName, string arguments)
|
||||
{
|
||||
try
|
||||
{
|
||||
ProcessStartInfo start = new ProcessStartInfo();
|
||||
start.FileName = fileName;
|
||||
start.Arguments = arguments;
|
||||
start.UseShellExecute = false;
|
||||
start.CreateNoWindow = true;
|
||||
start.RedirectStandardOutput = true;
|
||||
using (Process process = Process.Start(start))
|
||||
{
|
||||
if (process != null)
|
||||
{
|
||||
using (StreamReader reader = process.StandardOutput)
|
||||
{
|
||||
return reader.ReadToEnd();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void Init(PluginInitContext ctx)
|
||||
{
|
||||
this.context = ctx;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,118 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Windows.Forms;
|
||||
using Newtonsoft.Json;
|
||||
using Wox.Helper;
|
||||
using Wox.Infrastructure.Storage.UserSettings;
|
||||
using System.Text;
|
||||
using Wox.Plugin;
|
||||
using Wox.Plugin.SystemPlugins;
|
||||
|
||||
namespace Wox.PluginLoader {
|
||||
public abstract class BasePluginLoader {
|
||||
private static string PluginPath = Path.Combine(Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath), "Plugins");
|
||||
private static string PluginConfigName = "plugin.json";
|
||||
protected static List<PluginMetadata> pluginMetadatas = new List<PluginMetadata>();
|
||||
public abstract List<PluginPair> LoadPlugin();
|
||||
namespace Wox.PluginLoader
|
||||
{
|
||||
public class BasePluginLoader<T> : IPluginLoader where T : BasePlugin, new()
|
||||
{
|
||||
public virtual List<PluginPair> LoadPlugin(List<PluginMetadata> pluginMetadatas)
|
||||
{
|
||||
string supportedLanguage = new T().SupportedLanguage;
|
||||
List<PluginMetadata> metadatas = pluginMetadatas.Where(o => supportedLanguage.ToUpper() == o.Language.ToUpper()).ToList();
|
||||
|
||||
public static void ParsePluginsConfig() {
|
||||
pluginMetadatas.Clear();
|
||||
ParseSystemPlugins();
|
||||
ParseThirdPartyPlugins();
|
||||
|
||||
if (Plugins.DebuggerMode != null) {
|
||||
PluginMetadata metadata = GetMetadataFromJson(Plugins.DebuggerMode);
|
||||
if (metadata != null) pluginMetadatas.Add(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
private static void ParseSystemPlugins() {
|
||||
pluginMetadatas.Add(new PluginMetadata() {
|
||||
Name = "System Plugins",
|
||||
Author = "System",
|
||||
Description = "system plugins collection",
|
||||
Website = "http://www.getwox.com",
|
||||
Language = AllowedLanguage.CSharp,
|
||||
Version = "1.0",
|
||||
PluginType = PluginType.System,
|
||||
ActionKeyword = "*",
|
||||
ExecuteFileName = "Wox.Plugin.SystemPlugins.dll",
|
||||
PluginDirecotry = Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath)
|
||||
});
|
||||
}
|
||||
|
||||
private static void ParseThirdPartyPlugins() {
|
||||
if (!Directory.Exists(PluginPath))
|
||||
Directory.CreateDirectory(PluginPath);
|
||||
|
||||
string[] directories = Directory.GetDirectories(PluginPath);
|
||||
foreach (string directory in directories) {
|
||||
if (File.Exists((Path.Combine(directory, "NeedDelete.txt")))) {
|
||||
Directory.Delete(directory, true);
|
||||
continue;
|
||||
}
|
||||
PluginMetadata metadata = GetMetadataFromJson(directory);
|
||||
if (metadata != null) pluginMetadatas.Add(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
private static PluginMetadata GetMetadataFromJson(string pluginDirectory) {
|
||||
string configPath = Path.Combine(pluginDirectory, PluginConfigName);
|
||||
PluginMetadata metadata;
|
||||
|
||||
if (!File.Exists(configPath)) {
|
||||
Log.Warn(string.Format("parse plugin {0} failed: didn't find config file.", configPath));
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
metadata = JsonConvert.DeserializeObject<PluginMetadata>(File.ReadAllText(configPath));
|
||||
metadata.PluginType = PluginType.ThirdParty;
|
||||
metadata.PluginDirecotry = pluginDirectory;
|
||||
}
|
||||
catch (Exception) {
|
||||
string error = string.Format("Parse plugin config {0} failed: json format is not valid", configPath);
|
||||
Log.Warn(error);
|
||||
#if (DEBUG)
|
||||
{
|
||||
throw new WoxException(error);
|
||||
}
|
||||
#endif
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
if (!AllowedLanguage.IsAllowed(metadata.Language)) {
|
||||
string error = string.Format("Parse plugin config {0} failed: invalid language {1}", configPath, metadata.Language);
|
||||
Log.Warn(error);
|
||||
#if (DEBUG)
|
||||
{
|
||||
throw new WoxException(error);
|
||||
}
|
||||
#endif
|
||||
return null;
|
||||
}
|
||||
if (!File.Exists(metadata.ExecuteFilePath)) {
|
||||
string error = string.Format("Parse plugin config {0} failed: ExecuteFile {1} didn't exist", configPath, metadata.ExecuteFilePath);
|
||||
Log.Warn(error);
|
||||
#if (DEBUG)
|
||||
{
|
||||
throw new WoxException(error);
|
||||
}
|
||||
#endif
|
||||
return null;
|
||||
}
|
||||
|
||||
var customizedPluginConfig =
|
||||
UserSettingStorage.Instance.CustomizedPluginConfigs.FirstOrDefault(o => o.ID == metadata.ID);
|
||||
if (customizedPluginConfig != null && !string.IsNullOrEmpty(customizedPluginConfig.Actionword))
|
||||
{
|
||||
metadata.ActionKeyword = customizedPluginConfig.Actionword;
|
||||
}
|
||||
|
||||
return metadata;
|
||||
}
|
||||
}
|
||||
return metadatas.Select(metadata => new PluginPair()
|
||||
{
|
||||
Plugin = new T(),
|
||||
Metadata = metadata
|
||||
}).ToList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,10 @@ using Wox.Plugin.SystemPlugins;
|
||||
|
||||
namespace Wox.PluginLoader {
|
||||
|
||||
public class CSharpPluginLoader : BasePluginLoader {
|
||||
|
||||
public override List<PluginPair> LoadPlugin() {
|
||||
public class CSharpPluginLoader : IPluginLoader
|
||||
{
|
||||
public List<PluginPair> LoadPlugin(List<PluginMetadata> pluginMetadatas)
|
||||
{
|
||||
var plugins = new List<PluginPair>();
|
||||
|
||||
List<PluginMetadata> metadatas = pluginMetadatas.Where(o => o.Language.ToUpper() == AllowedLanguage.CSharp.ToUpper()).ToList();
|
||||
|
||||
13
Wox/PluginLoader/IPluginLoader.cs
Normal file
13
Wox/PluginLoader/IPluginLoader.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using Wox.Plugin;
|
||||
|
||||
namespace Wox.PluginLoader
|
||||
{
|
||||
public interface IPluginLoader
|
||||
{
|
||||
List<PluginPair> LoadPlugin(List<PluginMetadata> pluginMetadatas);
|
||||
}
|
||||
}
|
||||
119
Wox/PluginLoader/PluginConfigLoader.cs
Normal file
119
Wox/PluginLoader/PluginConfigLoader.cs
Normal file
@@ -0,0 +1,119 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Windows.Forms;
|
||||
using Newtonsoft.Json;
|
||||
using Wox.Helper;
|
||||
using Wox.Infrastructure.Storage.UserSettings;
|
||||
using Wox.Plugin;
|
||||
using Wox.Plugin.SystemPlugins;
|
||||
|
||||
namespace Wox.PluginLoader {
|
||||
public abstract class PluginConfigLoader {
|
||||
private static string PluginPath = Path.Combine(Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath), "Plugins");
|
||||
private static string PluginConfigName = "plugin.json";
|
||||
private static List<PluginMetadata> pluginMetadatas = new List<PluginMetadata>();
|
||||
|
||||
public static List<PluginMetadata> ParsePluginsConfig()
|
||||
{
|
||||
pluginMetadatas.Clear();
|
||||
ParseSystemPlugins();
|
||||
ParseThirdPartyPlugins();
|
||||
|
||||
if (Plugins.DebuggerMode != null) {
|
||||
PluginMetadata metadata = GetMetadataFromJson(Plugins.DebuggerMode);
|
||||
if (metadata != null) pluginMetadatas.Add(metadata);
|
||||
}
|
||||
return pluginMetadatas;
|
||||
}
|
||||
|
||||
private static void ParseSystemPlugins() {
|
||||
pluginMetadatas.Add(new PluginMetadata() {
|
||||
Name = "System Plugins",
|
||||
Author = "System",
|
||||
Description = "system plugins collection",
|
||||
Website = "http://www.getwox.com",
|
||||
Language = AllowedLanguage.CSharp,
|
||||
Version = "1.0",
|
||||
PluginType = PluginType.System,
|
||||
ActionKeyword = "*",
|
||||
ExecuteFileName = "Wox.Plugin.SystemPlugins.dll",
|
||||
PluginDirecotry = Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath)
|
||||
});
|
||||
}
|
||||
|
||||
private static void ParseThirdPartyPlugins() {
|
||||
if (!Directory.Exists(PluginPath))
|
||||
Directory.CreateDirectory(PluginPath);
|
||||
|
||||
string[] directories = Directory.GetDirectories(PluginPath);
|
||||
foreach (string directory in directories) {
|
||||
if (File.Exists((Path.Combine(directory, "NeedDelete.txt")))) {
|
||||
Directory.Delete(directory, true);
|
||||
continue;
|
||||
}
|
||||
PluginMetadata metadata = GetMetadataFromJson(directory);
|
||||
if (metadata != null) pluginMetadatas.Add(metadata);
|
||||
}
|
||||
}
|
||||
|
||||
private static PluginMetadata GetMetadataFromJson(string pluginDirectory) {
|
||||
string configPath = Path.Combine(pluginDirectory, PluginConfigName);
|
||||
PluginMetadata metadata;
|
||||
|
||||
if (!File.Exists(configPath)) {
|
||||
Log.Warn(string.Format("parse plugin {0} failed: didn't find config file.", configPath));
|
||||
return null;
|
||||
}
|
||||
|
||||
try {
|
||||
metadata = JsonConvert.DeserializeObject<PluginMetadata>(File.ReadAllText(configPath));
|
||||
metadata.PluginType = PluginType.ThirdParty;
|
||||
metadata.PluginDirecotry = pluginDirectory;
|
||||
}
|
||||
catch (Exception) {
|
||||
string error = string.Format("Parse plugin config {0} failed: json format is not valid", configPath);
|
||||
Log.Warn(error);
|
||||
#if (DEBUG)
|
||||
{
|
||||
throw new WoxException(error);
|
||||
}
|
||||
#endif
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
if (!AllowedLanguage.IsAllowed(metadata.Language)) {
|
||||
string error = string.Format("Parse plugin config {0} failed: invalid language {1}", configPath, metadata.Language);
|
||||
Log.Warn(error);
|
||||
#if (DEBUG)
|
||||
{
|
||||
throw new WoxException(error);
|
||||
}
|
||||
#endif
|
||||
return null;
|
||||
}
|
||||
if (!File.Exists(metadata.ExecuteFilePath)) {
|
||||
string error = string.Format("Parse plugin config {0} failed: ExecuteFile {1} didn't exist", configPath, metadata.ExecuteFilePath);
|
||||
Log.Warn(error);
|
||||
#if (DEBUG)
|
||||
{
|
||||
throw new WoxException(error);
|
||||
}
|
||||
#endif
|
||||
return null;
|
||||
}
|
||||
|
||||
var customizedPluginConfig =
|
||||
UserSettingStorage.Instance.CustomizedPluginConfigs.FirstOrDefault(o => o.ID == metadata.ID);
|
||||
if (customizedPluginConfig != null && !string.IsNullOrEmpty(customizedPluginConfig.Actionword))
|
||||
{
|
||||
metadata.ActionKeyword = customizedPluginConfig.Actionword;
|
||||
}
|
||||
|
||||
return metadata;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,96 +1,56 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using Microsoft.CSharp;
|
||||
using Wox.Helper;
|
||||
using Wox.Infrastructure;
|
||||
using Wox.Infrastructure.Storage;
|
||||
using Wox.Infrastructure.Storage.UserSettings;
|
||||
using Wox.Plugin;
|
||||
|
||||
namespace Wox.PluginLoader {
|
||||
public static class Plugins {
|
||||
//private static string debuggerMode = null;
|
||||
public static String DebuggerMode { get; private set; }
|
||||
namespace Wox.PluginLoader
|
||||
{
|
||||
public static class Plugins
|
||||
{
|
||||
public static String DebuggerMode { get; private set; }
|
||||
private static List<PluginPair> plugins = new List<PluginPair>();
|
||||
|
||||
private static List<PluginPair> plugins = new List<PluginPair>();
|
||||
private static ManualResetEvent initializing = null;
|
||||
public static void Init()
|
||||
{
|
||||
plugins.Clear();
|
||||
List<PluginMetadata> pluginMetadatas = PluginConfigLoader.ParsePluginsConfig();
|
||||
|
||||
public static void Init() {
|
||||
if (initializing != null) return;
|
||||
plugins.AddRange(new CSharpPluginLoader().LoadPlugin(pluginMetadatas));
|
||||
plugins.AddRange(new BasePluginLoader<PythonPlugin>().LoadPlugin(pluginMetadatas));
|
||||
|
||||
initializing = new ManualResetEvent(false);
|
||||
plugins.Clear();
|
||||
BasePluginLoader.ParsePluginsConfig();
|
||||
|
||||
plugins.AddRange(new PythonPluginLoader().LoadPlugin());
|
||||
plugins.AddRange(new CSharpPluginLoader().LoadPlugin());
|
||||
Forker forker = new Forker();
|
||||
foreach (IPlugin plugin in plugins.Select(pluginPair => pluginPair.Plugin)) {
|
||||
IPlugin plugin1 = plugin;
|
||||
PluginPair pluginPair = plugins.FirstOrDefault(o => o.Plugin == plugin1);
|
||||
if (pluginPair != null) {
|
||||
PluginMetadata metadata = pluginPair.Metadata;
|
||||
pluginPair.InitContext = new PluginInitContext() {
|
||||
Plugins = plugins,
|
||||
CurrentPluginMetadata = metadata,
|
||||
ChangeQuery = s => App.Window.Dispatcher.Invoke(new Action(() => App.Window.ChangeQuery(s))),
|
||||
CloseApp = () => App.Window.Dispatcher.Invoke(new Action(() => App.Window.CloseApp())),
|
||||
HideApp = () => App.Window.Dispatcher.Invoke(new Action(() => App.Window.HideApp())),
|
||||
ShowApp = () => App.Window.Dispatcher.Invoke(new Action(() => App.Window.ShowApp())),
|
||||
ShowMsg = (title, subTitle, iconPath) => App.Window.Dispatcher.Invoke(new Action(() =>
|
||||
App.Window.ShowMsg(title, subTitle, iconPath))),
|
||||
OpenSettingDialog = () => App.Window.Dispatcher.Invoke(new Action(() => App.Window.OpenSettingDialog())),
|
||||
ShowCurrentResultItemTooltip = (msg) => App.Window.Dispatcher.Invoke(new Action(() => App.Window.ShowCurrentResultItemTooltip(msg))),
|
||||
ReloadPlugins = () => App.Window.Dispatcher.Invoke(new Action(() => Init())),
|
||||
InstallPlugin = (filePath) => App.Window.Dispatcher.Invoke(new Action(() => {
|
||||
PluginInstaller.Install(filePath);
|
||||
})),
|
||||
StartLoadingBar = () => App.Window.Dispatcher.Invoke(new Action(() => App.Window.StartLoadingBar())),
|
||||
StopLoadingBar = () => App.Window.Dispatcher.Invoke(new Action(() => App.Window.StopLoadingBar())),
|
||||
//ShellRun = (cmd) => (bool)App.Window.Dispatcher.Invoke(new Func<bool>(() => App.Window.ShellRun(cmd)))
|
||||
};
|
||||
Forker forker = new Forker();
|
||||
foreach (PluginPair pluginPair in plugins)
|
||||
{
|
||||
PluginPair pair = pluginPair;
|
||||
forker.Fork(() => pair.Plugin.Init(new PluginInitContext()
|
||||
{
|
||||
CurrentPluginMetadata = pair.Metadata,
|
||||
API = App.Window
|
||||
}));
|
||||
}
|
||||
|
||||
pluginPair.InitContext.ShellRun = (cmd) => {
|
||||
try {
|
||||
return (bool)App.Window.Dispatcher.Invoke(new Func<bool>(() => App.Window.ShellRun(cmd)));
|
||||
}
|
||||
catch (Exception) {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
forker.Join();
|
||||
}
|
||||
|
||||
forker.Fork(() => plugin1.Init(pluginPair.InitContext));
|
||||
}
|
||||
}
|
||||
public static List<PluginPair> AllPlugins
|
||||
{
|
||||
get
|
||||
{
|
||||
return plugins;
|
||||
}
|
||||
}
|
||||
|
||||
ThreadPool.QueueUserWorkItem(o => {
|
||||
forker.Join();
|
||||
initializing.Set();
|
||||
initializing = null;
|
||||
});
|
||||
}
|
||||
public static bool HitThirdpartyKeyword(Query query)
|
||||
{
|
||||
if (string.IsNullOrEmpty(query.ActionName)) return false;
|
||||
|
||||
public static List<PluginPair> AllPlugins {
|
||||
get {
|
||||
var init = initializing;
|
||||
if (init != null) {
|
||||
init.WaitOne();
|
||||
}
|
||||
return plugins;
|
||||
}
|
||||
}
|
||||
return plugins.Any(o => o.Metadata.PluginType == PluginType.ThirdParty && o.Metadata.ActionKeyword == query.ActionName);
|
||||
}
|
||||
|
||||
public static bool HitThirdpartyKeyword(Query query) {
|
||||
if (string.IsNullOrEmpty(query.ActionName)) return false;
|
||||
|
||||
return plugins.Any(o => o.Metadata.PluginType == PluginType.ThirdParty && o.Metadata.ActionKeyword == query.ActionName);
|
||||
}
|
||||
|
||||
public static void ActivatePluginDebugger(string path) {
|
||||
DebuggerMode = path;
|
||||
}
|
||||
}
|
||||
public static void ActivatePluginDebugger(string path)
|
||||
{
|
||||
DebuggerMode = path;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
33
Wox/PluginLoader/PythonPlugin.cs
Normal file
33
Wox/PluginLoader/PythonPlugin.cs
Normal file
@@ -0,0 +1,33 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Wox.JsonRPC;
|
||||
using Wox.Plugin;
|
||||
|
||||
namespace Wox.PluginLoader
|
||||
{
|
||||
public class PythonPlugin : BasePlugin
|
||||
{
|
||||
private static string woxDirectory = Path.GetDirectoryName(System.Windows.Forms.Application.ExecutablePath);
|
||||
|
||||
public override string SupportedLanguage
|
||||
{
|
||||
get { return AllowedLanguage.Python; }
|
||||
}
|
||||
|
||||
protected override string ExecuteQuery(Query query)
|
||||
{
|
||||
string fileName = Path.Combine(woxDirectory, "PythonHome\\pythonw.exe");
|
||||
string parameters = string.Format("{0} \"{1}\"", context.CurrentPluginMetadata.ExecuteFilePath,
|
||||
string.Format(@"{{\""method\"": \""query\"", \""parameters\"": [\""{0}\""]}}",query.GetAllRemainingParameter()));
|
||||
|
||||
return Execute(fileName, parameters);
|
||||
}
|
||||
|
||||
protected override string ExecuteAction(JsonRPCRequestModel rpcRequest)
|
||||
{
|
||||
string fileName = Path.Combine(woxDirectory, "PythonHome\\pythonw.exe");
|
||||
string parameters = string.Format("{0} \"{1}\"", context.CurrentPluginMetadata.ExecuteFilePath,rpcRequest);
|
||||
return Execute(fileName, parameters);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,55 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Python.Runtime;
|
||||
using Wox.Plugin;
|
||||
using Wox.Helper;
|
||||
|
||||
namespace Wox.PluginLoader
|
||||
{
|
||||
public class PythonPluginLoader : BasePluginLoader
|
||||
{
|
||||
public override List<PluginPair> LoadPlugin()
|
||||
{
|
||||
if (!CheckPythonEnvironmentInstalled()) return new List<PluginPair>();
|
||||
|
||||
List<PluginPair> plugins = new List<PluginPair>();
|
||||
List<PluginMetadata> metadatas = pluginMetadatas.Where(o => o.Language.ToUpper() == AllowedLanguage.Python.ToUpper()).ToList();
|
||||
foreach (PluginMetadata metadata in metadatas)
|
||||
{
|
||||
PythonPluginWrapper python = new PythonPluginWrapper(metadata);
|
||||
PluginPair pair = new PluginPair()
|
||||
{
|
||||
Plugin = python,
|
||||
Metadata = metadata
|
||||
};
|
||||
plugins.Add(pair);
|
||||
}
|
||||
|
||||
return plugins;
|
||||
}
|
||||
|
||||
private bool CheckPythonEnvironmentInstalled() {
|
||||
try
|
||||
{
|
||||
SetPythonHome();
|
||||
PythonEngine.Initialize();
|
||||
PythonEngine.Shutdown();
|
||||
}
|
||||
catch {
|
||||
Log.Warn("Could't find python environment, all python plugins disabled.");
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void SetPythonHome()
|
||||
{
|
||||
//Environment.SetEnvironmentVariable("PYTHONHOME",Path.Combine(Path.GetDirectoryName(Application.ExecutablePath),"PythonHome"));
|
||||
//PythonEngine.PythonHome =
|
||||
//PythonEngine.ProgramName
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,142 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using Python.Runtime;
|
||||
using Wox.Helper;
|
||||
using Wox.Plugin;
|
||||
|
||||
namespace Wox.PluginLoader
|
||||
{
|
||||
public class PythonPluginWrapper : IPlugin
|
||||
{
|
||||
private PluginMetadata metadata;
|
||||
private string moduleName;
|
||||
|
||||
public PythonPluginWrapper(PluginMetadata metadata)
|
||||
{
|
||||
this.metadata = metadata;
|
||||
moduleName = metadata.ExecuteFileName.Replace(".py", "");
|
||||
}
|
||||
|
||||
public List<Result> Query(Query query)
|
||||
{
|
||||
try
|
||||
{
|
||||
string jsonResult = InvokeFunc("query", query.RawQuery);
|
||||
if (string.IsNullOrEmpty(jsonResult))
|
||||
{
|
||||
return new List<Result>();
|
||||
}
|
||||
|
||||
List<PythonResult> o = JsonConvert.DeserializeObject<List<PythonResult>>(jsonResult);
|
||||
List<Result> r = new List<Result>();
|
||||
foreach (PythonResult pythonResult in o)
|
||||
{
|
||||
PythonResult ps = pythonResult;
|
||||
if (!string.IsNullOrEmpty(ps.ActionName))
|
||||
{
|
||||
ps.Action = (context) =>
|
||||
{
|
||||
InvokeFunc(ps.ActionName, GetPythonActionContext(context), new PyString(ps.ActionPara));
|
||||
return true;
|
||||
};
|
||||
}
|
||||
r.Add(ps);
|
||||
}
|
||||
return r;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
#if (DEBUG)
|
||||
{
|
||||
throw new WoxPythonException(e.Message);
|
||||
}
|
||||
#endif
|
||||
Log.Error(string.Format("Python Plugin {0} query failed: {1}", metadata.Name, e.Message));
|
||||
}
|
||||
|
||||
return new List<Result>();
|
||||
}
|
||||
|
||||
private PyObject GetPythonActionContext(ActionContext context)
|
||||
{
|
||||
PyDict dict = new PyDict();
|
||||
PyDict specialKeyStateDict = new PyDict();
|
||||
specialKeyStateDict["CtrlPressed"] = new PyString(context.SpecialKeyState.CtrlPressed.ToString());
|
||||
specialKeyStateDict["AltPressed"] = new PyString(context.SpecialKeyState.AltPressed.ToString());
|
||||
specialKeyStateDict["WinPressed"] = new PyString(context.SpecialKeyState.WinPressed.ToString());
|
||||
specialKeyStateDict["ShiftPressed"] = new PyString(context.SpecialKeyState.ShiftPressed.ToString());
|
||||
|
||||
dict["SpecialKeyState"] = specialKeyStateDict;
|
||||
return dict;
|
||||
}
|
||||
|
||||
private string InvokeFunc(string func, params PyObject[] paras)
|
||||
{
|
||||
string json = null;
|
||||
|
||||
//if pythobn plugin folder name is chinese, here will deadlock.
|
||||
IntPtr gs = PythonEngine.AcquireLock();
|
||||
|
||||
PyObject module = PythonEngine.ImportModule(moduleName);
|
||||
if (module == null)
|
||||
{
|
||||
string error = string.Format("Python Invoke failed: {0} doesn't has module {1}",
|
||||
metadata.ExecuteFilePath, moduleName);
|
||||
Log.Error(error);
|
||||
return json;
|
||||
}
|
||||
|
||||
if (module.HasAttr(func))
|
||||
{
|
||||
try
|
||||
{
|
||||
PyObject res = paras.Length > 0 ? module.InvokeMethod(func, paras) : module.InvokeMethod(func);
|
||||
json = Runtime.GetManagedString(res.Handle);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
string error = string.Format("Python Invoke failed: {0}", e.Message);
|
||||
Log.Error(error);
|
||||
#if (DEBUG)
|
||||
{
|
||||
throw new WoxPythonException(error);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
string error = string.Format("Python Invoke failed: {0} doesn't has function {1}",
|
||||
metadata.ExecuteFilePath, func);
|
||||
Log.Error(error);
|
||||
#if (DEBUG)
|
||||
{
|
||||
throw new WoxPythonException(error);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
PythonEngine.ReleaseLock(gs);
|
||||
|
||||
return json;
|
||||
}
|
||||
|
||||
private string InvokeFunc(string func, params string[] para)
|
||||
{
|
||||
PyObject[] paras = { };
|
||||
if (para != null && para.Length > 0)
|
||||
{
|
||||
paras = para.Select(o => new PyString(o)).ToArray();
|
||||
}
|
||||
return InvokeFunc(func, paras);
|
||||
}
|
||||
|
||||
public void Init(PluginInitContext context)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -22,7 +22,7 @@
|
||||
<ColumnDefinition Width="32"></ColumnDefinition>
|
||||
<ColumnDefinition/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<Image x:Name="imgIco" Width="32" Height="32" HorizontalAlignment="Left" >
|
||||
<Image x:Name="imgIco" Width="32" Height="32" HorizontalAlignment="Left">
|
||||
<Image.Resources>
|
||||
<converters:ImagePathConverter x:Key="ImageConverter"/>
|
||||
</Image.Resources>
|
||||
|
||||
@@ -1,9 +1,12 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using Wox.Helper;
|
||||
using Wox.Plugin;
|
||||
using UserControl = System.Windows.Controls.UserControl;
|
||||
|
||||
@@ -23,6 +26,7 @@ namespace Wox
|
||||
|
||||
public void AddResults(List<Result> results)
|
||||
{
|
||||
|
||||
if (Dirty)
|
||||
{
|
||||
Dirty = false;
|
||||
@@ -30,6 +34,10 @@ namespace Wox
|
||||
}
|
||||
foreach (var result in results)
|
||||
{
|
||||
//ThreadPool.QueueUserWorkItem(delegate
|
||||
// {
|
||||
// ImageLoader.Load(Path.Combine(result.PluginDirectory, result.IcoPath));
|
||||
// });
|
||||
int position = GetInsertLocation(result.Score);
|
||||
lbResults.Items.Insert(position, result);
|
||||
}
|
||||
|
||||
@@ -120,6 +120,7 @@
|
||||
</Compile>
|
||||
<Compile Include="Helper\FontHelper.cs" />
|
||||
<Compile Include="Helper\Forker.cs" />
|
||||
<Compile Include="Helper\ImageLoader.cs" />
|
||||
<Compile Include="Helper\SyntaxSugars.cs" />
|
||||
<Compile Include="Helper\WallpaperPathRetrieval.cs" />
|
||||
<Compile Include="Helper\WindowIntelopHelper.cs" />
|
||||
@@ -138,14 +139,17 @@
|
||||
<DependentUpon>HotkeyControl.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="Converters\ImagePathConverter.cs" />
|
||||
<Compile Include="PluginLoader\IPluginLoader.cs" />
|
||||
<Compile Include="Msg.xaml.cs">
|
||||
<DependentUpon>Msg.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="PluginLoader\BasePluginLoader.cs" />
|
||||
<Compile Include="PluginLoader\PluginConfigLoader.cs" />
|
||||
<Compile Include="PluginLoader\CSharpPluginLoader.cs" />
|
||||
<Compile Include="PluginLoader\BasePluginLoader.cs" />
|
||||
<Compile Include="PluginLoader\BasePlugin.cs" />
|
||||
<Compile Include="JsonRPC\JsonPRCModel.cs" />
|
||||
<Compile Include="PluginLoader\Plugins.cs" />
|
||||
<Compile Include="PluginLoader\PythonPluginLoader.cs" />
|
||||
<Compile Include="PluginLoader\PythonPluginWrapper.cs" />
|
||||
<Compile Include="PluginLoader\PythonPlugin.cs" />
|
||||
<Compile Include="Properties\Annotations.cs" />
|
||||
<Compile Include="ResultPanel.xaml.cs">
|
||||
<DependentUpon>ResultPanel.xaml</DependentUpon>
|
||||
@@ -260,10 +264,6 @@
|
||||
<AppDesigner Include="Properties\" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Pythonnet.Runtime\Python.Runtime.csproj">
|
||||
<Project>{097b4ac0-74e9-4c58-bcf8-c69746ec8271}</Project>
|
||||
<Name>Python.Runtime</Name>
|
||||
</ProjectReference>
|
||||
<ProjectReference Include="..\Wox.Infrastructure\Wox.Infrastructure.csproj">
|
||||
<Project>{4fd29318-a8ab-4d8f-aa47-60bc241b8da3}</Project>
|
||||
<Name>Wox.Infrastructure</Name>
|
||||
|
||||
Reference in New Issue
Block a user