Autorun

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

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

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

Сообщение Orion9 »

Loopback
Теперь работает )

Добавив такую функцию в Autorun, вы, конечно, дали ключ от всех дверей, но проблем хватает :D Я не имею в виду этот небольшой баг с "ulong_ptr". Чтобы в полной мере пользоваться WIN API, нужно много знать и понимать, как работает Windows. Одним лишь сайтом Microsoft тут не обойтись.

Но кое-что можно уже пробовать и воплощать. Например, я сначала увлёкся иконкой в трее ради интереса, но теперь понимаю, что жить без неё не могу :mrgreen:

Многое ещё не доделано, но кое-что продемонстрировать уже можно:

[cut]

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

Pragma IncludeOnce

# 64000-65000

RegisterCommand 64000 TrayIcon
RegisterCommand 64001 ChangeTrayIcon
RegisterCommand 64002 NotifyInfo

# коды клавиш клавиатуры
Const K_SHIFT = 0x10, K_CTRL = 0x11, K_ALT = 0x12, K_ESC = 0x1B, K_WIN = 0x5B

# дополнительные настроки
Global AUTORUN_INI = %COMMANDER_PATH% & "\Ini\Autorun.ini"

# иконки окна уведомлений
Const NIIF_NONE    = 0x00000000, _
      NIIF_INFO    = 0x00000001, _
      NIIF_WARNING = 0x00000002, _
      NIIF_ERROR   = 0x00000003, _
      NIIF_USER    = 0x00000004
      
# без звука
Const NIIF_NOSOUND    = 0x00000010
# большая иконка
Const NIIF_LARGE_ICON = 0x00000020

# сообщения окна уведомлений
Const NIN_BALLOONSHOW      = 0x402, _
      NIN_BALLOONHIDE      = 0x403, _
      NIN_BALLOONTIMEOUT   = 0x404, _
      NIN_BALLOONUSERCLICK = 0x405, _
      NIN_POPUPOPEN        = 0x406, _
      NIN_POPUPCLOSE       = 0x407

# флаги структуры
Const NIF_MESSAGE = 0x00000001, _
      NIF_ICON    = 0x00000002, _
      NIF_TIP     = 0x00000004, _
      NIF_STATE   = 0x00000008, _
      NIF_INFO    = 0x00000010  

# системные сообщения 
Const WM_MOUSEMOVE     = 0x0200, _
      WM_LBUTTONDOWN   = 0x0201, _
      WM_LBUTTONUP     = 0x0202, _
      WM_LBUTTONDBLCLK = 0x0203, _
      WM_RBUTTONDOWN   = 0x0204, _
      WM_RBUTTONUP     = 0x0205, _
      WM_RBUTTONDBLCLK = 0x0206, _   
      WM_MBUTTONDOWN   = 0x0207, _
      WM_MBUTTONUP     = 0x0208, _      
      WM_MBUTTONDBLCLK = 0x0209

# функции обратного вызова
SetMessageAction /P 55555 TrayAction
SetMessageAction /P 55565 TrayNotifyInfo

Func TrayAction(hWnd, uMsg, wParam, lParam)
    # движение над иконкой
    If lParam = WM_MOUSEMOVE Then       
       If LAST_HINT_WINDOW = 0 Then          
          If IsPressed(K_CTRL) Then ShowHint(GetState("threads"), "", "", 2000, 1)
          #If IsPressed(K_CTRL) Then ShowDarkHint(GetState("threads"), 2000, 1)
       EndIf   
    EndIf     
    # левый клик       
    If lParam = WM_LBUTTONDOWN Then 
       If IsPressed(K_CTRL) Then 
          ShowDarkHint(GetState("threads"))
          Return
       EndIf
       AutorunMenu(0)
    # правый клик       
    Elseif lParam = WM_RBUTTONDOWN Then  
       ShowDarkHint(GetState("libs"))
    # клик по сообщению   
    Elseif lParam = NIN_BALLOONUSERCLICK Then        
       MsgBox("Baloon click")
       #WinSetState(23)
    # клик "закрыть сообщение"  
    ElseIf lParam = NIN_BALLOONTIMEOUT Then
       MsgBox("Time-out")            
    EndIf   
EndFunc

Func TrayNotifyInfo(hWnd, uMsg, wParam, lParam)
    NotifyIcon("delete", 1010) 
EndFunc

Global TrayShow = 0, TrayIcon = 0

TrayIcon(0)

Func TrayIcon(lParam)
    Local ico, idx = 0 
    IniRead TrayShow %AUTORUN_INI% "TrayIcon" "Show" 1
    If Not TrayShow Then
       Return
    EndIf
    IniRead ico %AUTORUN_INI% "TrayIcon" "Icon"
    IniRead idx %AUTORUN_INI% "TrayIcon" "Index"  
    If ico = "" Or Not FileExist(ico) Then
       idx = 0
       ico = %COMMANDER_PATH% & "\TOTALCMD.EXE"    
    EndIf
    Local hint = "Autorun " & FileGetVersion(AUTORUN_PATH & "\Autorun.wdx", "FileVersion")    
    Local hIco = DllCall("shell32\ExtractIconW", "ptr", AUTORUN_TCHANDLE, "wstr", ico, "uint", idx, "ptr")
    #NotifyIcon("add", 1001, 55555, hIco, hint, "Tray icon added", "Autorun", 1)  
    TrayIcon = NotifyIcon("add", 1001, 55555, hIco, hint)
    If hIco > 0 Then DllCall("DestroyIcon", "ptr", hIco, "bool")        
EndFunc

Func ChangeTrayIcon(lParam)
    Static f = GetKnownFolderPath("System") & "\shell32.dll", i = 10
    i += 1
    Local hIco = DllCall("shell32\ExtractIconW", "ptr", AUTORUN_TCHANDLE, "wstr", f, "uint", i, "ptr")   
    If IsPressed(0x11) Then
       NotifyIcon("delete", 1001)
    ElseIf IsPressed(0x10) Then
       NotifyIcon("add", 1001, 55555, hIco, "Autorun")
    Else
       If IsPressed(0x12) Then hIco = 0
       NotifyIcon("set", 1001, 55555, hIco, "", "Icon changed to shell32.dll, " & i, "", 2)
       Sleep(2000)
       NotifyIcon("set", 1001,, hIco,, "Icon changed to shell32.dll, " & i,, 2)                
    EndIf   
    If hIco > 0 Then DllCall("DestroyIcon", "ptr", hIco, "bool")        
EndFunc

Func DeleteTrayIcon(lParam)
     If NotifyIcon("delete", 1001) Then TrayIcon = 0
EndFunc

Func NotifyInfo(lParam)
   Local idx = 15
   Local file = GetKnownFolderPath("System") & "\shell32.dll"
   Local hIco = DllCall("shell32\ExtractIconW", "ptr", AUTORUN_TCHANDLE, "wstr", file, "uint", idx, "ptr")
   NotifyInfoMessage(hIco, "Test message", "", NIIF_INFO)
   If hIco > 0 Then DllCall("DestroyIcon", "ptr", hIco, "bool")
EndFunc

Func NotifyInfoMessage(hIcon, InfoText, InfoTitle = "Autorun", InfoType = 0)
    Local buf = Buffer((auPtrSize = 4 ? 956 : 976))
    Local dwFlags = 27 # NIF_MESSAGE|NIF_STATE|NIF_INFO
    buf.Zero()
    If auX64 Then
        buf.SetNum(0,  "dword", buf.size)
        buf.SetNum(8,  "hwnd", AUTORUN_TCHANDLE)
        buf.SetNum(16, "uint", 1010, _
                       "uint", dwFlags, _
                       "uint", 55565)             
        buf.SetNum(32, "ptr", hIcon)                       
        buf.SetNum(296, "dword", 1, _
                        "dword", 1)                            
    Else
        buf.SetNum(0, "dword", buf.size, _   
                      "hwnd", AUTORUN_TCHANDLE, _         
                      "uint", 1010, _
                      "uint", dwFlags, _
                      "uint", 55565, _
                      "ptr", hIcon) ) 
        buf.SetNum(280, "dword", 1, _
                        "dword", 1)

    EndIf    
    buf.SetStr(StrLeft(InfoText, 263) & Chr(0), (auX64 ? 40 : 24) + 256 + 4 + 4)
    If StrLen(InfoTitle) > 0 Then
       buf.SetStr(StrLeft(InfoTitle, 63) & Chr(0), (auX64 ? 40 : 24) + 256 + 4 + 4 + 512 + 4)
    EndIf   
    If InfoType > 0 Then
       buf.SetNum((auX64 ? 40 : 24) + 256 + 4 + 4 + 512 + 4 + 128, "dword", InfoType)       
    EndIf
    Local Result = DllCall("Shell32.dll\Shell_NotifyIconW", "uint", 0, "ptr", buf.ptr, "bool")
    Free(buf)
    Return Result
EndFunc

Func NotifyIcon(Action, ID, CallbackMessage = 0, hIcon = 0, Tip = "", InfoText = "", InfoTitle = "", InfoType = 0)
    Local Message, Result
    Local TIP_MAXCHAR = 127, INFO_MAXCHAR = 199, TITLE_MAXCHAR = 63
    Local buf = Buffer((auPtrSize = 4 ? 956 : 976))   
    buf.Zero()
    Local FLAGS = BitOR((CallbackMessage = 0 ? 0 : NIF_MESSAGE), _
                  (hIcon = 0 ? 0 : NIF_ICON), _
                  (StrLen(Tip) = 0 ? 0 : NIF_TIP), _
                  (StrLen(InfoText) = 0 ? 0 : NIF_INFO))                  
    Switch Action
       Case "add"
          Message = 0
       Case "set"
          Message = 1
      Case "delete"
          Message = 2         
       Else
          Return 
    EndSwitch                 
    If auX64 Then
        buf.SetNum(0,  "dword", buf.size)
        buf.SetNum(8,  "hwnd", AUTORUN_TCHANDLE)
        buf.SetNum(16, "uint", ID, _
                       "uint", FLAGS, _
                       "uint", CallbackMessage)
        buf.SetNum(32, "ptr", hIcon)
    Else
        buf.SetNum(0, "dword", buf.size, _   
                      "hwnd", AUTORUN_TCHANDLE, _         
                      "uint", ID, _
                      "uint", FLAGS, _
                      "uint", CallbackMessage, _
                      "ptr", hIcon) 
    EndIf
    If StrLen(Tip) > 0 Then
       buf.SetStr(StrLeft(Tip, TIP_MAXCHAR) & Chr(0), (auX64 ? 40 : 24)) # auPtrSize*2 + 4*4 + padding for X64
    EndIf   
    If StrLen(InfoText) > 0 Then
       buf.SetStr(StrLeft(InfoText, INFO_MAXCHAR) & Chr(0), (auX64 ? 40 : 24) + 264) # 256 + 4 + 4
       If StrLen(InfoTitle) > 0 Then
          buf.SetStr(StrLeft(InfoTitle, TITLE_MAXCHAR) & Chr(0), (auX64 ? 40 : 24) + 780) # 512 + 4
       EndIf   
       If InfoType > 0 Then
          buf.SetNum((auX64 ? 40 : 24) + 780 + 128, "dword", InfoType)       
       EndIf
    EndIf
    Result = DllCall("Shell32.dll\Shell_NotifyIconW", "uint", Message, "ptr", buf.ptr, "bool")
    Free(buf)
    Return Result
EndFunc
[/cut]
Вверху коды кнопок. Можно запустить два потока, чтобы иконка сама менялась в фоне с интервалом:
[cut]

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

RunThread ThreadWatchLangFunc

Func ThreadWatchLangFunc
    Local file = GetKnownFolderPath("System") & "\shell32.dll"
    Local lng = AUTORUN_TCLANG, idx
    While 1
       OutputDebugString("lang=" & AUTORUN_TCLANG & " lng=" & lng)
       If Not (lng = AUTORUN_TCLANG) Then
          Switch AUTORUN_TCLANG
             Case 'ENG'
                # ChangeLangEN 0
                idx = 13
             Case 'RUS'
                # ChangeLangRU 0
                idx = 15
          EndSwitch
          lng = AUTORUN_TCLANG
          Local hIco = DllCall("shell32\ExtractIconW", "ptr", AUTORUN_TCHANDLE, "wstr", file, "uint", idx, "ptr")
          NotifyIcon("set", 1001, 55555, hIco)          
          #NotifyIcon("set", 1001, 55555, hIco, "", "Language changed to " & lng, "", 1)
          If hIco > 0 Then DllCall("DestroyIcon", "ptr", hIco, "bool")        
       Endif   
       Sleep(1000)
    Wend
EndFunc

RunThread ThreadFunction 

# пример из справки
Func ThreadFunction
    Local sPath, sName
    Local ru = true
    While 1
        sPath = RequestCopyDataInfo("SP")
        sName = RequestCopyDataInfo("SN")
        sPath = sPath & sName
        # выводим путь, просматривать можно с DebugView
        # выполнение цикла при этом не блокируется
        OutputDebugString("Autorun: Path = " & sPath)
        Sleep(5000)
        ru = Not ru
        If ru Then
           CommandExec("em_change_lang_ru")
        Else
           CommandExec("em_change_lang_en")
        EndIf   
    Wend
EndFunc
[/cut]
Одмн поток меняет язык раз в 5 секунд, другой следит за сменой языка. Как только язык меняется, меняется и иконка.
Аватара пользователя
Orion9
Сообщения: 1283
Зарегистрирован: Пн янв 01, 2024 17:18

Сообщение Orion9 »

После внесения некоторых изменений можно считать, что данный вариант функций для работы с иконками в трее, более-менее законченный:
[cut]

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

Pragma IncludeOnce

# 64000-65000

RegisterCommand 64000 ShowTrayIcon
RegisterCommand 64001 ChangeTrayIcon
RegisterCommand 64002 NotifyInfo

# иконки окна уведомлений
Const NIIF_NONE    = 0x00000000, _
      NIIF_INFO    = 0x00000001, _
      NIIF_WARNING = 0x00000002, _
      NIIF_ERROR   = 0x00000003, _
      NIIF_USER    = 0x00000004
      
# без звука
Const NIIF_NOSOUND    = 0x00000010
# большая иконка
Const NIIF_LARGE_ICON = 0x00000020

# сообщения окна уведомлений
Const NIN_BALLOONSHOW      = 0x402, _
      NIN_BALLOONHIDE      = 0x403, _
      NIN_BALLOONTIMEOUT   = 0x404, _
      NIN_BALLOONUSERCLICK = 0x405, _
      NIN_POPUPOPEN        = 0x406, _
      NIN_POPUPCLOSE       = 0x407

# флаги структуры
Const NIF_MESSAGE = 0x00000001, _
      NIF_ICON    = 0x00000002, _
      NIF_TIP     = 0x00000004, _
      NIF_STATE   = 0x00000008, _
      NIF_INFO    = 0x00000010  

# системные сообщения 
Const WM_MOUSEMOVE     = 0x0200, _
      WM_LBUTTONDOWN   = 0x0201, _
      WM_LBUTTONUP     = 0x0202, _
      WM_LBUTTONDBLCLK = 0x0203, _
      WM_RBUTTONDOWN   = 0x0204, _
      WM_RBUTTONUP     = 0x0205, _
      WM_RBUTTONDBLCLK = 0x0206, _   
      WM_MBUTTONDOWN   = 0x0207, _
      WM_MBUTTONUP     = 0x0208, _      
      WM_MBUTTONDBLCLK = 0x0209

# функции обратного вызова
SetMessageAction /P 99999 TrayAction
SetMessageAction /P 99998 TrayNotifyInfo 

# главная иконка Autorun
Func TrayAction(hWnd, uMsg, wParam, lParam)
    # движение над иконкой
    If lParam = WM_MOUSEMOVE Then       
       If LAST_HINT_WINDOW = 0 Then          
          If IsPressed(KEY_CTRL) Then ShowHint(GetState("threads"), "", "", 2000, 1)
          #If IsPressed(KEY_CTRL) Then ShowDarkHint(GetState("threads"), 2000, 1)
       EndIf   
    EndIf
    Switch lParam
       # левый клик       
       Case WM_LBUTTONDOWN
          If IsPressed(KEY_CTRL) Then 
             ShowHint(GetState("threads"))
             #ShowDarkHint(GetState("threads"))             
             Return
          EndIf
          AutorunMenu(0)
      # правый клик
      Case WM_RBUTTONDOWN
           ShowDarkHint(GetState("libs"))
      # клик по сообщению        
      Case NIN_BALLOONUSERCLICK  
           MsgBox("Baloon click")
           #WinSetState(23)
      # клик "закрыть сообщение"  
      Case NIN_BALLOONTIMEOUT
           MsgBox("Time-out")                
    EndSwitch
EndFunc

# служебная иконка
Func TrayNotifyInfo(hWnd, uMsg, wParam, lParam)
    # освобождение невидимой иконки
    If lParam = NIN_BALLOONUSERCLICK or lParam = NIN_BALLOONTIMEOUT Then
       NotifyIcon("delete", 1010) 
    EndIf   
EndFunc

Global TrayShow = 0, Tray1001 = 0, Tray1002 = 0

TrayIcon()

# главная иконка
Func TrayIcon()
    Local ico, idx = 0
    # чтение конфигурации
    IniRead TrayShow %AUTORUN_INI% "TrayIcon" "Show" 1
    If Not TrayShow Then
       Return
    EndIf
    IniRead ico %AUTORUN_INI% "TrayIcon" "Icon"
    IniRead idx %AUTORUN_INI% "TrayIcon" "Index" 0 
    # откат к умолчаниям
    If ico = "" Or Not FileExist(ico) Then
       idx = 0
       ico = COMMANDER_PATH & "\TOTALCMD.EXE"
    EndIf
    Local hint = "Autorun " & FileGetVersion(AUTORUN_PATH & "\Autorun.wdx", "FileVersion")    
    Local hIco = DllCall("shell32\ExtractIconW", "ptr", AUTORUN_TCHANDLE, "wstr", ico, "uint", idx, "ptr")
    If NotifyIcon("add", 1001, 99999, hIco, hint) Then Tray1001 = 1
    If hIco > 0 Then DllCall("DestroyIcon", "ptr", hIco)        
EndFunc

Func ShowTrayIcon(lParam)
    If Tray1001 > 0 Then
       IniWrite %AUTORUN_INI% "TrayIcon" "Show" 0
       HideTrayIcon()
    Else
       IniWrite %AUTORUN_INI% "TrayIcon" "Show" 1
       TrayIcon()
    EndIf
    If Tray1001 > 0 Then
       ShowHint("Иконка включена")
    Else
       ShowHint("Иконка отключена")    
    EndIf   
EndFunc

Func HideTrayIcon()
    If NotifyIcon("delete", 1001) Then Tray1001 = 0
EndFunc

Func ChangeTrayIcon(lParam)
    Static f = GetKnownFolderPath("System") & "\shell32.dll", i = 10    
    If Tray1001 = 0 Then
       ShowHint("Иконка отключена")
       Return
    EndIf
    i += 1
    Local hIco = DllCall("shell32\ExtractIconW", "ptr", AUTORUN_TCHANDLE, "wstr", f, "uint", i, "ptr")   
    If IsPressed(KEY_CTRL) Then
       NotifyIcon("add", 1002, 99999, hIco, "Autorun #2", "Second icon added", "Autorun", NIIF_NONE)
       Tray1002 = 1
    Else
       If IsPressed(KEY_ALT) Then hIco = 0
       NotifyIcon("set", 1001, 99999, hIco, "", "Icon changed to shell32.dll, " & i, "", NIIF_INFO)
       Sleep(2000)
       NotifyIcon("set", 1001,, hIco,, "Icon changed to shell32.dll, " & i,, NIIF_ERROR)
    EndIf   
    If hIco > 0 Then DllCall("DestroyIcon", "ptr", hIco, "bool")        
EndFunc

Func NotifyInfo(lParam)
     # тест 1
     NotifyInfoMessage(1, "Test message", "", NIIF_INFO)
     sleep(3000)     
     # тест 2     
     txt = "Pragma Include %COMMANDER_PATH%\Ini\Scripts\Test.aucfg"
     NotifyInfoMessage(0, txt, "Script", NIIF_WARNING + NIIF_NOSOUND)
     sleep(3000)     
     # тест 3
     txt = "Test message line 1" & auCRLF & "Test message line 2"
     NotifyInfoMessage(0, txt, "Script", NIIF_ERROR)          
EndFunc

#{
     Функция для показа системных уведомлений:
     
               Icon - иконка в трее (1 - да, 0 - нет)
           InfoText - текст уведомления (199 символов)
          InfoTitle - текст заголовка уведомления (47 символов)
           InfoType - флаги NIIF_* меняющие вид и поведение окна уведомлений 
            
     Функция использует идентификатор "1010" и номер сообщения "99998"
#}
Func NotifyInfoMessage(Icon, InfoText, InfoTitle = "Autorun", InfoType = 0)
    Local dwFlags = 0
    Local buf = Buffer(auPtrSize = 4 ? 956 : 976)
    Local hIco = 0, tc = COMMANDER_PATH & "\TOTALCMD.EXE" 
    hIco = DllCall("shell32\ExtractIconW", "ptr", AUTORUN_TCHANDLE, "wstr", tc, "uint", 0, "ptr")    
    If Icon Then       
       dwFlags = BitOR(NIF_MESSAGE, NIF_ICON, NIF_INFO)
    Else
       dwFlags = BitOR(NIF_MESSAGE, NIF_STATE, NIF_ICON, NIF_INFO)
    Endif   
    buf.Zero()
    If auX64 Then
        buf.SetNum(0,  "dword", buf.size)
        buf.SetNum(8,  "hwnd", AUTORUN_TCHANDLE)
        buf.SetNum(16, "uint", 1010, _
                       "uint", dwFlags, _
                       "uint", 99998)             
        buf.SetNum(32, "ptr",  hIco)                       
        buf.SetNum(296, "dword", 1, _
                        "dword", 1)                            
    Else
        buf.SetNum(0, "dword", buf.size, _   
                      "hwnd", AUTORUN_TCHANDLE, _         
                      "uint", 1010, _
                      "uint", dwFlags, _
                      "uint", 99998, _
                      "ptr",  hIco) ) 
        buf.SetNum(280, "dword", 1, _
                        "dword", 1)

    EndIf
    Local offset = (auX64 ? 40 : 24) + 256 + 4 + 4
    buf.SetStr(StrLeft(InfoText, 199) & Chr(0), offset)
    If StrLen(InfoTitle) > 0 Then       
       buf.SetStr(StrLeft(InfoTitle, 47) & Chr(0), offset + 512 + 4)
    EndIf   
    If InfoType > 0 Then
       buf.SetNum(offset + 512 + 4 + 128, "dword", InfoType)
    EndIf
    Local Result = DllCall("Shell32.dll\Shell_NotifyIconW", "uint", 0, "ptr", buf.ptr)
    If hIco > 0 Then DllCall("DestroyIcon", "ptr", hIco)    
    Free(buf)
    Return Result
EndFunc

#{ 
    Отображение иконки в трее:
    https://learn.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-notifyicondataw
    
             Action - тип операции ("add", "set", "delete")
                 ID - внутренний идентификатор иконки (1001, 1002, ...)
    CallbackMessage - код сообщения для обратного вызова (99999, 99998, ...)
              hIcon - дескриптор иконки (обязателен для "add", необязателен для "set")
                Tip - текст подсказки в трее
           InfoText - текст уведомления (только при операции "add" или "set")
          InfoTitle - текст заголовка уведомления
           InfoType - флаги NIIF_* меняющие вид и поведение окна уведомлений
        
#}
Func NotifyIcon(Action, ID, CallbackMessage = 0, hIcon = 0, Tip = "", InfoText = "", InfoTitle = "", InfoType = 0)
    Local Message, Result
    Local TIP_MAXCHAR = 127, INFO_MAXCHAR = 199, TITLE_MAXCHAR = 47
    Local buf = Buffer((auPtrSize = 4 ? 956 : 976))   
    buf.Zero()
    Local FLAGS = BitOR((CallbackMessage = 0 ? 0 : NIF_MESSAGE), _
                  (hIcon = 0 ? 0 : NIF_ICON), _
                  (StrLen(Tip) = 0 ? 0 : NIF_TIP), _
                  (StrLen(InfoText) = 0 ? 0 : NIF_INFO))                  
    Switch Action
       Case "add"
          Message = 0
       Case "set"
          Message = 1
      Case "delete"
          Message = 2         
       Else
          Return 
    EndSwitch                 
    If auX64 Then
        buf.SetNum(0,  "dword", buf.size)
        buf.SetNum(8,  "hwnd", AUTORUN_TCHANDLE)
        buf.SetNum(16, "uint", ID, _
                       "uint", FLAGS, _
                       "uint", CallbackMessage)
        buf.SetNum(32, "ptr", hIcon)
    Else
        buf.SetNum(0, "dword", buf.size, _   
                      "hwnd", AUTORUN_TCHANDLE, _         
                      "uint", ID, _
                      "uint", FLAGS, _
                      "uint", CallbackMessage, _
                      "ptr", hIcon) 
    EndIf
    If StrLen(Tip) > 0 Then
       buf.SetStr(StrLeft(Tip, TIP_MAXCHAR) & Chr(0), (auX64 ? 40 : 24)) # auPtrSize*2 + 4*4 + padding for X64
    EndIf   
    If StrLen(InfoText) > 0 Then
       buf.SetStr(StrLeft(InfoText, INFO_MAXCHAR) & Chr(0), (auX64 ? 40 : 24) + 264) # 256 + 4 + 4
       If StrLen(InfoTitle) > 0 Then
          buf.SetStr(StrLeft(InfoTitle, TITLE_MAXCHAR) & Chr(0), (auX64 ? 40 : 24) + 780) # 512 + 4
       EndIf   
       If InfoType > 0 Then
          buf.SetNum((auX64 ? 40 : 24) + 780 + 128, "dword", InfoType)       
       EndIf
    EndIf
    Result = DllCall("Shell32.dll\Shell_NotifyIconW", "uint", Message, "ptr", buf.ptr, "bool")
    Free(buf)
    Return Result
EndFunc
[/cut]
Добавил туда важных комментариев, которые позволят быстрее разобраться, но если коротко, сейчас используются две функции: одна для добавления иконок в трей и работы с ними (NotifyIcon), другая - только для показа уведомлений (NotifyInfoMessage):

[cut]

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

1.Отображение иконки в трее:
https://learn.microsoft.com/en-us/windows/win32/api/shellapi/ns-shellapi-notifyicondataw

         Action - тип операции ("add", "set", "delete")
             ID - внутренний идентификатор иконки (1001, 1002, ...)
CallbackMessage - код сообщения для обратного вызова (99999, 99998, ...)
          hIcon - дескриптор иконки (обязателен для "add", необязателен для "set")
            Tip - текст подсказки в трее
       InfoText - текст уведомления (только при операции "add" или "set")
      InfoTitle - текст заголовка уведомления
       InfoType - флаги NIIF_* меняющие вид и поведение окна уведомлений
        
Func NotifyIcon(Action, ID, CallbackMessage = 0, hIcon = 0, Tip = "", InfoText = "", InfoTitle = "", InfoType = 0)

2.Функция для показа системных уведомлений:

          Icon - иконка в трее (1 - да, 0 - нет)
      InfoText - текст уведомления (199 символов)
     InfoTitle - текст заголовка уведомления (47 символов)
      InfoType - флаги NIIF_* меняющие вид и поведение окна уведомлений 
       
Функция использует идентификатор "1010" и номер сообщения "99998"

Func NotifyInfoMessage(Icon, InfoText, InfoTitle = "Autorun", InfoType = 0)
[/cut]
Кнопки для тестов:
[cut]TOTALCMD#BAR#DATA
64000

%COMMANDER_EXE%,1
Иконка в трее

1
-1
[/cut]
[cut]TOTALCMD#BAR#DATA
64001

%COMMANDER_EXE%,1
Смена икоки в трее|ALT - Только сообщение|CTRL - Добавление второй

1
-1
[/cut]
[cut]TOTALCMD#BAR#DATA
64002

%COMMANDER_EXE%,1
Тест уведомления

1
-1
[/cut]
Первая кнопка включает или отключает иконку в трее, вторая меняет иконку и показывает сообщения, третья тестируют уведомления.

В основном файле конфигурации важно не забыть удалить иконки при выходе в секции финализации:
[cut]

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

Pragma AutorunFinalizeSection

# удаление иконок
If Tray1001 > 0 Then NotifyIcon("delete", 1001)
If Tray1002 > 0 Then NotifyIcon("delete", 1002)
[/cut]

Loopback, хотел попробовать сделать по мотивам темы:
https://www.autohotkey.com/boards/viewt ... p?t=110783
Там есть рабочий код на AutoHotkey, вроде ничего сложного:
[cut]

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

class UCharDet
{
	#DllLoad 'libuchardet.dll'
	
	/**
	 * Create an encoding detector.
	 * @return an instance of uchardet_t.
	 *
	 * UCHARDET_INTERFACE uchardet_t uchardet_new(void);
	 */
	Ptr := DllCall('libuchardet\uchardet_new', 'CDecl Ptr')

	/**
	 * Delete an encoding detector.
	 * @param ud [in] the uchardet_t handle to delete.
	 *
	 * UCHARDET_INTERFACE void uchardet_delete(uchardet_t ud);
	 */
	__Delete() => this.Ptr && DllCall('libuchardet\uchardet_delete', 'Ptr', this, 'CDecl')

	/**
	 * Feed data to an encoding detector.
	 * The detector is able to shortcut processing when it reaches certainty
	 * for an encoding, so you should not worry about limiting input data.
	 * As far as you should be concerned: the more the better.
	 *
	 * @param ud [in] handle of an instance of uchardet
	 * @param data [in] data
	 * @param len [in] number of byte of data
	 * @return non-zero number on failure.
	 *
	 * UCHARDET_INTERFACE int uchardet_handle_data(uchardet_t ud, const char * data, size_t len);
	 */
	HandleData(pBytes, cBytes) => DllCall('libuchardet\uchardet_handle_data', 'Ptr', this, 'Ptr', pBytes, 'Ptr', cBytes, 'CDecl Int')

	/**
	 * Notify an end of data to an encoding detector.
	 * @param ud [in] handle of an instance of uchardet
	 * 
	 * UCHARDET_INTERFACE void uchardet_data_end(uchardet_t ud);
	 */
	DataEnd() => DllCall('libuchardet\uchardet_data_end', 'Ptr', this, 'CDecl')

	/**
	 * Reset an encoding detector.
	 * @param ud [in] handle of an instance of uchardet
	 * 
	 * UCHARDET_INTERFACE void uchardet_reset(uchardet_t ud);
	 */
	Reset() => DllCall('libuchardet\uchardet_reset', 'Ptr', this, 'CDecl')

	/**
	 * Get an iconv-compatible name of the encoding that was detected.
	 * @param ud [in] handle of an instance of uchardet
	 * @return name of charset on success and "" on failure.
	 * 
	 * UCHARDET_INTERFACE const char * uchardet_get_charset(uchardet_t ud);
	 */
	GetCharset() => DllCall('libuchardet\uchardet_get_charset', 'Ptr', this, 'CDecl AStr')

	DetectBuffer(Buffer) {
		this.Reset()

		if res := this.HandleData(Buffer.Ptr, Buffer.Size)
			throw Error("Internal 'libuchardet' error, uchardet_handle_data() returned " res)

		this.DataEnd()
		charset := this.GetCharset()
		this.Reset()

		return charset
	}
}

UCD := UCharDet()
MsgBox UCD.DetectBuffer(FileRead('txt.txt', 'RAW')) ; GB18030
[/cut]
И вроде выложили последние библиотеки:
https://github.com/telppa/ahk-chardet/tree/main/Lib
Я проверил - скрипт на них работает. Решил сделать то же самое на Autorun, но последняя функция возвращает пустую строку. Если у вас будет время, посмотрите, пожалуйста, в чём может быть причина. Здесь даже два варианта )
[cut]

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

Func DetectCharset()
    Local sLib = COMMANDER_PATH & "\Ini\Tools\Libs\" & (auX64 ? "" : "x86") & "\uchardet.dll"
    Local sFile = COMMANDER_PATH & "\Ini\Tools\Libs\test.txt", sBuf
    Static hLib = DllCall("LoadLibrary", "wstr", sLib, "ptr") 
    If hLib = 0 Then Return
    ProcessExecGetOutput sBuf %COMSPEC% '/c type "%sFile%"'     
    Local hUC = DllCall('uchardet\uchardet_new', 'ptr:cdecl')
    DllCall('uchardet\uchardet_reset', 'ptr', hUC, 'cdecl')    
    Local nBytes = StrLen(sBuf)
    Local Res = DllCall('uchardet\uchardet_handle_data', 'ptr', hUC, 'str', sBuf, 'uint', nBytes, 'int:cdecl')
    MsgBox(hLib & auCRLF & hUC & auCRLF & nBytes & auCRLF & Res)
    DllCall('uchardet\uchardet_data_end', 'ptr', hUC, 'cdecl')   
    Local sCharSet = DllCall('uchardet\uchardet_get_charset', 'ptr', hUC, 'str:cdecl')
    MsgBox(sCharSet)    
    DllCall('uchardet\uchardet_delete', 'ptr', hUC, 'cdecl')
    #DllCall('uchardet\uchardet_reset', 'ptr', hUC, 'cdecl')
EndFunc
[/cut]
[cut]

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

Func DetectCharset2()
    Local sLib = COMMANDER_PATH & "\Ini\Tools\Libs\" & (auX64 ? "" : "x86") & "\uchardet.dll"
    Local txt
    txt = "* Feed data to an encoding detector." & auCRLF & _
	  "* The detector is able to shortcut processing when it reaches certainty" & auCRLF & _
	  "* for an encoding, so you should not worry about limiting input data." & auCRLF & _
	  "* As far as you should be concerned: the more the better."
    Static hLib = DllCall("LoadLibrary", "wstr", sLib, "ptr") 
    If hLib = 0 Then Return     
    Local hUC = DllCall('uchardet\uchardet_new', 'ptr:cdecl')
    DllCall('uchardet\uchardet_reset', 'ptr', hUC, 'cdecl')    
    Local buf = Buffer(StrLen(txt)) 
    buf.SetStr(txt, 0, "ANSI")
    Local Res = DllCall('uchardet\uchardet_handle_data', 'ptr', hUC, 'ptr', buf.ptr, 'uint', buf.size, 'int:cdecl')    
    MsgBox(hLib & auCRLF & hUC & auCRLF & buf.size & auCRLF & Res)
    DllCall('uchardet\uchardet_data_end', 'ptr', hUC, 'cdecl')   
    Local sCharSet = DllCall('uchardet\uchardet_get_charset', 'ptr', hUC, 'str:cdecl')
    MsgBox(sCharSet)    
    #DllCall('uchardet\uchardet_delete', 'ptr', hUC, 'cdecl')
    DllCall('uchardet\uchardet_reset', 'ptr', hUC, 'cdecl')
EndFunc
[/cut]
Loopback
Сообщения: 1646
Зарегистрирован: Пн сен 07, 2009 09:29

Сообщение Loopback »

Orion9 писал(а): Решил сделать то же самое на Autorun, но последняя функция возвращает пустую строку.
В Autorun сейчас при задании cdecl тип параметра не опционален. Можно использовать int:cdecl для uchardet_get_charset. Сделаю опциональным.

Вторая проблема в том, что типы str/wstr в качестве возвращаемого значения по факту не работали. Я точно тестировал такой случай, но с тех пор, похоже, сломал. Исправил.

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

Сообщение Orion9 »

Loopback писал(а):сегодня будет новая версия.
Супер )

А можно ли сделать, чтобы GetState("threads") возвращала имена потоков в своём результате? А то сейчас не так просто понять "who is who" ))

[cut]

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

Thread #1:
    Origin: Main
    ThreadID: 1648
    Started: 02.03.2025 11:00:02

Thread #2:
    Origin: RunThread
    ThreadID: 10040
    Started: 02.03.2025 11:00:03

Thread #3:
    Origin: RunThread
    ThreadID: 7736
    Started: 02.03.2025 11:00:04

Thread #4:
    Origin: RunThread
    ThreadID: 9480
    Started: 02.03.2025 11:00:04

Thread #5:
    Origin: RunThread
    ThreadID: 9796
    Started: 02.03.2025 11:00:04
[/cut]
Два раза сбрасывал код и два раза забывал спросить. Параметры по-умолчанию, которые можно опускать в функциях, обязательно надо заменять пустыми кавычками? Первый вариант рабочий:

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

NotifyIcon("set", 1001, 99999, hIco, "", "Icon changed to shell32.dll, " & i, "", NIIF_INFO)
Второй приводит к неожиданным результатам:

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

NotifyIcon("set", 1001,, hIco,, "Icon changed to shell32.dll, " & i,, NIIF_ERROR)
Ещё пара вопросов по поводу переменных окружения в будущих версиях:

1. В дериктиве Pragma можно будет оставить всё без изменений? Такая запись и дальше будет рабочей?

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

Pragma Include %COMMANDER_PATH%\Ini\Scripts\Test.aucfg
2. Если есть переменная Local Dir = "%COMMANDER_PATH%\Ini", то в командах: %"Dir%" равно "%COMMANDER_PATH%\Ini", а %"%Dir%" равно "C:\Portable\TOTALCMD\Ini"? Если да, то не изменится ли такое поведение в будущих версиях, или надо как-то по-другому раскрывать?
Loopback
Сообщения: 1646
Зарегистрирован: Пн сен 07, 2009 09:29

Сообщение Loopback »

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

Сообщение Orion9 »

Loopback писал(а):Забавно, код для этого уже был сделан, но забыл включить. Хотя я до сих пор так и не понимаю, какой смысл в этой информации.
Когда крутился один-два потока, смысла большого не было, согласен. Но сейчас у меня бывает по 5-6 потоков крутится, так как приходится часто эксперементировать. Как-то раз забыл закомментировать один поток, после того, как он перестал быть нужным, так я потом понять долго не мог, откуда он взялся :?

Имя потока - это я неправильно выразился. Речь идет об имени функции, как вы правильно отметили.
Loopback писал(а):В настоящее время метод записи с пропусками официально не поддерживается и делать так я бы не рекомендовал
Не совсем понял. То есть обе записи следует избегать, и с кавычками тоже?
Loopback писал(а):конкретно в работу вычисляемых строк я не собирался вмешиваться, это уже своего рода legacy.
Просто я пересматриваю сейчас код. Заметил, что в некоторых случаях у меня завязано именно на раскрытие переменных окружения, но в большинстве других используется избыточная запись, например:

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

i  += 1 
IniWrite %bar% "Buttonbar" %"'Menu'   & %i%"  %"%i%-2"
Я все такие записи исправил на:

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

IniWrite %bar% "Buttonbar" %"'Menu'   & i"  %"i-2"
Но иногда нужно, чтобы переменная раскрылась:

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

SetEnv COMMANDER_VIDEO %"%SoftVideo%"
или:

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

ProcessExecGetOutput /OEM out %COMSPEC% "/c dir /s /b *.wav" %"%dir%"
В общем, хотел убедиться, что такие записи допустимы, правильны и не будут в будущем как-то меняться.

Хотел еще про определения яыка спросить. Мне нужно узнать, является ли система англоязычной (UI), если нет, то считать её русской. Как вы думаете, такая функция подойдет?
[cut]

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

Func GetSysLanguage()
    Local Ret = DllCall("GetUserDefaultUILanguage")
    #   ru-RU  0x0419  1049    
    #   en-US  0x0409  1033
    #   en-GB  0x0809  2057
    #   en-AU  0x0C09  3081
    #   en-CA  0x1009  4105    
    #   en-NZ  0x1409  5129
    #   en-IE  0x1809  6153 
    #   en-ZA  0x1C09  7177
    #   en-IN  0x4009  16393
    #   MsgBox("Return: " & Ret)
    If Ret = 1033 Or Ret = 2057 Or Ret = 3081 Or Ret = 4105 Or Ret = 5129 Then Return "en"
    Return "ru"
EndFunc
[/cut]
Хотел добавить возможность обработки англоязычной вкладки:
[cut]

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

Func FileSecInfo(lParam)
    Static SEE_MASK_INVOKEIDLIST = 0x0000000C, _
           LPSHELLEXECUTEINFO = (auX64 ? 112 : 60) , _
           SW_SHOWNORMAL = 1, SW_SHOW = 5
           
    Local p = RequestCopyDataInfo("SP")
    Local n = RequestCopyDataInfo("SN")
    Local f = p & n       
    If Not FileExist(f) Then 
       ShowHint("Файл не существует " & f)
       Return 
    Endif    
    Local buff = Buffer(LPSHELLEXECUTEINFO), verb = Buffer(10*2+2), file = Buffer(StrLen(f)*2+2), param = Buffer(12*2+2)
    buff.Zero() # обнуляем память
   
    verb.SetStr("properties" & Chr(0))
    file.SetStr(f & Chr(0))
    #param.SetStr("Security" & Chr(0))
    param.SetStr("Безопасность" & Chr(0))   

    buff.SetNum(0, "dword", buff.size, _   
                  "ulong", SEE_MASK_INVOKEIDLIST, _         
                  "ptr", 0, _
                  "ptr", verb.Ptr, _
                  "ptr", file.Ptr, _
                  "ptr", param.Ptr, _
                  "ptr", 0, _
                  "int", SW_SHOWNORMAL)
    DllCall("shell32\ShellExecuteExW", "ptr", buff.Ptr)
    Free(buff, verb, file, param)
EndFunc
[/cut]
Loopback
Сообщения: 1646
Зарегистрирован: Пн сен 07, 2009 09:29

Сообщение Loopback »

Версия Autorun 2.2.17 beta

[cut="Список изменений"]
- SendMessage/PostMessage не работали с HWND_BROADCAST
- в DllCall исправлены типы str и wstr для возвращаемого значения
- в List метод Split работал неправильно с разделителем в конце строки
+ ShellExec устанавливает значение макроса SYSERROR(TEXT) при ошибке
- ShellExec не запускала некоторые типы файлов (например, cpl)
- исправлена обрезка значений типа ptr/handle в DllCall
- ModifyDialogs: исправлена работа флага 4 центрирования AddDialog, если окно не имеет родителя
+ параметр в SendCommand для отправки команд через SendMessage
+ Runtime: добавлена функция GetCurrentPath, в GetCurrentItem изменен порядок индексов, добавлены новые
+ добавлено свойство SortMethod в List, добавлена натуральная сортировка (Windows7+)
+ LngRead при первом вызове будет использовать текущий язык, если второй параметр не задан
+ добавлен объект Map
+ добавлена функция MakeInt
+ в функции Ini* добавлена поддержка AlternateUserIni
* убрана функция Opt
* КРИТИЧНО: в функциональной записи убрано разворачивание переменных в тексте парамеров в ряде функций
- функция RegRead иногда возвращала мусор для REG_SZ и REG_EXPAND_SZ строк
[/cut]

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

[cut="Список затронутых функций"]
CommandExec
ShellExec
LoadLibrary
LoadFont
LngRead
MsgBox
SetEnv
StrLeft
StrLen
StrLower
StrMid
StrPart
StrPos
StrReplace
StrRight
StrTrim
StrUpper
IniDelete
IniRead
IniReadSection
IniReadSectionNames
IniRenameSection
IniWrite
IniWriteSection
FileExist
FileGetAttr
FileGetSize
FileGetTime
FileGetVersion
FileSetAttr
FileSetTime
ProcessCount
ProcessExecGetOutput
ProcessGetId
ProcessExist
ProcessTerminate
[/cut]

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

[cut="Подробно про исправление"]

Перестанет работать код в функциональной записи, который основывался на разворачивании переменных прямо в тексте:

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

Например
FileGetAttr("%COMMANDER_PATH%\Totalcmd.exe")
нужно заменить на 
FileGetAttr(COMMANDER_PATH & "\Totalcmd.exe")
или
FileGetAttr(Set("%COMMANDER_PATH%\Totalcmd.exe"))
Если текст с %переменной% содержится в другой переменной и раньше код основывался на разворачивании этого текста в параметре функции, то теперь в функциональной записи разворачивание производиться не будет. Чтобы достичь такого же результата, нужно будет добавить Set для явного разворачивания содержимого переменной:

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

path = "%COMMANDER_PATH%\Totalcmd.exe"
Было
FileGetAttr(path)
стало
FileGetAttr(Set(path))
Переключатель /EV-, встречающийся в ряде функций, теперь будет неприменим при записи в ФЗ.

Все записи функций в командном виде должны сохранить работоспособность без изменений.
[/cut]


Все же очень неудобна эта фича форума со склеиванием последовательных сообщений. Было бы куда логичнее выложить версию в одном посте, а ответы дать в другом...
Orion9 писал(а):То есть обе записи следует избегать, и с кавычками тоже?
Это про вторую. С первой вопросов нет.
Orion9 писал(а):Я все такие записи исправил на:
Правильно.
Orion9 писал(а):Но иногда нужно, чтобы переменная раскрылась:
Похоже, я не совсем точно понял изначальный вопрос.
Если есть переменная Local Dir = "%COMMANDER_PATH%\Ini", то в командах: %"Dir%" равно "%COMMANDER_PATH%\Ini", а %"%Dir%" равно "C:\Portable\TOTALCMD\Ini"?
Разве? В первом случае лишний %, предполагаю опечатка. Вот код:

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

Local Dir = "%COMMANDER_PATH%\Ini"

# тут содержимое не раскрывается OutputDebugString, поэтому выводит как есть
OutputDebugString %"Dir"
OutputDebugString %"%Dir%"

# тут содержимое второй раз раскрывается самим MsgBox
MsgBox %"Dir"
MsgBox %"%Dir%"
В любом случае выводит одинаковый результат.

Всё что внутри вычисляемой строки - считается выражением и подчиняется их правилам. А значит, в следующей версии такие записи %"%i%-2" тоже будут некорректны. Кстати забыл про этот вариант, надо его упомянуть в анонсе.

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

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

SetEnv COMMANDER_VIDEO %"%SoftVideo%"
SetEnv COMMANDER_VIDEO %"SoftVideo"
Но вообще-то SetEnv и без вычисляемых строк поддерживает переменные:

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

SetEnv COMMANDER_VIDEO %SoftVideo%
И тут по тому же принципу:

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

ProcessExecGetOutput /OEM out %COMSPEC% "/c dir /s /b *.wav" %"dir"
В общем поэтому и надо привести всё к одному знаменателю, а то неслабая путаница возникает.

Orion9 писал(а):такая функция подойдет?
Мне кажется странной идея считать систему русской, если она не английская, а так с виду ок. Но не уверен.
AkulaBig
Сообщения: 639
Зарегистрирован: Ср дек 03, 2008 11:48

Сообщение AkulaBig »

Loopback писал(а):Некоторые записи могут перестать работать

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

ShellExec %COMMANDER_PATH%\Utilities\MENUIMG\MENUIMG.exe %COMMANDER_PATH%\Bars\RESTART_RUS.BAR||#INPUT
IniRead /R flt %COMMANDER_INI% "Associations" "Filter1" ""
SetEnv AssocIco "%COMMANDER_PATH%\Images\Others\ICO\Light\LightOn.ico"
После обновления до Autorun 2.2.17 beta все эти выражения и подобные продолжают работать. Это правильно или надо их заранее переписать?
А переменные и до обновления только так работали:

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

Local ini_WinTitle = %COMMANDER_PATH% & "\Ini\WinTitle.ini"
Тогда что изменилось?
Аватара пользователя
Orion9
Сообщения: 1283
Зарегистрирован: Пн янв 01, 2024 17:18

Сообщение Orion9 »

Loopback
Всё заработало влёт, я аж офигел ) Спасибо!

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

Pragma AutorunPluginFields "CharSet:::CharDetect"

Func CharDetect(FileName, FieldIndex, UnitIndex)
    Static sLib = "uchardet" & (auX64 ? "" : "_x86") & ".dll", _
           hLib = DllCall("LoadLibrary", "wstr", COMMANDER_PATH & "\Ini\Tools\Libs\" & sLib, "ptr")
           
    If hLib = 0 Then Return "#Error# LoadLibrary " & sLib
    
    Static hUC = DllCall(sLib & '\uchardet_new', 'ptr:cdecl')
    If hUC = 0 Then Return "#Error# uchardet_new returned 0"
    
    DllCall(sLib & '\uchardet_reset', 'ptr', hUC, 'cdecl')
    ProcessExecGetOutput buf %COMSPEC% '/c type "%FileName%"'     
    
    Local size = StrLen(buf)
    Local Res = DllCall(sLib & '\uchardet_handle_data', 'ptr', hUC, 'str', buf, 'uint', size, 'int:cdecl')
    If Res > 0 Then Return "#Error# uchardet_handle_data returned " & Res

    DllCall(sLib & '\uchardet_data_end', 'ptr', hUC, 'cdecl')   
    Return DllCall(sLib & '\uchardet_get_charset', 'ptr', hUC, 'str:cdecl')
    #DllCall('uchardet\uchardet_delete', 'ptr', hUC, 'cdecl')
EndFunc
Знаю, что ProcessExecGetOutput для этих дел не годится, но это только эксперимент. Надеюсь, в будущем у Autorun найдутся свои функции для открытия файлов на чтение :D А пока можно через консольную утилиту гнать:
https://github.com/gentlehill/uchardet? ... me-ov-file
и код совсем простой:

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

Func EncDetect(FileName, FieldIndex, UnitIndex)
    Local pipe, exe_tool = COMMANDER_PATH & "\Ini\Tools\uchardet.exe"
    ProcessExecGetOutput pipe %exe_tool% '"%FileName%"'   
    Return pipe
EndFunc
И большое спасибо за имена функций в GetState. Теперь выглядит как надо:

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

Thread #1:
    Origin: Main
    ThreadID: 3388
    Started: 03.03.2025 16:47:52

Thread #2:
    Origin: RunThread
    Function: ThreadTitle
    ThreadID: 4704
    Started: 03.03.2025 16:47:53

Thread #3:
    Origin: RunThread
    Function: ThreadNewsbar
    ThreadID: 3404
    Started: 03.03.2025 16:47:53

Thread #4:
    Origin: RunThread
    Function: ThreadSounds
    ThreadID: 1536
    Started: 03.03.2025 16:47:53
Это далеко не всё. Ещё позже отпишусь.

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

AkulaBig
Скорее всего вам придется, как и мне, избавляться от таких записей:

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

%"%SoftVideo%"
К сожалению, на ранних этапах использования Autorun я не разобрался с этой записью и допустил ошибку. Теперь приходится все исправлять.
AkulaBig
Сообщения: 639
Зарегистрирован: Ср дек 03, 2008 11:48

Сообщение AkulaBig »

Orion9 писал(а):Скорее всего вам придется, как и мне, избавляться от таких записей:
Я еще в прошлый раз от них избавился по наводке Loopback. А сейчас посмотрел, есть еще одна такая запись.
Loopback
Сообщения: 1646
Зарегистрирован: Пн сен 07, 2009 09:29

Сообщение Loopback »

AkulaBig писал(а):После обновления до Autorun 2.2.17 beta все эти выражения и подобные продолжают работать. Это правильно или надо их заранее переписать?
Правильно. Я же специально акцентировал внимание, что изменения коснулись только функций по списку и только в функциональной записи.

Эти три функции хоть и в списке, но они записаны в командной записи, их трогать не нужно.

И в следующей версии эти три записи тоже не пострадают, т.к. в них нет вычисляемых строк.
AkulaBig писал(а):Тогда что изменилось?
Так, а анонс-то для чего? :) Там же чётко написано, на какие случаи надо обратить внимание. Их всего-то два. В посте выше спойлер Подробно про исправление.

Для лучшего понимания, ваш первый пример. Если бы он был записан так:

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

ShellExec("%COMMANDER_PATH%\Utilities\MENUIMG\MENUIMG.exe", "%COMMANDER_PATH%\Bars\RESTART_RUS.BAR||#INPUT")
то в предыдущей версии он бы работал, а в новой гарантированно сломался.
Orion9 писал(а):найдутся свои функции для открытия файлов на чтение
Обязательно найдутся.
Orion9 писал(а):на ранних этапах использования Autorun я не разобрался с этой записью и допустил ошибку
Не исключаю, что возможно я и сам когда-то где-то писал так же. В то время были такие, не самые удачные решения, типа для "облегчения перехода" и "сохранения совместимости". А в итоге всё равно приходится менять.
AkulaBig
Сообщения: 639
Зарегистрирован: Ср дек 03, 2008 11:48

Сообщение AkulaBig »

Loopback писал(а):Так, а анонс-то для чего?
Все ясно. Просто хотелось вашего разъяснения. Сразу стало наглядно понятно, как должны выглядеть правильные записи.
А то я левым полушарием разбираюсь с Autorun, правым WinDjView, написанным на MFC. Сделал плагин для него. А там полно рогаток, пришлось кодить. И тут и там методом тыка. Аж самому смешно :oops:
Аватара пользователя
Orion9
Сообщения: 1283
Зарегистрирован: Пн янв 01, 2024 17:18

Сообщение Orion9 »

Loopback писал(а):Похоже, я не совсем точно понял изначальный вопрос.
Просто мне не нужно было мудрить с ним ) Надо было просто спросить, равны ли эти две записи или нет. Да и вообще, стоило самому проверить прежде, чем на форум писать.
Loopback писал(а):В первом случае лишний %, предполагаю опечатка.
Да, опечатка. Причём дурацкая и в самом ненужном месте )
Loopback писал(а):В любом случае выводит одинаковый результат.
Не знаю, откуда у меня взялась идея, что проценты в вычисляемой строке раскрывают переменные окружения. Но иногда требуется именно раскрыть. Т.е. если SoftVideo = "%POT_PLAYER%", а POT_PLAYER = "%COMMANDER_PATH%\Soft\PotPlayer\PotPlayerMini.exe", то:

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

SetEnv COMMANDER_VIDEO %SoftVideo%
Не раскроет переменную, и COMMANDER_VIDEO будет равен "%POT_PLAYER%". А запись:

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

SetEnv COMMANDER_VIDEO %"SoftVideo"
Раскрывает, и тогда COMMANDER_VIDEO содержит в себе полный путь к PotPlayerMini.exe, что и требуется в одной задаче.
Loopback писал(а):Мне кажется странной идея считать систему русской, если она не английская
А мне другого и не нужно :D Делать многоязычную поддержку планов нет, просто заметил, что при минимальных усилиях можно учесть в коде английский UI, добавив условие к:

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

param.SetStr("Security" & Chr(0))
param.SetStr("Безопасность" & Chr(0))
То же самое относится и к строке поиска окна выбора цвета, где предусмотрен только русский вариант:

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

h = WinFind(0, "#32770", "Цвет")
А что касается релиза, то пока всё работает, но завтра я буду больше тестировать, тогда и посмотрим. Но надо сказать, что такими темпами, скоро и AutoHotkey будет не нужен :D
Аватара пользователя
Orion9
Сообщения: 1283
Зарегистрирован: Пн янв 01, 2024 17:18

Сообщение Orion9 »

Проиграть звук в Autorun? Да без проблем! :D

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

file = "C:\Windows\Media\tada.wav"
DllCall("Winmm.dll\PlaySoundW", "wstr", file,  "ptr", 0, "dword", 131072 + 1)
Loopback, пока не поставил в конце имени PlaySoundW, функция не хотела работать, хотя в справке говорится, что такая подстановка должна происходить автоматически. Уже второй раз замечаю.

Решил переделать тёмный хинт под новые параметры задержки:

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

Func ShowDarkHint(DarkHint, Delay = 0, Flags = 0)
    # формат подсказки
    SetHintParam("ShowHint", "Font", 10, "Arial")
    SetHintParam("ShowHint", "BackColor", 0x001C1C1C)
    SetHintParam("ShowHint", "Text", 0xFFFFFF)   
    # отображение подсказки
    ShowHint(DarkHint, "", "", Delay, Flags)
    # возвращение формата по умолчанию
    Sleep(50)
    SetHintParam("ShowHint", "Reload")    
EndFunc
Поскольку у этой функции два необязательных параметра на конце, не будет ли каких проблем с простым вызовом вроде ShowDarkHint("Текст"), или лучше указывать хотя бы один параметр, т.е. ShowDarkHint("Текст", 0)?

Раньше у меня был второй вариант.
Loopback
Сообщения: 1646
Зарегистрирован: Пн сен 07, 2009 09:29

Сообщение Loopback »

Orion9 писал(а): хотя в справке говорится, что такая подстановка должна происходить автоматически
В справке говорится, что если
...такой функции не окажется в перечисленных выше библиотеках, будет произведена попытка...
Т.е. схема применяется только к перечисленному списку, winmm.dll в нем отсутствует.

С другой стороны, получение адреса не сильно ресурсоемкая операция, наверно, можно распространить и на другие библиотеки. Но в любом случае лучше использовать суффикс W явно, будет чуть-чуть, но быстрее.
Orion9 писал(а):Поскольку у этой функции два необязательных параметра на конце, не будет ли каких проблем с простым вызовом вроде ShowDarkHint("Текст"), или лучше указывать хотя бы один параметр, т.е. ShowDarkHint("Текст", 0)?
С чего бы им быть? Параметры со значением по умолчанию для таких задач и предназначены.
Ответить