It is ALPHA CODE and may sell your firstborn on the black market.
It hiccups often, but usually hitting "Clear" repeatedly mends things. Use with (lots of) caution.
(Seems to run better compiled)
Your comments are appreciated.
Spoiler
I'm sure you know where the name came from Code: Select all
; KillBill.ahk ALPHA
;
; A small utility for the impatient to find and kill processes.
; *****************************
; Shift + Double-click to kill a process.
; Filter the listview with the query field,
; which will update as you type.
; *****************************
; Single clicks won't do much. Double clicks required.
; That's my only concession to safety so far.
; *****************************
; N.B. Contains bugs!
; Primary among them at the moment is that you
; have to hit "Clear" to completely update the LV.
; Cruft abounds.
; ******************************
; Tip: You can leave the script running.
; Regardless of whether you do this or not,
; you should click "Clear" after you delete
; several processes in a row after a
; filtering results.
; You may have to click "Clear" more than once
; for now, until I squash this bug.
; ******************************
; Double right-click will bring up some terse help.
;*******************************
; Use with great caution! This is DEFINITELY not a substitute for
; Task Manager. I use it for quickly killing rogue
; processes while troubleshooting, so I don't have
; to put up with Windows's assumption (certainly justified)
; that I don't have a clue what I'm doing, and requiring
; confirmation before I kill a process.
; You can do damage with this if you are so inclined.
; ********************************
; Alpha software: KillBill.ahk version 0.0.0.1
; burque505
; November 10, 2019
; ********************************
; Credits: Fanatic Guru for Sift, included;
; The AHK docs page for the ProcessList routine;
; If I left you out and you want in, let me know.
; If I put you in and you want out, let me know :)
; ********************************
; The compiled version uses an icon by Deviant Art.
; Thanks!
; ********************************
; Message from the Dept. of Redundancy Dept.:
; HIT CLEAR!!!!!!!!!!!
; ********************************
full_command_line := DllCall("GetCommandLine", "str")
if not (A_IsAdmin or RegExMatch(full_command_line, " /restart(?!\S)"))
{
try
{
if A_IsCompiled
Run *RunAs "%A_ScriptFullPath%" /restart
else
Run *RunAs "%A_AhkPath%" /restart "%A_ScriptFullPath%"
}
ExitApp
}
SetBatchLines, -1
d := "`r`n" ; string separator
s := 4096 ; size of buffers and arrays (4 KB)
global l, opt, Data, Display
global Options := "in"
gosub, ProcessList
sleep, 100
Menu, HelpMenu, Add, &Help, Help
Gui, Menu, HelpMenu
Gui, +Resize
Gui, Font, s12
Gui, Add, Edit, x10 y+10 w300 h25 vQueryText gQuery,
Gui, Font
Gui, Add, Text, x+10 w30, Query
;Gui, Add, CheckBox, x10 y+15 vopt gSetOption, Starts with ...
Gui, Add, Radio, x10 y+15 voNoopt gSetOption Checked, Contains
Gui, Add, Radio, x+10 vopt gSetOption, Starts with
Gui, Add, Button, x+10,Clear
Gui, Add, ListView, grid -Multi Sort x10 y+5 w390 r20 gMyListView vMyListView, Process
Loop, Parse, Data, `n, `r
{
if !A_LoopField
Continue
rows++
Array1 := StrSplit(A_Loopfield, ",")
LV_Add("", Array1[1], Array1[2], Array1[3])
}
Gui, Show, AutoSize, Kill Process
Loop, 3
LV_ModifyCol(A_Index, "AutoHdr")
return
SetOption:
If (opt)
Options := "left"
If (!opt)
Options := "in"
;Options := opt ? "left" : "in"
GuiControl, Focus, QueryText
return
Query:
Critical
Gui, Submit, NoHide
Display := Sift_Regex(Data, QueryText, Options)
displayRows := 0
LV_Delete()
Loop, Parse, Display, `n, `r
{
displayRows++
displayRow%a_index% := a_loopfield
}
loop % rows {
if (a_index <= displayRows) {
;Arrays not yet needed, future-proofing
;Add more columns if necessary
Array2 := StrSplit(displayRow%a_index%, ",")
LV_Add("", Array2[1], Array2[2], Array2[3])
}
}
Display := ""
l := ""
Data := ""
gosub, ProcessList
sleep, 100
return
Escape::
GuiClose:
ExitApp
MyListView:
if (A_GuiControlEvent == "R")
{
gosub Help
return
}
if (A_GuiControlEvent == "DoubleClick")
{
if GetKeyState("Shift", "P") {
c := 1
LV_GetText(proc, A_EventInfo, c)
Process, Close, %proc%
;clipboard := proc
SetTimer, TT1, 1000
ToolTip, Process %proc% was killed
LV_Delete(A_EventInfo)
;gosub, ProcessList
;Gui, Submit, NoHide
return
}
Else {
SetTimer, TT1, 1000
ToolTip, Shift+Double-click required!
return
}
}
if (A_GuiControlEvent == "ColClick")
return
ButtonClear:
Reload
ControlSetText, Edit1
LV_Delete()
Display := ""
l := ""
Data := ""
Gosub, ProcessList
sleep, 100
;Gui, Submit, NoHide
ControlFocus, Edit1
return
Help:
v =
(
Shift + double-click (left) to kill a process.
Modify the text in the "Query" field to search
That's it!
)
msgbox %v%
return
;Tooltip sections
TT1:
ToolTip
return
;{ Sift
; Fanatic Guru
; 2015 04 30
; Version 1.00
;
; LIBRARY to sift through a string or array and return items that match sift criteria.
;
; ===================================================================================================================================================
;
; Functions:
;
; ===================================================================================================================================================
; Sift_Regex(Haystack, Needle, Options, Delimiter)
;
; Parameters:
; 1) {Haystack} String or array of information to search, ByRef for efficiency but Haystack is not changed by function
;
; 2) {Needle} String providing search text or criteria, ByRef for efficiency but Needle is not changed by function
;
; 3) {Options}
; IN Needle anywhere IN Haystack item (Default = IN)
; LEFT Needle is to LEFT or beginning of Haystack item
; RIGHT Needle is to RIGHT or end of Haystack item
; EXACT Needle is an EXACT match to Haystack item
; REGEX Needle is an REGEX expression to check against Haystack item
; OC Needle is ORDERED CHARACTERS to be searched for even non-consecutively but in the given order in Haystack item
; OW Needle is ORDERED WORDS to be searched for even non-consecutively but in the given order in Haystack item
; UC Needle is UNORDERED CHARACTERS to be search for even non-consecutively and in any order in Haystack item
; UW Needle is UNORDERED WORDS to be search for even non-consecutively and in any order in Haystack item
;
; If an Option is all lower case then the search will be case insensitive
;
; 4) {Delimiter} Single character Delimiter of each item in a Haystack string (Default = `n)
;
; Returns:
; If Haystack is string then a string is returned of found Haystack items delimited by the Delimiter
; If Haystack is an array then an array is returned of found Haystack items
;
; Note:
; Sift_Regex searchs are all RegExMatch seaches with Needles crafted based on the options chosen
;
; ===================================================================================================================================================
; Sift_Ngram(Haystack, Needle, Delta, Haystack_Matrix, Ngram Size, Format)
;
; Parameters:
; 1) {Haystack} String or array of information to search, ByRef for efficiency but Haystack is not changed by function
;
; 2) {Needle} String providing search text or criteria, ByRef for efficiency but Needle is not changed by function
;
; 3) {Delta} (Default = .7) Fuzzy match coefficient, 1 is a prefect match, 0 is no match at all, only results above the Delta are returned
;
; 4) {Haystack_Matrix} (Default = false)
; An object containing the preprocessing of the Haystack for Ngrams content
; If a non-object is passed the Haystack is processed for Ngram content and the results are returned by ByRef
; If an object is passed then that is used as the processed Ngram content of Haystack
; If multiply calls to the function are made with no change to the Haystack then a previous processing of Haystack for Ngram content
; can be passed back to the function to avoid reprocessing the same Haystack again in order to increase efficiency.
;
; 5) {Ngram Size} (Default = 3) The length of Ngram used. Generally Ngrams made of 3 letters called a Trigram is good
;
; 6) {Format} (Default = S`n)
; S Return Object with results Sorted
; U Return Object with results Unsorted
; S%%% Return Sorted string delimited by characters after S
; U%%% Return Unsorted string delimited by characters after U
; Sorted results are by best match first
;
; Returns:
; A string or array depending on Format parameter.
; If string then it is delimited based on Format parameter.
; If array then an array of object is returned where each element is of the structure: {Object}.Delta and {Object}.Data
; Example Code to access object returned:
; for key, element in Sift_Ngram(Data, QueryText, NgramLimit, Data_Ngram_Matrix, NgramSize)
; Display .= element.delta "`t" element.data "`n"
;
; Dependencies: Sift_Ngram_Get, Sift_Ngram_Compare, Sift_Ngram_Matrix, Sift_SortResults
; These are helper functions that are generally not called directly. Although Sift_Ngram_Matrix could be useful to call directly to preprocess a large static Haystack
;
; Note:
; The string "dog house" would produce these Trigrams: dog|og |g h| ho|hou|ous|use
; Sift_Ngram breaks the needle and each item of the Haystack up into Ngrams.
; Then all the Needle Ngrams are looked for in the Haystack items Ngrams resulting in a percentage of Needle Ngrams found
;
; ===================================================================================================================================================
;
Sift_Regex(ByRef Haystack, ByRef Needle, Options := "IN", Delimit := "`n")
{
Sifted := {}
if (Options = "IN")
Needle_Temp := "\Q" Needle "\E"
else if (Options = "LEFT")
Needle_Temp := "^\Q" Needle "\E"
else if (Options = "RIGHT")
Needle_Temp := "\Q" Needle "\E$"
else if (Options = "EXACT")
Needle_Temp := "^\Q" Needle "\E$"
else if (Options = "REGEX")
Needle_Temp := Needle
else if (Options = "OC")
Needle_Temp := RegExReplace(Needle,"(.)","\Q$1\E.*")
else if (Options = "OW")
Needle_Temp := RegExReplace(Needle,"( )","\Q$1\E.*")
else if (Options = "UW")
Loop, Parse, Needle, " "
Needle_Temp .= "(?=.*\Q" A_LoopField "\E)"
else if (Options = "UC")
Loop, Parse, Needle
Needle_Temp .= "(?=.*\Q" A_LoopField "\E)"
if Options is lower
Needle_Temp := "i)" Needle_Temp
if IsObject(Haystack)
{
for key, Hay in Haystack
if RegExMatch(Hay, Needle_Temp)
Sifted.Insert(Hay)
}
else
{
Loop, Parse, Haystack, %Delimit%, `n, `r
if RegExMatch(A_LoopField, Needle_Temp)
Sifted .= A_LoopField Delimit
Sifted := SubStr(Sifted,1,-1)
}
return Sifted
}
Sift_Ngram(ByRef Haystack, ByRef Needle, Delta := .7, ByRef Haystack_Matrix := false, n := 3, Format := "S`n" )
{
if !IsObject(Haystack_Matrix)
Haystack_Matrix := Sift_Ngram_Matrix(Haystack, n)
Needle_Ngram := Sift_Ngram_Get(Needle, n)
if IsObject(Haystack)
{
Search_Results := {}
for key, Hay_Ngram in Haystack_Matrix
{
Result := Sift_Ngram_Compare(Hay_Ngram, Needle_Ngram)
if !(Result < Delta)
Search_Results[key,"Delta"] := Result, Search_Results[key,"Data"] := Haystack[key]
}
}
else
{
Search_Results := {}
Loop, Parse, Haystack, `n, `r
{
Result := Sift_Ngram_Compare(Haystack_Matrix[A_Index], Needle_Ngram)
if !(Result < Delta)
Search_Results[A_Index,"Delta"] := Result, Search_Results[A_Index,"Data"] := A_LoopField
}
}
if (Format ~= "i)^S")
Sift_SortResults(Search_Results)
if RegExMatch(Format, "i)^(S|U)(.+)$", Match)
{
for key, element in Search_Results
String_Results .= element.data Match2
return SubStr(String_Results,1,-StrLen(Match2))
}
else
return Search_Results
}
Sift_Ngram_Get(ByRef String, n := 3)
{
Pos := 1, Grams := {}
Loop, % (1 + StrLen(String) - n)
gram := SubStr(String, A_Index, n), Grams[gram] ? Grams[gram] ++ : Grams[gram] := 1
return Grams
}
Sift_Ngram_Compare(ByRef Hay, ByRef Needle)
{
for gram, Needle_Count in Needle
{
Needle_Total += Needle_Count
Match += (Hay[gram] > Needle_Count ? Needle_Count : Hay[gram])
}
return Match / Needle_Total
}
Sift_Ngram_Matrix(ByRef Data, n := 3)
{
if IsObject(Data)
{
Matrix := {}
for key, string in Data
Matrix.Insert(Sift_Ngram_Get(string, n))
}
else
{
Matrix := {}
Loop, Parse, Data, `n
Matrix.Insert(Sift_Ngram_Get(A_LoopField, n))
}
return Matrix
}
Sift_SortResults(ByRef Data)
{
Data_Temp := {}
for key, element in Data
Data_Temp[element.Delta SubStr("0000000000" key, -9)] := element
Data := {}
for key, element in Data_Temp
Data.InsertAt(1,element)
return
}
AutoXYWH(DimSize, cList*){ ; http://ahkscript.org/boards/viewtopic.php?t=1079
static cInfo := {}
If (DimSize = "reset")
Return cInfo := {}
For i, ctrl in cList {
ctrlID := A_Gui ":" ctrl
If ( cInfo[ctrlID].x = "" ){
GuiControlGet, i, %A_Gui%:Pos, %ctrl%
MMD := InStr(DimSize, "*") ? "MoveDraw" : "Move"
fx := fy := fw := fh := 0
For i, dim in (a := StrSplit(RegExReplace(DimSize, "i)[^xywh]")))
If !RegExMatch(DimSize, "i)" dim "\s*\K[\d.-]+", f%dim%)
f%dim% := 1
cInfo[ctrlID] := { x:ix, fx:fx, y:iy, fy:fy, w:iw, fw:fw, h:ih, fh:fh, gw:A_GuiWidth, gh:A_GuiHeight, a:a , m:MMD}
}Else If ( cInfo[ctrlID].a.1) {
dgx := dgw := A_GuiWidth - cInfo[ctrlID].gw , dgy := dgh := A_GuiHeight - cInfo[ctrlID].gh
For i, dim in cInfo[ctrlID]["a"]
Options .= dim (dg%dim% * cInfo[ctrlID]["f" dim] + cInfo[ctrlID][dim]) A_Space
GuiControl, % A_Gui ":" cInfo[ctrlID].m , % ctrl, % Options
} } }
GuiSize:
If (A_EventInfo = 1) ; The window has been minimized.
Return
AutoXYWH("wh", "MyListView")
return
ProcessList:
Process, Exist ; Sets ErrorLevel to the PID of this running script.
; Get the handle of this script with PROCESS_QUERY_INFORMATION (0x0400):
h := DllCall("OpenProcess", "UInt", 0x0400, "Int", false, "UInt", ErrorLevel, "Ptr")
; Open an adjustable access token with this process (TOKEN_ADJUST_PRIVILEGES = 32):
DllCall("Advapi32.dll\OpenProcessToken", "Ptr", h, "UInt", 32, "PtrP", t)
VarSetCapacity(ti, 16, 0) ; structure of privileges
NumPut(1, ti, 0, "UInt") ; one entry in the privileges array...
; Retrieves the locally unique identifier of the debug privilege:
DllCall("Advapi32.dll\LookupPrivilegeValue", "Ptr", 0, "Str", "SeDebugPrivilege", "Int64P", luid)
NumPut(luid, ti, 4, "Int64")
NumPut(2, ti, 12, "UInt") ; Enable this privilege: SE_PRIVILEGE_ENABLED = 2
; Update the privileges of this process with the new access token:
r := DllCall("Advapi32.dll\AdjustTokenPrivileges", "Ptr", t, "Int", false, "Ptr", &ti, "UInt", 0, "Ptr", 0, "Ptr", 0)
DllCall("CloseHandle", "Ptr", t) ; Close this access token handle to save memory.
DllCall("CloseHandle", "Ptr", h) ; Close this process handle to save memory.
hModule := DllCall("LoadLibrary", "Str", "Psapi.dll") ; Increase performance by preloading the library.
s := VarSetCapacity(a, s) ; An array that receives the list of process identifiers:
c := 0 ; counter for process idendifiers
DllCall("Psapi.dll\EnumProcesses", "Ptr", &a, "UInt", s, "UIntP", r)
Loop, % r // 4 ; Parse array for identifiers as DWORDs (32 bits):
{
id := NumGet(a, A_Index * 4, "UInt")
; Open process with: PROCESS_VM_READ (0x0010) | PROCESS_QUERY_INFORMATION (0x0400)
h := DllCall("OpenProcess", "UInt", 0x0010 | 0x0400, "Int", false, "UInt", id, "Ptr")
if !h
continue
VarSetCapacity(n, s, 0) ; a buffer that receives the base name of the module:
e := DllCall("Psapi.dll\GetModuleBaseName", "Ptr", h, "Ptr", 0, "Str", n, "UInt", A_IsUnicode ? s//2 : s)
if !e ; fall-back method for 64-bit processes when in 32-bit mode:
if e := DllCall("Psapi.dll\GetProcessImageFileName", "Ptr", h, "Str", n, "UInt", A_IsUnicode ? s//2 : s)
SplitPath n, n
DllCall("CloseHandle", "Ptr", h) ; close process handle to save memory
if (n && e) ; if image is not null add to list:
l .= n . d, c++
}
DllCall("FreeLibrary", "Ptr", hModule) ; Unload the library to free memory.
;Sort, l, C ; Uncomment this line to sort the list alphabetically.
;MsgBox, 0, %c% Processes, %l%
Sleep, 100
Data := l
Display := Data
return
Main screen - you can kill processes from here or after filtering. Either way, it requires SHIFT + DOUBLE-CLICK. Hit Clear afterward to be sure the LV updates!
- MainScreen.PNG (74.42 KiB) Viewed 2372 times
- filter.PNG (36.55 KiB) Viewed 2372 times
- TrayIcon.PNG (7.77 KiB) Viewed 2372 times