-
-
Notifications
You must be signed in to change notification settings - Fork 395
Process TPC Support & Kill Retry as Admin #1320
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: dev
Are you sure you want to change the base?
Changes from 1 commit
f984223
4590418
650875f
0ccb2da
4bafa46
b8a7503
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,179 @@ | ||
using Flow.Launcher.Infrastructure; | ||
using Flow.Launcher.Infrastructure.Logger; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Diagnostics; | ||
using System.Linq; | ||
using System.Management; | ||
|
||
namespace Flow.Launcher.Plugin.ProcessKiller | ||
{ | ||
internal class PortDetail | ||
{ | ||
public int Port { get; set; } | ||
public int ProcessID { get; set; } | ||
public string ProcessName { get; set; } | ||
|
||
public Process Process { get; set; } | ||
public string Path { get; set; } | ||
public override string ToString() | ||
{ | ||
return string.Format(@" Process Name: {0} ,Process ID: {1} , | ||
Jack251970 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Port: {2} ,\nPath : {3}", ProcessName, | ||
ProcessID, Port, Path); | ||
} | ||
|
||
} | ||
/// <summary> | ||
/// Usage: | ||
/// int port = 8081 | ||
/// TcpHelperUtil tcpHelper = new TcpHelperUtil(); | ||
/// var details = tcpHelper.GetPortDetails(port); | ||
/// if (details.Item1) | ||
/// { | ||
/// Console.WriteLine("Port {0} in Use",port); | ||
/// Console.WriteLine(details.Item2.ToString()); | ||
/// }else | ||
/// { | ||
/// Console.WriteLine("Port {0} is free ",port); | ||
/// } | ||
/// | ||
/// </summary> | ||
internal class PortHelper | ||
{ | ||
private const short MINIMUM_TOKEN_IN_A_LINE = 5; | ||
private const string COMMAND_EXE = "cmd"; | ||
|
||
public PortHelper() | ||
{ | ||
|
||
} | ||
|
||
public static Tuple<bool, PortDetail> GetPortDetails(int port) | ||
{ | ||
PortDetail PortDetail = new PortDetail(); | ||
Tuple<bool, PortDetail> result = Tuple.Create(false, PortDetail); | ||
|
||
// execute netstat command for the given port | ||
string commandArgument = string.Format("/c netstat -an -o -p tcp|findstr \":{0}.*LISTENING\"", port); | ||
|
||
string commandOut = ExecuteCommandAndCaptureOutput(COMMAND_EXE, commandArgument); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
if (string.IsNullOrEmpty(commandOut)) | ||
{ | ||
// port is not in use | ||
return result; | ||
} | ||
|
||
var stringTokens = commandOut.Split(default(Char[]), StringSplitOptions.RemoveEmptyEntries); | ||
if (stringTokens.Length < MINIMUM_TOKEN_IN_A_LINE) | ||
{ | ||
return result; | ||
} | ||
|
||
// split host:port | ||
var hostPortTokens = stringTokens[1].Split(new char[] { ':' }); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's possible to have multiple port in one line? Or that won't happen for Listening port? |
||
if (hostPortTokens.Length < 2) | ||
{ | ||
return result; | ||
} | ||
|
||
int portFromHostPortToken = 0; | ||
if (!int.TryParse(hostPortTokens[1], out portFromHostPortToken)) | ||
{ | ||
return result; | ||
} | ||
if (portFromHostPortToken != port) | ||
{ | ||
return result; | ||
} | ||
|
||
PortDetail.Port = port; | ||
PortDetail.ProcessID = int.Parse(stringTokens[4].Trim()); | ||
Tuple<string, string> processNameAndPath = null; | ||
Jack251970 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
try | ||
{ | ||
processNameAndPath = GetProcessNameAndCommandLineArgs(PortDetail.ProcessID); | ||
PortDetail.ProcessName = processNameAndPath.Item1; | ||
PortDetail.Path = processNameAndPath.Item2; | ||
PortDetail.Process = Process.GetProcessById(PortDetail.ProcessID); | ||
result = Tuple.Create(true, PortDetail); | ||
Jack251970 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
catch (Exception exp) | ||
{ | ||
Console.WriteLine(exp.ToString()); | ||
Jack251970 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
} | ||
|
||
return result; | ||
|
||
} | ||
/// <summary> | ||
/// Using WMI API to get process name and path instead of | ||
/// Process.GetProcessById, because if calling process ins | ||
/// 32 bit and given process id is 64 bit, caller will not be able to | ||
/// get the process name | ||
/// </summary> | ||
/// <param name="processID"></param> | ||
/// <returns></returns> | ||
private static Tuple<string, string> GetProcessNameAndCommandLineArgs(int processID) | ||
{ | ||
Tuple<string, string> result = Tuple.Create(string.Empty, string.Empty); | ||
string query = string.Format("Select Name,ExecutablePath from Win32_Process WHERE ProcessId='{0}'", processID); | ||
try | ||
{ | ||
ObjectQuery wql = new ObjectQuery(query); | ||
ManagementObjectSearcher searcher = new ManagementObjectSearcher(wql); | ||
ManagementObjectCollection results = searcher.Get(); | ||
|
||
// interested in first result. | ||
foreach (ManagementObject item in results) | ||
{ | ||
result = Tuple.Create<string, string>(Convert.ToString(item["Name"]), | ||
Jack251970 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Convert.ToString(item["ExecutablePath"])); | ||
break; | ||
|
||
} | ||
} | ||
catch (Exception) | ||
{ | ||
|
||
throw; | ||
} | ||
|
||
return result; | ||
|
||
} | ||
|
||
/// <summary> | ||
/// Execute the given command and captures the output | ||
/// </summary> | ||
/// <param name="commandName"></param> | ||
/// <param name="arguments"></param> | ||
/// <returns></returns> | ||
private static string ExecuteCommandAndCaptureOutput(string commandName, string arguments) | ||
{ | ||
string commandOut = string.Empty; | ||
Process process = new Process(); | ||
process.StartInfo.FileName = commandName; | ||
process.StartInfo.Arguments = arguments; | ||
process.StartInfo.UseShellExecute = false; | ||
process.StartInfo.CreateNoWindow = true; | ||
process.StartInfo.RedirectStandardOutput = true; | ||
process.StartInfo.RedirectStandardError = true; | ||
process.Start(); | ||
|
||
commandOut = process.StandardOutput.ReadToEnd(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This will be stuck if the process never ends. I think we should put it lower after waiting process ends. Also, probably make this part async. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. First of all, thank you very much for reviewing and pointing out the problems 😊, but in addition to some simple style problems, there are many problems that I can't fix due to my limited ability. You should close this pr, if you have time, can you add these two features🥺?sorry for wasting your precious time. (Actually, I know this code is shit, but I don't have the energy to learn how to write better implementations recently. 😢 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think the code is that bad. Those things I mention can be adjusted fairly easily. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Thank you very much, then I close this pr? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Just leave it here. I will finish it once I got time. |
||
string errors = process.StandardError.ReadToEnd(); | ||
try | ||
{ | ||
process.WaitForExit(TimeSpan.FromSeconds(2).Milliseconds); | ||
} | ||
catch (Exception exp) | ||
{ | ||
Log.Exception($"|ProcessKiller.CreateResultsFromProcesses|Failed to ExecuteCommandAndCaptureOutput {commandName + arguments}", exp); | ||
Console.WriteLine(exp.ToString()); | ||
} | ||
return commandOut; | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -38,10 +38,19 @@ public List<ProcessResult> GetMatchingProcesses(string searchTerm) | |
{ | ||
var processlist = new List<ProcessResult>(); | ||
|
||
int portNum; | ||
bool canConvert = int.TryParse(searchTerm, out portNum); | ||
Jack251970 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
Tuple<bool, PortDetail> tcpPortListeningProcess = null; | ||
if(canConvert) | ||
tcpPortListeningProcess = PortHelper.GetPortDetails(portNum); | ||
|
||
foreach (var p in Process.GetProcesses()) | ||
{ | ||
if (IsSystemProcess(p)) continue; | ||
|
||
if (tcpPortListeningProcess != null && tcpPortListeningProcess.Item1 && tcpPortListeningProcess.Item2.Process.Id == p.Id) | ||
Jack251970 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
{ | ||
continue; | ||
} | ||
if (string.IsNullOrWhiteSpace(searchTerm)) | ||
{ | ||
// show all non-system processes | ||
|
@@ -56,7 +65,11 @@ public List<ProcessResult> GetMatchingProcesses(string searchTerm) | |
} | ||
} | ||
} | ||
|
||
if (tcpPortListeningProcess != null && tcpPortListeningProcess.Item1) | ||
{ | ||
var p = tcpPortListeningProcess.Item2.Process; | ||
processlist.Add(new ProcessResult(p, StringMatcher.FuzzySearch(searchTerm, p.ProcessName + p.Id).Score, portNum)); | ||
} | ||
return processlist; | ||
} | ||
|
||
|
@@ -80,6 +93,26 @@ public void TryKill(Process p) | |
catch (Exception e) | ||
{ | ||
Log.Exception($"|ProcessKiller.CreateResultsFromProcesses|Failed to kill process {p.ProcessName}", e); | ||
TryKillRunAs(p); | ||
} | ||
} | ||
|
||
public void TryKillRunAs(Process p) | ||
{ | ||
try | ||
{ | ||
Process process = new Process(); | ||
ProcessStartInfo startInfo = new ProcessStartInfo(); | ||
startInfo.WindowStyle = ProcessWindowStyle.Hidden; | ||
startInfo.FileName = "powershell.exe"; | ||
startInfo.Arguments = $"Start cmd.exe -ArgumentList \"/k\",\"taskkill\",\"/f\",\"/pid\", \"{p.Id}\" -Verb Runas"; | ||
Comment on lines
+113
to
+114
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I forget this one. It's pretty weird that you start There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The startInfo do provide an |
||
startInfo.UseShellExecute = false; | ||
process.StartInfo = startInfo; | ||
process.Start(); | ||
} | ||
catch(Exception e) | ||
{ | ||
Log.Exception($"|ProcessKiller.CreateResultsFromProcesses|Failed to kill process again of run as admin {p.ProcessName}", e); | ||
} | ||
} | ||
|
||
|
Uh oh!
There was an error while loading. Please reload this page.