1

Тема: AutoHotkey: советы по автоматизации Total Commander

В файле Totalcmd.inc содержатся все внутренние команды Total Commander. Найдите в этом файле интересующую вас команду, и рядом с ней будет написан wParam в десятичном виде, который можно использовать для команды SendMessage. Например, возьмём команду "Показать окно быстрого поиска". Находим в указанном файле такую (или похожую, в зависимости от варианта локализации) строку: cm_ShowQuickSearch=2915;Показать окно быстрого поиска. Число 2915 и будет wParam для команды SendMessage.

А параметр Msg для команды SendMessage всегда будет 1075 - это десятичный код команды WM_USER+51. Можно использовать и шестнадцатеричный код этой команды. Число 1075 в HEX-виде будет 0x433.

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

; показать окно быстрого поиска (десятичные параметры)
SendMessage, 1075, 2915,,, ahk_class TTOTAL_CMD

или

; показать окно быстрого поиска (шестнадцатеричные параметры)
SendMessage, 0x433, 0xb63,,, ahk_class TTOTAL_CMD

или

; показать окно быстрого поиска (смешанные параметры)
SendMessage, 0x433, 2915,,, ahk_class TTOTAL_CMD

Команда WM_USER+51 была найдена с помощью программы Winspector.
Идею опубликовал Androgen.

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

2 (изменено: Androgen, 2006-12-17 12:31:18)

Re: AutoHotkey: советы по автоматизации Total Commander

В Total Commander'е, начиная с версии 7.0 public beta 1, появилась возможность создавать пользовательские команды. Это просто зверски расширяет возможности его автоматизации (да и просто зверски расширяет его возможности) . Расскажу о двух возможных способах это использовать.

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

ControlSend, Edit1, MyAlias{Enter}, ahk_class TTOTAL_CMD ; вбиваем свою команду в ком. строку

Тут надо сказать, что и сами пользовательские команды и псевдонимы для них можно писать в соответствующие ini-файлы скриптами. Причём без перезапуска Тотала. Т.е. прямо на ходу вписать нужную команду, да и выполнить её. А затем и удалить, если она больше не понадобится. Правда тут есть некоторые сложности (а куда без них) с определением местоположения этих самых "соответствующих ini-файлов". Дело в том, что одной из новых фич Тотала является возможность дробить ранее цельный wincmd.ini (или как там вы его назвали) на множество разных ini-файлов. И найти нужный не так просто, как может показаться, (это и раньше было тем ещё гемором). Но задача вполне решаемая. Собственно я её уже почти решил, но всё как-то некогда поставить последний штрих. Поставлю - выложу. Ну, это так, к слову. Двигаем далее.

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

;-----------------------------------------------------------------------------
Send_WM_COPYDATA( ParameterToSent, TargetTC ) ; функция высылки Тоталу пользовательской команды em_xyz
{
    ; В качестве параметров функция принимает имя команды em_xyz и целевое окно ТС
    VarSetCapacity( CopyDataStruct, 12 ) ; устанавливаем размер высылаемой структуры данных
    InsertInteger( Asc( "E" ) + 256 * Asc( "M" ), CopyDataStruct ) ; вставляем в структуру то, что требует ТС для исполнения команд
    InsertInteger( StrLen( ParameterToSent ) + 1, CopyDataStruct, 4 ) ; добавляем собственно команду (+ символ конца строки)
    InsertInteger( &ParameterToSent, CopyDataStruct, 8 ) ; добавляем указатель на собственно команду
    SendMessage, 0x4A,, &CopyDataStruct,, %TargetTC% ; шлём команду Тоталу, обязательно Send, а не Post (0x4A = WM_COPYDATA)
    Return, ErrorLevel ; выходим из функции и возвращаем ответ SendMessage'а
}
;-----------------------------------------------------------------------------
InsertInteger( pInteger, ByRef pDest, pOffset = 0, pSize = 4 ) ; функция заполнения структуры данными
{
    Loop, 4 ; копируем каждый байт целого числа в структуру как сырые двоичные данные
    {
        DllCall("RtlFillMemory" ; заполняем структуру нашими данными
        , "UInt" , &pDest + pOffset + A_Index-1 ; указатель на адрес, с которого начинается заполнение
        , "UInt" , 1 ; размер заполняемой структуры в байтах
        , "UChar", pInteger >> 8*( A_Index-1 ) & 0xFF) ; содержимое заполняемого байта
    }
}
;-----------------------------------------------------------------------------

Примеры их использования:
Простейший пример:

Send_WM_COPYDATA( "em_usercmd1", "ahk_class TTOTAL_CMD" ) ; шлём пользовательскую команду Тоталу

Пример чуть позаковыристей:

DetectHiddenWindows, On ; искать в скрытых окнах (на случай, если Тотал свёрнут в трей)
WinGet, hw_TTOTAL_CMD, ID, ahk_class TTOTAL_CMD ; получить ID окна TC (не абы какого, а последнего активного :) )
UserParameter = em_usercmd2 ; эту команду будем слать
Send_WM_COPYDATA( UserParameter, "ahk_id" hw_TTOTAL_CMD ) ; вызываем функцию
If ErrorLevel = FAIL ; проверяем, что сказал вызов функции
    MsgBox, Команда SendMessage не удалась. Вероятно, Тотал не запущен.

Примечание: Тотал возвращает 0, и если команда им была выполнена успешно, и если такой команды нет. Но во втором случае, он ещё и покажет соответствующее сообщение. На мой взгляд, не самая удачная реализация, но что есть, то есть.

Добавлю, что я пробовал с помощью Winspector Spy отловить, какие сообщения шлёт сам Тотал, когда выполняет пользовательскую команду, и использовать результат для высылки этих сообщений, но способ оказался нерабочий, т.к. wParam плавает от случая к случаю.

Удачи. Будут комменты - прошу высказываться.

Крокодил, крокожу и буду крокодить! (Твёрдое обещание нетрезвого кодера).