diff --git a/Flow.Launcher.sln b/Flow.Launcher.sln index 2be28daf1..43c012b5b 100644 --- a/Flow.Launcher.sln +++ b/Flow.Launcher.sln @@ -70,6 +70,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.Calcul EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.Explorer", "Plugins\Flow.Launcher.Plugin.Explorer\Flow.Launcher.Plugin.Explorer.csproj", "{F9C4C081-4CC3-4146-95F1-E102B4E10A5F}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Flow.Launcher.Plugin.ProcessKiller", "Plugins\Flow.Launcher.Plugin.ProcessKiller\Flow.Launcher.Plugin.ProcessKiller.csproj", "{588088F4-3262-4F9F-9663-A05DE12534C3}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -297,6 +299,18 @@ Global {F9C4C081-4CC3-4146-95F1-E102B4E10A5F}.Release|x64.Build.0 = Release|Any CPU {F9C4C081-4CC3-4146-95F1-E102B4E10A5F}.Release|x86.ActiveCfg = Release|Any CPU {F9C4C081-4CC3-4146-95F1-E102B4E10A5F}.Release|x86.Build.0 = Release|Any CPU + {588088F4-3262-4F9F-9663-A05DE12534C3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {588088F4-3262-4F9F-9663-A05DE12534C3}.Debug|Any CPU.Build.0 = Debug|Any CPU + {588088F4-3262-4F9F-9663-A05DE12534C3}.Debug|x64.ActiveCfg = Debug|Any CPU + {588088F4-3262-4F9F-9663-A05DE12534C3}.Debug|x64.Build.0 = Debug|Any CPU + {588088F4-3262-4F9F-9663-A05DE12534C3}.Debug|x86.ActiveCfg = Debug|Any CPU + {588088F4-3262-4F9F-9663-A05DE12534C3}.Debug|x86.Build.0 = Debug|Any CPU + {588088F4-3262-4F9F-9663-A05DE12534C3}.Release|Any CPU.ActiveCfg = Release|Any CPU + {588088F4-3262-4F9F-9663-A05DE12534C3}.Release|Any CPU.Build.0 = Release|Any CPU + {588088F4-3262-4F9F-9663-A05DE12534C3}.Release|x64.ActiveCfg = Release|Any CPU + {588088F4-3262-4F9F-9663-A05DE12534C3}.Release|x64.Build.0 = Release|Any CPU + {588088F4-3262-4F9F-9663-A05DE12534C3}.Release|x86.ActiveCfg = Release|Any CPU + {588088F4-3262-4F9F-9663-A05DE12534C3}.Release|x86.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -315,6 +329,7 @@ Global {9B130CC5-14FB-41FF-B310-0A95B6894C37} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} {59BD9891-3837-438A-958D-ADC7F91F6F7E} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} {F9C4C081-4CC3-4146-95F1-E102B4E10A5F} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} + {588088F4-3262-4F9F-9663-A05DE12534C3} = {3A73F5A7-0335-40D8-BF7C-F20BE5D0BA87} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {F26ACB50-3F6C-4907-B0C9-1ADACC1D0DED} diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj new file mode 100644 index 000000000..1fb5d2a69 --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Flow.Launcher.Plugin.ProcessKiller.csproj @@ -0,0 +1,50 @@ + + + + netcoreapp3.1 + Flow.Launcher.Plugin.ProcessKiller + Flow.Launcher.Plugin.ProcessKiller + Flow-Launcher + https://github.com/Flow-Launcher/Flow.Launcher.Plugin.ProcessKiller + https://github.com/Flow-Launcher/Flow.Launcher.Plugin.ProcessKiller + flow-launcher flow-plugin + false + false + + + + true + full + false + ..\..\Output\Debug\Plugins\Flow.Launcher.Plugin.ProcessKiller\ + DEBUG;TRACE + prompt + 4 + false + + + + pdbonly + true + ..\..\Output\Release\Plugins\Flow.Launcher.Plugin.ProcessKiller\ + TRACE + prompt + 4 + false + + + + + PreserveNewest + + + Always + + + + + + + + + \ No newline at end of file diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Images/app.png b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Images/app.png new file mode 100644 index 000000000..fa76a5d29 Binary files /dev/null and b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Images/app.png differ diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/Main.cs b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Main.cs new file mode 100644 index 000000000..919f1e135 --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/Main.cs @@ -0,0 +1,203 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Diagnostics; +using System.Dynamic; +using System.Runtime.InteropServices; +using Flow.Launcher.Infrastructure; +using Flow.Launcher.Infrastructure.Logger; + +namespace Flow.Launcher.Plugin.ProcessKiller +{ + public class Main : IPlugin + { + private readonly HashSet _systemProcessList = new HashSet(){ + "conhost", + "svchost", + "idle", + "system", + "rundll32", + "csrss", + "lsass", + "lsm", + "smss", + "wininit", + "winlogon", + "services", + "spoolsv", + "explorer"}; + + public List Query(Query query) + { + var termToSearch = query.Terms.Length == 1 + ? null + : query.FirstSearch.ToLower(); + var processlist = GetProcesslist(termToSearch); + + return + !processlist.Any() + ? null + : CreateResultsFromProcesses(processlist, termToSearch); + } + + private List CreateResultsFromProcesses(List processlist, string termToSearch) + { + var results = new List(); + + foreach (var pr in processlist) + { + var p = pr.Process; + var path = GetPath(p); + results.Add(new Result() + { + IcoPath = path, + Title = p.ProcessName + " - " + p.Id, + SubTitle = path, + Score = pr.Score, + Action = (c) => + { + KillProcess(p); + return true; + } + }); + } + + if (processlist.Count > 1 && !string.IsNullOrEmpty(termToSearch)) + { + results.Insert(0, new Result() + { + IcoPath = "Images\\app.png", + Title = "kill all \"" + termToSearch + "\" process", + SubTitle = "", + Score = 200, + Action = (c) => + { + foreach (var p in processlist) + { + KillProcess(p.Process); + } + + return true; + } + }); + } + + return results; + + void KillProcess(Process p) + { + try + { + if (!p.HasExited) + { + p.Kill(); + } + } + catch (Exception e) + { + Log.Exception($"Fail to kill process {p.ProcessName}", e); + } + } + } + private List GetProcesslist(string termToSearch) + { + var processlist = new List(); + var processes = Process.GetProcesses(); + if (string.IsNullOrWhiteSpace(termToSearch)) + { + // show all process + foreach (var p in processes) + { + if (FilterSystemProcesses(p)) continue; + + processlist.Add(new ProcessResult(p,0)); + } + } + else + { + foreach (var p in processes) + { + if (FilterSystemProcesses(p)) continue; + var score = StringMatcher.FuzzySearch(termToSearch, p.ProcessName + p.Id).Score; + if (score > 0) + { + processlist.Add(new ProcessResult(p, score)); + } + } + } + + return processlist; + + bool FilterSystemProcesses(Process p) + { + var name = p.ProcessName.ToLower(); + if (_systemProcessList.Contains(name)) + return true; + return false; + } + } + + internal class ProcessResult + { + public ProcessResult(Process process, int score) + { + Process = process; + Score = score; + } + + public Process Process { get; } + + public int Score { get; } + } + + private string GetPath(Process p) + { + try + { + var path = GetProcessFilename(p); + return path.ToLower(); + } + catch + { + return ""; + } + } + + public void Init(PluginInitContext context) + { + } + + [Flags] + private enum ProcessAccessFlags : uint + { + QueryLimitedInformation = 0x00001000 + } + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern bool QueryFullProcessImageName( + [In] IntPtr hProcess, + [In] int dwFlags, + [Out] StringBuilder lpExeName, + ref int lpdwSize); + + [DllImport("kernel32.dll", SetLastError = true)] + private static extern IntPtr OpenProcess( + ProcessAccessFlags processAccess, + bool bInheritHandle, + int processId); + + private string GetProcessFilename(Process p) + { + int capacity = 2000; + StringBuilder builder = new StringBuilder(capacity); + IntPtr ptr = OpenProcess(ProcessAccessFlags.QueryLimitedInformation, false, p.Id); + if (!QueryFullProcessImageName(ptr, 0, builder, ref capacity)) + { + return String.Empty; + } + + return builder.ToString(); + } + } +} diff --git a/Plugins/Flow.Launcher.Plugin.ProcessKiller/plugin.json b/Plugins/Flow.Launcher.Plugin.ProcessKiller/plugin.json new file mode 100644 index 000000000..f2e1eca12 --- /dev/null +++ b/Plugins/Flow.Launcher.Plugin.ProcessKiller/plugin.json @@ -0,0 +1,12 @@ +{ + "ID":"b64d0a79-329a-48b0-b53f-d658318a1bf6", + "ActionKeyword":"kill", + "Name":"Process Killer", + "Description":"kill running processes from Flow", + "Author":"Flow-Launcher", + "Version":"1.0.0", + "Language":"csharp", + "Website":"https://github.com/Flow-Launcher/Flow.Launcher.Plugin.ProcessKiller", + "IcoPath":"Images\\app.png", + "ExecuteFileName":"Flow.Launcher.Plugin.ProcessKiller.dll" +} \ No newline at end of file