Страница 212 из 243

Добавлено: Вт окт 28, 2025 12:51
Orion9
Loopback писал(а):Ну да, с Ctrl вряд ли удастся случайно что-то утянуть :)
Ну а Гислеру что мешает сделать то же самое?

Кто не в курсе о чем речь, напоминаю ответ маэстро в этой теме.

Ну да, я торопился и забыл написать про CTRL, но что это меняет? Можно и на Shift заменить, результат будет тем же:

Код: Выделить всё

Switch uMsg
   Case WM_LBUTTONDOWN 
      If BitAND(wParam, 0x0004) Then
Т.ч. мой вопрос остаётся в силе: ну и где здесь "случайное" перетаскивание кнопок? Что-то я его не наблюдаю.

Более того, можно было и без модификаторов обойтись, но у Гислера своя оконная процедура висит и мешает. В частности это приводит к тому, что при претаскивании кнопки на саму себя происходит ее запуск. Побороть может и получится, но будет сложно, поскольку простой выход из процедуры без вызова оригинальной приводит к другим проблемам.

Код: Выделить всё

Case WM_LBUTTONDOWN 
  If BitAND(wParam, 0x0004) Then
     MouseGetPos("x","y")
     IsDrag = 0 
     If DllCall("DragDetect", "hwnd", hWnd, "int64", MakeInt(y, x, 2)) Then
        IsDrag = 1
        WinSetStyle(0x80000, 3, hWnd)
        DllCall("SetLayeredWindowAttributes", "hwnd", hWnd, "ptr", 0, "byte", 128, "dword", 2)
        Return 1        
     EndIf
  EndIf    
Case WM_LBUTTONUP
  If IsDrag = 1 Then
     WinSetStyle(0x80000, 5, hWnd)
     IsDrag = 0
     Return 1
  EndIf
Кстати, вы заметили, что я использовал MakeInt? Руки так и чесались :lol:

В общем, хотел я по быстрому сделать модуль, ведь основная функция была уже готова, оставалось только ее разбить на блоки и внести небольшие изменения, но поскольку времени было совсем мало, процесс затянулся.

Однако удалось добиться состояния промежуточной готовности:
[cut="Bars.aucfg"]

Код: Выделить всё

Pragma IncludeOnce

# наведение на главную панель
ControlSetHint /F /D:50 28 "HBarShowHint"

Global gDragIndex, gDropIndex
Global gHBarButtons = 0, gHBarDivs = 0

Global gHBarUpdSec = 2, gHBarVerb
Global gHBarName, gHBarFile, gHBarMap = List(), gHBarTxt, gHBarWincmd

Global gHBarWndProc, hBarWnd = 0
Global gHBarWP = Callback("HBarWndProc", "hwnd;uint;wparam;lparam")

Func HBarWndProc(hWnd, uMsg, wParam, lParam)
    Static IsDrag = 0, _
           hTotal = DllCall("GetModuleHandleW", "Ptr", 0, "handle"), _
           MK_SHIFT        = 0x0004, _      
           MK_CONTROL      = 0x0008, _
           MK_LBUTTON      = 0x0001, _
           WM_MOUSEMOVE    = 0x0200, _
           WM_LBUTTONDOWN  = 0x0201, _
           WM_LBUTTONUP    = 0x0202
    Static drag_system = DllCall("LoadCursor", "Ptr", 0, "Ptr", 32646), _
           stop_system = DllCall("LoadCursor", "Ptr", 0, "Ptr", 32648), _
           drag_cursor = DllCall("LoadCursor", "Ptr", hTotal, "Ptr", 22), _
           stop_cursor = DllCall("LoadCursor", "Ptr", hTotal, "Ptr", 21)            
    Switch uMsg
       Case WM_LBUTTONDOWN 
          If BitAND(wParam, MK_CONTROL) Then
             MouseGetPos("x","y")
             IsDrag = 0 
             If DllCall("DragDetect", "hwnd", hWnd, "int64", MakeInt(y, x, 2)) Then
                IsDrag = 1
                WinSetStyle(0x80000, 3, hWnd)
                DllCall("SetLayeredWindowAttributes", "hwnd", hWnd, "ptr", 0, "byte", 128, "dword", 2)
                gDragIndex = HBarGetIdx()
                #Return 1
             EndIf
          EndIf    
       Case WM_LBUTTONUP
          If IsDrag = 1 Then
             gDropIndex = HBarGetIdx()
             WinSetStyle(0x80000, 5, hWnd)
             SetHintParam("ShowHint", "Font", 17, "Arial")
             SetHintParam("ShowHint", "BackColor", 0xFF0000)
             SetHintParam("ShowHint", "Text", 0xFFFFFF)
             If WinFromPoint() = hWnd Then         
                ShowHint("Button Index: " & gDragIndex & " To Index: " & gDropIndex, "", "", 3000, 1)
             Else
                #ShowHint("Drag operation aborted, "", "", 3000, 1)             
             EndIf
             Sleep(50)
             SetHintParam("ShowHint", "Reload")
             IsDrag = 0
             #Return 1
          EndIf  
       Case WM_MOUSEMOVE
          If IsDrag = 1 And BitAND(wParam, MK_LBUTTON) Then
             If WinFromPoint() = hWnd Then
                DllCall("SetCursor", "Ptr", drag_cursor)
             Else
                DllCall("SetCursor", "Ptr", stop_cursor)               
             EndIf
          EndIf   
    EndSwitch
    Return DllCall("CallWindowProcW", _
                   "ptr", gHBarWndProc, "hwnd", hWnd, "uint", uMsg, "wparam", wParam, "lparam", lParam)
EndFunc

Func HBarShowHint()
    # состояние Ctrl
    Local bMap = IsPressed(0x11)    
    # состояние CapsLock и Shift
    If Not bMap Then
       If BitAND(DllCall("GetKeyState", "int", 0x14, "short"), 1) = 0 Then
          If Not IsPressed(0x10) Then Return
       EndIf
    EndIf   
    # дескриптор горизонтальной панели 
    Local hWnd = RequestInfo(28)
    If hWnd = 0 Then 
       Return "Окно панели не найдено " & hWnd
    EndIf
    # глобальные переменные дескриптора и оконной процедуры
    If hBarWnd <> hWnd Then
       hBarWnd = hWnd
       gHBarWndProc = DllCall("SetWindowLong" & (auX64 ? "PtrW" : "W"), _
                             "hwnd", hBarWnd, "int", -4, "long_ptr", gHBarWP.Ptr, "ptr")
    EndIf
    # поиск файла панели
    If gHBarName <> WinGetText(hBarWnd) Then 
       gHBarFile = HBarGetFile()
       If Not FileExist(gHBarFile) Then Return "Файл панели не найден " & gHBarFile
       # загрузка панели    
       HBarLoad()
    EndIf   
    # индекс кнопки под курсором
    gDragIndex = HBarGetIdx()
    If Not gDragIndex Then Return "Не удалось определить индекс кнопки"
    Return HBarGetHint(bMap)  
EndFunc

Func HBarGetFile()
    Local bar, txt
    # информация о файле панели в wincmd.ini
    IniRead bar %COMMANDER_INI% "Buttonbar" "Buttonbar" "%COMMANDER_PATH%\DEFAULT.BAR"
    # раскрытие переменной окружения
    bar = Set(bar) 
    # в конфигурации указано только имя файла
    If FileGetDir(bar) = "" Then bar = COMMANDER_PATH & "" & bar
    gHBarWincmd = bar
    # чтение текста окна панели
    txt = WinGetText(hBarWnd)
    gHBarName = txt
    # на панель загружен временный .bar файл
    If Not StrPos(bar, txt) Then       
       bar = COMMANDER_PATH & "\Bars" & txt
    EndIf
    # проверка существования файла панели
    If Not FileExist(bar) Then
       bar = COMMANDER_PATH & "" & txt
    EndIf   
    Return bar
EndFunc

Func HBarLoad()
    # загрузка файла в массив
    Local aBar = List()
    aBar.LoadFromFile(gHBarFile)
    # количество кнопок в файле
    Local nCount = 0
    IniRead nCount  %gHBarFile% "Buttonbar" "Buttoncount" 0
    # обнуление счетчиков
    gHBarDivs = 0
    gHBarButtons = 0
    # локальные переменные
    Local j, key, val, found, oButton = Map(), oCmd = Map()
    # поиск кнопок и команд
    For j = 0 To aBar.Count - 1        
        found = 0    
        If StrLeft(aBar[j], 6) = "button" Then  
           found = 1
        ElseIf StrLeft(aBar[j], 3) = "cmd" Then  
           found = 2
        EndIf
        If found > 0 Then
           key = StrLower(StrPart(aBar[j], "=", 1))
           val = StrLen(StrPart(aBar[j], "=", 2))
           If found = 1 Then
              oButton.Set(key, val)              
           Else
              oCmd.Set(key, val)          
           EndIf
        EndIf
    Next
    gHBarMap.Count = 0    
    # подсчет кнопок и разделителей
    For j = 1 To nCount     
        key = "button" & j
        val = oButton.Get(key, 0)         
        If val > 0 Then
           # количество кнопок                 
           gHBarButtons += 1
           gHBarMap.Add(1)
        Else
           # количество разделителей  
           gHBarDivs += 1   
           gHBarMap.Add(0)
        EndIf
    Next
    Free(aBar, oButton, oCmd)    
    # карта панели
    gHBarTxt = auCRLF & auCRLF & "Loaded: " & gHBarFile & auCRLF
    For j = 0 To gHBarMap.Count - 1
        gHBarTxt &= gHBarMap[j] & "  "
        If j > 0 and Mod(j, 50) = 0 Then gHBarTxt &= auCRLF
    Next
    gHBarTxt &= auCRLF & "Wincmd.ini: " & gHBarWincmd
EndFunc

Func HBarGetIdx()
    # дескриптор монитора окна ТС
    Local hMon = DllCall("MonitorFromWindow", "hwnd", AUTORUN_TCHANDLE, "dword", 2)
    # информация о масштабировании экрана
    Local nScale = 0, bRes
    bRes = DllCall("Shcore.dll\GetScaleFactorForMonitor", "hwnd", hMon, "dword*", @nScale)
    # буфер для структуры MONITORINFOEX
    Local buf = Buffer(104)
    buf.Zero()
    buf.SetNum(0, "dword", 104)
    DllCall("GetMonitorInfoW", "ptr", hMon, "ptr", buf.ptr)
    # имя монитора
    Local sMon = buf.GetStr(40)
    # локальные переменные
    Local x, y, w, h, mx, my, idx, row, rows, rowh, bar, txt, b, extra
    # координаты и размеры окна панели
    WinGetPos("x", "y", "w", "h", hBarWnd) 
    # координаты указателя мыши
    MouseGetPos("mx", "my")
    # чтение информации о высоте кнопок
    IniRead b %COMMANDER_INI% "Buttonbar" "Buttonheight"
    # масштабирование экрана
    If nScale > 0 Then b = Round(b*nScale/100,0)
    # количество рядов кнопок на панели
    rows = Floor(h/b)
#    If rows = 0 Then Return "Error number of rows = 0"
    # количество дополнительных пикселей
    extra = Mod(h,b)
    # ширина разделителя    
    Local div = Floor(b/3)
    # высота одного ряда
    rowh = b + 3
    # номер ряда под указателем
    row = Ceil((my - y)/rowh)
    # абстрактные координаты по оси х
    Local tx = (mx - x + 1) + ((row - 1) * w), cx = 0
    # индекс кнопки в ряду    
    If gHBarDivs = 0 Then
       idx = (Floor((mx - x)/b) + 1) + (row-1)*(Floor(w/b))
    Else
       j = 1
       idx = 0       
       For i = 0 To gHBarMap.Count - 1
           cx += (gHBarMap[i] = 0 ? div : b)
           ex = j*w - cx
           If i + 1 <= gHBarMap.Count - 1 Then
              If ex < (gHBarMap[i+1] = 0 ? div : b) Then
                 cx += ex
                 j += 1
              EndIf
           Else
              cx += ex   
           EndIf   
           If cx >= tx Then
              idx = i + 1
              Break
           EndIf   
       Next        
    EndIf
    # дополнительная информация
    gHBarVerb = "mouse=" & mx & ", " & my & auCRLF & _
                "bar=" & x & ", " & y & ", " & w & ", " & h & auCRLF &  _
                "map=" & tx & ", " & cx & auCRLF & _
                "row=" & row & " of " & rows & auCRLF & _
                "height=" & rowh & " (" & extra & ")" & auCRLF & _ 
                "buttons=" & gHBarButtons & " + " & gHBarDivs & " divs" & auCRLF & _ 
                "width=" & b & ", " & div & auCRLF & _
                "mon=" & HMon & " scale=" & nScale & "%"     
    Return idx
EndFunc

Func HBarGetHint(bMap)
    # чтение информации о кнопке из .bar фйла
    Local sMenu, sButton, sCmd, sParam, sPath, sIcon
    IniRead sMenu   %gHBarFile% "Buttonbar" %'"menu"   & gDragIndex' ""
    IniRead sButton %gHBarFile% "Buttonbar" %'"button" & gDragIndex' ""
    IniRead sCmd    %gHBarFile% "Buttonbar" %'"cmd"    & gDragIndex' ""
    IniRead sParam  %gHBarFile% "Buttonbar" %'"param"  & gDragIndex' ""
    IniRead sPath   %gHBarFile% "Buttonbar" %'"path"   & gDragIndex' ""
    IniRead sIcon   %gHBarFile% "Buttonbar" %'"iconic" & gDragIndex' ""
    # удаление подсказки тотала
    Local hTip = WinFind(0, "TToolTip")
    If hTip > 0 Then DllCall("DestroyWindow", "handle", hTip)
    # возврат текста     
    Return gHBarVerb & auCRLF & _
           "" & auCRLF & _           
           "index=" & gDragIndex & " of " & gHBarButtons+gHBarDivs & auCRLF & _           
           "menu=" & sMenu & auCRLF & _
           "button=" & sButton & auCRLF & _
           "cmd=" & sCmd & auCRLF & _
           "param=" & sParam & auCRLF & _
           "path=" & sPath  & auCRLF & _
           "iconic=" & sIcon & (bMap ? gHBarTxt : "")
EndFunc
[/cut]
Сейчас подсказка вызывается по Ctrl, Shift и CapsLock. Ctrl добавляет карту панели и имеет возможность перетаскивания кнопок. Пока при перетаскивании показываются только индексы опрации. Пересобрать панель будет делом техники, но сначала нужно добавить дополнительные проверки и провести больше тестов. Например усовершенствовать блок с масштабированием экрана и оптимизировать количество вызовов. Также нужно что-то придумать, как обрабатывать временно загруженную панель, файл которой не находится в корне ТС или подкаталоге \Bars. Сейчас такая панель работать не будет.
Loopback писал(а):Думаю, можно и полностью исправить, но тогда придется отказаться от создания диалога с помощью DialogBox и полностью создать свое окно с нуля.
А откуда уверенность, что это поможет?
Loopback писал(а):Что-то может быть, конечно, но проблема с потоком маловероятно что связана с ним.
Согласен. Я больше имел в виду дурацкие приколы с загрузкой графического объекта.
Loopback писал(а):Из плагинов статистики нет, слишком много затрат для реализации.
То, что некоторые вещи реализовать сложно, это понятно. Но какие сложности с SetHotkeyAction? Разве во время парсинга вы не можете собрать статистику, что привязано к этому вызову? У меня много модулей, и в каждом что-то висит на SetHotkeyAction. Со временем забываешь, что именно. Можно конечно простым поиском по всем файлам найти, но ведь лень же да и не удобно это. Куда лучше было бы вызвать GetState("SetHotkeyAction") и всё увидеть.

Добавлено: Вт окт 28, 2025 13:25
Loopback
Orion9 писал(а):Побороть может и получится, но будет сложно, поскольку простой выход из процедуры без вызова оригинальной приводит к другим проблемам.
Тут еще проблема с x64. Новый вариант не пробовал, но предыдущий валит тотал x64 при выходе. С похожей проблемой я столкнулся, когда пытался делать сабклассинг окна тотала. Ставится-то он без проблем, но уже не снимается и тотал крашится. Т.е. выгружать плагин нельзя. Похоже здесь та же проблема.
Orion9 писал(а):А откуда уверенность, что это поможет?
Я делал тесты, меняя ID кнопки Отмена с IDCANCEL (2) на другой. В этом случае диалог появлялся всегда. Но тогда теряется возможность закрыть окно кнопкой Esc и что-то еще вроде было. При этом диалог, создаваемый DialogBox, имеет свой обработчик клавиш, не позволяющий что-то изменить.
Orion9 писал(а):Разве во время парсинга вы не можете собрать статистику, что привязано к этому вызову?
Нет API для передачи этих данных из плагина. Это дело не пяти минут. Пока слишком много более приоритетных задач.

Добавлено: Вт окт 28, 2025 19:31
Orion9
Loopback писал(а):Новый вариант не пробовал, но предыдущий валит тотал x64 при выходе.
Похоже, что так. В Win11 это происходит "тихо", даже не сразу заметил. Ну и ладно. Я все-равно этой версией редко пользуюсь, в том числе из-за разных проблем с Autorun.
Loopback писал(а):Ставится-то он без проблем, но уже не снимается и тотал крашится.
C окном ТС вероятно так и есть, однако в моем случае если добавить к секции финализации, то краш уходит даже на Win8:

Код: Выделить всё

Pragma AutorunFinalizeSection

If gHBarWndProc > 0 Then 
    DllCall("SetWindowLong" & (auX64 ? "PtrW" : "W"), _
            "hwnd", hBarWnd, "int", -4, "long_ptr", gHBarWndProc, "ptr")
EndIf
Loopback писал(а):Я делал тесты, меняя ID кнопки Отмена с IDCANCEL (2) на другой. В этом случае диалог появлялся всегда.
Интересный ход. Возможно из этого получится что-то выжать и обойти проблему, но всё-таки хотелось докапаться до причины, почему это вообще происходит. Сдается мне, что все это может быть связано - вылеты потоков, окон диалога, глючная загрузка bitmap и т.д. Сделал на скорую руку кнопку для теста потока на основе вашей первоначальной функции перебора торрента:
[cut]

Код: Выделить всё

RegisterCommand 70508 "TorrentBugTest"

Func TorrentBugTest(lParam)
    RunThread("TorrentThreadTest")
EndFunc

Func TorrentThreadTest()
    Local hIco = 0   
    Local hWnd = DllCall("CreateWindowExW", _
                         "dword", 0, _
                         "wstr", "msctls_progress32", _
                         "wstr", "", _
                         "dword", 0x00C80000, _
                         "int", 200, "int", 100, "int", Scale(400), "int", Scale(50), _
                         "handle", AUTORUN_TCHANDLE, _
                         "handle", 0, "handle", 0, "ptr", 0, "handle")
    If hWnd = 0 Then Return 0
    
    WinAlign(hWnd, 0, DllCall("GetDesktopWindow"))
    WinSetPos("", -Scale(50), "", "", 1, hWnd)
    WinSetState(5, hWnd)
                                
    Static PBS_MARQUEE     =  0x08, _
           PBM_SETMARQUEE  =  1034, _
           WM_GETICON      =  0x7f, _
           WM_SETICON      =  0x80
           
    hIco = SendMessage(AUTORUN_TCHANDLE, WM_GETICON, 2, 0)                     
    SendMessage(hWnd, WM_SETICON, 0, hIco)
    
    WinSetStyle(PBS_MARQUEE, 2, hWnd)    
    SendMessage(hWnd, PBM_SETMARQUEE, 1, 0)
    For i = 1 To 20
        TorrentInfo(hWnd, i, "d:\Temp\Jinn'sLiveUSB 11.2.2.torrent")
        If WinGetState(1, hWnd) = 0 Then
           MsgBox("Тестирование прервано", "Autorun", 48)
           Return
        EndIf
    Next    
    MsgBox("Тестирование успешно завершено", "Autorun", 64)
    DllCall("DestroyWindow", "handle", hWnd)
EndFunc

Func TorrentInfo(hWnd, nPass, sFile)
    Static aFixed = List('Name', 'TotalSize', 'FileCount', 'BlockSize', 'BlockCount', _
                         'Created', 'Creator', 'Hash', 'Comment', 'Encoding', _
                         'Multifile', 'PrivateTorrent', 'Publisher', 'PublisherURL')
    Static aMulti = List('Tracker', 'Webseed', 'Error', 'CustomField')

    Static sLibName = "TCTorrent.wlx" & (auX64 ? "64" : "")
    Static sLibPath = COMMANDER_PATH & "\Plugins\wlx\TCTorrent" & sLibName

    Local hDll = DllCall("LoadLibrary", "wstr", sLibPath, "handle")
    If hDll = 0 Then Return

    Local hHandle = DllCall(sLibName & "\TorrentOpen", "wstr", sFile, "handle")
    If hHandle = 0 Then
        DllCall("FreeLibrary", "handle", hDll)
        Return
    EndIf

    Local nCount, sRes

    For i = 0 to aFixed.Count - 1
        sRes = DllCall(sLibName & "\TorrentGet", "handle", hHandle, "wstr", aFixed[i], "int", 0, "wstr")
        OutputDebugString(aFixed[i] & ": " & sRes)
        WinSetText(nPass & ": " & sRes, hWnd)
    Next

    OutputDebugString(auCRLF & 'Files:')
    nCount = DllCall(sLibName & "\TorrentCountGet", "handle", hHandle, "wstr", "File", "uint")
    For j = 0 To nCount - 1
        sRes = StrFormat("[%12s] %s", _
                 DllCall(sLibName & "\TorrentGet", "handle", hHandle, "wstr", "FileSize", "int", j, "wstr"), _
                 DllCall(sLibName & "\TorrentGet", "handle", hHandle, "wstr", "File", "int", j, "wstr"))
        OutputDebugString(sRes)
        WinSetText(nPass & ": " & sRes, hWnd)
    Next

    For i = 0 to aMulti.Count - 1
        OutputDebugString(auCRLF & aMulti[i] & 's:')
        nCount = DllCall(sLibName & "\TorrentCountGet", "handle", hHandle, "wstr", aMulti[i], "uint")
        For j = 0 To nCount - 1
            sRes = DllCall(sLibName & "\TorrentGet", "handle", hHandle, "wstr", aMulti[i], "int", j, "wstr")
            OutputDebugString(sRes)
            WinSetText(nPass & ": " & sRes, hWnd)
        Next
    Next

    DllCall(sLibName & "\TorrentClose", "handle", hHandle)
    DllCall("FreeLibrary", "handle", hDll)
EndFunc 
[/cut]
Почему-то был уверен, что баг проявится быстро, однако не всё так просто. У меня используется Jinn'sLiveUSB 11.2.2 на 9800 файлов, но можно прописать любой большой торрент и увеличить количество циклов в For..Next.

В общем, не сразу, но через какое-то время потоки, которые также запущены в фоне (заголовок, подсчет времени воспроизведения, пинг трех адресов и т.д.) начинают отваливаться. Удивительно, но сам поток TorrentThreadTest мне так и не удалось завалить. Видимо он слишком простенький для этого, не использует какие-то критические части Autorun. Но проблема определенно есть.
Loopback писал(а):Нет API для передачи этих данных из плагина. Это дело не пяти минут.
Жалко, конечно, но что поделать. Как-нибудь пока проживем без этого )

Добавлено: Ср окт 29, 2025 20:36
Loopback
Orion9 писал(а): если добавить к секции финализации, то краш уходит
Я это попробовал в первую очередь, но не помогло. Во всяком случае на 10.
Orion9 писал(а): Но проблема определенно есть.
Ну это понятно. Как появится возможность, буду тестировать.

Добавлено: Чт окт 30, 2025 19:48
Orion9
Loopback писал(а):Я это попробовал в первую очередь, но не помогло. Во всяком случае на 10.
Если не ошибаюсь, на восьмерке тоже пару раз при выходе возникла ошибка даже с кодом финализации. Т.ч. возможно, что проблема не всегда просто проявляется, как и в случае с MsgBox().

Доделал я функцию drag-n-drop на панели, очень хотелось посмотреть, как она будет работать. Версия чисто DEMO, пока есть еще ряд недоработок, связанных прежде всего с масштабированием экрана. Все работает и при масштабировании, но если поменять размер кнопок, то индекс перестанет правильно определяться. При стандартном dpi проблем нет. В будущем надо будет и других улучшений добавить, например откат действия и бэкап панели. Пока бэкап нужно обязательно делать вручную, а то мало ли что.

В общем, если кто-то будет пробовать, только на свой страх и риск ) Но имхо, само перетаскивание классно смотрится и "ощущатся", жаль, что Гислер не хочет его реализовывать.

[cut="Bars.aucfg"]

Код: Выделить всё

Pragma IncludeOnce

# наведение на главную панель
ControlSetHint /F /D:50 28 "HBarShowHint"

Global gDragIndex, gDropIndex
Global gHBarButtons = 0, gHBarDivs = 0

Global gHBarHint = 0, gHBarVerb
Global gHBarList = List(), gHBarMap = List()
Global gHBarName, gHBarFile, gHBarTxt, gHBarWincmd

Global gHBarWndProc, hBarWnd = 0
Global gHBarWP = Callback("HBarWndProc", "hwnd;uint;wparam;lparam")

Func HBarWndProc(hWnd, uMsg, wParam, lParam)
    Static IsDrag = 0, _
           hTotal = DllCall("GetModuleHandleW", "Ptr", 0, "handle"), _
           MK_SHIFT        = 0x0004, _      
           MK_CONTROL      = 0x0008, _
           MK_LBUTTON      = 0x0001, _
           WM_MOUSEMOVE    = 0x0200, _
           WM_LBUTTONDOWN  = 0x0201, _
           WM_LBUTTONUP    = 0x0202
    Static drag_system = DllCall("LoadCursor", "Ptr", 0, "Ptr", 32646), _
           stop_system = DllCall("LoadCursor", "Ptr", 0, "Ptr", 32648), _
           drag_cursor = DllCall("LoadCursor", "Ptr", hTotal, "Ptr", 22), _
           stop_cursor = DllCall("LoadCursor", "Ptr", hTotal, "Ptr", 21)            
    Switch uMsg
       Case WM_LBUTTONDOWN 
          If IsDrag = 0 And BitAND(wParam, MK_CONTROL) Then
             MouseGetPos("x","y")
             If DllCall("DragDetect", "hwnd", hWnd, "int64", MakeInt(y, x, 2)) Then
                IsDrag = 1
                WinSetStyle(0x80000, 3, hWnd)
                DllCall("SetLayeredWindowAttributes", "hwnd", hWnd, "ptr", 0, "byte", 128, "dword", 2)
                gDragIndex = HBarGetIdx()
             EndIf
          EndIf    
       Case WM_LBUTTONUP
          If IsDrag = 1 Then
             gDropIndex = HBarGetIdx()
             If WinFromPoint() = hWnd Then
                If gDragIndex <> gDropIndex Then
                   If gHBarHint Then ShowDragHint("Index " & gDragIndex & " To Index: " & gDropIndex)
                   HBarDragnDrop(gDragIndex, gDropIndex)
                EndIf
             EndIf
             WinSetStyle(0x80000, 5, hWnd)             
             IsDrag = 0
             MouseGetPos("x","y")
             lParam = MakeInt(y, x + 200, 2)
          EndIf  
       Case WM_MOUSEMOVE
          If IsDrag = 1 And BitAND(wParam, MK_LBUTTON) Then
             If WinFromPoint() = hWnd Then
                DllCall("SetCursor", "Ptr", drag_cursor)
             Else
                DllCall("SetCursor", "Ptr", stop_cursor)               
             EndIf
          EndIf   
    EndSwitch
    Return DllCall("CallWindowProcW", _
                   "ptr", gHBarWndProc, "hwnd", hWnd, "uint", uMsg, "wparam", wParam, "lparam", lParam)
EndFunc

Func HBarShowHint()
    If WinHasStyle(0x80000, 1, hBarWnd) Then Return
    # состояние Ctrl
    Local bMap = IsPressed(0x11)    
    # состояние CapsLock и Shift
    If Not bMap Then
       If BitAND(DllCall("GetKeyState", "int", 0x14, "short"), 1) = 0 Then
          If Not IsPressed(0x10) Then Return
       EndIf
    EndIf   
    # дескриптор горизонтальной панели 
    Local hWnd = RequestInfo(28)
    If hWnd = 0 Then 
       Return "Окно панели не найдено " & hWnd
    EndIf
    # глобальные переменные дескриптора и оконной процедуры
    If hBarWnd <> hWnd Then
       hBarWnd = hWnd
       gHBarWndProc = DllCall("SetWindowLong" & (auX64 ? "PtrW" : "W"), _
                             "hwnd", hBarWnd, "int", -4, "long_ptr", gHBarWP.Ptr, "ptr")
    EndIf
    # поиск файла панели
    If gHBarName <> WinGetText(hBarWnd) Then 
       gHBarFile = HBarGetFile()
       If Not FileExist(gHBarFile) Then Return "Файл панели не найден " & gHBarFile
       # загрузка панели    
       HBarLoad()
    EndIf   
    # индекс кнопки под курсором
    gDragIndex = HBarGetIdx()
    If Not gDragIndex Then Return "Не удалось определить индекс кнопки"
    Return HBarGetHint(bMap)  
EndFunc

Func HBarGetFile()
    Local bar, txt
    # информация о файле панели в wincmd.ini
    IniRead bar %COMMANDER_INI% "Buttonbar" "Buttonbar" "%COMMANDER_PATH%\DEFAULT.BAR"
    # раскрытие переменной окружения
    bar = Set(bar) 
    # в конфигурации указано только имя файла
    If FileGetDir(bar) = "" Then bar = COMMANDER_PATH & "" & bar
    gHBarWincmd = bar
    # чтение текста окна панели
    txt = WinGetText(hBarWnd)
    gHBarName = txt
    # на панель загружен временный .bar файл
    If Not StrPos(bar, txt) Then       
       bar = COMMANDER_PATH & "\Bars" & txt
    EndIf
    # проверка существования файла панели
    If Not FileExist(bar) Then
       bar = COMMANDER_PATH & "" & txt
    EndIf   
    Return bar
EndFunc

Func HBarLoad()
    # загрузка файла в массив
    gHBarList.Count = 0
    gHBarList.LoadFromFile(gHBarFile, "ANSI")
    # количество кнопок в файле
    Local nCount = 0
    IniRead nCount  %gHBarFile% "Buttonbar" "Buttoncount" 0
    # обнуление счетчиков
    gHBarDivs = 0
    gHBarButtons = 0
    # локальные переменные
    Local j, key, val, found, oButton = Map(), oCmd = Map()
    # поиск кнопок и команд
    For j = 0 To gHBarList.Count - 1        
        found = 0    
        If StrLeft(gHBarList[j], 6) = "button" Then  
           found = 1
        ElseIf StrLeft(gHBarList[j], 3) = "cmd" Then  
           found = 2
        EndIf
        If found > 0 Then
           key = StrLower(StrPart(gHBarList[j], "=", 1))
           val = StrLen(StrPart(gHBarList[j], "=", 2))
           If found = 1 Then
              oButton.Set(key, val)              
           Else
              oCmd.Set(key, val)          
           EndIf
        EndIf
    Next
    gHBarMap.Count = 0    
    # подсчет кнопок и разделителей
    For j = 1 To nCount     
        key = "button" & j
        val = oButton.Get(key, 0)         
        If val > 0 Then
           # количество кнопок                 
           gHBarButtons += 1
           gHBarMap.Add(1)
        Else
           # количество разделителей  
           gHBarDivs += 1   
           gHBarMap.Add(0)
        EndIf
    Next
    Free(oButton, oCmd)    
    # карта панели
    gHBarTxt = auCRLF & auCRLF & "Loaded: " & gHBarFile & auCRLF
    For j = 0 To gHBarMap.Count - 1
        gHBarTxt &= gHBarMap[j] & "  "
        If j > 0 and Mod(j, 50) = 0 Then gHBarTxt &= auCRLF
    Next
    gHBarTxt &= auCRLF & "Wincmd.ini: " & gHBarWincmd
EndFunc

Func HBarGetIdx()
    # дескриптор монитора окна ТС
    Local hMon = DllCall("MonitorFromWindow", "hwnd", AUTORUN_TCHANDLE, "dword", 2)
    # информация о масштабировании экрана
    Local nScale = 0, bRes
    bRes = DllCall("Shcore.dll\GetScaleFactorForMonitor", "hwnd", hMon, "dword*", @nScale)
    # буфер для структуры MONITORINFOEX
    Local buf = Buffer(104)
    buf.Zero()
    buf.SetNum(0, "dword", 104)
    DllCall("GetMonitorInfoW", "ptr", hMon, "ptr", buf.ptr)
    # имя монитора
    Local sMon = buf.GetStr(40)
    # локальные переменные
    Local x, y, w, h, mx, my, idx, row, rows, rowh, bar, txt, b, extra
    # координаты и размеры окна панели
    WinGetPos("x", "y", "w", "h", hBarWnd) 
    # координаты указателя мыши
    MouseGetPos("mx", "my")
    # чтение информации о высоте кнопок
    IniRead b %COMMANDER_INI% "Buttonbar" "Buttonheight"
    # масштабирование экрана
    If nScale > 0 Then b = Round(b*nScale/100,0)
    # количество рядов кнопок на панели
    rows = Floor(h/b)
#    If rows = 0 Then Return "Error number of rows = 0"
    # количество дополнительных пикселей
    extra = Mod(h,b)
    # ширина разделителя    
    Local div = Floor(b/3)
    # высота одного ряда
    rowh = b + 3
    # номер ряда под указателем
    row = Ceil((my - y)/rowh)
    # абстрактные координаты по оси х
    Local tx = (mx - x + 1) + ((row - 1) * w), cx = 0
    # индекс кнопки в ряду    
    If gHBarDivs = 0 Then
       idx = (Floor((mx - x)/b) + 1) + (row-1)*(Floor(w/b))
    Else
       j = 1
       idx = 0       
       For i = 0 To gHBarMap.Count - 1
           cx += (gHBarMap[i] = 0 ? div : b)
           ex = j*w - cx
           If i + 1 <= gHBarMap.Count - 1 Then
              If ex < (gHBarMap[i+1] = 0 ? div : b) Then
                 cx += ex
                 j += 1
              EndIf
           Else
              cx += ex   
           EndIf   
           If cx >= tx Then
              idx = i + 1
              Break
           EndIf   
       Next        
    EndIf
    # дополнительная информация
    gHBarVerb = "mouse=" & mx & ", " & my & auCRLF & _
                "bar=" & x & ", " & y & ", " & w & ", " & h & auCRLF &  _
                "map=" & tx & ", " & cx & auCRLF & _
                "row=" & row & " of " & rows & auCRLF & _
                "height=" & rowh & " (" & extra & ")" & auCRLF & _ 
                "buttons=" & gHBarButtons & " + " & gHBarDivs & " divs" & auCRLF & _ 
                "width=" & b & ", " & div & auCRLF & _
                "mon=" & HMon & " scale=" & nScale & "%"     
    Return idx
EndFunc

Func HBarGetHint(bMap)
    # чтение информации о кнопке из .bar фйла
    Local sMenu, sButton, sCmd, sParam, sPath, sIcon
    IniRead sMenu   %gHBarFile% "Buttonbar" %'"menu"   & gDragIndex' ""
    IniRead sButton %gHBarFile% "Buttonbar" %'"button" & gDragIndex' ""
    IniRead sCmd    %gHBarFile% "Buttonbar" %'"cmd"    & gDragIndex' ""
    IniRead sParam  %gHBarFile% "Buttonbar" %'"param"  & gDragIndex' ""
    IniRead sPath   %gHBarFile% "Buttonbar" %'"path"   & gDragIndex' ""
    IniRead sIcon   %gHBarFile% "Buttonbar" %'"iconic" & gDragIndex' ""
    # удаление подсказки тотала
    Local hTip = WinFind(0, "TToolTip")
    If hTip > 0 Then DllCall("DestroyWindow", "handle", hTip)
    # возврат текста     
    Return gHBarVerb & auCRLF & _
           "" & auCRLF & _           
           "index=" & gDragIndex & " of " & gHBarButtons+gHBarDivs & auCRLF & _           
           "menu=" & sMenu & auCRLF & _
           "button=" & sButton & auCRLF & _
           "cmd=" & sCmd & auCRLF & _
           "param=" & sParam & auCRLF & _
           "path=" & sPath  & auCRLF & _
           "iconic=" & sIcon & (bMap ? gHBarTxt : "")
EndFunc

Func HBarDragnDrop(DragIdx, DropIdx)
    Static aItems = List("button","cmd","param","path","menu","iconic")
    Local T1, T2, bTL = 0
    If bTL Then T1 = GetUptime()    
    Local i, j, k, txt, key, new
    txt = gHBarList.Text
    # временная замена индекса
    For j = 0 To aItems.Count - 1
       key = aItems[j] & DragIdx & "="
       new = aItems[j] & 9999 & "="
       txt = StrReplace(txt, key, new)          
    Next
    If bTL Then   
       T2 = Round(GetUptime() - T1, 0) / 1000
       OutputDebugString("Время операции 1: " &  StrFormat("%.3f", T2) & " sec")
    EndIf   
    If DragIdx < DropIdx Then
       For i = DragIdx + 1 To DropIdx
            For k = 0 To aItems.Count - 1
               key = aItems[k] & i & "="
               new = aItems[k] & i - 1 & "="       
               txt = StrReplace(txt, key, new)
               If bTL Then OutputDebugString("DragIdx < " & key & " -> " & new)               
            Next
        Next
     Else
       For i = DragIdx - 1 TO DropIdx Step -1
            For k = 0 To aItems.Count - 1
               key = aItems[k] & i & "="
               new = aItems[k] & i + 1 & "="       
               txt = StrReplace(txt, key, new)
               If bTL Then OutputDebugString("DragIdx > " & key & " -> " & new)               
            Next
        Next
     EndIf
    If bTL Then   
       T2 = Round(GetUptime() - T1, 0) / 1000
       OutputDebugString("Время операции 2: " &  StrFormat("%.3f", T2) & " sec")
    EndIf 
    For j = 0 To aItems.Count - 1
       key = aItems[j] & 9999 & "="
       new = aItems[j] & DropIdx & "="
       txt = StrReplace(txt, key, new)          
    Next
    gHBarList.Text = txt
    gHBarList.SaveToFile(gHBarFile, "ANSI")
    HBarLoad()
    If bTL Then   
       T2 = Round(GetUptime() - T1, 0) / 1000
       OutputDebugString("Время операции 3: " &  StrFormat("%.3f", T2) & " sec")
    EndIf     
    SendCommand(2945)     # cm_ReloadBarIcons
EndFunc

Func ShowDragHint(DragHint)
    SetHintParam("ShowHint", "Font", 14, "Arial")
    SetHintParam("ShowHint", "BackColor", 0x000000)
    SetHintParam("ShowHint", "Text", 0xFFFFFF)
    ShowHint(DragHint, "", "", 3000, 1)
    Sleep(10)
    SetHintParam("ShowHint", "Reload")  
EndFunc
[/cut]

Добавлено: Пт окт 31, 2025 23:27
Orion9
Loopback
Почему-то вызов не работает:

Код: Выделить всё

If DllCall("Ntdll.dll\IsWindows8Point1OrGreater", "bool") Then
Есть идеи почему?

Добавлено: Сб ноя 01, 2025 11:54
Orion9
Loopbak
Метод с явным указанием ANSI

Код: Выделить всё

lst.LoadFromFile(sFile, "ANSI")
загружает юникодный файл (UTF-16) полностью и без проблем. Так задумано, или ошибка?

Добавлено: Сб ноя 01, 2025 18:31
Loopback
Orion9 писал(а):Почему-то вызов не работает
Макрос еrror возвращает ошибку 2 - отсутствие функции в dll.

А всё потому, что это не реальная функция в dll, а враппер. В файле VersionHelpers.h он задается так:

Код: Выделить всё

VERSIONHELPERAPI
IsWindows8Point1OrGreater()
{
    return IsWindowsVersionOrGreater(HIBYTE(_WIN32_WINNT_WINBLUE), LOBYTE(_WIN32_WINNT_WINBLUE), 0);
}

VERSIONHELPERAPI
IsWindowsVersionOrGreater(WORD wMajorVersion, WORD wMinorVersion, WORD wServicePackMajor)
{
    OSVERSIONINFOEXW osvi = { sizeof(osvi), 0, 0, 0, 0, {0}, 0, 0 };
    DWORDLONG        const dwlConditionMask = VerSetConditionMask(
        VerSetConditionMask(
        VerSetConditionMask(
            0, VER_MAJORVERSION, VER_GREATER_EQUAL),
               VER_MINORVERSION, VER_GREATER_EQUAL),
               VER_SERVICEPACKMAJOR, VER_GREATER_EQUAL);

    osvi.dwMajorVersion = wMajorVersion;
    osvi.dwMinorVersion = wMinorVersion;
    osvi.wServicePackMajor = wServicePackMajor;

    return VerifyVersionInfoW(&osvi, VER_MAJORVERSION | VER_MINORVERSION | VER_SERVICEPACKMAJOR, dwlConditionMask) != FALSE;
}
Orion9 писал(а):Так задумано, или ошибка?
Так задумано. Если файл содержит BOM, он всегда читается в кодировке, определяемой BOM. Указываемые здесь значения служат для интерпретации файла без BOM. Наверно, это стоит уточнить в справке.

Добавлено: Сб ноя 01, 2025 19:45
Orion9
И всё-таки я ещё раз спрошу у Гислера: ну и где здесь "случайное" перетаскивание кнопок на панели?

[cut]Изображение[/cut]
Ладно, шучу я. Понятно, что он просто не захотел этим заморачиваться, а я взял и заморочился :)

Последняя версия модуля.
[cut="Bars.aucfg"]

Код: Выделить всё

Pragma IncludeOnce

# наведение на главную панель
ControlSetHint /F /D:50 28 "HBarShowHint"

# правый клик с удержанием Ctrl
ControlSetMouseAction /R /K:C 28 "HBarShowMenu"

Global gDragIndex, gDropIndex
Global gHBarButtons = 0, gHBarDivs = 0

Global gHBarHint = 0, gHBarVerb, gHBarCancel, gHBarCancelLoad
Global gHBarName, gHBarFile, gHBarTxt, gHBarCP = "ANSI", gHBarWincmd = 0
Global gHBarList = List(), gHBarMap = List(), gHBarUndo, gHBarUndoTs, gHBarUndoLoad

Global gHBarWndProc, hBarWnd = 0
Global gHBarWP = Callback("HBarWndProc", "hwnd;uint;wparam;lparam")

Func HBarWndProc(hWnd, uMsg, wParam, lParam)
    Static IsDrag = 0, _
           hTotal = DllCall("GetModuleHandleW", "Ptr", 0, "handle"), _
           MK_SHIFT        = 0x0004, _      
           MK_CONTROL      = 0x0008, _
           MK_LBUTTON      = 0x0001, _
           WM_MOUSEMOVE    = 0x0200, _
           WM_LBUTTONDOWN  = 0x0201, _
           WM_LBUTTONUP    = 0x0202
    Static drag_system = DllCall("LoadCursor", "Ptr", 0, "Ptr", 32646), _
           stop_system = DllCall("LoadCursor", "Ptr", 0, "Ptr", 32648), _
           drag_cursor = DllCall("LoadCursor", "Ptr", hTotal, "Ptr", 22), _
           stop_cursor = DllCall("LoadCursor", "Ptr", hTotal, "Ptr", 21)            
    Switch uMsg
       Case WM_LBUTTONDOWN 
          If IsDrag = 0 And BitAND(wParam, MK_CONTROL) Then
             MouseGetPos("x","y")
             If DllCall("DragDetect", "hwnd", hWnd, "int64", MakeInt(y, x, 2)) Then
                IsDrag = 1
                WinSetStyle(0x80000, 3, hWnd)
                DllCall("SetLayeredWindowAttributes", "hwnd", hWnd, "ptr", 0, "byte", 128, "dword", 2)
                gDragIndex = HBarGetIdx()
             EndIf
          EndIf    
       Case WM_LBUTTONUP
          If IsDrag = 1 Then
             gDropIndex = HBarGetIdx()
             If WinFromPoint() = hWnd Then
                If gDragIndex <> gDropIndex Then
                   If gHBarHint Then ShowDragHint("Index " & gDragIndex & " To Index: " & gDropIndex)
                   HBarDragnDrop(gDragIndex, gDropIndex)
                EndIf
             EndIf
             WinSetStyle(0x80000, 5, hWnd)             
             IsDrag = 0
             MouseGetPos("x","y")
             lParam = MakeInt(y, x + 200, 2)
          EndIf  
       Case WM_MOUSEMOVE
          If IsDrag = 1 And BitAND(wParam, MK_LBUTTON) Then
             If WinFromPoint() = hWnd Then
                DllCall("SetCursor", "Ptr", drag_cursor)
             Else
                DllCall("SetCursor", "Ptr", stop_cursor)               
             EndIf
          EndIf   
    EndSwitch
    Return DllCall("CallWindowProcW", _
                   "ptr", gHBarWndProc, "hwnd", hWnd, "uint", uMsg, "wparam", wParam, "lparam", lParam)
EndFunc

Func HBarShowHint()
    If WinHasStyle(0x80000, 1, hBarWnd) Then Return
    # состояние Ctrl
    Local bMap = IsPressed(0x11)    
    # состояние CapsLock и Shift
    If Not bMap Then
       If BitAND(DllCall("GetKeyState", "int", 0x14, "short"), 1) = 0 Then
          If Not IsPressed(0x10) Then Return
       EndIf
    EndIf   
    # дескриптор горизонтальной панели 
    Local hWnd = RequestInfo(28)
    If hWnd = 0 Then 
       Return "Окно панели не найдено " & hWnd
    EndIf
    # глобальные переменные дескриптора и оконной процедуры
    If hBarWnd <> hWnd Then
       hBarWnd = hWnd
       gHBarWndProc = DllCall("SetWindowLong" & (auX64 ? "PtrW" : "W"), _
                             "hwnd", hBarWnd, "int", -4, "long_ptr", gHBarWP.Ptr, "ptr")
    EndIf
    # поиск файла панели
    If gHBarName <> WinGetText(hBarWnd) Then
       gHBarUndo = false
       gHBarUndoLoad = ""
       gHBarCancel = false
       gHBarCancelLoad = ""       
       gHBarFile = HBarGetFile()
       If Not FileExist(gHBarFile) Then Return "Файл панели не найден " & gHBarFile
       # загрузка панели    
       HBarLoad()
    EndIf   
    # индекс кнопки под курсором
    gDragIndex = HBarGetIdx()
    If Not gDragIndex Then Return "Не удалось определить индекс кнопки"
    Return HBarGetHint(bMap)  
EndFunc

Func HBarGetFile()
    Local bar, txt
    # информация о файле панели в wincmd.ini
    IniRead bar %COMMANDER_INI% "Buttonbar" "Buttonbar" "%COMMANDER_PATH%\DEFAULT.BAR"
    # раскрытие переменной окружения
    bar = Set(bar) 
    # в конфигурации указано только имя файла
    If FileGetDir(bar) = "" Then bar = COMMANDER_PATH & "" & bar
    gHBarWincmd = bar
    # чтение текста окна панели
    txt = WinGetText(hBarWnd)
    gHBarName = txt
    # на панель загружен временный .bar файл
    If Not StrPos(bar, txt) Then       
       bar = COMMANDER_PATH & "\Bars" & txt
    EndIf
    # проверка существования файла панели
    If Not FileExist(bar) Then
       bar = COMMANDER_PATH & "" & txt
    EndIf   
    Return bar
EndFunc

Func HBarLoad()
    # загрузка файла в массив
    gHBarList.Count = 0
    gHBarList.LoadFromFile(gHBarFile, gHBarCP)    
    # количество кнопок в файле
    Local nCount = 0
    IniRead nCount  %gHBarFile% "Buttonbar" "Buttoncount" 0
    # обнуление счетчиков
    gHBarDivs = 0
    gHBarButtons = 0
    # локальные переменные
    Local j, key, val, found, oButton = Map(), oCmd = Map()
    # поиск кнопок и команд
    For j = 0 To gHBarList.Count - 1        
        found = 0    
        If StrLeft(gHBarList[j], 6) = "button" Then  
           found = 1
        ElseIf StrLeft(gHBarList[j], 3) = "cmd" Then  
           found = 2
        EndIf
        If found > 0 Then
           key = StrLower(StrPart(gHBarList[j], "=", 1))
           val = StrLen(StrPart(gHBarList[j], "=", 2))
           If found = 1 Then
              oButton.Set(key, val)              
           Else
              oCmd.Set(key, val)          
           EndIf
        EndIf
    Next
    gHBarMap.Count = 0    
    # подсчет кнопок и разделителей
    For j = 1 To nCount     
        key = "button" & j
        val = oButton.Get(key, 0)         
        If val > 0 Then
           # количество кнопок                 
           gHBarButtons += 1
           gHBarMap.Add(1)
        Else
           # количество разделителей  
           gHBarDivs += 1   
           gHBarMap.Add(0)
        EndIf
    Next
    Free(oButton, oCmd)    
    # карта панели
    gHBarTxt = auCRLF & auCRLF & "Loaded: " & gHBarFile & auCRLF
    For j = 0 To gHBarMap.Count - 1
        gHBarTxt &= gHBarMap[j] & "  "
        If j > 0 and Mod(j, 50) = 0 Then gHBarTxt &= auCRLF
    Next
    gHBarTxt &= auCRLF & "Wincmd.ini: " & gHBarWincmd
EndFunc

Func HBarGetIdx()
    # дескриптор монитора окна ТС
    Local hMon = DllCall("MonitorFromWindow", "hwnd", AUTORUN_TCHANDLE, "dword", 2)
    # буфер для структуры MONITORINFOEX
    Local buf = Buffer(104)
    buf.Zero()
    buf.SetNum(0, "dword", 104)
    DllCall("GetMonitorInfoW", "ptr", hMon, "ptr", buf.ptr)
    # имя монитора
    Local sMon = buf.GetStr(40)
    # информация о масштабировании экрана
    Local DC = DllCall("GetDC", "int", 0)
    Local nDPI = DllCall("GetDeviceCaps", "handle", DC, "int", 88) # LOGPIXELSX
    Local nScale = DllCall("MulDiv", "int", 100, "int", nDPI, "int", 96)
    DllCall("ReleaseDC", "int", 0, "handle", DC)     
    # локальные переменные
    Local x, y, w, h, mx, my, idx, row, rows, rowh, dpi, b, extra
    # координаты и размеры окна панели
    WinGetPos("x", "y", "w", "h", hBarWnd) 
    # координаты указателя мыши
    MouseGetPos("mx", "my")
    # чтение информации о высоте кнопок
    IniRead b %COMMANDER_INI% "Buttonbar" "Buttonheight"
    IniRead dpi %COMMANDER_INI% "Buttonbar" "DefaultDpi" %'nDPI'
    Local b_ini = b, b_calc
    # масштабирование экрана
    If dpi <> nDPI Then
       IniRead d %COMMANDER_INI% "Buttonbar" %'"Buttonheight" & nDPI' 0
       If d <> 0 Then 
          b = d
       Else   
          b = Round(b / (dpi / nDPI), 0)
          b_calc = "*"
       EndIf
    EndIf   
    # количество рядов кнопок на панели
    rows = Floor(h/b)
    If rows = 0 Then Return HBarShowHint("Error number of rows can't be zero")
    # количество дополнительных пикселей
    extra = Mod(h,b)
    # ширина разделителя    
    Local div = Floor(b/3)
    # высота одного ряда
    rowh = b + 3
    # номер ряда под указателем
    row = Ceil((my - y)/rowh)
    # абстрактные координаты по оси х
    Local tx = (mx - x + 1) + ((row - 1) * w), cx = 0
    # индекс кнопки в ряду    
    If gHBarDivs = 0 Then
       idx = (Floor((mx - x)/b) + 1) + (row-1)*(Floor(w/b))
    Else
       j = 1
       idx = 0       
       For i = 0 To gHBarMap.Count - 1
           cx += (gHBarMap[i] = 0 ? div : b)
           ex = j*w - cx
           If i + 1 <= gHBarMap.Count - 1 Then
              If ex < (gHBarMap[i+1] = 0 ? div : b) Then
                 cx += ex
                 j += 1
              EndIf
           Else
              cx += ex   
           EndIf   
           If cx >= tx Then
              idx = i + 1
              Break
           EndIf   
       Next        
    EndIf
    # дополнительная информация
    gHBarVerb = "mouse=" & mx & ", " & my & auCRLF & _
                "bar=" & x & ", " & y & ", " & w & ", " & h & auCRLF &  _
                "map=" & tx & ", " & cx & auCRLF & _
                "row=" & row & " of " & rows & auCRLF & _
                "height=" & rowh & " (" & extra & ")" & " b=" & b & b_calc & " (" & b_ini & ")" & auCRLF & _
                "buttons=" & gHBarButtons & " + " & gHBarDivs & " divs" & auCRLF & _ 
                "width=" & b & ", " & div & auCRLF & _
                "mon=" & HMon & " dpi=" & nDPI & " scale=" & nScale & "%"     
    Return idx
EndFunc

Func HBarGetHint(bMap)
    # чтение информации о кнопке из .bar фйла
    Local sMenu, sButton, sCmd, sParam, sPath, sIcon
    IniRead sMenu   %gHBarFile% "Buttonbar" %'"menu"   & gDragIndex' ""
    IniRead sButton %gHBarFile% "Buttonbar" %'"button" & gDragIndex' ""
    IniRead sCmd    %gHBarFile% "Buttonbar" %'"cmd"    & gDragIndex' ""
    IniRead sParam  %gHBarFile% "Buttonbar" %'"param"  & gDragIndex' ""
    IniRead sPath   %gHBarFile% "Buttonbar" %'"path"   & gDragIndex' ""
    IniRead sIcon   %gHBarFile% "Buttonbar" %'"iconic" & gDragIndex' ""
    # удаление подсказки тотала
    Local hTip = WinFind(0, "TToolTip")
    If hTip > 0 Then DllCall("DestroyWindow", "handle", hTip)
    # возврат текста     
    Return gHBarVerb & auCRLF & _
           "" & auCRLF & _           
           "index=" & gDragIndex & " of " & gHBarButtons+gHBarDivs & auCRLF & _           
           "menu=" & sMenu & auCRLF & _
           "button=" & sButton & auCRLF & _
           "cmd=" & sCmd & auCRLF & _
           "param=" & sParam & auCRLF & _
           "path=" & sPath  & auCRLF & _
           "iconic=" & sIcon & (bMap ? gHBarTxt : "")
EndFunc

Func HBarDragnDrop(DragIdx, DropIdx)
    Static aItems = List("button","cmd","param","path","menu","iconic")
    Local T1, T2, bTL = 0
    If bTL Then T1 = GetUptime()    
    Local i, j, k, txt, key, new
    txt = gHBarList.Text
    gHBarUndoLoad = txt
    If Not gHBarCancel Then
       gHBarCancel = true
       gHBarCancelLoad = txt
    EndIf   
    # временная замена индекса
    For j = 0 To aItems.Count - 1
       key = aItems[j] & DragIdx & "="
       new = aItems[j] & 9999 & "="
       txt = StrReplace(txt, key, new)          
    Next
    If bTL Then   
       T2 = Round(GetUptime() - T1, 0) / 1000
       OutputDebugString("Время операции 1: " &  StrFormat("%.3f", T2) & " sec")
    EndIf   
    If DragIdx < DropIdx Then
       For i = DragIdx + 1 To DropIdx
            For k = 0 To aItems.Count - 1
               key = aItems[k] & i & "="
               new = aItems[k] & i - 1 & "="       
               txt = StrReplace(txt, key, new)
               If bTL Then OutputDebugString("DragIdx < " & key & " -> " & new)               
            Next
        Next
     Else
       For i = DragIdx - 1 TO DropIdx Step -1
            For k = 0 To aItems.Count - 1
               key = aItems[k] & i & "="
               new = aItems[k] & i + 1 & "="       
               txt = StrReplace(txt, key, new)
               If bTL Then OutputDebugString("DragIdx > " & key & " -> " & new)               
            Next
        Next
     EndIf
    If bTL Then   
       T2 = Round(GetUptime() - T1, 0) / 1000
       OutputDebugString("Время операции 2: " &  StrFormat("%.3f", T2) & " sec")
    EndIf 
    For j = 0 To aItems.Count - 1
       key = aItems[j] & 9999 & "="
       new = aItems[j] & DropIdx & "="
       txt = StrReplace(txt, key, new)          
    Next
    gHBarList.Text = txt
    gHBarList.SaveToFile(gHBarFile, gHBarCP)
    gHBarUndoTs = FileGetTime(gHBarFile)
    If gHBarUndoTs Then 
       gHBarUndo = true
    Else
       gHBarUndo = false    
       gHBarUndoLoad = ""   
    EndIf   
    HBarLoad()
    If bTL Then   
       T2 = Round(GetUptime() - T1, 0) / 1000
       OutputDebugString("Время операции 3: " &  StrFormat("%.3f", T2) & " sec")
    EndIf     
    SendCommand(2945)     # cm_ReloadBarIcons
EndFunc

Func ShowDragHint(DragHint)
    SetHintParam("ShowHint", "Font", 14, "Arial")
    SetHintParam("ShowHint", "BackColor", 0x000000)
    SetHintParam("ShowHint", "Text", 0xFFFFFF)
    SetHintParam("ShowHint", "DarkBackColor", 0xFF0000)
    SetHintParam("ShowHint", "DarkText", 0xFFFFFF)    
    ShowHint(DragHint, "", "", 3000, 1)
    WinAlign(LAST_HINT_WINDOW)    
    Sleep(10)
    SetHintParam("ShowHint", "Reload")  
EndFunc

Func HBarShowMenu()
    Local hWnd = RequestInfo(28)
    If hWnd = 0 Then 
       ShowDragHint("Окно панели не найдено")
       Return
    EndIf
    If gHBarName <> WinGetText(hWnd) Then
       ShowDragHint("Нет сведений о файле панели")
       Return
    EndIf
    ShowPopupMenu /D /F /I:0 "HBarMenu"
EndFunc

Func HBarMenu()
    Local txt
    Local bak1 = FileChangeExt(gHBarFile, "bak1")
    Local bak2 = FileChangeExt(gHBarFile, "bak2")    
    txt &= 'MENUITEM "'  & gHBarName & '", em_aucmd /D' & auCRLF
    txt &= 'MENUITEM SEPARATOR' & auCRLF
    txt &= 'MENUITEM "Открывать как ANSI", em_aucmd ' & (gHBarCP = "ANSI" ? "/C" : "") & ' -1 HBarSetCodePage 1' & auCRLF
    txt &= 'MENUITEM "Открывать как UTF-16", em_aucmd ' & (gHBarCP = "UTF-16" ? "/C" : "") & ' -1 HBarSetCodePage 2' & auCRLF
    txt &= 'MENUITEM SEPARATOR' & auCRLF
    txt &= 'MENUITEM "Отменить действие", em_aucmd ' & (gHBarUndo ?  "" : "/D") & ' -1 HBarUndo' & auCRLF
    txt &= 'MENUITEM "Вернуть первоначальную панель", em_aucmd ' & (gHBarCancel ?  "" : "/D") & ' -1 HBarCancel' & auCRLF
    txt &= 'MENUITEM SEPARATOR' & auCRLF
    txt &= 'MENUITEM "Резервная копия 1", em_aucmd ' & (FileExist(bak1) ? "" : "/D") & ' -1 HBarLoadBak 1' & auCRLF
    txt &= 'MENUITEM "Резервная копия 2", em_aucmd ' & (FileExist(bak2) ? "" : "/D") & ' -1 HBarLoadBak 2' & auCRLF    
    txt &= 'MENUITEM SEPARATOR' & auCRLF
    txt &= 'MENUITEM "Сделать резервную копию 1", em_aucmd -1 HBarSaveBak 1' & auCRLF
    txt &= 'MENUITEM "Сделать резервную копию 2", em_aucmd -1 HBarSaveBak 2' & auCRLF    
    Return txt
EndFunc

Func HBarSetCodePage(nCodePage)
    Local sCP = (nCodePage = 1 ? "ANSI" : "UTF-16")
    Local bLoadQ = gHBarCP <> sCP
    gHBarCP = sCP
    If bLoadQ Then
       MsgBox("Открыть панель в кодировке " & gHBarCP & "?", "Autorun", 3+64+0)
       If EXTENDED = 6 Then 
          HBarLoad()
          ShowDragHint("Панель открыта как " & gHBarCP)
          SendCommand(2945)  
       EndIf   
    EndIf
EndFunc

Func HBarSaveBak(nBak)
     Local bak = FileChangeExt(gHBarFile, "bak" & nBak)
     If FileExist(bak) Then
        MsgBox("Файл существует" & auCRLF & auCRLF & _
                bak & auCRLF & auCRLF & "Перезаписать?", "Autorun", 3+32+0)
        If EXTENDED <> 6 Then Return
     EndIf
     FileCopy(gHBarFile, bak, 1)
     ShowDragHint("Файл сохранен " & bak)
EndFunc

Func HBarLoadBak(nBak)
     Local bak = FileChangeExt(gHBarFile, "bak" & nBak)
     If Not FileExist(bak) Then
        MsgBox("Файл не существует " & bak, "Autorun")
        Return
     EndIf
     If Not FileExist(gHBarFile) Then
        MsgBox("Файл не существует " & gHBarFile, "Autorun")
        Return
     EndIf     
     MsgBox("Файл " & gHBarFile & " будет перезаписан файлом " & _
                bak & auCRLF & auCRLF & "Продолжить?", "Autorun", 3+32+0)
     If EXTENDED <> 6 Then Return
     FileCopy(bak, gHBarFile, 1)     
     HBarLoad()
     ShowDragHint("Файл загружен " & bak)
     SendCommand(2945)
EndFunc

Func HBarUndo()
    If Not gHBarUndo Then Return
    If FileGetTime(gHBarFile) <> gHBarUndoTs Then
       MsgBox("Файл " & gHBarFile & " изменился на диске" & auCRLF & auCRLF & _
              "Отмена действия невозможна", "Autorun", 64)
       Return       
    EndIf
    FileWrite(gHBarFile, gHBarUndoLoad, gHBarCP)    
    If ERROR = 1 Then
       MsgBox("Ошибка записи " & gHBarFile, "Autorun", 64)
    Else
       gHBarUndo = false
       gHBarUndoLoad = ""
       HBarLoad()
       ShowDragHint("Действие отменено")
       SendCommand(2945)
    EndIf   
EndFunc

Func HBarCancel()
    If Not gHBarCancel Then Return
    If gHBarCancelLoad = "" Then Return MsgBox("Пустое значение CancelLoad")
    MsgBox("Файл будет перезаписан" & auCRLF & auCRLF & _
            gHBarFile & auCRLF & auCRLF & "Продолжить?", "Autorun", 3+32+0)
    If EXTENDED <> 6 Then Return
    FileWrite(gHBarFile, gHBarCancelLoad, gHBarCP)    
    If ERROR = 1 Then
       MsgBox("Ошибка записи " & gHBarFile, "Autorun", 64)
    Else
       gHBarCancel = false
       gHBarCancelLoad = ""
       HBarLoad()
       ShowDragHint("Первоначальная панель загружена")
       SendCommand(2945)
    EndIf   
EndFunc
[/cut]
Добавлена отмена действия и возврат к первоначальной панели, а также возможность создания бэкапов. Исправлено масштабирование экрана. Ветка с загрузкой панели в ANSI или UTF-16 получается не сильно нужна и остается пока недоделанной по причинам описанным выше. Однако важное замечание: если панель хранится в юникоде, по умолчанию она сохраняться будет как ANSI, если не поставить соответствующую галочку в меню. Галочка между сессиями не сохраняется, тоже имейте это в виду. У меня все панели храняться в ANSI, а к модулю я могу еще вернуться не скоро, хотя автосохранение в корректной кодировке само напрашивается.

Окно панели хранит только имя файла, информация о пути недоступна. Поэтому файлы ищутся только в каталоге ТС или подкаталоге \Bars. Если и там, и там есть одинаковое имя файла, это может привести к проблемам.

У Гислера висит своя оконная процедура, во избежание проблем приходится передавать ей управление. Чтобы избавится от клика, которая посылает эта процедура, используется подмена х-координаты указателя мыши:

Код: Выделить всё

MouseGetPos("x","y")
lParam = MakeInt(y, x + 200, 2)
Клик происходит на 200 пикселей правее и не приводит к запуску кнопки. Но если используется слишком большое масштабирование, запуск может произойти.

В остальном проблем не замечено. Пользуюсь с большим удовольствием )
Loopbak писал(а):А всё потому, что это не реальная функция в dll, а враппер
Понятно. Спасибо, что разобрались. Хотел было использовать что-то вроде:

Код: Выделить всё

Local pX, pY
Local nScale = 0, bRes
If DllCall("Ntdll.dll\IsWindows8Point1OrGreater", "bool") Then
   bRes = DllCall("Shcore.dll\GetDpiForMonitor", "hwnd", hMon, "int", 0, "uint*", @pX, "uint*", @pY)
   bRes = DllCall("Shcore.dll\GetScaleFactorForMonitor", "hwnd", hMon, "dword*", @nScale)
   nDPI = pX       
EndIf
Но почитав немного про эти функции и про DPI в целом, понял, что оно того не стоит.
Loopbak писал(а):Так задумано. Если файл содержит BOM, он всегда читается в кодировке, определяемой BOM.
Имхо, правильно задумано. А если во взятом таким образом массиве есть маркер BOM то сохраняться через SaveToFile он тоже будет корректно?

Добавлено спустя 4 минуты:

Забыл написать, что меню вызывается по правому клику мыши с зажатым Ctrl.

Добавлено: Сб ноя 01, 2025 21:22
Loopback
Orion9 писал(а):В остальном проблем не замечено.
Ну что же, как минимум с точки зрения "Proof of Concept" неплохо. Работает с указанным ограничением по расположению. Только пришлось добавить /R в IniRead, у меня перенаправление включено.
Orion9 писал(а): А если во взятом таким образом массиве есть маркер BOM то сохраняться через SaveToFile он тоже будет корректно?
Маркер это принадлежность файла, после чтения текста он нигде не сохраняется. В SaveToFile необходимо явно указывать кодировку (если она отличается от умолчальной) и нужно ли записывать BOM.

Добавлено: Сб ноя 01, 2025 23:33
Orion9
Loopbak писал(а):Ну что же, как минимум с точки зрения "Proof of Concept" неплохо.
А с точки зрения чего же ещё? ) Как говорится, могЁм когда умеем. А вот маэстро со своими ответами в стиле "это невозможно" лишь портит себе репутацию. Что вообще значит невозможно? Любой грамотный специалист знает, что нет такого слова в принципе: при правильно настроенном контроллере головного мозга и прямом драйвере руки.sys возможно всё :mrgreen:
Loopbak писал(а):Только пришлось добавить /R в IniRead, у меня перенаправление включено.
Ах да, как-то забыл об этом совсем, надо будет подправить в будущих версиях. Хотя кто знает, вдруг Гислеру загорится и он решит сделать свой драгендроп в ТС, тогда этот модуль потеряет в ценности. Правда там еще подсказка о кнопках всплывает, а для меня она значит больше, чем перетаскивание. Впрочем, Гислеру и подсказку ничего не мешает сделать такую же, или почти такую же.
Loopbak писал(а):В SaveToFile необходимо явно указывать кодировку (если она отличается от умолчальной) и нужно ли записывать BOM.
Понятно. В общем, надо будет всё это исправить и учесть, но не в ближайшее время. Сейчас мне нужно, к сожалению, отправиться восвояси. Как говорится, теперь я свободен как udp-пакет в полете :mrgreen: Но надеюсь не на долго )

Добавлено: Чт ноя 06, 2025 13:18
ZiabrevLV
При выполнении команды:

Код: Выделить всё

RegisterCommand 60007 "BarCommand"

Func BarCommand(lParam)
        
IniWrite %COMMANDER_INI% "Buttonbar" "Buttonbar" "%COMMANDER_PATH%\Bars\Default_2.bar"
CommandExec cm_Exit 1

EndFunc
в wincmd.ini переменная переписываетса на абсолютный путь:
Buttonbar=D:\TotalCommander\Bars\Defaul_2t.bar

Как -то можно поправить, на переменную %COMMANDER_PATH%?

Добавлено: Пт ноя 07, 2025 10:50
Loopback
ZiabrevLV писал(а):Как -то можно поправить, на переменную %COMMANDER_PATH%?
Да, добавить переключатель, чтобы значение записывалось как есть:

Код: Выделить всё

IniWrite /EV- %COMMANDER_INI% "Buttonbar" "Buttonbar" "%COMMANDER_PATH%\Bars\Default_2.bar"

Добавлено: Пт ноя 07, 2025 12:53
Orion9
Loopback
А почему потоки, запускаемые из кнопок и горячих клавиш, не отображаются в GetState? Ведь эти функции тоже в отдельных потоках запускаются, верно? Если да, то какая разница между запуском из кнопки и запуском через RunThread?

Вопросы не на ровном месте. Убрал запуск окна прогресс-бара в отдельном потоке через переменную и условие:

Код: Выделить всё

Global g_WinThread = 0

If g_WinThread Then 
   RunThread "WinFindTorrentData"
   While g_FindTorrTask = 0
       Sleep(50)
   Wend
Else
    WinFindTorrentData(0)
EndIf
Окно теперь создается в том же потоке, что и функция запроса FileFindEv, при этом стабильности в х64 значительно прибавилось. Целый час тестировал, операция ни разу не зависла. Правда тотал все-таки один раз упал, а параллельные потоки заголовка и др. продолжали отваливаться и исчезать из GetState, но общая стабильность работы возрасла. Проверить это можно, если вернуть все назад через g_WinThread=1. Как только окно запускается через RunThread, зависания происходят через считанные секунды или минуты.

В общем, оставил запуск без второго потока по умолчания. Из минусов: при захвате и перемещении окна мышью операция поиска на данное время прерывается. Это понятно, т.к. окно создано в том же потоке, что и функция поиска, из которой этому окну посылаются сообщения. Второй минус - в GetState ничего не отображается, а хотелось бы.

Но плюс довольно большой: операция выполняется более стабильно, а значит выбор очевиден. Обновленный модуль:
[cut="Torrent.aucfg"]

Код: Выделить всё

Pragma IncludeOnce

# 70500-70599

RegisterCommand 70500 "TorrentFindData" 0
RegisterCommand 70501 "TorrentFindData" 1
RegisterCommand 70502 "GoToPathFromTextFile"
RegisterCommand 70503 "ToggleEverything"
RegisterCommand 70504 "FindTorrentParts"
RegisterCommand 70505 "TorrentSize"
RegisterCommand 70506 "TorrentFindOptions"
RegisterCommand 70507 "TorrentDebugInfo"

RegisterCommand 70508 "TorrentBugTest"

SetHotkeyAction /K:A /H:0 /DM /S TorrentDebugInfo
SetHotkeyAction /K:A /K:W /H:0 /DM /S TorrentFindOptions

Global gEvPath = COMMANDER_PATH & "\Everything.exe", gEvAuto = 0, gEvDelay = 100

Global gTorrentDbg = 0, gDbgStep, gCapsReverse = 0
Global gTorrentSize = 0, gTorrentCount = 0, gDriveInclude = "e:\;f:\;g:\;h:\;i:\;j:\"

Global h_WinFindTorr = 0, g_WinThread = 0
Global g_WinFindTorr = 0, g_FindTorrTask = 0
Global o_WinFindTorr = Callback("WinFindTorrProc", "hwnd;uint;wparam;lparam")

Func WinFindTorrProc(hWnd, uMsg, wParam, lParam)
    Static WM_CLOSE = 0x0010
    If uMsg = WM_CLOSE Then
       If DllCall("DestroyWindow", "handle", hWnd) Then
          h_WinFindTorr = 0        
          g_FindTorrTask = 0
       EndIf   
       Return 0
    EndIf
    Return DllCall("CallWindowProcW", "ptr", g_WinFindTorr, _
                                      "hwnd", hWnd, "uint", uMsg, "wparam", wParam, "lparam", lParam)
EndFunc

Func WinFindTorrentData(bWhile = 1)
    Local hIco    
    h_WinFindTorr = DllCall("CreateWindowExW", _
                            "dword", 0, _
                            "wstr", "msctls_progress32", _
                            "wstr", "", _
                            "dword", 0x00C80000, _
                            "int", 200, "int", 100, "int", Scale(400), "int", Scale(50), _
                            "handle", AUTORUN_TCHANDLE, _
                            "handle", 0, "handle", 0, "ptr", 0, "handle")
    If h_WinFindTorr = 0 Then Return 0
    
    WinAlign(h_WinFindTorr, 0, DllCall("GetDesktopWindow"))
    WinSetPos("", -Scale(50), "", "", 1, h_WinFindTorr)
    WinSetState(5, h_WinFindTorr)
    
    g_WinFindTorr = DllCall("SetWindowLong" & (auX64 ? "PtrW" : "W"), _
                            "hwnd", h_WinFindTorr, _
                            "int", -4, _
                            "long_ptr", o_WinFindTorr.Ptr, "ptr")
                            
    Static PBS_MARQUEE     =  0x08, _
           PBM_SETMARQUEE  =  1034, _
           WM_GETICON      =  0x7f, _
           WM_SETICON      =  0x80
           
    hIco = SendMessage(AUTORUN_TCHANDLE, WM_GETICON, 2, 0)                     
    SendMessage(h_WinFindTorr, WM_SETICON, 0, hIco)
    
    WinSetStyle(PBS_MARQUEE, 2, h_WinFindTorr)    
    SendMessage(h_WinFindTorr, PBM_SETMARQUEE, 1, 0)
    
    WinSetText("Searching...", h_WinFindTorr)
    
    g_FindTorrTask = 1
    If bWhile Then
       While g_FindTorrTask
           Sleep(50)
       Wend
       h_WinFindTorr = 0
    EndIf   
EndFunc

Func TorrentFindData(lParam, nMode)
    If IsPressed(0x10) And Not nMode Then
       SetTorrentDrives()
       Return
    EndIf
    Local bEverything = nMode
    If h_WinFindTorr Then
       SendMessage(h_WinFindTorr, 0x0010, 0, 0)
       g_FindTorrTask = 0  
       Return
    Endif
    Static buf = Buffer(256)
    buf.Zero()
    Local nSymb = DllCall("GetLogicalDriveStringsW", "dword", buf.size, "ptr", buf.ptr)    
    If Not nSymb Then
       MsgBox("Не удалось получить список логических дисков" & auCRLF "SYSERROR: " & SYSERROR, "Autorun")
       Return
    EndIf
    Static aDrive = List(), aFound = List()
    Local i = 0, sz, sDrives
    aDrive.Count = 0
    While 1
       sDrive = buf.GetStr(i)
       sz = StrLen(sDrive)
       If sz = 0 Then break
       aDrive.add(sDrive)
       i = i + sz*2 + 2
    Wend
    sDrives = aDrive.text
    #MsgBox(sDrives)    
    Local obj = Plugin("TCTorrent")
    If ERROR <> 0 Then
       ShowHint("TCTorrent.wdx plugin error " & ERROR)
       Return
    Endif
    Local lRet = false 
    Local sPath = RequestCopyDataInfo("SP")    
    Local sName = RequestCopyDataInfo("SN")        
    Local sFile = sPath & sName
    If Not FileExist(sFile) Then 
       ShowHint("Файл не существует " & sFile)
       lRet = true
    ElseIf StrPos(FileGetAttr(sFile), "D") Then
       ShowHint("Каталог " & sFile)
       lRet = true
    ElseIf FileGetSize(sFile) > 1024*1024*5 Then
       ShowHint("Размер файла больше 5 Мб " & sFile)
       lRet = true
    Else
       obj.FileName = sFile
       Local name =  obj.GetValue(0)
       Local size = obj.GetValue(2,0)	# size -> bytes       
       Local files = obj.GetValue(1)
       If files < 1 Then
          ShowHint("Файл не является торрент-файлом " & sFile)
          lRet = true        
       EndIf
    Endif
    Free(obj)
    If lRet Then Return
    IniRead gDriveInclude %COMMANDER_INI% "Autorun" "TorrentDrives" %"gDriveInclude"
    Local bCaps = BitAND(DllCall("GetKeyState", "int", 0x14, "short"), 1)
    If gCapsReverse Then bCaps = Not bCaps
    If Not bCaps Then
       MsgBox("Поиск данных торрента:" & auCRLF & auCRLF & _
              "Имя: "    & name & auCRLF & _
              "Размер: " & size & auCRLF & _
              "Файлов: " & files & auCRLF & auCRLF & _ 
              "Диски поиска: " & gDriveInclude & auCRLF & auCRLF & _       
              "Продолжить?", "Autorun", 3+32+0)
       If EXTENDED <> 6 Then Return
    Endif
    If bEverything Then 
       If gEvAuto And Not ProcessExist("Everything.exe") Then 
          ShellExec(gEvPath, "-startup")
          Sleep(gEvDelay)
       EndIf   
    EndIf      
    aFound.Count = 0    
    gTorrentSize = size
    h_WinFindTorr = 0
    gTorrentCount = 0
    RunThread "WinFindTorrentData"
    While g_FindTorrTask = 0
        Sleep(50)
    Wend
    Local found
    If bEverything Then      
       found = FileFindEv("size:" & gTorrentSize, "", "sort:3")
       Local nError = ERROR
       If nError = 1 Then MsgBox("Не найдено окно Everything.")
       If nError = 2 Then MsgBox("Ошибка выполнения запроса к IPC Everything.")  
       If nError > 0 Then 
          g_FindTorrTask = 0
          Return
        EndIf  
    Else   
       For i = 0 to aDrive.Count -1
           If StrPos(gDriveInclude, aDrive[i]) Then
            If files > 1 Then
               found &= FileFind(aDrive[i], "*.*", 1, 2, "PathList", "Func:FindTorrentDir") & auCRLF
            Else
               found &= FileFind(aDrive[i], "*.*", 1, 1, "PathList", "Func:FindTorrentFile") & auCRLF
            EndIf   
           Endif   
       Next
    EndIf   
    found = StrTrim(found)
    aFound.Text = found
    If bEverything Then gTorrentCount = aFound.Count
    If bEverything And gEvAuto Then ShellExec(gEvPath, "-exit")     
    If g_FindTorrTask = 0 Then
       If gTorrentCount = 0 Then
          MsgBox("Поиск отменен" & auCRLF & auCRLF & _
                 "Найдено: " & gTorrentCount & auCRLF & auCRLF & found, "Autorun", 48)
       
       Else
          MsgBox("Поиск отменен" & auCRLF & auCRLF & _
                 "Найдено: " & gTorrentCount & auCRLF & auCRLF & found & auCRLF & auCRLF & _       
                 "Сохранить в текстовый файл?", "Autorun", 3+48+0)
          If EXTENDED = 2 Then Return
          If EXTENDED = 7 Then GoToPathFromMsg(aFound[0])
          If EXTENDED = 6 Then SaveDataPathToText(sFile, found)
       EndIf
    Else 
       g_FindTorrTask = 0
       SendMessage(h_WinFindTorr, 0x0010, 0, 0)
       If DllCall("DestroyWindow", "handle", h_WinFindTorr) Then h_WinFindTorr = 0
       If gTorrentCount = 0 Then
          Local mode = files > 1 ? 0 : 1
          Local sMode = (mode = 0 ? "«Имя и размер»" : "«Только имя»")
          MsgBox("Найдено: " & gTorrentCount & auCRLF & auCRLF & _
                 "Файлов в торренте: " & files & " " & auCRLF & auCRLF & _         
                 "Продолжить в режиме " & sMode & "?", "Autorun", 3+64+0)
             If EXTENDED = 6 Then Return FindTorrentParts(mode)               
       Else
          bCaps = BitAND(DllCall("GetKeyState", "int", 0x14, "short"), 1)
          If gCapsReverse Then bCaps = Not bCaps
          If bCaps Then      
             SetHintParam("ShowHint", "Font", 15, "Arial")
             SetHintParam("ShowHint", "BackColor", 0xFF0000)
             SetHintParam("ShowHint", "Text", 0xFFFFFF)     
             ShowHint("Автопереход к найденному", 0, 0, 1000, 1)
             WinAlign(LAST_HINT_WINDOW)
             Sleep(100)         
             SetHintParam("ShowHint", "Reload")             
             GoToPathFromMsg(aFound[0])
             Return
          EndIf
          MsgBox("Найдено: " & gTorrentCount & auCRLF & auCRLF & found & auCRLF & auCRLF & _       
                 "Сохранить в текстовый файл?", "Autorun", 3+64+0)
          If EXTENDED = 2 Then Return
          If EXTENDED = 7 Then GoToPathFromMsg(aFound[0])
          If EXTENDED = 6 Then SaveDataPathToText(sFile, found)
       EndIf
    EndIf
EndFunc

Func SaveDataPathToText(Filename, DataPath)
     Local file = FileChangeExt(Filename, "txt"), bGoto = false
     If FileExist(file) Then
        MsgBox("Файл существует" & auCRLF & auCRLF & _
                file & auCRLF & auCRLF & "Перезаписать?", "Autorun", 3+32+0)
        If EXTENDED <> 6 Then Return
     EndIf
     FileWrite(file, DataPath)
     #MsgBox("Файл сохранен " & auCRLF & auCRLF & file, "Autorun", 64)
     SetHintParam("ShowHint", "Font", 15, "Arial")
     SetHintParam("ShowHint", "BackColor", 0xFF0000)
     SetHintParam("ShowHint", "Text", 0xFFFFFF)     
     ShowHint("Файл сохранен", 0, 0, 1000, 1)
     WinAlign(LAST_HINT_WINDOW)
     Sleep(100)         
     SetHintParam("ShowHint", "Reload")
     If bGoto Then
        If RequestInfo(1000) = 1 Then
           CommandExec /CD %'file'
        Else
           CommandExec /CD '' %'file'
        Endif
     Endif   
EndFunc

Func GoToPathFromTextFile()
    Local sPath = RequestCopyDataInfo("SP")    
    Local sName = RequestCopyDataInfo("SN")        
    Local sFile = sPath & sName
    If Not FileExist(sFile) Then 
       ShowHint("Файл не существует " & sFile)
       Return
    ElseIf StrPos(FileGetAttr(sFile), "D") Then
       ShowHint("Файл является каталогом " & sFile)
       Return
    ElseIf FileGetExt(sFile) <> "TXT" Then
       ShowHint("Расширение файла не .txt " & sFile)
       Return
    ElseIf FileGetSize(sFile) > 1024*2 Then
       ShowHint("Размер файла больше 2 Кб " & sFile)
       Return       
    EndIf
    Local txt = FileRead(sFile)
    Local target = StrPart(txt, auCRLF, 1)
    If target <> "" Then
       GoToPathFromMsg(target)
    Else   
       ShowHint("Пустой путь" & target)  
    EndIf    
EndFunc

Func GoToPathFromMsg(Target)
    If FileExist(Target) Then
       If RequestInfo(1000) = 2 Then
          CommandExec /CD %'Target'
       Else
          CommandExec /CD '' %'Target'
       Endif
       SendCommand(4006)
       If StrPos(FileGetAttr(Target), "D") Then SendCommand(2002)
       Local ForceRedraw = 0
       If ForceRedraw Then
          WinRedraw(1)
          SendCommand(540)     # cm_RereadSource
       EndIf
    Else
       ShowHint("Путь не существует " & Target)
    EndIf    
EndFunc

Func FindTorrentFile(file)
    Static T1 = GetUptime()
    If Not g_FindTorrTask Then Return 0
    If Round(GetUptime() - T1, 0) > 200 Then 
       WinSetText(" [" & gTorrentCount & "] " & file.FullPath, h_WinFindTorr)
       T1 = GetUptime()
       Sleep(5)
    EndIf         
    If file.size = gTorrentSize Then 
       gTorrentCount += 1
       Return 1
    EndIf
    Return 2
EndFunc

Func FindTorrentDir(file)
    Static T2 = GetUptime()
    If Not g_FindTorrTask Then Return 0
    If Round(GetUptime() - T2, 0) > 200 Then 
       WinSetText(" [" & gTorrentCount & "] " & file.FullPath, h_WinFindTorr)
       T2 = GetUptime()
       Sleep(5)
    EndIf   
    Local sz = FileFind(file.FullPath, "*.*", 1, 0, "TotalSize")  
    If sz = gTorrentSize Then 
       gTorrentCount += 1
       Return 1
    EndIf    
    Return 2
EndFunc

Global gVbsInputBox

Func SetTorrentDrives()
    Local out, drives, vbs
    
    IniRead drives %COMMANDER_INI% "Autorun" "TorrentDrives" %"gDriveInclude"    
    vbs = '/c ECHO Wscript.Echo Inputbox("Search on these disks:","Autorun","' & drives & '")>%TEMP%\~auto_0001.vbs'
    
    ProcessExecGetOutput out %COMSPEC% %vbs%
    
    gVbsInputBox = 1
    RunThread("WinVbsInputBoxActivate")
    ProcessExecGetOutput /OEM out "cscript.exe" "/nologo ~auto_0001.vbs" %TEMP%
    gVbsInputBox = 0
    
    out = StrTrim(out)
    If out = "" Then Return
    
    IniWrite %COMMANDER_INI% "Autorun" "TorrentDrives" %out%
    Sleep(50)
    MsgBox("Ключ сохранен.", "Autorun", 64)           
EndFunc

Func WinVbsInputBoxActivate()
    Local hVbs
    While gVbsInputBox
        hVbs = WinFind(0, "#32770", "Autorun")
        If hVbs > 0 Then
           WinSetState(23, hVbs)
           Break
        EndIf
        Sleep(50)
    Wend
EndFunc

Func TorrentSize(lParam)
    Local T1 = GetUptime()
    Local obj = Plugin("TCTorrent")
    If ERROR <> 0 Then
       ShowHint("TCTorrent.wdx plugin error " & ERROR)
       Return
    Endif
    Local size = 0, files = 0
    Local aSel = List()
          aSel.Text = GetSelectedItems(3, 0)       
    Local sPath = RequestCopyDataInfo("SP")    
    Local sName = RequestCopyDataInfo("SN")        
    Local sFile = sPath & sName
    Local lRet = false
    If aSel.Count = 0 Then
       If Not FileExist(sFile) Then 
          ShowHint("Файл не существует " & sFile)
          lRet = true
       ElseIf StrPos(FileGetAttr(sFile), "D") Then
          ShowHint("Каталог " & sFile)
          lRet = true       
       Else
          obj.FileName = sFile
          files = obj.GetValue(1)
          size = obj.GetValue(2,0)	# size -> bytes
          Free(obj)
       Endif
    EndIf
    If lRet Then
       Free(obj, aSel)
       Return
    EndIf
    If aSel.Count > 10 Then
       ShowHint("Выделено: " & aSel.Count & auCRLF & "Подсчёт времени...")
    EndIf    
    Local j, k = 0, dirs = 0, torrs = 0
    If aSel.Count > 0 Then
       For j = 0 To aSel.Count - 1
          sFile = sPath & aSel[j]
          If FileExist(sFile) Then 
             k += 1
             If Not StrPos(FileGetAttr(sFile), "D") Then
               obj.FileName = sFile
               s = obj.GetValue(2,0)
               If s > 0 Then 
                  size += s
                  files += obj.GetValue(1)
                  torrs += 1 
               Endif  
             Else   
               dirs += 1
             Endif   
          EndIf
       Next
       sName = "S/A: " & aSel.Count & "/" & k	# Selected / Available
    Else
       SetHintParam("ShowHint", "Font", 10, "")
       ShowHint("" & sName & auCRLF & _
                "Размер: " & SizeFormat(size, 1, 'G', 2, 1) & auCRLF & _
                "Файлов: " & files)
       Sleep(100)
       SetHintParam("ShowHint", "Reload")
       Free(aSel)
       Return
    EndIf
    Local tl = Round(GetUptime() - T1, 0) / 1000
    SetHintParam("ShowHint", "Font", 10, "")
    ShowHint((k = aSel.Count ? "" : "Файл " & sName & auCRLF) & _
             "Элементов: " & aSel.Count & auCRLF & _
             "Обработано: " & torrs & auCRLF & _
             "Каталогов: " & dirs & auCRLF & _              
             "Размер: " & SizeFormat(size, 0, 'M', 2) & auCRLF & _
             "Размер: " & SizeFormat(size, 0, 'G', 2) & auCRLF & _
             "Размер: " & SizeFormat(size, 0, 'T', 4) & auCRLF & _
             "Файлов: " & files & auCRLF & _                       
             "Powered by TCTorrent.wdx" & auCRLF & _
             "Время операции: " &  StrFormat("%.3f", tl) & " sec")
    Sleep(100)
    SetHintParam("ShowHint", "Reload")          
    Free(obj, aSel)
EndFunc

Func ToggleEverything()    
    If Not ProcessExist("Everything.exe") Then
       CommandExec em_everything
    Else
       CommandExec em_everything_exit
    Endif    
EndFunc 

Func TerminateEverything()
    CommandExec em_everything_exit
EndFunc

Func TorrentBugTest(lParam)
    RunThread("TorrentThreadTest")
EndFunc

Func TorrentThreadTest()
    Local out, tor, vbs
    tor = "d:\Temp\Jinn'sLiveUSB 11.2.2.torrent"
    vbs = '/c ECHO Wscript.Echo Inputbox("Torrent file for testing:","Autorun","' & tor & '")>%TEMP%\~auto_0002.vbs'    
    ProcessExecGetOutput out %COMSPEC% %vbs%
    
    gVbsInputBox = 1
    RunThread("WinVbsInputBoxActivate")
    ProcessExecGetOutput /OEM out "cscript.exe" "/nologo ~auto_0002.vbs" %TEMP%
    gVbsInputBox = 0
    
    out = StrTrim(out)
    If out = "" Then Return
    If Not FileExist(out) Then 
       MsgBox("File doesn't exist " & out)
       Return
    EndIf
    
    Local hIco = 0   
    Local hWnd = DllCall("CreateWindowExW", _
                         "dword", 0, _
                         "wstr", "msctls_progress32", _
                         "wstr", "", _
                         "dword", 0x00C80000, _
                         "int", 200, "int", 100, "int", Scale(400), "int", Scale(50), _
                         "handle", AUTORUN_TCHANDLE, _
                         "handle", 0, "handle", 0, "ptr", 0, "handle")
    If hWnd = 0 Then Return 0
    
    WinAlign(hWnd, 0, DllCall("GetDesktopWindow"))
    WinSetPos("", -Scale(50), "", "", 1, hWnd)
    WinSetState(5, hWnd)
                                
    Static PBS_MARQUEE     =  0x08, _
           PBM_SETMARQUEE  =  1034, _
           WM_GETICON      =  0x7f, _
           WM_SETICON      =  0x80
           
    hIco = SendMessage(AUTORUN_TCHANDLE, WM_GETICON, 2, 0)                     
    SendMessage(hWnd, WM_SETICON, 0, hIco)
    
    WinSetStyle(PBS_MARQUEE, 2, hWnd)    
    SendMessage(hWnd, PBM_SETMARQUEE, 1, 0)
    For i = 1 To 500
        TorrentInfo(hWnd, i, out)
        If WinGetState(1, hWnd) = 0 Then
           MsgBox("Тестирование прервано", "Autorun", 48)
           Return
        EndIf
    Next    
    MsgBox("Тестирование успешно завершено", "Autorun", 64)
    DllCall("DestroyWindow", "handle", hWnd)
EndFunc

# original function by Loopback
Func TorrentInfo(hWnd, nPass, sFile)
    Static aFixed = List('Name', 'TotalSize', 'FileCount', 'BlockSize', 'BlockCount', _
                         'Created', 'Creator', 'Hash', 'Comment', 'Encoding', _
                         'Multifile', 'PrivateTorrent', 'Publisher', 'PublisherURL')
    Static aMulti = List('Tracker', 'Webseed', 'Error', 'CustomField')

    Static sLibName = "TCTorrent.wlx" & (auX64 ? "64" : "")
    Static sLibPath = COMMANDER_PATH & "\Plugins\wlx\TCTorrent\" & sLibName

    Local hDll = DllCall("LoadLibrary", "wstr", sLibPath, "handle")
    If hDll = 0 Then Return MsgBox("Can't load " & sLibPath)

    Local hHandle = DllCall(sLibName & "\TorrentOpen", "wstr", sFile, "handle")
    If hHandle = 0 Then
        DllCall("FreeLibrary", "handle", hDll)
        Return MsgBox("Can't open " & sFile)
    EndIf

    Local nCount, sRes

    For i = 0 to aFixed.Count - 1
        sRes = DllCall(sLibName & "\TorrentGet", "handle", hHandle, "wstr", aFixed[i], "int", 0, "wstr")
        OutputDebugString(aFixed[i] & ": " & sRes)
        WinSetText(nPass & ": " & sRes, hWnd)
    Next

    OutputDebugString(auCRLF & 'Files:')
    nCount = DllCall(sLibName & "\TorrentCountGet", "handle", hHandle, "wstr", "File", "uint")
    For j = 0 To nCount - 1
        sRes = StrFormat("[%12s] %s", _
                 DllCall(sLibName & "\TorrentGet", "handle", hHandle, "wstr", "FileSize", "int", j, "wstr"), _
                 DllCall(sLibName & "\TorrentGet", "handle", hHandle, "wstr", "File", "int", j, "wstr"))
        OutputDebugString(sRes)
        WinSetText(nPass & ": " & sRes, hWnd)
    Next

    For i = 0 to aMulti.Count - 1
        OutputDebugString(auCRLF & aMulti[i] & 's:')
        nCount = DllCall(sLibName & "\TorrentCountGet", "handle", hHandle, "wstr", aMulti[i], "uint")
        For j = 0 To nCount - 1
            sRes = DllCall(sLibName & "\TorrentGet", "handle", hHandle, "wstr", aMulti[i], "int", j, "wstr")
            OutputDebugString(sRes)
            WinSetText(nPass & ": " & sRes, hWnd)
        Next
    Next

    DllCall(sLibName & "\TorrentClose", "handle", hHandle)
    DllCall("FreeLibrary", "handle", hDll)
EndFunc 

#Func FindTorrentParts(lParam)
#    RunThread "ThreadTorrentParts" lParam
#EndFunc

Func FindTorrentParts(lParam)
    # модификаторы вызова
    Local b_CTRL = IsPressed (0x11), b_Shift = IsPressed (0x10)
    If lParam = 1 Then b_CTRL = true
    If lParam = 2 Then b_Shift = true    
    
    # повторный вызов при запущенной задаче
    If h_WinFindTorr Then
       SendMessage(h_WinFindTorr, 0x0010, 0, 0)
       g_FindTorrTask = 0  
       Return
    Endif
    
    If gEvAuto And Not ProcessExist("Everything.exe") Then 
       ShellExec(gEvPath, "-startup")
       Sleep(gEvDelay)       
    Endif
    
    # имя файла под курсором
    Local sPath = RequestCopyDataInfo("SP")    
    Local sName = RequestCopyDataInfo("SN")        
    Local sFile = sPath & sName
    
    # файл не существует или является каталогом
    If Not FileExist(sFile) Then 
       ShowHint("File doesn't exist " & sFile)
       Return
    ElseIf StrPos(FileGetAttr(sFile), "D") Then
       ShowHint("Not a torrent file " & sFile)
       Return
    ElseIf FileGetSize(sFile) > 1024*1024*5 Then
       ShowHint("File size > 5 Mb " & sFile)
       Return
    EndIf    
    
    # путь к библиотеке плагина
    Static sLibName = "TCTorrent.wlx" & (auX64 ? "64" : "")
    Static sLibPath = COMMANDER_PATH & "\Plugins\wlx\TCTorrent\" & sLibName

    # не удалось загрузить библиотеку
    Local hDll = DllCall("LoadLibrary", "wstr", sLibPath, "handle")
    If hDll = 0 Then 
       ShowHint("TCTorrent.wlx can't load library " & sLibPath)
       Return
    EndIf    

    # библиотеке не удалось открыть файл
    Local hHandle = DllCall(sLibName & "\TorrentOpen", "wstr", sFile, "handle")
    If hHandle = 0 Then
        ShowHint("TCTorrent.wlx can't open file " & sFile)    
        DllCall("FreeLibrary", "handle", hDll)
        Return
    EndIf
    
    # файл не является торрент-файлом
    Local nFiles
    nFiles = DllCall(sLibName & "\TorrentGet", "handle", hHandle, "wstr", "FileCount", "int", 0, "wstr")
    If nFiles < 1 Then
       ShowHint("Corrupt torrent file " & sFile)
       DllCall(sLibName & "\TorrentClose", "handle", hHandle)       
       DllCall("FreeLibrary", "handle", hDll)       
       Return             
    EndIf

    # окно прогресса операции
    h_WinFindTorr = 0
    If g_WinThread Then 
       RunThread "WinFindTorrentData"
       While g_FindTorrTask = 0
           Sleep(50)
       Wend
    Else
        WinFindTorrentData(0)
    EndIf
    # локальные переменные
    Local T1 = GetUptime(), T2 = T1, T3, bSpeed = 0, nRes = 0
    Local bName = Not b_Shift, bSize = Not b_CTRL, sSize, sMode, sMem, sDbg
    Local j, nCount, sRes, nError, sList, sDirs, aQuery = List(), aCount = List()
    
    Static aMode = List("«Имя и размер»", "«Только имя»", "«Только размер»")    
    If bName And bSize Then
       nMode = 0
    ElseIf bName Then
       nMode = 1    
    Else
       nMode = 2
    EndIf
    sMode = aMode[nMode]
    
    # количество файлов в торренте
    nCount = DllCall(sLibName & "\TorrentCountGet", "handle", hHandle, "wstr", "File", "uint")

    # перечисление файлов в торренте
    For j = 0 To nCount - 1
        
        If gTorrentDbg Then gDbgStep = "Step 1. TorrentGet j=" & j & auCRLF
        
        # имя файла
        sRes = DllCall(sLibName & "\TorrentGet", "handle", hHandle, "wstr", "File", "int", j, "wstr")
        
        # размер файла
        If bSize Then
           sSize = DllCall(sLibName & "\TorrentGet", "handle", hHandle, "wstr", "FileSize", "int", j, "wstr")
        EndIf
        
        sDbg = Round((j+1)/nCount*100,0) & '% - '
        If gTorrentDbg Then
           nRes += StrLen(sRes) + 8
           sMem = StrLen(sList) + StrLen(sDirs) + nRes
           sDbg &= SizeFormat(sMem*2, 1, 'G', 2) &  ' - '        
        EndIf

        If gTorrentDbg Then gDbgStep &= "Step 2. WinSetText " & sRes & auCRLF
        
        # меньше сообщений окну прогресса
        If bSpeed Then
           T3 = GetUptime()
           If Round(T3 - T2, 0) > 250 Then 
              WinSetText(sDbg & sRes, h_WinFindTorr)
              T2 = T3
           EndIf
        Else
           WinSetText(sDbg & sRes, h_WinFindTorr)
        EndIf

        If gTorrentDbg Then gDbgStep &= "Step 3. FileFindEv " & sRes & auCRLF
        
        # запрос к Everything
        If bName And bSize Then
           aQuery.Text = FileFindEv('*\"' & sRes & '" size:' & sSize, "", "")
        ElseIf bName Then
           aQuery.Text = FileFindEv('*\"' & sRes & '"', "", "")        
        Else
           aQuery.Text = FileFindEv('size:' & sSize, "", "")
        EndIf
                
        # ошибка запроса
        nError = ERROR
        If nError > 0 Then Break

        If gTorrentDbg Then gDbgStep &= "Step 4. aCount.Add" & auCRLF
        
        # обработка запроса
        aCount.Add("[" & aQuery.Count & "] " & sRes)        
        If aQuery.Count > 0 Then 
           If gTorrentDbg Then gDbgStep &= "Step 5. sList" & auCRLF
           sList &= aQuery.Text & auCRLF
           If gTorrentDbg Then gDbgStep &= "Step 6. sDirs" & auCRLF
           If nFiles > 1 Then 
              If gTorrentDbg Then gDbgStep &= "Step 7. StrReplace" & auCRLF
              sDirs &= StrReplace(aQuery.Text, sRes, "") & auCRLF
           Else
              sDirs &= aQuery.Text & auCRLF
           EndIf
        Else
           If gTorrentDbg Then 
              gDbgStep &= "Step 5. Skip" & auCRLF
              gDbgStep &= "Step 6. Skip" & auCRLF
              gDbgStep &= "Step 7. Skip" & auCRLF              
           EndIf             
        EndIf  

        If gTorrentDbg Then gDbgStep &= "Step 8. Next"
        #Sleep(3000)
        
        # опрерация прервана закрытием окна прогресса
        If g_FindTorrTask = 0 Then Break
    Next
    
    If gTorrentDbg Then gDbgStep &= "Step 9. Out"
       
    If nError = 1 Then MsgBox("Everything window not found.")
    If nError = 2 Then MsgBox("IPC Everything query execution error.")  
    If nError > 0 Then 
       g_FindTorrTask = 0
       SendMessage(h_WinFindTorr, 0x0010, 0, 0)       
       Free(aCount, aQuery)
       DllCall(sLibName & "\TorrentClose", "handle", hHandle)
       DllCall("FreeLibrary", "handle", hDll)           
       Return
    EndIf

    Local c = 0, m = Map(), top5 = List(), sTop5, bDirs = StrLen(StrTrim(sDirs))
    
    # суммирование путей при непустом результате
    If g_FindTorrTask And bDirs Then 
       aQuery.Text = sDirs
       For value In aQuery
           c = 1
           If m.Has(value) Then c += m.Get(value)
           m.Set(value, c)
       Next
    EndIf
    
    # сортировка путей по убыванию
    If g_FindTorrTask And bDirs Then
       top5.SortMethod = 1 
       For key, value In m          
           top5.Add("[" & value & "]" & Chr(160) & key)
       Next
       top5.Sort(1)
       
       # выбор верхних пяти путей
       For j = 0 To top5.Count - 1
          sTop5 &= top5[j] & auCRLF
          If j >= 4 Then Break
       Next   
    EndIf
    
    c = top5.Count
    Local top1, files = aCount.Text
    If c > 0 Then top1 = StrTrim(StrPart(top5[0], Chr(160), 2))

    # освобождение объектов и библиотеки    
    Free(aCount, aQuery, top5, m)    
    DllCall(sLibName & "\TorrentClose", "handle", hHandle)
    DllCall("FreeLibrary", "handle", hDll)
    
    # время операции    
    T2 = Round(GetUptime() - T1, 0) / 1000
    T3 = "Время поиска: " &  StrFormat("%.3f", T2) & " sec"
    
    If gEvAuto Then ShellExec(gEvPath, "-exit")    
    
    If g_FindTorrTask = 0 Then
       MsgBox("Поиск отменен", "Autorun", 48)
    Else        
       # закрытие окна прогресса
       g_FindTorrTask = 0
       SendMessage(h_WinFindTorr, 0x0010, 0, 0)
       If DllCall("DestroyWindow", "handle", h_WinFindTorr) Then h_WinFindTorr = 0
       
       # ничего не найдено
       If c = 0 Then
          If nMode < 2 Then
             MsgBox("Найдено: " & c & auCRLF & auCRLF & _
                    "Торрент: " & nCount & " файлов" & auCRLF & T3 & auCRLF & _
                    "Режим: " & sMode & auCRLF & auCRLF & _                
                    "Продолжить в режиме " & aMode[nMode+1] & "?", "Autorun", 3+64+0)
             If EXTENDED = 6 Then Return FindTorrentParts(nMode+1)                
          Else
             MsgBox("Найдено: " & c & auCRLF & auCRLF & _
                    "Торрент: " & nCount & " файлов" & auCRLF & T3 & auCRLF & _
                    "Режим: " & sMode, "Autorun", 64)
          EndIf           
       Else          
          # проверка CapsLock
          Local bCaps = BitAND(DllCall("GetKeyState", "int", 0x14, "short"), 1)
          If gCapsReverse Then bCaps = Not bCaps
          If bCaps Then
             ShowRedHint("Автопереход к найденному")
             GoToPathFromMsg(top1)
             Return
          EndIf          
          MsgBox("Найдено: " & c & auCRLF & auCRLF & sTop5 & auCRLF & _
                 "Торрент: " & nCount & " файлов" & auCRLF & T3 & auCRLF & _
                 "Режим: " & sMode & auCRLF & auCRLF & _                
                 "Сохранить в текстовый файл?", "Autorun", 3+64+0)
          If EXTENDED = 2 Then Return
          If EXTENDED = 7 Then GoToPathFromMsg(top1)
          If EXTENDED = 6 Then
             Local txt
             txt &= top1 & auCRLF & auCRLF
             txt &= "-----------------" & auCRLF             
             txt &= "Top 5 locations:" & auCRLF 
             txt &= "-----------------" & auCRLF             
             txt &= sTop5 & auCRLF
             txt &= "-----------------" & auCRLF             
             txt &= "Torrent files:" & auCRLF     
             txt &= "-----------------" & auCRLF             
             txt &= files & auCRLF & auCRLF
             txt &= "-----------------" & auCRLF                          
             txt &= "Full list:" & auCRLF
             txt &= "-----------------" & auCRLF                
             txt &= sList             
             SaveDataPathToText(sFile, txt)
          EndIf   
       EndIf
    EndIf
EndFunc

Func TorrentFindOptions()
     gTorrentDbg = Not gTorrentDbg
     ShowRedHint("Торрент Debug " & (gTorrentDbg ? "включен" : "выключен"))
EndFunc

Func TorrentDebugInfo()
    If Not gTorrentDbg Then gDbgStep = "Торрент Debug выключен"
    If gDbgStep = "" Then gDbgStep = "Empty"
    SetHintParam("ShowHint", "Font", 13, "Arial")
    SetHintParam("ShowHint", "BackColor", 0x000000)
    SetHintParam("ShowHint", "Text", 0xFFFFFF)
    ShowHint(gDbgStep)
    WinAlign(LAST_HINT_WINDOW)    
    ClipPut(gDbgStep)  
    SetHintParam("ShowHint", "Reload") 
EndFunc
[/cut]

Добавлено: Пт ноя 07, 2025 14:06
A55555
Orion9 писал(а): Но плюс довольно большой: операция выполняется более стабильно, а значит выбор очевиден. Обновленный модуль:
[cut="Torrent.aucfg"]

Код: Выделить всё

Pragma IncludeOnce

# 70500-70599

RegisterCommand 70500 "TorrentFindData" 0
RegisterCommand 70501 "TorrentFindData" 1
RegisterCommand 70502 "GoToPathFromTextFile"
RegisterCommand 70503 "ToggleEverything"
RegisterCommand 70504 "FindTorrentParts"
RegisterCommand 70505 "TorrentSize"
RegisterCommand 70506 "TorrentFindOptions"
RegisterCommand 70507 "TorrentDebugInfo"

RegisterCommand 70508 "TorrentBugTest"

SetHotkeyAction /K:A /H:0 /DM /S TorrentDebugInfo
SetHotkeyAction /K:A /K:W /H:0 /DM /S TorrentFindOptions

Global gEvPath = COMMANDER_PATH & "\Everything.exe", gEvAuto = 0, gEvDelay = 100

Global gTorrentDbg = 0, gDbgStep, gCapsReverse = 0
Global gTorrentSize = 0, gTorrentCount = 0, gDriveInclude = "e:\;f:\;g:\;h:\;i:\;j:"

Global h_WinFindTorr = 0, g_WinThread = 0
Global g_WinFindTorr = 0, g_FindTorrTask = 0
Global o_WinFindTorr = Callback("WinFindTorrProc", "hwnd;uint;wparam;lparam")

Func WinFindTorrProc(hWnd, uMsg, wParam, lParam)
    Static WM_CLOSE = 0x0010
    If uMsg = WM_CLOSE Then
       If DllCall("DestroyWindow", "handle", hWnd) Then
          h_WinFindTorr = 0        
          g_FindTorrTask = 0
       EndIf   
       Return 0
    EndIf
    Return DllCall("CallWindowProcW", "ptr", g_WinFindTorr, _
                                      "hwnd", hWnd, "uint", uMsg, "wparam", wParam, "lparam", lParam)
EndFunc

Func WinFindTorrentData(bWhile = 1)
    Local hIco    
    h_WinFindTorr = DllCall("CreateWindowExW", _
                            "dword", 0, _
                            "wstr", "msctls_progress32", _
                            "wstr", "", _
                            "dword", 0x00C80000, _
                            "int", 200, "int", 100, "int", Scale(400), "int", Scale(50), _
                            "handle", AUTORUN_TCHANDLE, _
                            "handle", 0, "handle", 0, "ptr", 0, "handle")
    If h_WinFindTorr = 0 Then Return 0
    
    WinAlign(h_WinFindTorr, 0, DllCall("GetDesktopWindow"))
    WinSetPos("", -Scale(50), "", "", 1, h_WinFindTorr)
    WinSetState(5, h_WinFindTorr)
    
    g_WinFindTorr = DllCall("SetWindowLong" & (auX64 ? "PtrW" : "W"), _
                            "hwnd", h_WinFindTorr, _
                            "int", -4, _
                            "long_ptr", o_WinFindTorr.Ptr, "ptr")
                            
    Static PBS_MARQUEE     =  0x08, _
           PBM_SETMARQUEE  =  1034, _
           WM_GETICON      =  0x7f, _
           WM_SETICON      =  0x80
           
    hIco = SendMessage(AUTORUN_TCHANDLE, WM_GETICON, 2, 0)                     
    SendMessage(h_WinFindTorr, WM_SETICON, 0, hIco)
    
    WinSetStyle(PBS_MARQUEE, 2, h_WinFindTorr)    
    SendMessage(h_WinFindTorr, PBM_SETMARQUEE, 1, 0)
    
    WinSetText("Searching...", h_WinFindTorr)
    
    g_FindTorrTask = 1
    If bWhile Then
       While g_FindTorrTask
           Sleep(50)
       Wend
       h_WinFindTorr = 0
    EndIf   
EndFunc

Func TorrentFindData(lParam, nMode)
    If IsPressed(0x10) And Not nMode Then
       SetTorrentDrives()
       Return
    EndIf
    Local bEverything = nMode
    If h_WinFindTorr Then
       SendMessage(h_WinFindTorr, 0x0010, 0, 0)
       g_FindTorrTask = 0  
       Return
    Endif
    Static buf = Buffer(256)
    buf.Zero()
    Local nSymb = DllCall("GetLogicalDriveStringsW", "dword", buf.size, "ptr", buf.ptr)    
    If Not nSymb Then
       MsgBox("Не удалось получить список логических дисков" & auCRLF "SYSERROR: " & SYSERROR, "Autorun")
       Return
    EndIf
    Static aDrive = List(), aFound = List()
    Local i = 0, sz, sDrives
    aDrive.Count = 0
    While 1
       sDrive = buf.GetStr(i)
       sz = StrLen(sDrive)
       If sz = 0 Then break
       aDrive.add(sDrive)
       i = i + sz*2 + 2
    Wend
    sDrives = aDrive.text
    #MsgBox(sDrives)    
    Local obj = Plugin("TCTorrent")
    If ERROR <> 0 Then
       ShowHint("TCTorrent.wdx plugin error " & ERROR)
       Return
    Endif
    Local lRet = false 
    Local sPath = RequestCopyDataInfo("SP")    
    Local sName = RequestCopyDataInfo("SN")        
    Local sFile = sPath & sName
    If Not FileExist(sFile) Then 
       ShowHint("Файл не существует " & sFile)
       lRet = true
    ElseIf StrPos(FileGetAttr(sFile), "D") Then
       ShowHint("Каталог " & sFile)
       lRet = true
    ElseIf FileGetSize(sFile) > 1024*1024*5 Then
       ShowHint("Размер файла больше 5 Мб " & sFile)
       lRet = true
    Else
       obj.FileName = sFile
       Local name =  obj.GetValue(0)
       Local size = obj.GetValue(2,0)	# size -> bytes       
       Local files = obj.GetValue(1)
       If files < 1 Then
          ShowHint("Файл не является торрент-файлом " & sFile)
          lRet = true        
       EndIf
    Endif
    Free(obj)
    If lRet Then Return
    IniRead gDriveInclude %COMMANDER_INI% "Autorun" "TorrentDrives" %"gDriveInclude"
    Local bCaps = BitAND(DllCall("GetKeyState", "int", 0x14, "short"), 1)
    If gCapsReverse Then bCaps = Not bCaps
    If Not bCaps Then
       MsgBox("Поиск данных торрента:" & auCRLF & auCRLF & _
              "Имя: "    & name & auCRLF & _
              "Размер: " & size & auCRLF & _
              "Файлов: " & files & auCRLF & auCRLF & _ 
              "Диски поиска: " & gDriveInclude & auCRLF & auCRLF & _       
              "Продолжить?", "Autorun", 3+32+0)
       If EXTENDED <> 6 Then Return
    Endif
    If bEverything Then 
       If gEvAuto And Not ProcessExist("Everything.exe") Then 
          ShellExec(gEvPath, "-startup")
          Sleep(gEvDelay)
       EndIf   
    EndIf      
    aFound.Count = 0    
    gTorrentSize = size
    h_WinFindTorr = 0
    gTorrentCount = 0
    RunThread "WinFindTorrentData"
    While g_FindTorrTask = 0
        Sleep(50)
    Wend
    Local found
    If bEverything Then      
       found = FileFindEv("size:" & gTorrentSize, "", "sort:3")
       Local nError = ERROR
       If nError = 1 Then MsgBox("Не найдено окно Everything.")
       If nError = 2 Then MsgBox("Ошибка выполнения запроса к IPC Everything.")  
       If nError > 0 Then 
          g_FindTorrTask = 0
          Return
        EndIf  
    Else   
       For i = 0 to aDrive.Count -1
           If StrPos(gDriveInclude, aDrive[i]) Then
            If files > 1 Then
               found &= FileFind(aDrive[i], "*.*", 1, 2, "PathList", "Func:FindTorrentDir") & auCRLF
            Else
               found &= FileFind(aDrive[i], "*.*", 1, 1, "PathList", "Func:FindTorrentFile") & auCRLF
            EndIf   
           Endif   
       Next
    EndIf   
    found = StrTrim(found)
    aFound.Text = found
    If bEverything Then gTorrentCount = aFound.Count
    If bEverything And gEvAuto Then ShellExec(gEvPath, "-exit")     
    If g_FindTorrTask = 0 Then
       If gTorrentCount = 0 Then
          MsgBox("Поиск отменен" & auCRLF & auCRLF & _
                 "Найдено: " & gTorrentCount & auCRLF & auCRLF & found, "Autorun", 48)
       
       Else
          MsgBox("Поиск отменен" & auCRLF & auCRLF & _
                 "Найдено: " & gTorrentCount & auCRLF & auCRLF & found & auCRLF & auCRLF & _       
                 "Сохранить в текстовый файл?", "Autorun", 3+48+0)
          If EXTENDED = 2 Then Return
          If EXTENDED = 7 Then GoToPathFromMsg(aFound[0])
          If EXTENDED = 6 Then SaveDataPathToText(sFile, found)
       EndIf
    Else 
       g_FindTorrTask = 0
       SendMessage(h_WinFindTorr, 0x0010, 0, 0)
       If DllCall("DestroyWindow", "handle", h_WinFindTorr) Then h_WinFindTorr = 0
       If gTorrentCount = 0 Then
          Local mode = files > 1 ? 0 : 1
          Local sMode = (mode = 0 ? "«Имя и размер»" : "«Только имя»")
          MsgBox("Найдено: " & gTorrentCount & auCRLF & auCRLF & _
                 "Файлов в торренте: " & files & " " & auCRLF & auCRLF & _         
                 "Продолжить в режиме " & sMode & "?", "Autorun", 3+64+0)
             If EXTENDED = 6 Then Return FindTorrentParts(mode)               
       Else
          bCaps = BitAND(DllCall("GetKeyState", "int", 0x14, "short"), 1)
          If gCapsReverse Then bCaps = Not bCaps
          If bCaps Then      
             SetHintParam("ShowHint", "Font", 15, "Arial")
             SetHintParam("ShowHint", "BackColor", 0xFF0000)
             SetHintParam("ShowHint", "Text", 0xFFFFFF)     
             ShowHint("Автопереход к найденному", 0, 0, 1000, 1)
             WinAlign(LAST_HINT_WINDOW)
             Sleep(100)         
             SetHintParam("ShowHint", "Reload")             
             GoToPathFromMsg(aFound[0])
             Return
          EndIf
          MsgBox("Найдено: " & gTorrentCount & auCRLF & auCRLF & found & auCRLF & auCRLF & _       
                 "Сохранить в текстовый файл?", "Autorun", 3+64+0)
          If EXTENDED = 2 Then Return
          If EXTENDED = 7 Then GoToPathFromMsg(aFound[0])
          If EXTENDED = 6 Then SaveDataPathToText(sFile, found)
       EndIf
    EndIf
EndFunc

Func SaveDataPathToText(Filename, DataPath)
     Local file = FileChangeExt(Filename, "txt"), bGoto = false
     If FileExist(file) Then
        MsgBox("Файл существует" & auCRLF & auCRLF & _
                file & auCRLF & auCRLF & "Перезаписать?", "Autorun", 3+32+0)
        If EXTENDED <> 6 Then Return
     EndIf
     FileWrite(file, DataPath)
     #MsgBox("Файл сохранен " & auCRLF & auCRLF & file, "Autorun", 64)
     SetHintParam("ShowHint", "Font", 15, "Arial")
     SetHintParam("ShowHint", "BackColor", 0xFF0000)
     SetHintParam("ShowHint", "Text", 0xFFFFFF)     
     ShowHint("Файл сохранен", 0, 0, 1000, 1)
     WinAlign(LAST_HINT_WINDOW)
     Sleep(100)         
     SetHintParam("ShowHint", "Reload")
     If bGoto Then
        If RequestInfo(1000) = 1 Then
           CommandExec /CD %'file'
        Else
           CommandExec /CD '' %'file'
        Endif
     Endif   
EndFunc

Func GoToPathFromTextFile()
    Local sPath = RequestCopyDataInfo("SP")    
    Local sName = RequestCopyDataInfo("SN")        
    Local sFile = sPath & sName
    If Not FileExist(sFile) Then 
       ShowHint("Файл не существует " & sFile)
       Return
    ElseIf StrPos(FileGetAttr(sFile), "D") Then
       ShowHint("Файл является каталогом " & sFile)
       Return
    ElseIf FileGetExt(sFile) <> "TXT" Then
       ShowHint("Расширение файла не .txt " & sFile)
       Return
    ElseIf FileGetSize(sFile) > 1024*2 Then
       ShowHint("Размер файла больше 2 Кб " & sFile)
       Return       
    EndIf
    Local txt = FileRead(sFile)
    Local target = StrPart(txt, auCRLF, 1)
    If target <> "" Then
       GoToPathFromMsg(target)
    Else   
       ShowHint("Пустой путь" & target)  
    EndIf    
EndFunc

Func GoToPathFromMsg(Target)
    If FileExist(Target) Then
       If RequestInfo(1000) = 2 Then
          CommandExec /CD %'Target'
       Else
          CommandExec /CD '' %'Target'
       Endif
       SendCommand(4006)
       If StrPos(FileGetAttr(Target), "D") Then SendCommand(2002)
       Local ForceRedraw = 0
       If ForceRedraw Then
          WinRedraw(1)
          SendCommand(540)     # cm_RereadSource
       EndIf
    Else
       ShowHint("Путь не существует " & Target)
    EndIf    
EndFunc

Func FindTorrentFile(file)
    Static T1 = GetUptime()
    If Not g_FindTorrTask Then Return 0
    If Round(GetUptime() - T1, 0) > 200 Then 
       WinSetText(" [" & gTorrentCount & "] " & file.FullPath, h_WinFindTorr)
       T1 = GetUptime()
       Sleep(5)
    EndIf         
    If file.size = gTorrentSize Then 
       gTorrentCount += 1
       Return 1
    EndIf
    Return 2
EndFunc

Func FindTorrentDir(file)
    Static T2 = GetUptime()
    If Not g_FindTorrTask Then Return 0
    If Round(GetUptime() - T2, 0) > 200 Then 
       WinSetText(" [" & gTorrentCount & "] " & file.FullPath, h_WinFindTorr)
       T2 = GetUptime()
       Sleep(5)
    EndIf   
    Local sz = FileFind(file.FullPath, "*.*", 1, 0, "TotalSize")  
    If sz = gTorrentSize Then 
       gTorrentCount += 1
       Return 1
    EndIf    
    Return 2
EndFunc

Global gVbsInputBox

Func SetTorrentDrives()
    Local out, drives, vbs
    
    IniRead drives %COMMANDER_INI% "Autorun" "TorrentDrives" %"gDriveInclude"    
    vbs = '/c ECHO Wscript.Echo Inputbox("Search on these disks:","Autorun","' & drives & '")>%TEMP%\~auto_0001.vbs'
    
    ProcessExecGetOutput out %COMSPEC% %vbs%
    
    gVbsInputBox = 1
    RunThread("WinVbsInputBoxActivate")
    ProcessExecGetOutput /OEM out "cscript.exe" "/nologo ~auto_0001.vbs" %TEMP%
    gVbsInputBox = 0
    
    out = StrTrim(out)
    If out = "" Then Return
    
    IniWrite %COMMANDER_INI% "Autorun" "TorrentDrives" %out%
    Sleep(50)
    MsgBox("Ключ сохранен.", "Autorun", 64)           
EndFunc

Func WinVbsInputBoxActivate()
    Local hVbs
    While gVbsInputBox
        hVbs = WinFind(0, "#32770", "Autorun")
        If hVbs > 0 Then
           WinSetState(23, hVbs)
           Break
        EndIf
        Sleep(50)
    Wend
EndFunc

Func TorrentSize(lParam)
    Local T1 = GetUptime()
    Local obj = Plugin("TCTorrent")
    If ERROR <> 0 Then
       ShowHint("TCTorrent.wdx plugin error " & ERROR)
       Return
    Endif
    Local size = 0, files = 0
    Local aSel = List()
          aSel.Text = GetSelectedItems(3, 0)       
    Local sPath = RequestCopyDataInfo("SP")    
    Local sName = RequestCopyDataInfo("SN")        
    Local sFile = sPath & sName
    Local lRet = false
    If aSel.Count = 0 Then
       If Not FileExist(sFile) Then 
          ShowHint("Файл не существует " & sFile)
          lRet = true
       ElseIf StrPos(FileGetAttr(sFile), "D") Then
          ShowHint("Каталог " & sFile)
          lRet = true       
       Else
          obj.FileName = sFile
          files = obj.GetValue(1)
          size = obj.GetValue(2,0)	# size -> bytes
          Free(obj)
       Endif
    EndIf
    If lRet Then
       Free(obj, aSel)
       Return
    EndIf
    If aSel.Count > 10 Then
       ShowHint("Выделено: " & aSel.Count & auCRLF & "Подсчёт времени...")
    EndIf    
    Local j, k = 0, dirs = 0, torrs = 0
    If aSel.Count > 0 Then
       For j = 0 To aSel.Count - 1
          sFile = sPath & aSel[j]
          If FileExist(sFile) Then 
             k += 1
             If Not StrPos(FileGetAttr(sFile), "D") Then
               obj.FileName = sFile
               s = obj.GetValue(2,0)
               If s > 0 Then 
                  size += s
                  files += obj.GetValue(1)
                  torrs += 1 
               Endif  
             Else   
               dirs += 1
             Endif   
          EndIf
       Next
       sName = "S/A: " & aSel.Count & "/" & k	# Selected / Available
    Else
       SetHintParam("ShowHint", "Font", 10, "")
       ShowHint("" & sName & auCRLF & _
                "Размер: " & SizeFormat(size, 1, 'G', 2, 1) & auCRLF & _
                "Файлов: " & files)
       Sleep(100)
       SetHintParam("ShowHint", "Reload")
       Free(aSel)
       Return
    EndIf
    Local tl = Round(GetUptime() - T1, 0) / 1000
    SetHintParam("ShowHint", "Font", 10, "")
    ShowHint((k = aSel.Count ? "" : "Файл " & sName & auCRLF) & _
             "Элементов: " & aSel.Count & auCRLF & _
             "Обработано: " & torrs & auCRLF & _
             "Каталогов: " & dirs & auCRLF & _              
             "Размер: " & SizeFormat(size, 0, 'M', 2) & auCRLF & _
             "Размер: " & SizeFormat(size, 0, 'G', 2) & auCRLF & _
             "Размер: " & SizeFormat(size, 0, 'T', 4) & auCRLF & _
             "Файлов: " & files & auCRLF & _                       
             "Powered by TCTorrent.wdx" & auCRLF & _
             "Время операции: " &  StrFormat("%.3f", tl) & " sec")
    Sleep(100)
    SetHintParam("ShowHint", "Reload")          
    Free(obj, aSel)
EndFunc

Func ToggleEverything()    
    If Not ProcessExist("Everything.exe") Then
       CommandExec em_everything
    Else
       CommandExec em_everything_exit
    Endif    
EndFunc 

Func TerminateEverything()
    CommandExec em_everything_exit
EndFunc

Func TorrentBugTest(lParam)
    RunThread("TorrentThreadTest")
EndFunc

Func TorrentThreadTest()
    Local out, tor, vbs
    tor = "d:\Temp\Jinn'sLiveUSB 11.2.2.torrent"
    vbs = '/c ECHO Wscript.Echo Inputbox("Torrent file for testing:","Autorun","' & tor & '")>%TEMP%\~auto_0002.vbs'    
    ProcessExecGetOutput out %COMSPEC% %vbs%
    
    gVbsInputBox = 1
    RunThread("WinVbsInputBoxActivate")
    ProcessExecGetOutput /OEM out "cscript.exe" "/nologo ~auto_0002.vbs" %TEMP%
    gVbsInputBox = 0
    
    out = StrTrim(out)
    If out = "" Then Return
    If Not FileExist(out) Then 
       MsgBox("File doesn't exist " & out)
       Return
    EndIf
    
    Local hIco = 0   
    Local hWnd = DllCall("CreateWindowExW", _
                         "dword", 0, _
                         "wstr", "msctls_progress32", _
                         "wstr", "", _
                         "dword", 0x00C80000, _
                         "int", 200, "int", 100, "int", Scale(400), "int", Scale(50), _
                         "handle", AUTORUN_TCHANDLE, _
                         "handle", 0, "handle", 0, "ptr", 0, "handle")
    If hWnd = 0 Then Return 0
    
    WinAlign(hWnd, 0, DllCall("GetDesktopWindow"))
    WinSetPos("", -Scale(50), "", "", 1, hWnd)
    WinSetState(5, hWnd)
                                
    Static PBS_MARQUEE     =  0x08, _
           PBM_SETMARQUEE  =  1034, _
           WM_GETICON      =  0x7f, _
           WM_SETICON      =  0x80
           
    hIco = SendMessage(AUTORUN_TCHANDLE, WM_GETICON, 2, 0)                     
    SendMessage(hWnd, WM_SETICON, 0, hIco)
    
    WinSetStyle(PBS_MARQUEE, 2, hWnd)    
    SendMessage(hWnd, PBM_SETMARQUEE, 1, 0)
    For i = 1 To 500
        TorrentInfo(hWnd, i, out)
        If WinGetState(1, hWnd) = 0 Then
           MsgBox("Тестирование прервано", "Autorun", 48)
           Return
        EndIf
    Next    
    MsgBox("Тестирование успешно завершено", "Autorun", 64)
    DllCall("DestroyWindow", "handle", hWnd)
EndFunc

# original function by Loopback
Func TorrentInfo(hWnd, nPass, sFile)
    Static aFixed = List('Name', 'TotalSize', 'FileCount', 'BlockSize', 'BlockCount', _
                         'Created', 'Creator', 'Hash', 'Comment', 'Encoding', _
                         'Multifile', 'PrivateTorrent', 'Publisher', 'PublisherURL')
    Static aMulti = List('Tracker', 'Webseed', 'Error', 'CustomField')

    Static sLibName = "TCTorrent.wlx" & (auX64 ? "64" : "")
    Static sLibPath = COMMANDER_PATH & "\Plugins\wlx\TCTorrent" & sLibName

    Local hDll = DllCall("LoadLibrary", "wstr", sLibPath, "handle")
    If hDll = 0 Then Return MsgBox("Can't load " & sLibPath)

    Local hHandle = DllCall(sLibName & "\TorrentOpen", "wstr", sFile, "handle")
    If hHandle = 0 Then
        DllCall("FreeLibrary", "handle", hDll)
        Return MsgBox("Can't open " & sFile)
    EndIf

    Local nCount, sRes

    For i = 0 to aFixed.Count - 1
        sRes = DllCall(sLibName & "\TorrentGet", "handle", hHandle, "wstr", aFixed[i], "int", 0, "wstr")
        OutputDebugString(aFixed[i] & ": " & sRes)
        WinSetText(nPass & ": " & sRes, hWnd)
    Next

    OutputDebugString(auCRLF & 'Files:')
    nCount = DllCall(sLibName & "\TorrentCountGet", "handle", hHandle, "wstr", "File", "uint")
    For j = 0 To nCount - 1
        sRes = StrFormat("[%12s] %s", _
                 DllCall(sLibName & "\TorrentGet", "handle", hHandle, "wstr", "FileSize", "int", j, "wstr"), _
                 DllCall(sLibName & "\TorrentGet", "handle", hHandle, "wstr", "File", "int", j, "wstr"))
        OutputDebugString(sRes)
        WinSetText(nPass & ": " & sRes, hWnd)
    Next

    For i = 0 to aMulti.Count - 1
        OutputDebugString(auCRLF & aMulti[i] & 's:')
        nCount = DllCall(sLibName & "\TorrentCountGet", "handle", hHandle, "wstr", aMulti[i], "uint")
        For j = 0 To nCount - 1
            sRes = DllCall(sLibName & "\TorrentGet", "handle", hHandle, "wstr", aMulti[i], "int", j, "wstr")
            OutputDebugString(sRes)
            WinSetText(nPass & ": " & sRes, hWnd)
        Next
    Next

    DllCall(sLibName & "\TorrentClose", "handle", hHandle)
    DllCall("FreeLibrary", "handle", hDll)
EndFunc 

#Func FindTorrentParts(lParam)
#    RunThread "ThreadTorrentParts" lParam
#EndFunc

Func FindTorrentParts(lParam)
    # модификаторы вызова
    Local b_CTRL = IsPressed (0x11), b_Shift = IsPressed (0x10)
    If lParam = 1 Then b_CTRL = true
    If lParam = 2 Then b_Shift = true    
    
    # повторный вызов при запущенной задаче
    If h_WinFindTorr Then
       SendMessage(h_WinFindTorr, 0x0010, 0, 0)
       g_FindTorrTask = 0  
       Return
    Endif
    
    If gEvAuto And Not ProcessExist("Everything.exe") Then 
       ShellExec(gEvPath, "-startup")
       Sleep(gEvDelay)       
    Endif
    
    # имя файла под курсором
    Local sPath = RequestCopyDataInfo("SP")    
    Local sName = RequestCopyDataInfo("SN")        
    Local sFile = sPath & sName
    
    # файл не существует или является каталогом
    If Not FileExist(sFile) Then 
       ShowHint("File doesn't exist " & sFile)
       Return
    ElseIf StrPos(FileGetAttr(sFile), "D") Then
       ShowHint("Not a torrent file " & sFile)
       Return
    ElseIf FileGetSize(sFile) > 1024*1024*5 Then
       ShowHint("File size > 5 Mb " & sFile)
       Return
    EndIf    
    
    # путь к библиотеке плагина
    Static sLibName = "TCTorrent.wlx" & (auX64 ? "64" : "")
    Static sLibPath = COMMANDER_PATH & "\Plugins\wlx\TCTorrent" & sLibName

    # не удалось загрузить библиотеку
    Local hDll = DllCall("LoadLibrary", "wstr", sLibPath, "handle")
    If hDll = 0 Then 
       ShowHint("TCTorrent.wlx can't load library " & sLibPath)
       Return
    EndIf    

    # библиотеке не удалось открыть файл
    Local hHandle = DllCall(sLibName & "\TorrentOpen", "wstr", sFile, "handle")
    If hHandle = 0 Then
        ShowHint("TCTorrent.wlx can't open file " & sFile)    
        DllCall("FreeLibrary", "handle", hDll)
        Return
    EndIf
    
    # файл не является торрент-файлом
    Local nFiles
    nFiles = DllCall(sLibName & "\TorrentGet", "handle", hHandle, "wstr", "FileCount", "int", 0, "wstr")
    If nFiles < 1 Then
       ShowHint("Corrupt torrent file " & sFile)
       DllCall(sLibName & "\TorrentClose", "handle", hHandle)       
       DllCall("FreeLibrary", "handle", hDll)       
       Return             
    EndIf

    # окно прогресса операции
    h_WinFindTorr = 0
    If g_WinThread Then 
       RunThread "WinFindTorrentData"
       While g_FindTorrTask = 0
           Sleep(50)
       Wend
    Else
        WinFindTorrentData(0)
    EndIf
    # локальные переменные
    Local T1 = GetUptime(), T2 = T1, T3, bSpeed = 0, nRes = 0
    Local bName = Not b_Shift, bSize = Not b_CTRL, sSize, sMode, sMem, sDbg
    Local j, nCount, sRes, nError, sList, sDirs, aQuery = List(), aCount = List()
    
    Static aMode = List("«Имя и размер»", "«Только имя»", "«Только размер»")    
    If bName And bSize Then
       nMode = 0
    ElseIf bName Then
       nMode = 1    
    Else
       nMode = 2
    EndIf
    sMode = aMode[nMode]
    
    # количество файлов в торренте
    nCount = DllCall(sLibName & "\TorrentCountGet", "handle", hHandle, "wstr", "File", "uint")

    # перечисление файлов в торренте
    For j = 0 To nCount - 1
        
        If gTorrentDbg Then gDbgStep = "Step 1. TorrentGet j=" & j & auCRLF
        
        # имя файла
        sRes = DllCall(sLibName & "\TorrentGet", "handle", hHandle, "wstr", "File", "int", j, "wstr")
        
        # размер файла
        If bSize Then
           sSize = DllCall(sLibName & "\TorrentGet", "handle", hHandle, "wstr", "FileSize", "int", j, "wstr")
        EndIf
        
        sDbg = Round((j+1)/nCount*100,0) & '% - '
        If gTorrentDbg Then
           nRes += StrLen(sRes) + 8
           sMem = StrLen(sList) + StrLen(sDirs) + nRes
           sDbg &= SizeFormat(sMem*2, 1, 'G', 2) &  ' - '        
        EndIf

        If gTorrentDbg Then gDbgStep &= "Step 2. WinSetText " & sRes & auCRLF
        
        # меньше сообщений окну прогресса
        If bSpeed Then
           T3 = GetUptime()
           If Round(T3 - T2, 0) > 250 Then 
              WinSetText(sDbg & sRes, h_WinFindTorr)
              T2 = T3
           EndIf
        Else
           WinSetText(sDbg & sRes, h_WinFindTorr)
        EndIf

        If gTorrentDbg Then gDbgStep &= "Step 3. FileFindEv " & sRes & auCRLF
        
        # запрос к Everything
        If bName And bSize Then
           aQuery.Text = FileFindEv('*"' & sRes & '" size:' & sSize, "", "")
        ElseIf bName Then
           aQuery.Text = FileFindEv('*"' & sRes & '"', "", "")        
        Else
           aQuery.Text = FileFindEv('size:' & sSize, "", "")
        EndIf
                
        # ошибка запроса
        nError = ERROR
        If nError > 0 Then Break

        If gTorrentDbg Then gDbgStep &= "Step 4. aCount.Add" & auCRLF
        
        # обработка запроса
        aCount.Add("[" & aQuery.Count & "] " & sRes)        
        If aQuery.Count > 0 Then 
           If gTorrentDbg Then gDbgStep &= "Step 5. sList" & auCRLF
           sList &= aQuery.Text & auCRLF
           If gTorrentDbg Then gDbgStep &= "Step 6. sDirs" & auCRLF
           If nFiles > 1 Then 
              If gTorrentDbg Then gDbgStep &= "Step 7. StrReplace" & auCRLF
              sDirs &= StrReplace(aQuery.Text, sRes, "") & auCRLF
           Else
              sDirs &= aQuery.Text & auCRLF
           EndIf
        Else
           If gTorrentDbg Then 
              gDbgStep &= "Step 5. Skip" & auCRLF
              gDbgStep &= "Step 6. Skip" & auCRLF
              gDbgStep &= "Step 7. Skip" & auCRLF              
           EndIf             
        EndIf  

        If gTorrentDbg Then gDbgStep &= "Step 8. Next"
        #Sleep(3000)
        
        # опрерация прервана закрытием окна прогресса
        If g_FindTorrTask = 0 Then Break
    Next
    
    If gTorrentDbg Then gDbgStep &= "Step 9. Out"
       
    If nError = 1 Then MsgBox("Everything window not found.")
    If nError = 2 Then MsgBox("IPC Everything query execution error.")  
    If nError > 0 Then 
       g_FindTorrTask = 0
       SendMessage(h_WinFindTorr, 0x0010, 0, 0)       
       Free(aCount, aQuery)
       DllCall(sLibName & "\TorrentClose", "handle", hHandle)
       DllCall("FreeLibrary", "handle", hDll)           
       Return
    EndIf

    Local c = 0, m = Map(), top5 = List(), sTop5, bDirs = StrLen(StrTrim(sDirs))
    
    # суммирование путей при непустом результате
    If g_FindTorrTask And bDirs Then 
       aQuery.Text = sDirs
       For value In aQuery
           c = 1
           If m.Has(value) Then c += m.Get(value)
           m.Set(value, c)
       Next
    EndIf
    
    # сортировка путей по убыванию
    If g_FindTorrTask And bDirs Then
       top5.SortMethod = 1 
       For key, value In m          
           top5.Add("[" & value & "]" & Chr(160) & key)
       Next
       top5.Sort(1)
       
       # выбор верхних пяти путей
       For j = 0 To top5.Count - 1
          sTop5 &= top5[j] & auCRLF
          If j >= 4 Then Break
       Next   
    EndIf
    
    c = top5.Count
    Local top1, files = aCount.Text
    If c > 0 Then top1 = StrTrim(StrPart(top5[0], Chr(160), 2))

    # освобождение объектов и библиотеки    
    Free(aCount, aQuery, top5, m)    
    DllCall(sLibName & "\TorrentClose", "handle", hHandle)
    DllCall("FreeLibrary", "handle", hDll)
    
    # время операции    
    T2 = Round(GetUptime() - T1, 0) / 1000
    T3 = "Время поиска: " &  StrFormat("%.3f", T2) & " sec"
    
    If gEvAuto Then ShellExec(gEvPath, "-exit")    
    
    If g_FindTorrTask = 0 Then
       MsgBox("Поиск отменен", "Autorun", 48)
    Else        
       # закрытие окна прогресса
       g_FindTorrTask = 0
       SendMessage(h_WinFindTorr, 0x0010, 0, 0)
       If DllCall("DestroyWindow", "handle", h_WinFindTorr) Then h_WinFindTorr = 0
       
       # ничего не найдено
       If c = 0 Then
          If nMode < 2 Then
             MsgBox("Найдено: " & c & auCRLF & auCRLF & _
                    "Торрент: " & nCount & " файлов" & auCRLF & T3 & auCRLF & _
                    "Режим: " & sMode & auCRLF & auCRLF & _                
                    "Продолжить в режиме " & aMode[nMode+1] & "?", "Autorun", 3+64+0)
             If EXTENDED = 6 Then Return FindTorrentParts(nMode+1)                
          Else
             MsgBox("Найдено: " & c & auCRLF & auCRLF & _
                    "Торрент: " & nCount & " файлов" & auCRLF & T3 & auCRLF & _
                    "Режим: " & sMode, "Autorun", 64)
          EndIf           
       Else          
          # проверка CapsLock
          Local bCaps = BitAND(DllCall("GetKeyState", "int", 0x14, "short"), 1)
          If gCapsReverse Then bCaps = Not bCaps
          If bCaps Then
             ShowRedHint("Автопереход к найденному")
             GoToPathFromMsg(top1)
             Return
          EndIf          
          MsgBox("Найдено: " & c & auCRLF & auCRLF & sTop5 & auCRLF & _
                 "Торрент: " & nCount & " файлов" & auCRLF & T3 & auCRLF & _
                 "Режим: " & sMode & auCRLF & auCRLF & _                
                 "Сохранить в текстовый файл?", "Autorun", 3+64+0)
          If EXTENDED = 2 Then Return
          If EXTENDED = 7 Then GoToPathFromMsg(top1)
          If EXTENDED = 6 Then
             Local txt
             txt &= top1 & auCRLF & auCRLF
             txt &= "-----------------" & auCRLF             
             txt &= "Top 5 locations:" & auCRLF 
             txt &= "-----------------" & auCRLF             
             txt &= sTop5 & auCRLF
             txt &= "-----------------" & auCRLF             
             txt &= "Torrent files:" & auCRLF     
             txt &= "-----------------" & auCRLF             
             txt &= files & auCRLF & auCRLF
             txt &= "-----------------" & auCRLF                          
             txt &= "Full list:" & auCRLF
             txt &= "-----------------" & auCRLF                
             txt &= sList             
             SaveDataPathToText(sFile, txt)
          EndIf   
       EndIf
    EndIf
EndFunc

Func TorrentFindOptions()
     gTorrentDbg = Not gTorrentDbg
     ShowRedHint("Торрент Debug " & (gTorrentDbg ? "включен" : "выключен"))
EndFunc

Func TorrentDebugInfo()
    If Not gTorrentDbg Then gDbgStep = "Торрент Debug выключен"
    If gDbgStep = "" Then gDbgStep = "Empty"
    SetHintParam("ShowHint", "Font", 13, "Arial")
    SetHintParam("ShowHint", "BackColor", 0x000000)
    SetHintParam("ShowHint", "Text", 0xFFFFFF)
    ShowHint(gDbgStep)
    WinAlign(LAST_HINT_WINDOW)    
    ClipPut(gDbgStep)  
    SetHintParam("ShowHint", "Reload") 
EndFunc
[/cut]
Orion9
спасибо. Сегодня попробую.
Можно ли добавить к этому поиску такую фишку, чтоб "http://" торрента-файла по которому ты только что искал файлы сразу попадала в буфер обмена?
Т.е. можешь сразу идти в браузер и легко попасть на страницу релиза, если тебе это необходимо в силу каких-то причин.
И наверно опционально, потому как предположительно это кому-то может и наоборот помешать, затирая что-то.
Если это не космическое что-то, я не разбираюсь, просто спрашиваю.