1

Тема: AHK: Получение имени файла под курсором в Проводнике

Скрипт определяет содержание первой колонки (имя файла/папки) той строки контрола SysListView32 проводника Windows, над которой находится курсор. При небольшой задержке курсора над строкой появляется ToolTip с именем файла.

Принцип работы скрипта. При остановке курсора над контролом SysListView32 определяются координаты курсора, затем определяются координаты всех видимых строк, а также считывается текст из их первых колонок. При пересечении координат курсора и какой-либо из строк содержание её первой колонки показывается в ToolTip'е.

Координаты строк считываются с помощью посылки контролу SysListView32 сообщения LVM_GETITEMRECT. Некоторая сложность в том, что информацию это сообщение может записать только в буфер, находящийся в виртуальном адресном пространстве процесса, которому принадлежит контрол. Поэтому перед использованием сообщения нужно зарезервировать место в виртуальной памяти процесса под буфер (это делает ф-ция VirtualAllocEx()), а затем уже скопировать информацию из него в буфер, принадлежащий процессу скрипта (ReadProcessMemory()).

   LVM_FIRST := 0x1000
   LVM_GETITEMCOUNT := (LVM_FIRST + 4)
   LVM_GETTOPINDEX := (LVM_FIRST + 39)
   LVM_GETITEMRECT := (LVM_FIRST + 14)
   PROCESS_VM_OPERATION := 0x8
   PROCESS_VM_READ := 0x10
   MEM_COMMIT := 0x1000
   PAGE_READWRITE := 0x4
   MEM_RELEASE := 0x8000

   #Persistent
   Process, Priority,, H
   CoordMode, Mouse
   CoordMode, ToolTip
   VarSetCapacity(RECT, 16)   ; буфер в адресном пространстве скрипта
   SetTimer, MouseGetPos, 50
   Return

MouseGetPos:
   MouseGetPos,,,, Control
   if !InStr(Control, "SysListView")
   {
      ToolTip
      Return
   }

   MouseGetPos, XM, YM, Win_ID, LV_ID, 2
   if (XM != XM_Prev || YM != YM_Prev)
   {
      ToolTip
      SetTimer, GetItem, -100
   }
   XM_Prev := XM, YM_Prev := YM
   Return

GetItem:
   WinGetPos, X_LV, Y_LW,,, ahk_id %LV_ID%
   WinGet, PID, PID, ahk_id %Win_ID%

   SendMessage, LVM_GETITEMCOUNT,,,, ahk_id %LV_ID%
   Rows := ErrorLevel
   SendMessage, LVM_GETTOPINDEX,,,, ahk_id %LV_ID%
   TopIndex := ErrorLevel
   ControlGet, Text, List, Col1,, ahk_id %LV_ID%

   Stop =
   While !Stop && (A_Index <= Rows - TopIndex)
   {
      CurrentItem := TopIndex + A_Index - 1

      hProcess := DllCall("OpenProcess", UInt, PROCESS_VM_OPERATION|PROCESS_VM_READ
                                       , UInt, 0
                                       , UInt, PID)
   ; буфер в адресном пространстве окна проводника:
      pBuffer := DllCall("VirtualAllocEx", UInt, hProcess
                                         , UInt, 0
                                         , UInt, 16
                                         , UInt, MEM_COMMIT
                                         , UInt, PAGE_READWRITE)

      SendMessage, LVM_GETITEMRECT, CurrentItem, pBuffer,, ahk_id %LV_ID%
      DllCall("ReadProcessMemory", UInt, hProcess
                                 , UInt, pBuffer
                                 , UInt, &RECT
                                 , UInt, 16
                                 , UInt, 0)

      Left := NumGet(RECT), Right := NumGet(RECT, 8)
      Top := NumGet(RECT, 4), Bottom := NumGet(RECT, 12)

      DllCall("VirtualFreeEx", UInt, hProcess
                             , UInt, pBuffer
                             , UInt, 0
                             , UInt, MEM_RELEASE)
      DllCall("CloseHandle", UInt, hProcess)

      if (XM >= X_LV + Left && XM <= X_LV + Right && YM >= Y_LW + Top && YM <= Y_LW + Bottom)
      {
         Loop, parse, Text, `n
         {
            if (A_Index = CurrentItem + 1)
            {
               ToolTip, %A_LoopField%, XM+20, YM-5   ; в переменной A_LoopField имя файла под курсором
               Stop = 1
               Break
            }
         }
      }
   }
   Return

Тема для обсуждения на форуме.

Разработка AHK-скриптов:
e-mail dfiveg@mail.ru
Skype dmitry_fiveg