Autorun

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

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

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

Сообщение Orion9 »

Только не сбивайте мне вайб, у меня маза пошла, иду на рекорд :mrgreen:

Титаник и Леон лежат ровно, чего не скажешь о бэкапах ТС - их словно пробили на перфокарте )

[cut]Изображение[/cut]

Шутки шутками, а я нашёл серьёзный косяк. Не учёл, что панель может изменяться не только при перетаскивании кнопок, но и при обычных операциях копирования и вставки. Соответственно, индекс нарушался. Внёс небольшие изменения, а также добавил ключ "/R", который забыл в прошлый раз добавить.
[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 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
             #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)
    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' & 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
[/cut]
И хотя всё работает, от глюков по-прежнему гарантий нет. Так что делайте резервные копии, если будете пользоваться. А мы тем временем еще раз продемонстрируем Гислеру как происходит "случайное" перетаскивание кнопок на главной панели инструментов:

[cut]Изображение[/cut]

Ладно, пора заканчивать этот кордебалет. Осталось только бандл завернуть, и в общем-то для этого всё уже почти готово.
Loopback
Сообщения: 1646
Зарегистрирован: Пн сен 07, 2009 09:29

Сообщение Loopback »

Orion9 писал(а):Касаемо Autorun, не совсем понятно, что именно происходит при запуске длительных операций из нескольких кнопок. Как осуществляется многозадачность? Тоталу отсылается номер зарегистрированной команды и адрес привязанной функции, а он уже сам дальше ее крутит? Крутит в своем отдельно созданном для этого потоке?
Многозадачности тут нет. Когда тотал выполняет команду из кнопки, он посылает сообщение WM_USER + 51 с помощью PostMessage, которое перехватывает хук, устанавливаемый Autorun. Если переданный номер команды зарегистрирован, то управление передается скриптовой функции, если нет - передается дальше тоталу.

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

Сообщение Orion9 »

Ну всё, не выйдет из меня рекордсмена :mrgreen: Такой шанс упустил )

Loopback
Спасибо за объяснение. Будем юзать потоки, и Autorun будем юзать. Ведь Autorun - это сила, движение и жизнь :mrgreen:

[cut]Изображение[/cut]
Аватара пользователя
Orion9
Сообщения: 1283
Зарегистрирован: Пн янв 01, 2024 17:18

Сообщение Orion9 »

Если Autorun не скриптовый язык, то на чём тогда 11,000 строк написано? :mrgreen:
https://www.upload.ee/files/18792409/TC.11.51.7z.html

P.S. Описания на последний функционал, к сожалению, нет. Всё есть на последних страницах темы и чуть далее, если кому-то будет нужно.
AkulaBig
Сообщения: 639
Зарегистрирован: Ср дек 03, 2008 11:48

Сообщение AkulaBig »

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

Сообщение Orion9 »

AkulaBig
А что там может зависеть? Последние версии ТС это тупо обновления rar, 7z и кодеков.

Ну ладно, про кодеки шучу, но у маэстро реальный авторский блок и застой идей. Я уже писал об этом год назад. А потому спасение утопающих - дело рук самих утопающих. Autorun дает всю полноту спектра действий, что говорится Гислеру и не снилось. Это ж надо было так положить всю Виндузу к ногам ТС, на такое способен только настощий мастер - Loopback.

В сборке последняя версия Autorun и практически все скрипты, которые у меня есть. Понятно, что Autorun не для всех и некоторые скрипты довольно сложные, я старался в последнее время делать все модульно - подключил модуль и забыл. Но, к сожалению, не всегда так получается, иногда нужно еще в ini файлы настройки вносить, и не в один. Но кого заинтересует функционал, думаю, разберется. Никаких ограничений нет, можете пользоваться всем как сочтете нужным.
AkulaBig
Сообщения: 639
Зарегистрирован: Ср дек 03, 2008 11:48

Сообщение AkulaBig »

Orion9 писал(а):А что там может зависеть?
Например, проблема, которую мы долго и тщательно обсуждали с Loopback. Улет сообщения об ошибки за пределы экрана в х64. Она исчезла, хотя Loopback ее не устранил. А у вас вроде много кода, где используются окна.
Аватара пользователя
Orion9
Сообщения: 1283
Зарегистрирован: Пн янв 01, 2024 17:18

Сообщение Orion9 »

AkulaBig
ТС х64 в конексте Autorun это отдельная песня, вы же знаете. Поэтому могут быть косяки, и наверняка они есть.

Я, если честно, даже не проверил (не успел просто) работоспособность сборки в х64, и, видимо, напрасно. Сейчас запустил и сразу же заметил, что функционал CapsLock сломан. Поскольку конфиг autorun.cfg остался в сборке старый, в нем отсутствует последние мелкие изменения, но одно из них критичное - ключ /S на CapsLock и возврат кода -1 в привязанной функции:

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

SetHotkeyAction /S /V:20   JoinHintLock 1
SetHotkeyAction /V:20 /K:S JoinHintLock 2
SetHotkeyAction /V:20 /K:C JoinHintLock 3
SetHotkeyAction /V:20 /K:A JoinHintLock 4

Func JoinHintLock(lParam)
    If MediaInfoLock > 0 Then 
       MediaInfoLock = 0
    Else
       MediaInfoLock = 1
    Endif  
    If lParam = 2 Then MediaInfoLock = 2
    If lParam = 3 Then MediaInfoLock = 3 
    If lParam = 4 Then MediaInfoLock = 4   
    Return -1
EndFunc
В секцию финализации, пожалуй, тоже можно добавить

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

If gHBarWndProc > 0 Then 
    DllCall("SetWindowLong" & (auX64 ? "PtrW" : "W"), _
            "hwnd", hBarWnd, "int", -4, "long_ptr", gHBarWndProc, "ptr")
EndIf
чтобы х64 не крашился при закрытии (хоть и через раз, но помогает).

Забыл еще путь к exiftool поменять в модуле MediaInfo. Без него переключение подсказки по Alt+F12 не срабатывает, и непонятно сразу в чем проблема.

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

Global gMediaExifX32 = COMMANDER_PATH & "\Tools\ExifTool\exiftool.exe"
В общем, признаю - фиговенько бандл завернул :) Многие интересные вещи забыл, например добавить монитор каталога в планировщик, которым я в действительности пользуюсь:
[cut="Title\Config.ini"][Schedule]
em_update_wdx_menu=1800,10,2,Updating Wdx Array
81000=3600,30,50,Directory Monitor[/cut]
Хайлайтер от yozhik забыл обновить. Да там копни - много чего можно обнаружить, но перезаливать из-за этого пока не буду. Основная цель ведь не предоставить готовый функционал как таковой, а обменяться идеями.
Аватара пользователя
Orion9
Сообщения: 1283
Зарегистрирован: Пн янв 01, 2024 17:18

Сообщение Orion9 »

AkulaBig
Все-таки перезалил с последней версией ТС.
Может и будет что-то не рвботать, но главное, что все скрипты собраны в одном месте.

Хотел было и другие компоненты обновить, типа ExifTool и MediaInfo.dll, но подумал что нет смысла.
AkulaBig
Сообщения: 639
Зарегистрирован: Ср дек 03, 2008 11:48

Сообщение AkulaBig »

Orion9 писал(а):AkulaBig
Все-таки перезалил с последней версией ТС.
Ну и правильно. А то кто-нибудь да напишет, что у него не работает, что работает у вас.
Аватара пользователя
Orion9
Сообщения: 1283
Зарегистрирован: Пн янв 01, 2024 17:18

Сообщение Orion9 »

AkulaBig
Сломанный Capslock был реальныи зашкваром, оставлять в таком виде было нельзя. А так, мне кажется, большой разницы между ТС 11.51 и ТС 11.56 нет, всё работает и там, и там.

Loopback
Вызов работает

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

DllCall("GetVolumeInformationW", _
"wstr", sDrive, "wstr:256", @sName, "dword", 512, "ptr", 0, "ptr", 0, "ptr", 0, "wstr:256", @sFS, "dword", 512)
Если сравнивать эти два вызова

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

Static nam = Buffer(512), fs = Buffer(512)
nam.Zero()
fs.Zero()       
DllCall("GetVolumeInformationW", _
        "wstr", sDrive, "ptr", nam.ptr, "dword", 512, "ptr", 0, "ptr", 0, "ptr", 0, "ptr", fs.ptr, "dword", 512)
sName = nam.GetStr()
sFS = fs.GetStr()
они полностью эквивалентны?
Аватара пользователя
Orion9
Сообщения: 1283
Зарегистрирован: Пн янв 01, 2024 17:18

Сообщение Orion9 »

Autorun большая плюшка
Раз, два, три и есть менюшка )

[cut="Drives.aucfg"]

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

Pragma IncludeOnce

Global hDiskWnd, gDiskWndProc, gBindDiskWnd = true

Global gDriveList = List()

ControlSetMouseAction /R 15 DrivesMenu
ControlSetMouseAction /K:S /R 15 DrivesMenu
ControlSetMouseAction /K:C /R 15 DrivesMenu

If gBindDiskWnd Then
   Global gDiskWP = Callback("DiskWndProc", "hwnd;uint;wparam;lparam")
   hDiskWnd = WinFind(AUTORUN_TCHANDLE, _
              AUTORUN_TCARCH = 32 ? "TMyPanel" : "Window", AUTORUN_TCARCH = 32 ? 6 : 10)
   If hDiskWnd > 0 Then
      gDiskWndProc = DllCall("SetWindowLong" & (auX64 ? "PtrW" : "W"), _
                             "hwnd", hDiskWnd, "int", -4, "long_ptr", gDiskWP.Ptr, "ptr")   
   EndIf
EndIf

Func DiskWndProc(hWnd, uMsg, wParam, lParam)
    Static WM_LBUTTONDOWN = 0x0201, _
           WM_RBUTTONDOWN = 0x0204
    Switch uMsg
       Case WM_RBUTTONDOWN
          DrivesMenu
    EndSwitch
    Return DllCall("CallWindowProcW", _
                   "ptr", gDiskWndProc, "hwnd", hWnd, "uint", uMsg, "wparam", wParam, "lparam", lParam)
EndFunc

Func DrivesMenu()
    ShowPopupMenu /D /F "CreateDrivesMenu"
    #ShowPopupMenu /D /F /I:24 "CreateDrivesMenu"    
EndFunc

Func CreateDrivesMenu()
    Local txt, bBuffer, bLine, bExtra
    Local bRecInfo = IsPressed(0x10) ? false : true
    If IsPressed(0x11) Then
       bBuffer = true
       bLine = true
       bExtra = true
    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    
    Local i = 0, sz, sDrive
    gDriveList.Count = 0
    While 1
       sDrive = buf.GetStr(i)
       sz = StrLen(sDrive)
       If sz = 0 Then break
       gDriveList.add(sDrive)
       i = i + sz*2 + 2
    Wend
    Local sVolume, nCluster, nSector, nFree, nTotal, sName, sFS
    txt = 'MENUITEM "Этот компьютер", em_aucmd Shell32.dll,15 CommandExec cm_OpenDesktop' & auCRLF
    txt &= 'MENUITEM SEPARATOR' & auCRLF
    For i = 0 To gDriveList.Count - 1
       sDrive = gDriveList[i]
       Local nDriveIco
       Local nDriveType = DllCall("GetDriveType", "wstr", sDrive, "uint")
       Switch nDriveType
         Case 0 To 1
            nDriveIco = 53	# DRIVE_UNKNOWN
         Case 2
            nDriveIco = 6	# DRIVE_REMOVABLE
         Case 3
            nDriveIco = 8	# DRIVE_FIXED
         Case 4
            nDriveIco = 9	# DRIVE_REMOTE
         Case 5
            nDriveIco = 11	# DRIVE_CDROM           
         Case 6
            nDriveIco = 12	# DRIVE_RAMDISK
         Else
           nDriveIco = 7	# DEFAULT
       EndSwitch
       If sDrive = SystemDrive & "\" Then
          sDriveIco = "imageres.dll,31"
       Else
          sDriveIco = "shell32.dll," & nDriveIco
       EndIf   
       nFree = 0
       nTotal = 0
       DllCall("GetDiskFreeSpaceW", "wstr", sDrive, _
                                    "dword*", @nCluster, "dword*", @nSector, _
                                    "dword*", @nFree, "dword*", @nTotal)
       If nTotal = 0 Then
          IF nDriveIco = 11 Then sDrive = "CD-ROM (" & StrReplace(sDrive, "\", "") & ")"
          txt &= 'MENUITEM "' & sDrive & '\t' & '", em_aucmd /D ' & sDriveIco & " DrivesMenuGoto " & i & auCRLF
          If bLine Then
             txt &= 'MENUITEM "' & Chr(9620) & '\t'  & "" & '"'& auCRLF
          EndIf          
          Continue
       EndIf 
       Local nLine = 25 - Ceil(nFree/nTotal*25)
       Local sLine = StrRepeat(Chr(9620), nLine)
       Local nBytes = nCluster*nSector
       Local nPrc = Round(100 - nFree/nTotal*100,0) & "%"       
       Local nSize = SizeFormat(nFree*nBytes, 1, "T", 1, 3) & " / " & SizeFormat(nTotal*nBytes, 1, "T", 1, 3) & " "      
       DllCall("GetVolumeInformationW", _
               "wstr", sDrive, "wstr:256", @sName, "dword", 512, "ptr", 0, "ptr", 0, "ptr", 0, "wstr:256", @sFS, "dword", 512)
       If bBuffer Then        
          Static nam = Buffer(512), fs = Buffer(512)
          nam.Zero()
          fs.Zero()       
          DllCall("GetVolumeInformationW", _
                  "wstr", sDrive, "ptr", nam.ptr, "dword", 512, "ptr", 0, "ptr", 0, "ptr", 0, "ptr", fs.ptr, "dword", 512)
          sName = nam.GetStr()
          sFS = fs.GetStr()
       EndIf   
       nSize = SizeFormat(nFree*nBytes, 1, "T", 1, 3) & " из " & SizeFormat(nTotal*nBytes, 1, "T", 1, 3) & " свободно"
       sDrive = sName & " (" & StrReplace(gDriveList[i], "\", "") & ")"
       txt &= 'MENUITEM "' & sDrive & "  " & nSize  & '\t'  & nPrc & '", em_aucmd ' & sDriveIco & " DrivesMenuGoto " & i & auCRLF
       If bLine Then
          txt &= 'MENUITEM "' & sLine & '\t'  & "" & '", em_aucmd ' & "-1" & " DrivesMenuGoto " & i & auCRLF
       EndIf
    Next
    Local rbSize, rbNumber, sRecInfo
    If bRecInfo Then
       RecycleBinInfo(rbSize, rbNumber)
       sRecInfo = SizeFormat(rbSize, 1, "T", 1, 3) & ", " & rbNumber & " элементов"
    EndIf   
    txt &= 'MENUITEM SEPARATOR' & auCRLF
    txt &= 'MENUITEM "Корзина:  ' & sRecInfo &'" , cm_OpenRecycled' & auCRLF
    If bExtra Then
       txt &= 'MENUITEM SEPARATOR' & auCRLF    
       txt &= 'MENUITEM "Сеть", cm_OpenNetwork'  & auCRLF
       txt &= 'MENUITEM "Панель управления", cm_OpenControls' & auCRLF
    EndIf   
    Return txt
EndFunc

Func DrivesMenuGoto(nItem)
   If IsPressed(0x11) Then
      SendCommand("cm_OpenDriveByIndex", nItem+1)
      Return
   EndIf
   Local Target = gDriveList[nItem]
   If RequestInfo(1000) = 1 Then
      CommandExec /CD %'Target'
   Else
      CommandExec /CD '' %'Target'
   Endif
EndFunc

Func RecycleBinInfo(ByRef nSize, ByRef nNumber)
    Static buf = Buffer(auX64 ? 24 : 20)
    buf.Zero()
    buf.SetNum(0, "dword", buf.size)
    DllCall("Shell32.dll\SHQueryRecycleBinW", "ptr", 0, "ptr", buf.ptr)
    If auX64 Then
       nSize = buf.GetNum(8, "int64")
       nNumber = buf.GetNum(16, "int64")    
    Else
       nSize = buf.GetNum(4, "int64")
       nNumber = buf.GetNum(12, "int64")    
    EndIf
EndFunc
[/cut]
Функция перечисления дисков была реализована еще в модуле Torrents.aucfg, но не пропадать же добру напрасно? Решил, что можно развить эту тему и придать функции вторую жизнь.

Меню отображает логические диски с расширенной информацией о размере и занятом пространстве. Вызов с CTRL добавляет полосу для графического представления, но полоса не является графическим объектом (обычный юникодный символ), поэтому смотрится так себе.

Меня больше привлекла возможность использовать это меню в полноэкранном режиме, вызывая его, например, кликом рядом с вкладками или горячей клавишей, но можно использовать и по-другому. Выбор пункта открывает корень диска. Удержание CTRL - текущий каталог на диске.

Есть у меня террабайтный диск, которому больше 10 лет. Большую часть времени он просто спит. Но в последнее время стал просыпаться медленно, и если вызвать меню в этот момент, то оно может не сразу появиться.

Похоже, это происходит из-за подсчета места в корзине, пришлось добавить еще один модификатор Shift. Вызов меню с Shift не вызывает функцию RecycleBinInfo, которая получает сведения о корзине.

В общем, меню пока очень и очень эксперементальное. Над новыми пунктами и функционалом еще можно подумать.

Loopback
Пока я оставил оба варианта в коде, как вы можете видеть. Вопрос больше связан с примером в справке:

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

Local sysdir
DllCall("GetSystemDirectoryW", "wstr:256", @sysdir, "int", 255)
Почему используется int 255 и какой размер буфера создает wstr:256?

Еще вопрос. ControlSetMouseAction /R 15 DrivesMenu, получается, кликает по кнопкам [\] и [..], можно сделать, чтобы эти кнопки не попадали в индекс 15?

P.S.

Лень все-таки была побеждена, и сводка по зарегистрированным командам родилась.

[cut]

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

# Alt + "\"
SetHotkeyAction /K:A /V:220 ModuleRegInfo

Global aModuleName = List()

Func ModuleRegInfo()
    AutorunModules()
    Global gRegCmdCount = 0, gRegCmdName
    ShowPopupMenu /D /F /I:0 "ModuleRegInfoMenu"
EndFunc

Func AutorunModules()
    Local j = 1, s = ""
    Static p = GetState("paths")
    aModuleName.Count = 0   
    While 1 
       s = StrPart(p, auCRLF, j)      
       If ERROR = 1 then break
       If StrPos(s , '#') And StrRight(s, 3) ="cfg" Then
          s = StrPart(StrTrim(s), ": ", 2)
          aModuleName.Add(s)
       Endif 
       j += 1
    Wend
EndFunc

Func ModuleRegInfoMenu()
    Local mnu, txt, text, rex, reg, nRegs, name, i, cmd
    Static lst = List("RegisterCommand", "SetHotkeyAction", "ControlSetMouseAction")    
    Static c = 0
    c += 1
    If c > lst.Count Then c = 1
    cmd = lst[c-1]
    For i = 0 To aModuleName.Count - 1
        text = FileRead(aModuleName[i])
        rex = RegExp("(.)(" & cmd & ".*?)\r\n", text)
        txt = ""
        reg = 0
        If rex.Exec() Then
            Do
              reg += 1
              mark = rex.Match[1] = Chr(10) ? "" : "/D"
              txt &= 'MENUITEM "' & StrReplace(rex.Match[2],'"',"") & '", em_aucmd ' & mark & auCRLF              
            Until not rex.ExecNext()
            gRegCmdCount += reg
            name = FileGetBaseName(aModuleName[i])        
            mnu &= 'POPUP "' & name & ' (' & reg & ')"' & auCRLF
            mnu &= txt & auCRLF        
            mnu &= 'END_POPUP' & auCRLF
        EndIf
        Free(rex)        
    Next
    gRegCmdName = cmd
    mnu = 'MENUITEM "' & cmd & '", em_aucmd -1 ClipPut %"gRegCmdName"' & auCRLF & _
          'MENUITEM SEPARATOR' & auCRLF & mnu & auCRLF & _
          'MENUITEM SEPARATOR' & auCRLF & _
          'MENUITEM "Total commands:  ' & gRegCmdCount & '", em_aucmd'
    Return mnu
EndFunc
[/cut]
Регулярные выражения, конечно, значительно упростили задачу, спасибо за функционал. Само меню выглядит так:
[cut]Изображение[/cut]
Неактивные пункты значит команда находится не в начале строки и скорее всего закомментирована или ее имя просто упоминается где-то в переменных или функциях.
Аватара пользователя
Orion9
Сообщения: 1283
Зарегистрирован: Пн янв 01, 2024 17:18

Сообщение Orion9 »

Loopback
После внесения последних изменений заметил косяк неприятный. Вот так в ТС х64 не работает:
[cut]

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

Global hDiskWnd, gDiskWndProc, gBindDiskWnd = true

Global gDriveList = List()

ControlSetMouseAction /R 15 DrivesMenu
ControlSetMouseAction /K:S /R 15 DrivesMenu
ControlSetMouseAction /K:C /R 15 DrivesMenu

If gBindDiskWnd Then
   Global gDiskWP = Callback("DiskWndProc", "hwnd;uint;wparam;lparam")
   hDiskWnd = WinFind(AUTORUN_TCHANDLE, _
              AUTORUN_TCARCH = 32 ? "TMyPanel" : "Window", AUTORUN_TCARCH = 32 ? 6 : 10)
   If hDiskWnd > 0 Then
      gDiskWndProc = DllCall("SetWindowLong" & (auX64 ? "PtrW" : "W"), _
                             "hwnd", hDiskWnd, "int", -4, "long_ptr", gDiskWP.Ptr, "ptr")   
   EndIf
EndIf
[/cut]
А вот так работает:
[cut]

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

Global hDiskWnd, gDiskWndProc, gBindDiskWnd = true

Global gDriveList = List()

#ControlSetMouseAction /R 15 DrivesMenu
#ControlSetMouseAction /K:S /R 15 DrivesMenu
ControlSetMouseAction /K:C /R 15 DrivesMenu

If gBindDiskWnd Then
   Global gDiskWP = Callback("DiskWndProc", "hwnd;uint;wparam;lparam")
   hDiskWnd = WinFind(AUTORUN_TCHANDLE, _
              AUTORUN_TCARCH = 32 ? "TMyPanel" : "Window", AUTORUN_TCARCH = 32 ? 6 : 10)
   If hDiskWnd > 0 Then
      gDiskWndProc = DllCall("SetWindowLong" & (auX64 ? "PtrW" : "W"), _
                             "hwnd", hDiskWnd, "int", -4, "long_ptr", gDiskWP.Ptr, "ptr")   
   EndIf
EndIf
[/cut]
Но не просто работает или не работает (если бы так), все, что идет за директивой Pragma Include %COMMANDER_PATH%\Ini\Scripts\Drives.aucfg в основном конфиге не загружается и не обрабатывается. Так я и заметил сначала - нажал на кнопку, а в ответ сообщение, что функция с кодом не зарегистрирована. Такое может прозойти только, если модуль не был подключен, а значит Autorun его не подключил. При выходе мелькает какое-то окно, возможно окно Autorun с ошибкой.

Вообше-то, я хотел повесить оконную функцию на контрол с классом Window:10 для удобства, чтобы не только на строке вкладок можно было вызыввать меню. Есть шанс исправить?

Ранее забыл написать. Если использовать ключ /D в расширенно меню, то ShowPopupMenu без /I:0 создает серый квадрат у неактивных пунктов, если у них нет значка. С этим можно что-то сделать?

А еще в такой записи

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

mnu = 'MENUITEM "' & cmd & '", em_aucmd -1 ClipPut %"gRegCmdName"'
ClipPut работает только с глобальной переменной, так и задумано? Кстати, и глобальную переменную с большим текстом такая запись, кажется, режет.

P.S.

Регулярные выражения безусловно добавили прыти. Недавно yozhik писал, что возникаект задача скачать и обработать несколько файлов с интернета, и теперь когда регулярные выражения есть, остается закачать файлы. Самый простой способ сделать всего один вызов к Urlmon.dll\URLDownloadToFileW. Метод имеет недостатки, но для небольших файлов вполне подходит. Простой пример на загрузке и парсинге rss-ленты
[cut]

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

RegisterCommand 60033 "RSSCheck"

Func RSSCheck()
    Local hr, txt, rex, out, i
    Local url = "https://totalcmd.net/rss.xml"
    Local file = TEMP & "\rss.xml"
    hr = DllCall("Urlmon.dll\URLDownloadToFileW", _
                 "ptr", 0, "wstr", url, "wstr", file, "dword", 0, "ptr", 0, "hresult")
    If hr <> 0 Then
       txt = "An error occured." & auCRLF & url & auCRLF & _
             "Error code: " & hr & auCRLF & GetINetECode(hr)
       Return MsgBox(txt, "Autorun", 16)
    EndIf
    txt = FileRead(file)
    rex = RegExp('<item>\R<title>(.*?)</title>(?:.*?)<link>(.*?)</link>\R<pubDate>(.*?)</pubDate>(?:.*?)</item>', txt)
    If rex.Exec() Then 
       Do
          i += 1          
          out &= rex.Match[1] & auCRLF
          out &= rex.Match[2] & auCRLF
          out &= rex.Match[3] & auCRLF & auCRLF  
       Until not rex.ExecNext()
    EndIf     
    Free(rex)
    MsgBox(out, "RSS " & i, 64)
EndFunc

Func GetINetECode(nCode)
    Local sCode
    Switch nCode
    Case 0x800C0002	# INET_E_INVALID_URL 
        sCode = "The URL could not be parsed."
    Case 0x800C0003	# INET_E_NO_SESSION
        sCode = "No Internet session was established."    
    Case 0x800C0004	# INET_E_CANNOT_CONNECT 
        sCode = "The attempt to connect to the Internet has failed."
    Case 0x800C0005	# INET_E_RESOURCE_NOT_FOUND 
        sCode = "The Internet resource was not found."
    Case 0x800C0007	# INET_E_DATA_NOT_AVAILABLE 
        sCode = "An Internet connection was established, but the data cannot be retrieved."   
    Case 0x800C0008	# INET_E_DOWNLOAD_FAILURE 
        sCode = "The download has failed (the connection was interrupted)."               
    Case 0x800C000B	# INET_E_CONNECTION_TIMEOUT 
        sCode = "The Internet connection has timed out."
    Case 0x800C000C	# INET_E_INVALID_REQUEST 
        sCode = "The request was invalid."
    Case 0x800C000D	#  INET_E_UNKNOWN_PROTOCOL  
        sCode = "The protocol is not known and no pluggable protocols have been entered that match."
    Case 0x800C000E	# INET_E_SECURITY_PROBLEM 
        sCode = "A security problem was encountered (certificate problems, client authentication, etc.)"        
    Case 0x800C0019	# INET_E_INVALID_CERTIFICATE 
        sCode = "The SSL certificate is invalid."        
    Else
        sCode = "No error code description"
    EndSwitch
    Return sCode
EndFunc
[/cut]
Функция при всей простоте имеет недостатки: не все адреса могут открыться, а также отсутствует гибкая обработка ошибок. К тому же, если файл довольно большой, будет заметное зависание.

Поэтому пришлось сделать еще одну функцию на основе Wininet.dll. В принципе, она уже готова, осталось только оформить все с примерами. Вероятно завтра доделаю.
Loopback
Сообщения: 1646
Зарегистрирован: Пн сен 07, 2009 09:29

Сообщение Loopback »

Orion9 писал(а):они полностью эквивалентны
Параметры размера принимают значение в TCHAR, а не байтах, т.е. должно тоже быть 256. В остальном вроде равноценны.
Orion9 писал(а):Почему используется int 255 и какой размер буфера создает wstr:256?
Создаёт с указанным размером, 256. Размер 255 просто чтобы записанная строка гарантированно завершалось нулем.
Orion9 писал(а):чтобы эти кнопки не попадали в индекс 15?
Нет.
Orion9 писал(а):сводка по зарегистрированным командам родилась
Вот и хорошо, и не нужно обвес для статистики городить.
Orion9 писал(а):Есть шанс исправить?
Не знаю, у меня сейчас нет возможности с этим разбираться.
Orion9 писал(а): С этим можно что-то сделать?
Без кастомной отрисовки нет.
Orion9 писал(а):так и задумано? Кстати, и глобальную переменную с большим текстом такая запись, кажется, режет.
Это ограничение, достаточно очевидное. В пунктах меню напрямую могут использоваться только глобальные переменные, доступные в момент вызова. По обрезке не знаю.


@All
В силу обстоятельств я не смогу отвечать на форуме какое-то время. Отвечу, когда появится такая возможность.
Аватара пользователя
Orion9
Сообщения: 1283
Зарегистрирован: Пн янв 01, 2024 17:18

Сообщение Orion9 »

Loopback
Мне стоило спросить это у "ЫЫ", обычно он хорошо отвечает на такие вопросы. Просто взялся сейчас за многое сразу, не хотел отвлекаться. В частности долго возился с winnet, даже устал как-то. Но в целом оно того стоило.

Сначала думал, что функции URLDownloadToFile хватит для потребностей, и её хватило бы, если бы не один серьёзный недостаток - не все адреса открывает.

Например, такой адрес она не открывает и пишет ошибку INET_E_DATA_NOT_AVAILABLE:
[cut]

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

https://api.open-meteo.com/v1/forecast?latitude=47.37&longitude=8.55&daily=temperature_2m_max,temperature_2m_min&models=meteoswiss_icon_ch1&current=temperature_2m,relative_humidity_2m,cloud_cover&timezone=auto&forecast_days=1&format=csv
[/cut]
Решения, как обойти проблему, мне найти не удалось. А ведь хочется узнать как там у маэстро погода в горах ) Поэтому и пришлось заморочиться Wininet.dll.

И всё работает. Я чуть позже сброшу код, но картинку уже отснял:
[cut]Изображение[/cut]
[cut]Изображение[/cut]
Ответить