Autorun

Обсуждение только плагинов и утилит для Total Commander.

Модераторы: Avada, CaptainFlint, Nik, d-view, Моторокер

FallenAngel
Сообщения: 47
Зарегистрирован: Вт дек 30, 2025 20:01

Сообщение FallenAngel »

Ничего себе :shock:
Я думал просто сменить три параметра в ini и перезапустить тотал.

Да и я [AllResolutions] использую.
Аватара пользователя
Orion9
Сообщения: 1283
Зарегистрирован: Пн янв 01, 2024 17:18

Сообщение Orion9 »

FallenAngel
Autorun не боится поставленных задач )

Попробовать сделать такое можно, но будет сложно, не смотря на то, что все необходимые инструменты для этого есть, включая макросы SYSINFO_DESKTOPWIDTH, SYSINFO_DESKTOPHEIGHT, SYSINFO_DESKTOPDPI.

Нечто подобное уже делалось при реализации Drag-And-Drop на панели инструментов (имеется в виду учитывание размера кнопок и параметров масштабирования экрана). Отсутствие этой фичи, кстати, до сих пор приводит в ярость пользователей ТС, как и меня в свое время ) Но как гласит один из лозунгов Autorun: «Гислер не может — Autorun поможет» :mrgreen:

[cut]Изображение[/cut]
[cut]Изображение[/cut]
[cut="Bars.aufg"]

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

Pragma IncludeOnce

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

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

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

Global gHBarName, gHBarFile, gHBarFileTs, 
Global gHBarTxt, gHBarCP = "ANSI", gHBarWincmd = 0
Global gHBarHint = 0, gHBarVerb, gHBarCancel, gHBarCancelLoad, gHBarLoadError = 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)
    Static SM_CXDRAG = 68, SM_CYDRAG = 69, _
           dragX = GetSystemMetrics(SM_CXDRAG), dragY = GetSystemMetrics(SM_CYDRAG), _
           startX, startY
    Local x, y, pos
    If gHBarLoadError Then 
       Return DllCall("CallWindowProcW", _
              "ptr", gHBarWndProc, "hwnd", hWnd, "uint", uMsg, "wparam", wParam, "lparam", lParam)
    EndIf
    Switch uMsg
       Case WM_LBUTTONDOWN
          If IsDrag = 0 And BitAND(wParam, MK_CONTROL) Then
             If FileGetTime(gHBarFile) <> gHBarFileTs Then
                ShowDragHint("Операция невозможна. Файл панели изменился.")
                Return DllCall("CallWindowProcW", _
                "ptr", gHBarWndProc, "hwnd", hWnd, "uint", uMsg, "wparam", wParam, "lparam", lParam)
             Endif
             #MouseGetPos("x","y")
             Static buf = Buffer(8)	# POINT
             buf.Zero()
             x = BitAND(lParam, 0xFFFF)
             y = BitAND(BitShift(lParam,16), 0xFFFF)
             startX = x
             startY = y
             buf.SetNum(0, "int", x, "int", y)
             DllCall("ClientToScreen", "hwnd", hWnd, "ptr", buf.ptr)
             pos = buf.GetNum(0, "int64")             
             #x = buf.GetNum(0)
             #y = buf.GetNum(4)
             #If DllCall("DragDetect", "hwnd", hWnd, "int64", MakeInt(y, x, 2)) Then
             If DllCall("DragDetect", "hwnd", hWnd, "int64", pos) Then             
                IsDrag = 1
                WinSetStyle(0x80000, 3, hWnd)
                DllCall("SetLayeredWindowAttributes", "hwnd", hWnd, "ptr", 0, "byte", 128, "dword", 2)
                gDragIndex = HBarGetIdx()
             Else
                IsDrag = 0
                DllCall("CallWindowProcW", _
                   "ptr", gHBarWndProc, "hwnd", hWnd, "uint", uMsg, "wparam", wParam, "lparam", lParam) 
                DllCall("CallWindowProcW", _
                   "ptr", gHBarWndProc, "hwnd", hWnd, "uint", WM_LBUTTONUP, "wparam", wParam, "lparam", lParam)
                Return 0
             EndIf
          EndIf    
       Case WM_LBUTTONUP
          If IsDrag = 1 Then
             DllCall("ReleaseCapture")
             IsDrag = 0
             If WinFromPoint() = hWnd Then
                gDropIndex = HBarGetIdx()
                If gDragIndex <> gDropIndex Then
                   If gHBarHint Then ShowDragHint("Index " & gDragIndex & " To Index: " & gDropIndex)
                   HBarDragnDrop(gDragIndex, gDropIndex)
                EndIf
             EndIf
             WinSetStyle(0x80000, 5, hWnd)
             #Return 0
             #MouseGetPos("x","y")
             #lParam = MakeInt(y, x + 200, 2)
             lParam = 0
          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
          gHBarName = ""
          Return "Файл панели не найден " & gHBarFile
       EndIf
       # метка времени
       gHBarFileTs = FileGetTime(gHBarFile)
       # загрузка панели       
       HBarLoad()
       If gHBarLoadError Then Return HBarGetHint(bMap)
    ElseIf FileGetTime(gHBarFile) <> gHBarFileTs Then
       gHBarUndo = false
       gHBarUndoLoad = ""
       If Not FileExist(gHBarFile) Then
          gHBarName = ""
          Return "Файл панели не найден " & gHBarFile
       EndIf   
       gHBarFileTs = FileGetTime(gHBarFile)
       HBarLoad()
       If gHBarLoadError Then Return HBarGetHint(bMap)       
    EndIf
    # индекс кнопки под курсором
    gDragIndex = HBarGetIdx()
    If Not gDragIndex Then Return "Не удалось определить индекс кнопки"
    Return HBarGetHint(bMap)  
EndFunc

Func HBarGetFile()
    Local bar, txt
    # информация о файле панели в wincmd.ini
    IniRead /R 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 = GetCurrentPath() & "\" & txt
    EndIf     
    # проверка существования файла панели
    If Not FileExist(bar) Then
       bar = COMMANDER_PATH & "\" & txt
    EndIf      
    Return bar
EndFunc

Func HBarLoad()
    gHBarLoadError = 0
    Local bar = FileRead(gHBarFile, 128, "RAW")
    Local bom = "FFFE"
    Local utf = "5B0042007500740074006F006E006200610072005D000D000A00"
    If ERROR = 1 Then
       gHBarLoadError = 1
       gHBarCP = "Unknown"       
       Return
    EndIf   
    If StrLeft(bar, 4) = "FFFE" Then 
       gHBarCP = "UTF-16 BOM"
    Else
       IF StrPos(bar, utf) Then
          gHBarCP = "UTF-16 без BOM"
       Else
          gHBarCP = "ANSI"
       EndIf
    EndIf
    # загрузка файла в массив
    gHBarList.Count = 0
    gHBarList.LoadFromFile(gHBarFile, gHBarCP)    
    # количество кнопок в файле
    Local nCount = 0
    IniRead /R 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)
    If gHBarButtons = 0 Then gHBarLoadError = 1
    # карта панели
    gHBarTxt = auCRLF & auCRLF & "Loaded" & ": " & gHBarFile & " > " & gHBarCP & " "
    If gHBarLoadError Then gHBarTxt &= " -- ERROR LOADING"
    gHBarTxt &= 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 /R b %COMMANDER_INI% "Buttonbar" "Buttonheight"
    IniRead /R dpi %COMMANDER_INI% "Buttonbar" "DefaultDpi" %'nDPI'
    Local b_ini = b, b_calc
    # масштабирование экрана
    If dpi <> nDPI Then
       IniRead /R 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)
    gHBarFileTs = 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)
    Local dark = IniRead(COMMANDER_INI, "Configuration", "DarkMode", 0)
    SetHintParam("ShowHint", "Font", 13, "Tahoma")
    SetHintParam("ShowHint", "BackColor", 0x0F0F0F)
    SetHintParam("ShowHint", "Text", 0xFFFFFF)
    SetHintParam("ShowHint", "DarkBackColor", 0xFF0000)
    SetHintParam("ShowHint", "DarkText", 0xFFFFFF)    
    ShowHint(auCRLF & "    " & DragHint & "    " & auCRLF, 0, 0, 1000, 1)
    WinAlign(LAST_HINT_WINDOW)
    If Not dark Then
       WinSetStyle(0x80000, 3, LAST_HINT_WINDOW)
       DllCall("SetLayeredWindowAttributes", _
                "hwnd", LAST_HINT_WINDOW, "ptr", 0, "byte", 192, "dword", 2)
    EndIf                                         
    Sleep(100)
    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' & auCRLF
    txt &= 'MENUITEM "Загружена как UTF-16", em_aucmd  ' & (StrPos(gHBarCP, "UTF-16") ? "/C" : "") & ' -1' & 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 = ""
       #gHBarFileTs = FileGetTime(gHBarFile)                  
       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 = ""
       #gHBarFileTs = FileGetTime(gHBarFile)           
       HBarLoad()
       ShowDragHint("Первоначальная панель загружена")
       SendCommand(2945)
    EndIf   
EndFunc

#{  
    поиск индекса по ключу и значению:
    
    bar = COMMANDER_PATH & "\Bars\Main.bar"
    
    idx = FindButtonIdx(bar, "cmd", "61007")
    idx = FindButtonIdx(bar, "menu", "Auto_bars")   
    idx = FindButtonIdx(bar, "button", "WCMICONS.dll,72") 
    
    MsgBox(FindButtonIdx(bar, "param", '/ef "tcm(60011,1)"'))
#}
Func FindButtonIdx(ButtonBar, ButtonKey, ButtonVal)
    Local txt, pos, len, sub, idx = 0
    If Not FileExist(ButtonBar) Then
       ShowDragHint("Панель не найдена " & ButtonBar)
       Return 0   
    EndIf   
    len = StrLen(ButtonKey)
    ProcessExecGetOutput txt %COMSPEC% '/c type "%ButtonBar%"'
    pos = StrPos(txt, "=" & ButtonVal)
    If pos = 0 Then Return 0
    For i = 0 To 3
       sub = StrMid(txt, pos-len-i, len)
       If sub = ButtonKey Then
          idx = StrMid(txt, pos-i, i)
          If IsInt(idx) Then Break
       Endif
    Next
    # перепроверка индекса
    If idx > 0 Then
       IniRead txt %ButtonBar% "Buttonbar" %"ButtonKey & idx"
       If StrPos(txt, ButtonVal) > 0 Then Return idx
    EndIf
    Return 0
EndFunc
[/cut]

По поводу отлова Shift + Click по заголовку Листера через GetRawInputData, вышла небольшая заминка с этим вариантом:

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

DllCall("RegisterRawInputDevices", "Ptr", Buff.Ptr, "UInt", 1, "UInt", 8 + auPtrSize)

# WM_INPUT
SetMessageAction /P 0x00FF "OnRawInput" 
SetMessageAction не отлавливает сообщение WM_INPUT из-за каких-то ограничений Autorun. Было у меня предчувствие, что так просто не прокатит, пришлось делать отдельное окно перехватчик. Кажись, получилось. Чуть позже выложу этот вариант.
FallenAngel
Сообщения: 47
Зарегистрирован: Вт дек 30, 2025 20:01

Сообщение FallenAngel »

Я все равно не понимаю, почему просто не сменить:

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

[Buttonbar]
Buttonheight=30 (37)
SmallIconSize=default (24)
[AllResolutions]
Iconsize32=16 (24)
...и потом зарестартить (если иначе никак) TotalCmd.
Аватара пользователя
Orion9
Сообщения: 1283
Зарегистрирован: Пн янв 01, 2024 17:18

Сообщение Orion9 »

FallenAngel
Я тут выше писал, что Autorun не боится поставленных задач, но правильнее было написать так: с тех пор, как Loopback добавил возможность работать с WinAPI через DllCall, Autorun вообще перестал бояться каких-либо задач ) Конечно, дело не только в DllCall. Есть еще объекты Buffer, Callback, побитовые операции и некоторые другие вещи, но в целом мощь Autorun зашкаливает.

И вот очень жаль, что болван об этом ничего не знает. Иначе можно было бы вытягивать из него готовый код как горячие пирожки из печки :mrgreen:

Сами судите. Я последовательно вводил запросы, и каждый раз он мне выдавал готовые решения. Меня очень удивило то, что все решения оказались рабочими, именно рабочими, т.е. достаточно было просто сохранить файл и проверить его на работоспособность.

[cut="1"]

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

#Requires AutoHotkey v2.0
Persistent

; 1. Регистрация устройства (Мышь)
; RAWINPUTDEVICE структура
UsagePage := 1
Usage     := 2
Flags     := 0x00000100 ; RIDEV_INPUTSINK (получать ввод даже если окно не в фокусе)
hTarget   := A_ScriptHwnd

RAWINPUTDEVICE := Buffer(8 + A_PtrSize, 0)
NumPut("UShort", UsagePage, RAWINPUTDEVICE, 0)
NumPut("UShort", Usage,     RAWINPUTDEVICE, 2)
NumPut("UInt",   Flags,     RAWINPUTDEVICE, 4)
NumPut("Ptr",    hTarget,   RAWINPUTDEVICE, 8)

if !DllCall("RegisterRawInputDevices", "Ptr", RAWINPUTDEVICE, "UInt", 1, "UInt", 8 + A_PtrSize)
    MsgBox "Ошибка регистрации Raw Input"

; 2. Подписка на сообщение WM_INPUT (0x00FF)
OnMessage(0x00FF, OnRawInput)

OnRawInput(wParam, lParam, msg, hwnd) {
    ; Определяем размер данных
    size := 0
    DllCall("GetRawInputData", "Ptr", lParam, "UInt", 0x10000003, "Ptr", 0, "UInt*", &size, "UInt", 8 + A_PtrSize * 2)
    
    if (size > 0) {
        rawBuffer := Buffer(size)
        DllCall("GetRawInputData", "Ptr", lParam, "UInt", 0x10000003, "Ptr", rawBuffer, "UInt*", &size, "UInt", 8 + A_PtrSize * 2)
        
        ; Проверяем, что это мышь (тип 0)
        type := NumGet(rawBuffer, 0, "UInt")
        if (type == 0) {
            ; Смещение для данных мыши в структуре RAWINPUT
            ; header (16 байт на x86, 24 на x64) + данные мыши
            headerSize := (A_PtrSize == 8) ? 24 : 16
            
            flags := NumGet(rawBuffer, headerSize, "UShort")
            lastX := NumGet(rawBuffer, headerSize + 8, "Int")
            lastY := NumGet(rawBuffer, headerSize + 12, "Int")
            
            ToolTip "Raw Delta X: " lastX " | Y: " lastY
        }
    }
}
[/cut]
[cut="2"]

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

#Requires AutoHotkey v2.0
Persistent

; Регистрация Raw Input для мыши
RAWINPUTDEVICE := Buffer(8 + A_PtrSize, 0)
NumPut("UShort", 1, RAWINPUTDEVICE, 0)
NumPut("UShort", 2, RAWINPUTDEVICE, 2)
NumPut("UInt", 0x00000100, RAWINPUTDEVICE, 4) ; RIDEV_INPUTSINK
NumPut("Ptr", A_ScriptHwnd, RAWINPUTDEVICE, 8)

if !DllCall("RegisterRawInputDevices", "Ptr", RAWINPUTDEVICE, "UInt", 1, "UInt", 8 + A_PtrSize)
    MsgBox "Ошибка регистрации"

OnMessage(0x00FF, OnRawInput)

OnRawInput(wParam, lParam, *) {
    size := 0
    DllCall("GetRawInputData", "Ptr", lParam, "UInt", 0x10000003, "Ptr", 0, "UInt*", &size, "UInt", 8 + A_PtrSize * 2)
    
    if (size > 0) {
        raw := Buffer(size)
        DllCall("GetRawInputData", "Ptr", lParam, "UInt", 0x10000003, "Ptr", raw, "UInt*", &size, "UInt", 8 + A_PtrSize * 2)
        
        headerSize := (A_PtrSize == 8) ? 24 : 16
        ; Извлекаем флаги кнопок мыши
        btnFlags := NumGet(raw, headerSize + 4, "UShort")
        
        ; 0x0001 — это флаг RI_MOUSE_LEFT_BUTTON_DOWN
        if (btnFlags & 0x0001) {
            ; Проверяем, зажат ли Shift (логическое состояние)
            if GetKeyState("Shift", "P") {
                HandleShiftClick()
            }
        }
    }
}

HandleShiftClick() {
    ; Получаем окно под курсором
    DllCall("GetCursorPos", "Ptr", pt := Buffer(8))
    hWnd := DllCall("WindowFromPoint", "Int64", NumGet(pt, 0, "Int64"), "Ptr")
    
    if (hWnd) {
        classBuffer := Buffer(512)
        DllCall("GetClassName", "Ptr", hWnd, "Ptr", classBuffer, "Int", 256)
        className := StrGet(classBuffer)
        
        ToolTip "Shift + Click на окне класса: " className
        SetTimer () => ToolTip(), -2000
    }
}
[/cut]
[cut="3"]

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

#Requires AutoHotkey v2.0
Persistent

; Константы WinAPI
WM_NCHITTEST := 0x84
HTCAPTION := 2

; Регистрация Raw Input
RAWINPUTDEVICE := Buffer(8 + A_PtrSize, 0)
NumPut("UShort", 1, RAWINPUTDEVICE, 0)
NumPut("UShort", 2, RAWINPUTDEVICE, 2)
NumPut("UInt", 0x00000100, RAWINPUTDEVICE, 4)
NumPut("Ptr", A_ScriptHwnd, RAWINPUTDEVICE, 8)

if !DllCall("RegisterRawInputDevices", "Ptr", RAWINPUTDEVICE, "UInt", 1, "UInt", 8 + A_PtrSize)
    MsgBox "Ошибка регистрации"

OnMessage(0x00FF, OnRawInput)

OnRawInput(wParam, lParam, *) {
    size := 0
    DllCall("GetRawInputData", "Ptr", lParam, "UInt", 0x10000003, "Ptr", 0, "UInt*", &size, "UInt", 8 + A_PtrSize * 2)
    
    if (size > 0) {
        raw := Buffer(size)
        DllCall("GetRawInputData", "Ptr", lParam, "UInt", 0x10000003, "Ptr", raw, "UInt*", &size, "UInt", 8 + A_PtrSize * 2)
        
        headerSize := (A_PtrSize == 8) ? 24 : 16
        btnFlags := NumGet(raw, headerSize + 4, "UShort")
        
        ; Проверяем нажатие левой кнопки мыши + Shift
        if (btnFlags & 0x0001) && GetKeyState("Shift", "P") {
            HandleShiftClick()
        }
    }
}

HandleShiftClick() {
    ; 1. Получаем текущие координаты курсора
    DllCall("GetCursorPos", "Ptr", pt := Buffer(8))
    x := NumGet(pt, 0, "Int")
    y := NumGet(pt, 4, "Int")
    
    ; 2. Находим окно под курсором
    hWnd := DllCall("WindowFromPoint", "Int64", NumGet(pt, 0, "Int64"), "Ptr")
    
    if (hWnd) {
        ; Поднимаемся к главному родительскому окну (если кликнули по дочернему элементу)
        rootHWnd := DllCall("GetAncestor", "Ptr", hWnd, "UInt", 2, "Ptr") ; GA_ROOT
        
        ; 3. Получаем класс окна
        classBuffer := Buffer(512)
        DllCall("GetClassName", "Ptr", rootHWnd, "Ptr", classBuffer, "Int", 256)
        className := StrGet(classBuffer)
        
        ; 4. Проверяем, заголовок ли это (WM_NCHITTEST)
        ; Передаем координаты в формате (y << 16) | (x & 0xFFFF)
        hitTest := DllCall("SendMessage", "Ptr", rootHWnd, "UInt", WM_NCHITTEST, "Ptr", 0, "Ptr", (y << 16) | (x & 0xFFFF))
        
        isTitleBar := (hitTest == HTCAPTION)
        
        ; Вывод результата
        msg := "Class: " className "`n"
        msg .= "Is Title Bar: " (isTitleBar ? "✅ ДА" : "❌ НЕТ")
        
        ToolTip msg
        SetTimer () => ToolTip(), -3000
    }
}
[/cut]
[cut="4"]

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

#Requires AutoHotkey v2.0
Persistent

; Константы для читаемости
RI_MOUSE_LEFT_BUTTON_DOWN := 0x0001
WM_INPUT := 0xFF
RID_INPUT := 0x10000003

; Регистрация устройства
RAWINPUTDEVICE := Buffer(8 + A_PtrSize, 0)
NumPut("UShort", 1, RAWINPUTDEVICE, 0)
NumPut("UShort", 2, RAWINPUTDEVICE, 2)
NumPut("UInt", 0x00000100, RAWINPUTDEVICE, 4) ; RIDEV_INPUTSINK
NumPut("Ptr", A_ScriptHwnd, RAWINPUTDEVICE, 8)

DllCall("RegisterRawInputDevices", "Ptr", RAWINPUTDEVICE, "UInt", 1, "UInt", 8 + A_PtrSize)

OnMessage(WM_INPUT, OnRawInput)

OnRawInput(wParam, lParam, *) {
    ; 1. БЫСТРАЯ ПРОВЕРКА: Если нет нажатия кнопок, мгновенно выходим.
    ; Это отсекает 99% вызовов, связанных с простым движением мыши.
    
    ; Сначала получаем размер данных
    size := 0
    DllCall("GetRawInputData", "Ptr", lParam, "UInt", RID_INPUT, "Ptr", 0, "UInt*", &size, "UInt", 8 + A_PtrSize * 2)
    
    if (size <= 0)
        return

    raw := Buffer(size)
    DllCall("GetRawInputData", "Ptr", lParam, "UInt", RID_INPUT, "Ptr", raw, "UInt*", &size, "UInt", 8 + A_PtrSize * 2)
    
    headerSize := (A_PtrSize == 8) ? 24 : 16
    btnFlags := NumGet(raw, headerSize + 4, "UShort")

    ; 2. ПРОВЕРКА СОБЫТИЯ: Нас интересует только момент НАЖАТИЯ левой кнопки (0x0001)
    if !(btnFlags & RI_MOUSE_LEFT_BUTTON_DOWN)
        return

    ; 3. ПРОВЕРКА МОДИФИКАТОРА: Зажат ли Shift?
    if !GetKeyState("Shift", "P")
        return

    ; Если мы дошли сюда, значит произошло ровно то, что нужно: Shift + Left Down
    HandleAction()
}

HandleAction() {
    ; Вся тяжелая логика (WinAPI, ToolTip и т.д.) теперь вызывается 
    ; ТОЛЬКО в момент клика, а не при каждом движении.
    
    DllCall("GetCursorPos", "Ptr", pt := Buffer(8))
    x := NumGet(pt, 0, "Int"), y := NumGet(pt, 4, "Int")
    
    hWnd := DllCall("WindowFromPoint", "Int64", NumGet(pt, 0, "Int64"), "Ptr")
    if (hWnd) {
        rootHWnd := DllCall("GetAncestor", "Ptr", hWnd, "UInt", 2)
        
        classBuffer := Buffer(512)
        DllCall("GetClassName", "Ptr", rootHWnd, "Ptr", classBuffer, "Int", 256)
        
        hitTest := DllCall("SendMessage", "Ptr", rootHWnd, "UInt", 0x84, "Ptr", 0, "Ptr", (y << 16) | (x & 0xFFFF))
        isTitleBar := (hitTest == 2) ; HTCAPTION

        MsgBox "Класс: " . StrGet(classBuffer) . "`nЗаголовок: " . (isTitleBar ? "Да" : "Нет")
    }
}
[/cut]
[cut="5"]

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

#Requires AutoHotkey v2.0

; --- 1. Регистрация класса окна ---
className := "MyInvisibleReceiver"
wndClass := Buffer(120, 0) ; Структура WNDCLASSEX
NumPut("UInt", 80,          wndClass, 0)  ; cbSize
NumPut("Ptr",  CallbackCreate(WndProc), wndClass, 8) ; lpfnWndProc
NumPut("Ptr",  StrPtr(className), wndClass, 64)      ; lpszClassName

if !DllCall("RegisterClassEx", "Ptr", wndClass) {
    MsgBox "Ошибка регистрации класса"
    ExitApp
}

; --- 2. Создание Message-Only окна ---
; HWND_MESSAGE = -3
hwnd := DllCall("CreateWindowEx", 
    "UInt", 0, 
    "Str", className, 
    "Str", "HiddenWindow", 
    "UInt", 0, 
    "Int", 0, "Int", 0, "Int", 0, "Int", 0, 
    "Ptr", -3, ; ПЕРЕМЕННАЯ HWND_MESSAGE
    "Ptr", 0, "Ptr", 0, "Ptr", 0, "Ptr")

if !hwnd {
    MsgBox "Ошибка создания окна"
    ExitApp
}

MsgBox("Окно создано. HWND: " hwnd)

; --- 3. Обработчик событий (Window Procedure) ---
WndProc(hwnd, msg, wParam, lParam) {
    ; Пример: ловим кастомное сообщение 0x5555
    if (msg == 0x5555) {
        MsgBox "Событие перехвачено через WinAPI! wParam: " wParam
        return 0
    }
    
    ; Обязательно вызываем стандартный обработчик для остальных сообщений
    return DllCall("DefWindowProc", "Ptr", hwnd, "UInt", msg, "Ptr", wParam, "Ptr", lParam, "Ptr")
}

; Тест: отправить сообщение самому себе
F2::DllCall("PostMessage", "Ptr", hwnd, "UInt", 0x5555, "Ptr", 1, "Ptr", 2)
[/cut]

Мне оставалось только привести все это к формату Autorun, добавив небольшой специфики. Но на этом все.

[cut="aucfg"]

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

RunThread("InvisibleReceiver")
   
Func InvisibleReceiver()
    Local text = "InvisibleReceiver"
    Local proc = Callback("ReceiverWndProc", "hwnd;uint;wparam;lparam")
    Local name = Buffer(StrLen(text) + 2)
    
    name.Zero()
    name.SetStr(text, 0, StrLen(text), "ANSI")

    Local wndClass = Buffer(auX64 ? 80 : 48)             # Структура WNDCLASSEX
    wndClass.Zero()
    wndClass.SetNum(0, "UInt", wndClass.Size)            # cbSize
    wndClass.SetNum(8, "Ptr",  proc.ptr)                 # lpfnWndProc
    wndClass.SetNum(auX64 ? 64 : 40, "Ptr", name.ptr)    # lpszClassName

    If Not DllCall("RegisterClassExA", "Ptr", wndClass.Ptr) Then
       MsgBox('Ошибка регистрации класса "MyInvisibleReceiver"')
       Return 0
    EndIf
    Free(wndClass)
    
    # Message-Only window
    Static HWND_MESSAGE = -3
    Local hwnd = DllCall("CreateWindowExA", _
          "Dword", 0, _
          "Str", text, _ 
          "Str", "HiddenWindow", _
          "Dword", 0, _
          "Int", 0, "Int", 0, "Int", 0, "Int", 0, _
          "Ptr", HWND_MESSAGE, _
          "Ptr", 0, "Ptr", 0, "Ptr", 0, "Ptr")
                    
    If Not hwnd Then
       MsgBox 'Ошибка создания окна "HiddenWindow"'
       Return 0
    EndIf
    
    Static RIDEV_INPUTSINK = 0x00000100
    
    Local rid, buf
    rid = Buffer(8 + auPtrSize, 0)
    rid.Zero()
    rid.SetNum(0, "UShort", 1, "UShort", 2, "UInt", RIDEV_INPUTSINK, "Ptr", hwnd)
    
    # Регистрация устройства
    If Not DllCall("RegisterRawInputDevices", "Ptr", rid.Ptr, "UInt", 1, "UInt", 8 + auPtrSize) Then
       MsgBox("Ошибка регистрации Raw Input")
       Return 0
    EndIf
    
    buf = Buffer(auX64 ? 56 : 28)
    While 1
       DllCall("GetMessage", "ptr", buf.ptr, "hwnd", hwnd, "uint", 0, "uint", 0) 
       DllCall("TranslateMessage", "ptr", buf.ptr)
       DllCall("DispatchMessage", "ptr", buf.ptr)
    Wend
    Free(rid, buf)
    Return 1
EndFunc

Func ReceiverWndProc(hwnd, uMsg, wParam, lParam)
    If uMsg = 0x00FF Then 
       OnRawInput(hWnd, uMsg, wParam, lParam)
    EndIf
    Return DllCall("DefWindowProc", _
                   "hwnd", hWnd, "uint", uMsg, "wparam", wParam, "lparam", lParam, "ptr")
EndFunc

Func OnRawInput(hWnd, uMsg, wParam, lParam)
    Static RID_INPUT = 0x10000003, _
           RI_MOUSE_LEFT_BUTTON_DOWN = 0x0001

    # Получение размера данных           
    Local size = 0    
    DllCall("GetRawInputData", "Ptr", lParam, "UInt", RID_INPUT, "Ptr", 0, "UInt*", @size, "UInt", 8 + auPtrSize * 2)
    
    If size <= 0 Then Return

    Local raw = Buffer(size)
    DllCall("GetRawInputData", "Ptr", lParam, "UInt", RID_INPUT, "Ptr", raw.ptr, "UInt*", @size, "UInt", 8 + auPtrSize * 2)

    # Извлечение флагов кнопок мыши    
    Local headerSize = auX64 ? 24 : 16
    Local btnFlags = raw.GetNum(headerSize + 4, "UShort")
    Free(raw)

    # Проверка левого клика
    If Not BitAND(btnFlags, RI_MOUSE_LEFT_BUTTON_DOWN) Then Return

    # Проверка состояния Shift
    If Not IsPressed(0x10) Then Return

    # Произошло нажатие Shift + Left Down
    HandleAction()
EndFunc

Func HandleAction()
    Local x, y
    MouseGetPos("x","y")
    
    # Дескриптор окна под курсором
    Local hWnd = DllCall("WindowFromPoint", "Int64", MakeInt(x, y, 2), "Ptr")    
    If Not hWnd Then Return

    # Переход к главному родительскому окну    
    Local rootHWnd = DllCall("GetAncestor", "Ptr", hWnd, "UInt", 2)

    # Буфер для получения имени класса    
    Static classBuffer = Buffer(512)
    classBuffer.Zero()

    # Получение имени класса
    Static WM_NCHITTEST = 0x0084
    DllCall("GetClassName", "Ptr", rootHWnd, "Ptr", classBuffer.Ptr, "Int", 256)    
    Local hitTest = DllCall("SendMessage", _
                            "Ptr", rootHWnd, "UInt", WM_NCHITTEST, "Ptr", 0, "Ptr", MakeInt(x, y, 0))
    # Проверка области клика                            
    Static HTCAPTION = 2
    Local isTitleBar = (hitTest = HTCAPTION)
    
    If isTitleBar And classBuffer.GetStr() = "TLister" Then 
       AlignListerWindow()
    EndIf   
    
    # MsgBox("Класс: " & classBuffer.GetStr() & auCRLF & "Заголовок: " & (isTitleBar ? "Да" : "Нет"))
EndFunc
[/cut]

Решение полностью рабочее. Перехват клика в других окнах помимо листера еще может пригодиться.
FallenAngel писал(а):Я все равно не понимаю, почему просто не сменить:
Ну попробуйте, никто ведь не мешает. Может я и перегнул палку, вдруг у вас все заработает.

Если используется ResolutionSpecific=0, то надо проверить, как поведет себя запись в AllResolutions. Но если в секции Buttonbar есть ключи типа Buttonheight96 и SmallIconSize96, то простая смена Buttonheight и SmallIconSize точно работать не будет.

В любом случае, даже если у вас все получится, то это будет только на тоненького и только для вашей сборки и скорее всего до первой смены параметров DPI дисплея.
FallenAngel
Сообщения: 47
Зарегистрирован: Вт дек 30, 2025 20:01

Сообщение FallenAngel »

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

Func Notebook
    If IniRead(COMMANDER_INI, "AllResolutions", "Iconsize32") = 16 Then
        IniWrite %COMMANDER_INI% "AllResolutions" "Iconsize32" "24"
    Else
        IniWrite %COMMANDER_INI% "AllResolutions" "Iconsize32" "16"
    EndIf
    If IniRead(COMMANDER_INI, "Buttonbar", "Buttonheight") = 30 Then
        IniWrite %COMMANDER_INI% "Buttonbar" "Buttonheight" "37"
    Else
        IniWrite %COMMANDER_INI% "Buttonbar" "Buttonheight" "30"
    EndIf
    If IniRead(COMMANDER_INI, "Buttonbar", "SmallIconSize") = 16 Then
        IniWrite %COMMANDER_INI% "Buttonbar" "SmallIconSize" "24"
    Else
        IniWrite %COMMANDER_INI% "Buttonbar" "SmallIconSize" "16"
    EndIf
    SendCommand cm_Exit 9
EndFunc 
Как мне обыграть что у SmallIconSize может отсутствовать знание, но по-умолчанию считаем что 16 ?
Аватара пользователя
Orion9
Сообщения: 1283
Зарегистрирован: Пн янв 01, 2024 17:18

Сообщение Orion9 »

FallenAngel писал(а):Как мне обыграть что у SmallIconSize может отсутствовать знание, но по-умолчанию считаем что 16 ?
Добавить еще один параметр <default>

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

IniRead(["~[/R]",] <ini>, <section, <key>[, <default>])
IniRead [/R] <VAR> <ini> <section> <key>[ <default>]
Т.е.

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

If IniRead(COMMANDER_INI, "AllResolutions", "Iconsize32", 16) = 16 Then
P.s. Так изменение всех этих параметров дает нужный эффект? А то я так и не проверил.
FallenAngel
Сообщения: 47
Зарегистрирован: Вт дек 30, 2025 20:01

Сообщение FallenAngel »

Да, спс, все получилось. Хотелось бы в идеале без рестарта, но хоть так.
Аватара пользователя
Orion9
Сообщения: 1283
Зарегистрирован: Пн янв 01, 2024 17:18

Сообщение Orion9 »

FallenAngel
Это еще одна проблема. Записать ключи в INI недостаточно, нужно еще как-то подстимулировать тотал, чтобы он их перечитал, но, к сожалению, это не всегда удается.

Иногда помогают специальные команды cm_ReloadBarIcons, cm_ReloadFileIcons или cm_RereadSource, но в данном случае они не работают. Навскидку работает:

1) Для панели инструментов
- скрыть и заново отобразить панель

2) Для файловой панели
- сменить режим просмотра (можно потом вернуть свой)

Может еще что-то есть, но я глубоко не проверял.

Если применить эти команды (из пунктов 1 и 2), то главное окно ТС (скорее всего) будет неприятно дергаться и перерисовываться. Чтобы этого не происходило, можно заблокировать окно перед выполнением команд и затем снова его разблокировать:

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

SendMessage(AUTORUN_TCHANDLE, 11, 0, 0)
...
команды
команды
...
Sleep(50)
SendMessage(AUTORUN_TCHANDLE, 11, 1, 0)
WinRedraw(1)
Значение Sleep нужно подобрать под себя, оптимальное. Поскольку команды выполняются несинхронно с Autorun, он их не ждет и движется дальше. Может получится так, что окно разблокируется раньше, чем команды завершились, это сведет на нет саму блокировку, т.е. окно все-равно будет перерисовываться перед глазами.

Нет никаких гарантий, что все получится. Т.ч. вариант с перезагрузкой вполне себе вариант, хоть и крайний.
AkulaBig
Сообщения: 638
Зарегистрирован: Ср дек 03, 2008 11:48

Сообщение AkulaBig »

Orion9 писал(а):Скорость - космос.
Наконец-то дошли руки до тестирования. Идея стала понятна. Только воплотить пока не удается. Вот накропал код на основе вашего:

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

Func ET1(FileName, FieldIndex, UnitIndex)
	Local ExifToolPID = 0, ExifToolOut = TEMP & "\exiftool_out.txt", ExifToolArgs = TEMP & "\exiftool_args.txt"

	If StrPos(FileGetAttr(FileName), "D") Then Return

	ExifToolPID = ProcessGetId("exiftool.exe")
	If ExifToolPID = 0 Then
		FileWrite(ExifToolArgs, "", "UTF-8 NOBOM")
		ShellExec /TT /SW_HIDE %util_ET% "-stay_open True -@ ""%ExifToolArgs%"""
	EndIf

	If FileExist(ExifToolOut) Then
		ShellExec /SW_HIDE %COMSPEC% '/c del /f /q "%gExifOut%"'
	EndIf

	Local sArgs = "-f" & auCRLF & _
		"-s3" & auCRLF & _
		"-m" & auCRLF & _
		"-q" & auCRLF & _
		"-q" & auCRLF & _
		"-Title" & auCRLF & _
		"-W+!" & auCRLF & ExifToolOut & auCRLF & FileName & auCRLF & "-execute" & auCRLF

	Local obj = BinaryFile(ExifToolArgs, "a")
	obj.WriteStr(sArgs, "", "UTF-8")
	Free(obj)

	ansi = "<time-out>"
	For i = 1 To 50
		If FileExist(ExifToolOut) Then
			ansi = FileRead(ExifToolOut)
			ShellExec /SW_HIDE %COMSPEC% '/c del /f /q "%ExifToolOut%"'
			Break
		EndIf
		Sleep(20)   # time-out
	Next

	Return ansi
EndFunc
Пока без всяких преобразований кривой кодировки. Только код вывода данных. Вывожу только одно поле Title. Работает также медленно, но это из-за того что здесь я применил ваш код задержки чтения из временного файла. Если убрать ненужные задержки скорость норм. Но вот беда. Вывод получается вот таким:
Изображение
Слева как должно быть, справа как получается. Сначала я подумал, что кривой код. Но похоже код не успевает отработать. Ваша подсказка работает только для одного файла. А когда надо много обработать, вот такая фигня получается.
Может у вас есть какие-то идеи?
Аватара пользователя
Orion9
Сообщения: 1283
Зарегистрирован: Пн янв 01, 2024 17:18

Сообщение Orion9 »

AkulaBig
Я поздно увидел ваше сообщение. Теперь только завтра смогу посмотреть.
AkulaBig
Сообщения: 638
Зарегистрирован: Ср дек 03, 2008 11:48

Сообщение AkulaBig »

Orion9
Я его и написал поздно. Надо еще с ProcessExecGetOutput попробовать. Боюсь проблема как-то связана с wait.
Аватара пользователя
Orion9
Сообщения: 1283
Зарегистрирован: Пн янв 01, 2024 17:18

Сообщение Orion9 »

AkulaBig писал(а): Сначала я подумал, что кривой код. Но похоже код не успевает отработать.
Так и есть. Для этого там и стоит задержка. ExifTool в режиме -stay_open тупо дергает файл с параметрами каждые 10 миллисекунд и проверяет не появились ли там новые команды. Когда новые команды появляются, результат их выполнения сохраняется в другой файл. Заранее не известно, когда этот файл появится, поэтому приходится ждать его появления. Если в течении 1 секунды файл не появляется, скрипт вернет текст "<time-out>", который и попадет в поле.

И хотя кажется, что задержка может быть большой, на самом деле всё происходит быстро: на порядок быстрее, чем просто вызывать ExifTool для каждого файла по отдельности.

Если убрать задержку, Autorun начнет считывать данные быстрее, чем новые данные будут приходить от ExifTool, поэтому приходится переодически проверять существование файла в цикле с небольшой задержкой.

Но это никак не должно влиять на скорость. У меня сейчас подсказка ExifTool на видео файлах открывается мгновенно, не говоря уж об аудио или картинках. Скорость ничем не уступает MediaInfo, можете сами проверить. У вас вроде есть последняя версия набора скриптов. На предыдущей странице я сбрасывал концовку модуля MediaInfo.aucfg. Смена подсказки по Alt+F12.

А почему у вас нет прироста в скорости, я не знаю. Вроде бы всё как надо сделано. Ну если только убрать запуск ExifTool во вне, и проверку существования процесса не делать в теле функции, а заменить проверкой переменной (флага). Функция будет вызывается для всех полей, это тоже надо будет в будущем учитывать.
AkulaBig
Сообщения: 638
Зарегистрирован: Ср дек 03, 2008 11:48

Сообщение AkulaBig »

Orion9 писал(а):Но это никак не должно влиять на скорость.
Не стоит это сейчас обсуждать. У вас еще приведено решение задержки от ИИ через While. У себя я его тестил и мне больше понравилось. Давайте лучше разберемся, почему код не работает. Я уже написал выше. У вас выводится подсказка для одного файла. Как видите, ваш код для пользовательских колонок работает неправильно (или я что-то неправильно пишу, хотя вроде практически один в один ваш код). И я про задержки в этом варианте имею ввиду. То-есть есть подозрение, что функция не годится для обработки множества файлов.
Аватара пользователя
Orion9
Сообщения: 1283
Зарегистрирован: Пн янв 01, 2024 17:18

Сообщение Orion9 »

AkulaBig
Похоже, какая-то проблема действительно есть. Не всё так гладко, как я думал.

Вообще-то, я проверял не только подсказку, но и набор колонок. На предыдущей странице я его выкладывал

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

Widths32=80,30,30,30,30,30,30,30,30,30,30,30,30
Headers32=C1\nC2\nC3\nC4\nC5\nC6\nC7\nC8\nC9\nC10\nC11
Contents32=[=autorun.C1]\n[=autorun.C2]\n[=autorun.C3]\n[=autorun.C4]\n[=autorun.C5]\n[=autorun.C6]\n[=autorun.C7]\n[=autorun.C8]\n[=autorun.C9]\n[=autorun.C10]\n[=autorun.C11]
Options32=-1|0|96
Этот набор специально был создан для того, чтобы проверить скорость. Но я даже не посмотрел, что там зажато в самих колонках, только обратил внимание, что они грузятся гораздо быстрее по сравнению со старым вариантом, где ExifTool вызывается для каждого файла.

Удивляет, что с подсказкой проблем вроде нет, а значит действительно что-то может быть с набором. Я чуть попробовал, такое ощущение, что файл просто не успевает удаляться вот этой строчкой

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

ShellExec /SW_HIDE %COMSPEC% '/c del /f /q "%gExifOut%"'
Пришлось поставить задержку

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

ShellExec /SW_HIDE /WAIT:500 %COMSPEC% '/c del /f /q "%gExifOut%"'
Так лучше, но тоже не гарантия, и задержку увеличивает. Т.ч. в итоге подобное использование может и правда оказаться непригодным. Если Loopback вернется, починит FileDelete, можно будет еще раз пробовать. А пока придется искать другие решения, наверное.
AkulaBig
Сообщения: 638
Зарегистрирован: Ср дек 03, 2008 11:48

Сообщение AkulaBig »

Orion9 писал(а):/WAIT
Вот-вот. Я выше писал про это в другом случае. Там тоже без задержки работало быстро, но неправильно, а с задержкой очень медленно. Это при выводе самих данных. Из-за этого я перешел на буфер обмена. Но данные можно обрабатывать без ShellExec, а удалить файл пока никак.
Так что без сансея точно ничего не решим.
Правда у меня возник вопрос. В ваших постах об ИИ я встретил интересную фишку. Файл очищается с помощью команды break. Не знал о таком ее применении. Интересно, чтобы -execute сработало файл именно удалять нужно? А может достаточно изменения?

Добавлено спустя 1 час 58 минут:

Orion9
Вроде получилось более-менее решить вопрос с задержкой, заменив вашу на от ИИ:

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

# ждем, пока ExifTool создаст файл (цикл ожидания)
Local WaitCount = 0
While Not FileExist("%gExifOut%")
	Sleep 50
	WaitCount = WaitCount + 1
	if WaitCount > 20 then Break # Таймаут 1 сек
Wend
Правда идут пропуски выводы данных. Не все наименования выводятся. Видимо надо очень кропотливо подбирать значения задержки. Но не вижу в этом смысла, так как работает это точно также, как и без -stay_open. Очень длинное зависание и потом данные выводятся. Насколько понимаю, ShellExex может работать только так. Надо попробовать реализовать этот код в au3. Вдруг там это даст прирост скорости.
Ответить