From 102d5fdd7f9283e77035754afbde7cd383ee62bc Mon Sep 17 00:00:00 2001 From: Coenraad Stijne Date: Fri, 18 Jul 2014 20:15:35 +0200 Subject: [PATCH] Update Control Panel The Control Panel now also includes third party panel items. --- .../ControlPanel/ControlPanel.cs | 6 +- .../ControlPanel/ControlPanelItem.cs | 6 +- .../ControlPanel/ControlPanelList.cs | 362 +++++++++++------- Wox.sln | 4 +- 4 files changed, 221 insertions(+), 157 deletions(-) diff --git a/Wox.Plugin.SystemPlugins/ControlPanel/ControlPanel.cs b/Wox.Plugin.SystemPlugins/ControlPanel/ControlPanel.cs index c260a4c053..9f9f10d70a 100644 --- a/Wox.Plugin.SystemPlugins/ControlPanel/ControlPanel.cs +++ b/Wox.Plugin.SystemPlugins/ControlPanel/ControlPanel.cs @@ -51,9 +51,9 @@ namespace Wox.Plugin.SystemPlugins.ControlPanel foreach (ControlPanelItem item in controlPanelItems) { - if (!File.Exists(iconFolder + item.ApplicationName + fileType)) + if (!File.Exists(iconFolder + item.LocalizedString + fileType)) { - item.Icon.ToBitmap().Save(iconFolder + item.ApplicationName + fileType); + item.Icon.ToBitmap().Save(iconFolder + item.LocalizedString + fileType); } } } @@ -75,7 +75,7 @@ namespace Wox.Plugin.SystemPlugins.ControlPanel Title = item.LocalizedString, SubTitle = item.InfoTip, Score = item.Score, - IcoPath = "Images\\ControlPanelIcons\\" + item.ApplicationName + fileType, + IcoPath = "Images\\ControlPanelIcons\\" + item.LocalizedString + fileType, Action = e => { try diff --git a/Wox.Plugin.SystemPlugins/ControlPanel/ControlPanelItem.cs b/Wox.Plugin.SystemPlugins/ControlPanel/ControlPanelItem.cs index 712e384131..faceb6481d 100644 --- a/Wox.Plugin.SystemPlugins/ControlPanel/ControlPanelItem.cs +++ b/Wox.Plugin.SystemPlugins/ControlPanel/ControlPanelItem.cs @@ -8,18 +8,16 @@ namespace Wox.Plugin.SystemPlugins.ControlPanel { 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) + public ControlPanelItem(string newLocalizedString, string newInfoTip, ProcessStartInfo newExecutablePath, Icon newIcon) { LocalizedString = newLocalizedString; InfoTip = newInfoTip; - ApplicationName = newApplicationName; ExecutablePath = newExecutablePath; - Icon = (Icon)newLargeIcon.Clone(); + Icon = newIcon; } } } diff --git a/Wox.Plugin.SystemPlugins/ControlPanel/ControlPanelList.cs b/Wox.Plugin.SystemPlugins/ControlPanel/ControlPanelList.cs index 2e04a38203..bfa7a38ef1 100644 --- a/Wox.Plugin.SystemPlugins/ControlPanel/ControlPanelList.cs +++ b/Wox.Plugin.SystemPlugins/ControlPanel/ControlPanelList.cs @@ -45,172 +45,238 @@ namespace Wox.Plugin.SystemPlugins.ControlPanel 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"); + static RegistryKey nameSpace = Registry.LocalMachine.OpenSubKey("SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Explorer\\ControlPanel\\NameSpace"); + static RegistryKey clsid = Registry.ClassesRoot.OpenSubKey("CLSID"); + + public static List Create(uint iconSize) + { + int size = (int)iconSize; RegistryKey currentKey; + ProcessStartInfo executablePath; + List controlPanelItems = new List(); + string localizedString; + string infoTip; + Icon myIcon; 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) { - 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); + executablePath = getExecutablePath(currentKey); - stringTableIndex = sanitizeUint(localizedString[1]); + if (executablePath == null) + continue; //Cannot have item without executable path - resource = new StringBuilder(255); - LoadString(dataFilePointer, stringTableIndex, resource, resource.Capacity + 1); + localizedString = getLocalizedString(currentKey); - localizedString[0] = resource.ToString(); + if (string.IsNullOrEmpty(localizedString)) + continue; //Cannot have item without Title - 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]); + infoTip = getInfoTip(currentKey); - dataFilePointer = LoadLibraryEx(infoTip[0], IntPtr.Zero, LOAD_LIBRARY_AS_DATAFILE); + myIcon = getIcon(currentKey, size); - stringTableIndex = sanitizeUint(infoTip[1]); + controlPanelItems.Add(new ControlPanelItem(localizedString, infoTip, executablePath, myIcon)); - 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 ProcessStartInfo getExecutablePath(RegistryKey currentKey) + { + ProcessStartInfo executablePath = new ProcessStartInfo(); + string applicationName; + + if (currentKey.GetValue("System.ApplicationName") != null) + { + //CPL Files (usually native MS items) + applicationName = currentKey.GetValue("System.ApplicationName").ToString(); + executablePath.FileName = Environment.ExpandEnvironmentVariables(CONTROL); + executablePath.Arguments = "-name " + applicationName; + } + else if (currentKey.OpenSubKey("Shell\\Open\\Command") != null && currentKey.OpenSubKey("Shell\\Open\\Command").GetValue(null) != null) + { + //Other files (usually third party items) + executablePath.FileName = Environment.ExpandEnvironmentVariables(currentKey.OpenSubKey("Shell\\Open\\Command").GetValue(null).ToString()); + } + else + { + return null; + } + + return executablePath; + } + + private static string getLocalizedString(RegistryKey currentKey) + { + IntPtr dataFilePointer; + string[] localizedStringRaw; + uint stringTableIndex; + StringBuilder resource; + string localizedString; + + if (currentKey.GetValue("LocalizedString") != null) + { + localizedStringRaw = currentKey.GetValue("LocalizedString").ToString().Split(new char[] { ',' }, 2); + + if (localizedStringRaw.Length > 1) + { + if (localizedStringRaw[0][0] == '@') + { + localizedStringRaw[0] = localizedStringRaw[0].Substring(1); + } + + localizedStringRaw[0] = Environment.ExpandEnvironmentVariables(localizedStringRaw[0]); + + dataFilePointer = LoadLibraryEx(localizedStringRaw[0], IntPtr.Zero, LOAD_LIBRARY_AS_DATAFILE); //Load file with strings + + stringTableIndex = sanitizeUint(localizedStringRaw[1]); + + resource = new StringBuilder(255); + LoadString(dataFilePointer, stringTableIndex, resource, resource.Capacity + 1); //Extract needed string + FreeLibrary(dataFilePointer); + + localizedString = resource.ToString(); + + /*This shouldn't be necessary, but some apps (e.g. Bootcamp) + * don't follow Microsoft's standard. Have to make a choice whether + * empty string == failure, or use default name. I'm using default name */ + + if (String.IsNullOrEmpty(localizedString)) + { + if (currentKey.GetValue(null) != null) + { + localizedString = currentKey.GetValue(null).ToString(); + } + else + { + return null; //Cannot have item without title. + } + } + } + else + { + localizedString = localizedStringRaw[0]; + } + } + else if (currentKey.GetValue(null) != null) + { + localizedString = currentKey.GetValue(null).ToString(); + } + else + { + return null; //Cannot have item without title. + } + return localizedString; + } + + private static string getInfoTip(RegistryKey currentKey) + { + IntPtr dataFilePointer; + string[] infoTipRaw; + uint stringTableIndex; + StringBuilder resource; + string infoTip = ""; + + if (currentKey.GetValue("InfoTip") != null) + { + infoTipRaw = currentKey.GetValue("InfoTip").ToString().Split(new char[] { ',' }, 2); + + if (infoTipRaw.Length == 2) + { + if (infoTipRaw[0][0] == '@') + { + infoTipRaw[0] = infoTipRaw[0].Substring(1); + } + infoTipRaw[0] = Environment.ExpandEnvironmentVariables(infoTipRaw[0]); + + dataFilePointer = LoadLibraryEx(infoTipRaw[0], IntPtr.Zero, LOAD_LIBRARY_AS_DATAFILE); //Load file with strings + + stringTableIndex = sanitizeUint(infoTipRaw[1]); + + resource = new StringBuilder(255); + LoadString(dataFilePointer, stringTableIndex, resource, resource.Capacity + 1); //Extract needed string + FreeLibrary(dataFilePointer); + + infoTip = resource.ToString(); + } + } + else + { + infoTip = ""; + } + + return infoTip; + } + + private static Icon getIcon(RegistryKey currentKey, int iconSize) + { + IntPtr iconPtr = IntPtr.Zero; + List iconString; + IntPtr dataFilePointer; + IntPtr iconIndex; + Icon myIcon = null; + + 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); + } + + FreeLibrary(dataFilePointer); + + try + { + myIcon = Icon.FromHandle(iconPtr); + myIcon = (Icon)myIcon.Clone(); //Remove pointer dependancy. + } + catch + { + //Silently fail for now.. + } + } + } + + if (iconPtr != IntPtr.Zero) + { + DestroyIcon(iconPtr); + } + return myIcon; + } + private static uint sanitizeUint(string args) //Remove all chars before and after first set of digits. { int x = 0; @@ -241,12 +307,14 @@ namespace Wox.Plugin.SystemPlugins.ControlPanel 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) diff --git a/Wox.sln b/Wox.sln index 24814d1260..abd0307244 100644 --- a/Wox.sln +++ b/Wox.sln @@ -1,8 +1,6 @@  Microsoft Visual Studio Solution File, Format Version 12.00 -# Visual Studio 2013 -VisualStudioVersion = 12.0.30110.0 -MinimumVisualStudioVersion = 10.0.40219.1 +# Visual Studio 2012 Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wox.Test", "Wox.Test\Wox.Test.csproj", "{FF742965-9A80-41A5-B042-D6C7D3A21708}" EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Wox.Plugin", "Wox.Plugin\Wox.Plugin.csproj", "{8451ECDD-2EA4-4966-BB0A-7BBC40138E80}"