Orion9

|
Posted: Sat Mar 01, 2025 00:20 Post subject: |
|
|
После внесения некоторых изменений можно считать, что данный вариант функций для работы с иконками в трее, более-менее законченный:
 Hidden text Code: | 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 |
Добавил туда важных комментариев, которые позволят быстрее разобраться, но если коротко, сейчас используются две функции: одна для добавления иконок в трей и работы с ними (NotifyIcon), другая - только для показа уведомлений (NotifyInfoMessage):
 Hidden text Code: | 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) |
Кнопки для тестов:
 Hidden text TOTALCMD#BAR#DATA
64000
%COMMANDER_EXE%,1
Иконка в трее
1
-1
 Hidden text TOTALCMD#BAR#DATA
64001
%COMMANDER_EXE%,1
Смена икоки в трее|ALT - Только сообщение|CTRL - Добавление второй
1
-1
 Hidden text TOTALCMD#BAR#DATA
64002
%COMMANDER_EXE%,1
Тест уведомления
1
-1
Первая кнопка включает или отключает иконку в трее, вторая меняет иконку и показывает сообщения, третья тестируют уведомления.
В основном файле конфигурации важно не забыть удалить иконки при выходе в секции финализации:
 Hidden text Code: | Pragma AutorunFinalizeSection
# удаление иконок
If Tray1001 > 0 Then NotifyIcon("delete", 1001)
If Tray1002 > 0 Then NotifyIcon("delete", 1002) |
Loopback, хотел попробовать сделать по мотивам темы:
https://www.autohotkey.com/boards/viewtopic.php?t=110783
Там есть рабочий код на AutoHotkey, вроде ничего сложного:
 Hidden text Code: | 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 |
И вроде выложили последние библиотеки:
https://github.com/telppa/ahk-chardet/tree/main/Lib
Я проверил - скрипт на них работает. Решил сделать то же самое на Autorun, но последняя функция возвращает пустую строку. Если у вас будет время, посмотрите, пожалуйста, в чём может быть причина. Здесь даже два варианта )
 Hidden text Code: | 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
|
 Hidden text Code: | 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 |
|
|