From 7be02731ee8354d2349c1550770fc06a3dec25af Mon Sep 17 00:00:00 2001 From: qianlifeng Date: Fri, 18 Jul 2014 14:09:52 +0800 Subject: [PATCH] Fix issues in ControlPanel plugin. --- .../ControlPanel/ControlPanel.cs | 57 ++-- .../ControlPanel/ControlPanelItem.cs | 25 ++ .../ControlPanel/ControlPanelList.cs | 265 ++++++++++++++++++ .../Wox.Plugin.SystemPlugins.csproj | 5 +- 4 files changed, 315 insertions(+), 37 deletions(-) create mode 100644 Wox.Plugin.SystemPlugins/ControlPanel/ControlPanelItem.cs create mode 100644 Wox.Plugin.SystemPlugins/ControlPanel/ControlPanelList.cs diff --git a/Wox.Plugin.SystemPlugins/ControlPanel/ControlPanel.cs b/Wox.Plugin.SystemPlugins/ControlPanel/ControlPanel.cs index e693ed78b7..c260a4c053 100644 --- a/Wox.Plugin.SystemPlugins/ControlPanel/ControlPanel.cs +++ b/Wox.Plugin.SystemPlugins/ControlPanel/ControlPanel.cs @@ -1,12 +1,9 @@ using System; using System.Collections.Generic; -using System.Linq; -using System.Text; -using Wox.Infrastructure; -using Wox.Infrastructure.Storage.UserSettings; -using WindowsControlPanelItems; using System.Diagnostics; using System.IO; +using System.Linq; +using Wox.Infrastructure; namespace Wox.Plugin.SystemPlugins.ControlPanel { @@ -42,10 +39,16 @@ namespace Wox.Plugin.SystemPlugins.ControlPanel protected override void InitInternal(PluginInitContext context) { this.context = context; - controlPanelItems = WindowsControlPanelItems.List.Create(48); + controlPanelItems = ControlPanelList.Create(48); iconFolder = @"Images\ControlPanelIcons\"; fileType = ".bmp"; + if (!Directory.Exists(iconFolder)) + { + Directory.CreateDirectory(iconFolder); + } + + foreach (ControlPanelItem item in controlPanelItems) { if (!File.Exists(iconFolder + item.ApplicationName + fileType)) @@ -61,37 +64,17 @@ namespace Wox.Plugin.SystemPlugins.ControlPanel string myQuery = query.RawQuery.Trim(); List results = new List(); - List filteredResults = new List(); foreach (var item in controlPanelItems) { - if (item.LocalizedString.IndexOf(myQuery, StringComparison.OrdinalIgnoreCase) >= 0) - { - results.Insert(0, new Result() - { - Title = item.LocalizedString, - SubTitle = item.InfoTip, - IcoPath = "Images\\ControlPanelIcons\\" + item.ApplicationName + fileType, - Action = e => - { - try - { - Process.Start(item.ExecutablePath); - } - catch (Exception) - { - //Silently Fail for now.. - } - return true; - } - }); - } - else if (item.InfoTip.IndexOf(myQuery, StringComparison.OrdinalIgnoreCase) >= 0) + var fuzzyMather = FuzzyMatcher.Create(myQuery); + if (MatchProgram(item, fuzzyMather)) { results.Add(new Result() { Title = item.LocalizedString, SubTitle = item.InfoTip, + Score = item.Score, IcoPath = "Images\\ControlPanelIcons\\" + item.ApplicationName + fileType, Action = e => { @@ -108,12 +91,18 @@ namespace Wox.Plugin.SystemPlugins.ControlPanel }); } } - for (int i = 0; i < 2 && i < results.Count; i++) - { - filteredResults.Add(results[i]); - } - return filteredResults; + return results.OrderByDescending(o => o.Score).Take(5).ToList(); + } + + private bool MatchProgram(ControlPanelItem item, FuzzyMatcher matcher) + { + if (item.LocalizedString != null && (item.Score = matcher.Evaluate(item.LocalizedString).Score) > 0) return true; + if (item.InfoTip != null && (item.Score = matcher.Evaluate(item.InfoTip).Score) > 0) return true; + + if (item.LocalizedString != null && (item.Score = matcher.Evaluate(item.LocalizedString.Unidecode()).Score) > 0) return true; + + return false; } } } diff --git a/Wox.Plugin.SystemPlugins/ControlPanel/ControlPanelItem.cs b/Wox.Plugin.SystemPlugins/ControlPanel/ControlPanelItem.cs new file mode 100644 index 0000000000..712e384131 --- /dev/null +++ b/Wox.Plugin.SystemPlugins/ControlPanel/ControlPanelItem.cs @@ -0,0 +1,25 @@ +using System.Diagnostics; +using System.Drawing; + +namespace Wox.Plugin.SystemPlugins.ControlPanel +{ + //from:https://raw.githubusercontent.com/CoenraadS/Windows-Control-Panel-Items + public class ControlPanelItem + { + public string LocalizedString { get; private set; } + public string InfoTip { get; private set; } + public string ApplicationName { get; private set; } + public ProcessStartInfo ExecutablePath { get; private set; } + public Icon Icon { get; private set; } + public int Score { get; set; } + + public ControlPanelItem(string newLocalizedString, string newInfoTip, string newApplicationName, ProcessStartInfo newExecutablePath, Icon newLargeIcon) + { + LocalizedString = newLocalizedString; + InfoTip = newInfoTip; + ApplicationName = newApplicationName; + ExecutablePath = newExecutablePath; + Icon = (Icon)newLargeIcon.Clone(); + } + } +} diff --git a/Wox.Plugin.SystemPlugins/ControlPanel/ControlPanelList.cs b/Wox.Plugin.SystemPlugins/ControlPanel/ControlPanelList.cs new file mode 100644 index 0000000000..2e04a38203 --- /dev/null +++ b/Wox.Plugin.SystemPlugins/ControlPanel/ControlPanelList.cs @@ -0,0 +1,265 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.Win32; +using System.Runtime.InteropServices; +using System.Diagnostics; +using System.Drawing; + +namespace Wox.Plugin.SystemPlugins.ControlPanel +{ + //from:https://raw.githubusercontent.com/CoenraadS/Windows-Control-Panel-Items + public static class ControlPanelList + { + private const uint GROUP_ICON = 14; + private const uint LOAD_LIBRARY_AS_DATAFILE = 0x00000002; + private const string CONTROL = @"%SystemRoot%\System32\control.exe"; + + private delegate bool EnumResNameDelegate( + IntPtr hModule, + IntPtr lpszType, + IntPtr lpszName, + IntPtr lParam); + + [DllImport("kernel32.dll", EntryPoint = "EnumResourceNamesW", CharSet = CharSet.Unicode, SetLastError = true)] + static extern bool EnumResourceNamesWithID(IntPtr hModule, uint lpszType, EnumResNameDelegate lpEnumFunc, IntPtr lParam); + + [DllImport("kernel32.dll", SetLastError = true)] + static extern IntPtr LoadLibraryEx(string lpFileName, IntPtr hFile, uint dwFlags); + + [DllImport("kernel32.dll", SetLastError = true)] + static extern bool FreeLibrary(IntPtr hModule); + + [DllImport("user32.dll", CharSet = CharSet.Auto)] + static extern int LoadString(IntPtr hInstance, uint uID, StringBuilder lpBuffer, int nBufferMax); + + [DllImport("user32.dll", SetLastError = true, CharSet = CharSet.Auto)] + static extern IntPtr LoadImage(IntPtr hinst, IntPtr lpszName, uint uType, + int cxDesired, int cyDesired, uint fuLoad); + + [DllImport("user32.dll", CharSet = CharSet.Auto)] + extern static bool DestroyIcon(IntPtr handle); + + [DllImport("kernel32.dll")] + static extern IntPtr FindResource(IntPtr hModule, IntPtr lpName, IntPtr lpType); + + static Queue iconQueue; + + public static List Create(int iconSize) + { + List controlPanelItems = new List(); + string applicationName; + string[] localizedString; + string[] infoTip = new string[1]; + List iconString; + IntPtr dataFilePointer; + uint stringTableIndex; + IntPtr iconIndex; + StringBuilder resource; + ProcessStartInfo executablePath; + IntPtr iconPtr = IntPtr.Zero; + Icon myIcon; + + RegistryKey nameSpace = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\NameSpace"); + RegistryKey clsid = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Classes\\CLSID"); + RegistryKey currentKey; + + foreach (string key in nameSpace.GetSubKeyNames()) + { + //todo:throw exceptions in my computer, need to check this,Silently Fail for now. + try + { + currentKey = clsid.OpenSubKey(key); + if (currentKey != null) + { + if (currentKey.GetValue("System.ApplicationName") != null && + currentKey.GetValue("LocalizedString") != null) + { + applicationName = currentKey.GetValue("System.ApplicationName").ToString(); + //Debug.WriteLine(key.ToString() + " (" + applicationName + ")"); + localizedString = currentKey.GetValue("LocalizedString") + .ToString() + .Split(new char[] {','}, 2); + if (localizedString[0][0] == '@') + { + localizedString[0] = localizedString[0].Substring(1); + } + localizedString[0] = Environment.ExpandEnvironmentVariables(localizedString[0]); + if (localizedString.Length > 1) + { + dataFilePointer = LoadLibraryEx(localizedString[0], IntPtr.Zero, + LOAD_LIBRARY_AS_DATAFILE); + + stringTableIndex = sanitizeUint(localizedString[1]); + + resource = new StringBuilder(255); + LoadString(dataFilePointer, stringTableIndex, resource, resource.Capacity + 1); + + localizedString[0] = resource.ToString(); + + if (currentKey.GetValue("InfoTip") != null) + { + infoTip = currentKey.GetValue("InfoTip").ToString().Split(new char[] {','}, 2); + if (infoTip[0][0] == '@') + { + infoTip[0] = infoTip[0].Substring(1); + } + infoTip[0] = Environment.ExpandEnvironmentVariables(infoTip[0]); + + dataFilePointer = LoadLibraryEx(infoTip[0], IntPtr.Zero, LOAD_LIBRARY_AS_DATAFILE); + + stringTableIndex = sanitizeUint(infoTip[1]); + + resource = new StringBuilder(255); + LoadString(dataFilePointer, stringTableIndex, resource, resource.Capacity + 1); + + infoTip[0] = resource.ToString(); + } + else if (currentKey.GetValue(null) != null) + { + infoTip[0] = currentKey.GetValue(null).ToString(); + } + else + { + infoTip[0] = ""; + } + + FreeLibrary(dataFilePointer); + //We are finished with extracting strings. Prepare to load icon file. + dataFilePointer = IntPtr.Zero; + myIcon = null; + iconPtr = IntPtr.Zero; + + if (currentKey.OpenSubKey("DefaultIcon") != null) + { + if (currentKey.OpenSubKey("DefaultIcon").GetValue(null) != null) + { + iconString = + new List( + currentKey.OpenSubKey("DefaultIcon") + .GetValue(null) + .ToString() + .Split(new char[] {','}, 2)); + if (iconString[0][0] == '@') + { + iconString[0] = iconString[0].Substring(1); + } + + dataFilePointer = LoadLibraryEx(iconString[0], IntPtr.Zero, + LOAD_LIBRARY_AS_DATAFILE); + + if (iconString.Count < 2) + { + iconString.Add("0"); + } + + + iconIndex = (IntPtr) sanitizeUint(iconString[1]); + + if (iconIndex == IntPtr.Zero) + { + iconQueue = new Queue(); + EnumResourceNamesWithID(dataFilePointer, GROUP_ICON, + new EnumResNameDelegate(EnumRes), IntPtr.Zero); + //Iterate through resources. + + while (iconPtr == IntPtr.Zero && iconQueue.Count > 0) + { + iconPtr = LoadImage(dataFilePointer, iconQueue.Dequeue(), 1, iconSize, + iconSize, 0); + } + + } + else + { + iconPtr = LoadImage(dataFilePointer, iconIndex, 1, iconSize, iconSize, 0); + } + + try + { + myIcon = Icon.FromHandle(iconPtr); + } + catch (Exception) + { + //Silently fail for now. + } + } + } + + + executablePath = new ProcessStartInfo(); + executablePath.FileName = Environment.ExpandEnvironmentVariables(CONTROL); + executablePath.Arguments = "-name " + applicationName; + controlPanelItems.Add(new ControlPanelItem(localizedString[0], infoTip[0], + applicationName, executablePath, myIcon)); + FreeLibrary(dataFilePointer); + if (iconPtr != IntPtr.Zero) + { + DestroyIcon(myIcon.Handle); + } + } + } + } + } + + catch (Exception e) + { + Debug.Write(e); + } + } + + return controlPanelItems; + } + + private static uint sanitizeUint(string args) //Remove all chars before and after first set of digits. + { + int x = 0; + + while (x < args.Length && !Char.IsDigit(args[x])) + { + args = args.Substring(1); + } + + x = 0; + + while (x < args.Length && Char.IsDigit(args[x])) + { + x++; + } + + if (x < args.Length) + { + args = args.Remove(x); + } + + return Convert.ToUInt32(args); + } + + private static bool IS_INTRESOURCE(IntPtr value) + { + if (((uint)value) > ushort.MaxValue) + return false; + return true; + } + private static uint GET_RESOURCE_ID(IntPtr value) + { + if (IS_INTRESOURCE(value) == true) + return (uint)value; + throw new System.NotSupportedException("value is not an ID!"); + } + private static string GET_RESOURCE_NAME(IntPtr value) + { + if (IS_INTRESOURCE(value) == true) + return value.ToString(); + return Marshal.PtrToStringUni((IntPtr)value); + } + + private static bool EnumRes(IntPtr hModule, IntPtr lpszType, IntPtr lpszName, IntPtr lParam) + { + //Debug.WriteLine("Type: " + GET_RESOURCE_NAME(lpszType)); + //Debug.WriteLine("Name: " + GET_RESOURCE_NAME(lpszName)); + iconQueue.Enqueue(lpszName); + return true; + } + } +} diff --git a/Wox.Plugin.SystemPlugins/Wox.Plugin.SystemPlugins.csproj b/Wox.Plugin.SystemPlugins/Wox.Plugin.SystemPlugins.csproj index 38a88dd562..0c101e28f1 100644 --- a/Wox.Plugin.SystemPlugins/Wox.Plugin.SystemPlugins.csproj +++ b/Wox.Plugin.SystemPlugins/Wox.Plugin.SystemPlugins.csproj @@ -41,9 +41,6 @@ - - ..\packages\WindowsControlPanelItems.dll.1.0.0\lib\net35\WindowsControlPanelItems.dll - ..\packages\YAMP.1.3.0\lib\net35\YAMP.dll @@ -63,6 +60,8 @@ + + FolderPluginSettings.xaml