Тема: AHK: Поиск в ListView
Поиск в контроле SysListView32 по словам, с выделением строки и подсветкой нужной колонки.
#NoEnv
SetBatchLines, -1
#If Control := ListViewFocus()
^vk46:: ; Ctrl + F
hWnd := WinExist("A")
Gui, Search:Default
Gui, +Owner%hWnd% +AlwaysOnTop
Gui, Margin,, 10
Gui, Add, Text, x10 y10, Текст для поиска:
Gui, Add, Edit, x+5 yp-3 w150 h21 vEdit, % Edit
Gui, Add, Button, x+-125 y+10 w60 h21 gGo Default, Искать
Gui, Add, Button, x+5 yp wp hp gCancel, Отмена
Gui, Add, Radio, % "x15 yp+4 vRadio" (Radio != 0 ? " Checked" : ""), Вниз
Gui, Add, Radio, % "x+5 yp" (Radio = 0 ? " Checked" : ""), Вверх
WinGetPos, X, Y,,, A
Gui, Show, % "x" X + 100 " y" Y + 50, Поиск в ListView
return
Go:
GuiControlGet, Edit, Search:
if (Edit = "")
Goto, Cancel
ControlGet, hLv, hwnd,, % Control, ahk_id %hWnd%
oLv := ""
if !IsObject(oLv := New ListView(hLv, Edit))
{
MsgBox, 0x1030, Ошибка, Невозможно извлечь информацию из ListView!
return
}
GuiControlGet, Radio, Search:
Gui, Search:Destroy
ControlGet, Focus, List, Count Focused,, % "ahk_id" oLv.h
oFound := oLv.SearchWord(Focus, 1, Radio)
if (oFound.state = "not_found")
DllCall("MessageBox", Ptr, oLv.h, Str, "Текст """ Edit """ не найден!", Str, "Не найдено", UInt, 0x30)
else if (oFound.state = "found")
{
CurrentRow := oFound.row, CurrentCol := oFound.col
oLv.SetSel(CurrentRow), oLv.Highlight(CurrentRow, CurrentCol)
Hotkey, If, % ListViewFocus()
Hotkey, F3, Search, On
}
oFound := ""
return
Search:
(Radio && ++CurrentCol > oLv.CountCol) ? (CurrentCol := 1, ++CurrentRow)
(!Radio && --CurrentCol = 0) ? (CurrentCol := oLv.CountCol, --CurrentRow)
oFound := oLv.SearchWord(CurrentRow, CurrentCol, Radio)
if (oFound.state != "found")
Return
CurrentRow := oFound.row, CurrentCol := oFound.col
oLv.SetSel(CurrentRow), oLv.Highlight(CurrentRow, CurrentCol)
return
SearchGuiClose:
SearchGuiEscape:
Cancel:
Gui, Search:Destroy
return
Class ListView
{
__New(hListView, word)
{
ControlGet, CountCol, List, Count Col,, ahk_id %hListView%
if !CountCol
Return ""
WinGet, PID, PID, ahk_id %hListView%
this.h := hListView
this.pid := PID
this.comp := this.CompareCapacity(PID)
this.CountCol := CountCol
this.word := word
}
CompareCapacity(PID)
{
if !A_Is64bitOS
Return 1
if !hProc := DllCall("OpenProcess", UInt, PROCESS_QUERY_INFORMATION := 0x400, Int, 0, UInt, PID, Ptr)
Return
VarSetCapacity(b, 4)
DllCall("IsWow64Process", Ptr, hProc, Ptr, &b)
DllCall("CloseHandle", Ptr, hProc)
b := NumGet(b, "UInt")
Return ((A_PtrSize = 4 && b) || (A_PtrSize = 8 && !b)) ? 1 : ""
}
SearchWord(StartRow, StartCol, Direction)
{
if this.comp
Return this.SearchViaMessage(StartRow, StartCol, Direction)
else
Return this.SearchViaParsing(StartRow, StartCol, Direction)
}
SearchViaMessage(StartRow, StartCol, Direction)
{
static found
Direction ? (CurrentRow := StartRow-1
, CurrentCol := StartCol-1) : (CurrentRow := StartRow+1, CurrentCol := StartCol+1)
RemoteBuff := New RemoteBuffer(this.pid, (A_PtrSize = 4 ? 60 : 68) + 260*(A_IsUnicode ? 2 : 1))
Loop
{
ControlGet, RowsCount, List, Count,, % "ahk_id" this.h
(Direction && ++CurrentRow > RowsCount) ? CurrentRow := 1
(!Direction && --CurrentRow = 0) ? CurrentRow := RowsCount
Loop
{
if (Direction && ++CurrentCol > this.CountCol && !(CurrentCol := 0))
|| (!Direction && --CurrentCol = 0 && (CurrentCol := this.CountCol + 1))
break
Text := this.GetItemText(CurrentRow, CurrentCol, RemoteBuff)
if ((A_IsUnicode ? RegExMatch(Text, "i)(*UCP)\Q" this.word "\E") : InStr(Text, this.word)) && found := 1)
Return {state: "found", row: CurrentRow, col: CurrentCol}
if (board && CurrentRow = StartRow && CurrentCol = StartCol && !found)
Return {state: "not_found"}
((Direction && CurrentRow = RowsCount && CurrentCol = this.CountCol)
|| (!Direction && CurrentRow = 1 && CurrentCol = 1)) ? board := 1
(CurrentRow = StartRow && CurrentCol = StartCol) ? found := ""
}
}
}
SearchViaParsing(StartRow, StartCol, Direction)
{
static found, FirstItem
StartIndex := StartRow * this.CountCol + StartCol
ControlGet, Content, List,,, % "ahk_id" this.h
Loop, parse, Content, `n
{
CurrentRow := A_Index
Loop, parse, A_LoopField, % A_Tab
{
CurrentIndex := CurrentRow * this.CountCol + A_Index
if (!WaitingNear && (A_IsUnicode ? RegExMatch(A_LoopField, "i)(*UCP)\Q" this.word "\E") : InStr(A_LoopField, this.word)))
LastItem := CurrentIndex, !found ? (FirstItem := CurrentIndex, found := 1)
if (CurrentIndex = StartIndex)
{
if (!Direction && found && !(found := 0))
Return this.CreateFromIndex(LastItem)
Direction ? WaitingNear := 1
}
if (WaitingNear
&& (A_IsUnicode ? RegExMatch(A_LoopField, "i)(*UCP)\Q" this.word "\E") : InStr(A_LoopField, this.word))
&& !(found := 0))
Return this.CreateFromIndex(CurrentIndex)
}
}
if !found
Return {state: "not_found"}
else if !(found := 0)
Return this.CreateFromIndex(Direction ? FirstItem : LastItem)
}
CreateFromIndex(idx)
{
i := idx//this.CountCol, m := Mod(idx, this.CountCol)
Return {state: "found", row: m ? i : i - 1, col: m ? m : this.CountCol}
}
GetItemText(item, col, RemoteBuff)
{
static LVIF_TEXT := 1, LVM_GETITEM := (A_IsUnicode ? 0x104B : 0x1005), LVITEM_SIZE := A_PtrSize = 4 ? 60 : 68
VarSetCapacity(LVITEM, LVITEM_SIZE)
NumPut(LVIF_TEXT, LVITEM, "UInt")
NumPut(item-1, LVITEM, 4, "Int")
NumPut(col-1, LVITEM, 8, "Int")
NumPut(RemoteBuff.Ptr + LVITEM_SIZE, LVITEM, 16 + A_PtrSize, "Ptr")
NumPut(260, LVITEM, 16 + A_PtrSize*2, "Int")
RemoteBuff.Write(&LVITEM, LVITEM_SIZE)
SendMessage, LVM_GETITEM, 0, RemoteBuff.Ptr,, % "ahk_id" this.h
Return StrGet(RemoteBuff.Read(260*(A_IsUnicode ? 2 : 1), LVITEM_SIZE))
}
SetSel(row)
{
static LVIS_FOCUSED := 1, LVIS_SELECTED := 2, LVM_SETITEMSTATE := 0x102B, LVM_ENSUREVISIBLE := 0x1013
VarSetCapacity(LVITEM, LVITEM_SIZE := A_PtrSize = 4 ? 60 : 68)
NumPut(LVIS_FOCUSED | LVIS_SELECTED, LVITEM, 12)
NumPut(LVIS_FOCUSED | LVIS_SELECTED, LVITEM, 16)
RemoteBuff := New RemoteBuffer(this.pid, LVITEM_SIZE)
RemoteBuff.Write(&LVITEM, LVITEM_SIZE)
SendMessage, LVM_ENSUREVISIBLE, row - 1,,, % "ahk_id" this.h
SendMessage, LVM_SETITEMSTATE, row - 1, RemoteBuff.Ptr,, % "ahk_id" this.h
}
Highlight(row, col)
{
static counter
counter := 0, th := 3 ; толщина рамки
Gui, Highlighting:Default
Gui, Destroy
VarSetCapacity(Init, 4)
NumPut(col = 1 ? 1 : col - 1, Init, "UInt")
RemoteBuff := New RemoteBuffer(this.pid, 16)
RemoteBuff.Write(&Init, 4, 4)
SendMessage, LVM_GETSUBITEMRECT := 0x1038, row - 1, RemoteBuff.Ptr,, % "ahk_id" this.h
pAddr := RemoteBuff.Read(16)
l := NumGet(pAddr+0, "UInt"), t := NumGet(pAddr+0, 4, "UInt")
r := NumGet(pAddr+0, 8, "UInt"), b := NumGet(pAddr+0, 12, "UInt")
RemoteBuff := ""
(col = 1) ? (lprev := l, l := 0, r := lprev)
WinGetPos, X, Y,,, % "ahk_id" this.h
Gui, % "-Caption +ToolWindow +Owner" this.h " +hwndhGui"
Gui, Color, Red
Gui, Show, % "x" X + l + 1 " y" Y + t + 2 " w" (w := r - l) " h" (h := b - t) " Hide"
Prev_DHW := A_DetectHiddenWindows
DetectHiddenWindows, On
WinSet, Region, % "0-0 " w "-0 " w "-" h " 0-" h " 0-0 "
. th "-" th " " w - th "-" th " " w - th "-" h - th " " th "-" h - th " " th "-" th
, ahk_id %hGui%
DetectHiddenWindows, %Prev_DHW%
Gui, Show, NA
SetTimer, Flashing, 300
return
Flashing:
Gui, Highlighting:Default
if (++counter = 1)
Gui, Show, Hide
if (counter = 2)
Gui, Show, NA
if (counter = 3)
{
Gui, Destroy
SetTimer, Flashing, Off
}
return
}
}
Class RemoteBuffer
{
__New(PID, size)
{
static PROCESS_VM_OPERATION := 0x8, PROCESS_VM_WRITE := 0x20, PROCESS_VM_READ := 0x10
, MEM_COMMIT := 0x1000, PAGE_READWRITE := 0x4
if !(this.hProc := DllCall("OpenProcess", UInt, PROCESS_VM_OPERATION|PROCESS_VM_READ|PROCESS_VM_WRITE, Int, 0, UInt, PID, Ptr))
Return ""
if !(this.ptr := DllCall("VirtualAllocEx", UInt, this.hProc, UInt, 0, UInt, size, UInt, MEM_COMMIT, UInt, PAGE_READWRITE, Ptr))
Return ""
this.size := size
}
__Delete()
{
DllCall("VirtualFreeEx", Ptr, this.hProc, Ptr, this.ptr, UInt, 0, UInt, MEM_RELEASE := 0x8000)
DllCall("CloseHandle", Ptr, this.hProc)
}
Read(size, offset = 0)
{
static LocalBuff
VarSetCapacity(LocalBuff, s := (size > (s := this.size - offset) ? s : size), 0)
DllCall("ReadProcessMemory", Ptr, this.hProc, Ptr, this.ptr + offset, Ptr, &LocalBuff, UInt, s, UInt, 0)
VarSetCapacity(LocalBuff, -1)
Return &LocalBuff
}
Write(pLocalBuff, size, offset = 0)
{
return DllCall("WriteProcessMemory", Ptr, this.hProc, Ptr, this.ptr + offset, Ptr, pLocalBuff, UInt, size, UInt, 0)
}
}
ListViewFocus()
{
ControlGetFocus, Control, A
if InStr(Control, "SysListView32") && !WinExist("Поиск в ListView ahk_class AutoHotkeyGUI")
return Control
}
Пример использования.
Запускаем Диспетчер задач, открываем вкладку Процессы. Нажимаем Ctrl + F, в появившемся окне вводим autohotkey и кликаем "Искать", либо Enter. Далее жмём F3.
Контрол SysListView32 для обязательно должен быть в фокусе. В ANSI-версии кириллица регистрозависимая.
Скрипт довольно сложный, вопросы задавайте в этой теме.