А знаете ли вы?..
...как опpеделить задачу, котоpая не будет отобpажаться в меню Start Task и Edit?
Назвать задачу так: CLASSIC-TASK-#-ххх.
#( CLASSIC-TASK-#-xxx NoActive Action: MSG: "CLASSIC-TASK-#-xxx" )#
Вместо ххх можно указывать любые символы кроме пробела (например, CLASSIC-TASK-#-ABCD, CLASSIC-TASK-#-123456 или CLASSIC-TASK-#-my_task). А если вдpуг понадобится запустить задачу "вpучную", то сделать это можно из командной стpоки:
nncron -run CLASSIC-TASK-#-my_task
Обратите внимание, что информация о запуске задач CLASSIC-TASK-#-ххх не отображается в логе nnCron. Если вы хотите, чтобы эта информация присутствовала в логе - воспользуйтесь словами LOG: или CRON-LOG в теле задачи.
...как передать задаче аргументы из командной строки?
Это возможно, если запускать задачу с помощью ключа -runfile:
nncron.exe -runfile <file_name>
Все, что находится в командной строке после имени запускаемого файла считается произвольными аргументами и может быть "считано" Фортовой конструкцией BL WORD (пробел в качестве "делимитера" при разборе). Вот пример, который последовательно выводит месседжбоксы со всеми найденными аргументами командной строки:
\ ---start of args.spf---- : main BEGIN BL WORD COUNT ?DUP \ Blank space as delimiter \ BL SKIP [CHAR] " SKIP [CHAR] " WORD COUNT ?DUP \ Skipping blank spaces, quote as delimiter WHILE MsgBox REPEAT DROP ; \ ---end of args.spf--- \ запуск: nncron.exe -wp -runfile args.spf one two three four
К тому же, в nnCrone есть слово get-string которое выполняет всю черновую работу при "разборе" аргумента: если строка окружена кавычками, то аргументом считается все, что находится внутри кавычек, а если нет, то до первого встреченного пробела.
Пример:
\ ---start of args1.spf--- CREATE str1 256 ALLOT : main get-string str1 PLACE MSG: "%str1 COUNT%" ; \ ---end of args1.spf--- \ запуск: \ nncron.exe -wp -runfile args1.spf "Very long argument in quotes"
...как вести счет недель, т. е. запускать задачу, например, только во второй понедельник месяца или третье воскресенье декабря?
\ это каждый 2-й понедельник января (08:00) Time: 0 8 8-14 Jan Mon * \ а это каждое 3-е воскресенье декабря (08:00) Time: 0 8 15-21 Dec Sun *
Так же можно сделать и для первой (1-7) и для четвертой недели (22-28), а вот
для последней недели так не получится. Тут надо уже мудрить. Hо день месяца
доступен (Day@), и день недели тоже (WDay@). Так что, можно
мудрить с произвольной сложностью, и не забывайте про OnceAWeek.
...как узнать имя выполняемой задачи и имя кронтаб-файла, где эта задача находится?
Имя задачи:
%CUR-NODE CRON-NAME @ COUNT%
Имя кронтаба:
%CUR-NODE CRON-FILENAME @ COUNT%
Чтобы получить имя задачи изнутри самой задачи, воспользуйтесь словом CUR-TASK-NAME ( -- a u ).
...как вывести на экран сообщение с заданным текстом и заголовком?
Очень просто:
0 S" Заголовок" DROP S" Сообщение" DROP 0 MessageBoxA DROP
Контролировать можно не только текст и заголовок сообщения, но и иконку сообщения и даже количество кнопок на сообщении. Для этого вместо первого нуля "подставьте" в вышеприведенный пример одно из следующих значений:
0 MB_OK 1 MB_OKCANCEL 2 MB_ABORTRETRYIGNORE 3 MB_YESNOCANCEL 4 MB_YESNO 5 MB_RETRYCANCEL 6 MB_CANCELTRYAGAINCONTINUE 16 MB_ICONERROR 32 MB_ICONQUESTION 48 MB_ICONEXCLAMATION 64 MB_ICONINFORMATION 128 MB_USERICON 4096 MB_SYSTEMMODAL 8192 MB_TASKMODAL 16384 MB_HELP 32768 MB_NOFOCUS 262144 MB_TOPMOST 524288 MB_RIGHT 1048576 MB_RTLREADING
Примеры:
\ выводим сообщение с иконкой ошибки: 16 S" Заголовок" DROP S" Сообщение" DROP 0 MessageBoxA DROP \ выводим сообщение с тремя кнопками (Yes, No, Cancel): 3 S" Заголовок" DROP S" Сообщение" DROP 0 MessageBoxA DROP
Функция MessageBoxA возвращает числовое значение, по которому можно определить: какую из кнопок нажал пользователь. Вот список возвращаемых значений:
1 OK 2 CANCEL 3 ABORT 4 RETRY 5 IGNORE 6 YES 7 NO 10 TRY AGAIN 11 CONTINUE
Примеры:
#( test_retrycancel NoActive Action: 5 S" test_retrycancel" DROP S" Click me!" DROP 0 MessageBoxA 4 = IF MSG: "Retry" ELSE MSG: "Cancel" THEN )# #( test_yesnocancel NoActive Action: 3 S" test_yesnocancel" DROP S" Click me!" DROP 0 MessageBoxA DUP 6 = IF DROP MSG: "Yes" ELSE 7 = IF MSG: "No" ELSE MSG: "Cancel" THEN THEN )#
...как запускать задачу только после загрузки/перезагрузки компьютера?
Решение этой проблемы разделено на две (несложные) части:
1) Сначала надо организовать создание специального файл-флага после каждого старта системы. Для этого можно, например, поместить в каталог Startup шорткат к следующему bat-файлу:
echo started > c:\started.sem
2) Теперь осталось написать само задание:
#( after_system_start WatchFile: "c:\started.sem" Action: FILE-DELETE: "c:\started.sem" \ тут выполняем всю необходимую работу )#
Вуаля!.. Задание запускается только после старта системы.
Причем, в отличие от заданий, запускаемых по START-TIME,
наш вариант начинает выполняться сразу после загрузки компьютера, не
дожидаясь начала "новой" минуты.
Вот еще один способ: слово GetTickCount
кладет на стек время (в миллисекундах), прошедшее с момента старта системы.
Значит, мы можем проверять это время и если оно меньше минуты-двух, то значит
система только что стартовала.
Пример:
#( system_restart Time: START-TIME Rule: GetTickCount 90000 < Action: \ тут выполняем всю необходимую работу )#
Для медленно стартующих компьютеров, время с которым мы сравниваем GetTickCount, возможно, придется увеличить (90000 - 150000).
...как вpеменно заблокиpовать юзеpу ввод с мыши/клавиатуpы?
Вот как:
WINAPI: BlockInput USER32.DLL : BlockTheInput TRUE BlockInput DROP ; : UnblockTheInput FALSE BlockInput DROP ;
Hо pаботать это будет только в Win9*/2000/XP. Под Win9x вышеуказанная констpукция блокиpует не только действия пользователя, но и pаботу команд SEND-KEYS: и (видимо) команд MOUSE*... Будьте внимательны!
Пpимеp:
#( test_hint WINAPI: BlockInput USER32.DLL : BlockTheInput TRUE BlockInput DROP ; : UnblockTheInput FALSE BlockInput DROP ; Action: BlockTheInput HINT: ">>>>> Warning! <<<<<%crlf%User input is blocked!%crlf%" PAUSE: 2000 START-APP: "Notepad" PAUSE: 1000 SEND-KEYS-DELAY: 200 500 WIN-SEND-KEYS: "*Notepad" "t{ENTER}te{ENTER}tes{ENTER}test" SEND-KEYS: "{ENTER}test{ENTER}tes{ENTER}te{ENTER}t" PAUSE: 1000 HINT-OFF UnblockTheInput THINT: "User input unblocked!" 3 )#
Обратите также внимание, что пользовательский ввод блокируется только на время работы задачи, из которой был вызван BlockTheInput. Как только задача прекращает работу, пользовательский ввод автоматически разблокируется.
...как "приказать" nnCron вести единый лог-файл, а не создавать каждый день новый?
Для этого надо изменить значения переменных Cronlog и (опционально) LogTimeFormat в nncron.ini:
\ path of log Cronlog: "log\nncron.log" \ log time pattern LogTimeFormat: "%DD% %MMM% %hh%:%mm%:%ss% %ThreadId%"
Вот как будет выглядеть информация в логе:
11 Jul 13:25:04 436 Start nnCron 11 Jul 13:25:07 436 Load crontab 11 Jul 13:25:08 436 D:\TOOLS\NNCRON\nncron.tab 11 Jul 13:25:08 436 D:\TOOLS\NNCRON\vk.tab 11 Jul 13:25:08 436 D:\TOOLS\NNCRON\hotkey.tab 11 Jul 13:25:08 436 D:\TOOLS\NNCRON\test.tab 11 Jul 13:25:10 988 TASK: system_restart 11 Jul 13:25:35 508 TASK: hotkey_Ctrl+Alt+F 11 Jul 13:25:36 508 Start: d:\tools\far\far.exe 11 Jul 13:25:36 508 Start result: 0
Кстати говоря, единый лог можно время от времени "урезать", пользуясь конструкцией FILE-CROP:.
...как программно прекратить выполнение задачи (например, в случае ошибки)?
Воспользоваться словом из ядра Форта EXIT, которое предназначено для выхода из текущего слова. Его можно употреблять, поскольку Action: - это тоже Форт-слово.
#( test_exit NoActive Action: \ ... делаем что-нибудь полезное и \ проверяем, не произошла ли ошибка: FILE-EXIST: "error.log" IF \ произошла ошибка, \ удалаем файл и прекращаем выполнение задачи FILE-DELETE: "error.log" EXIT THEN \ ... продолжаем работать, если не было ошибки )#
Будьте внимательны: слово EXIT нельзя напрямую использовать в циклах DO ... LOOP, так как EXIT удаляет из стека один из аргументов, занесенных в него оператором DO, вместо того, чтобы удалить из вершины стека возвратов адрес возврата. Чтобы выйти и из цикла, и из задачи используйте конструкцию UNLOOP EXIT:
DO ... IF UNLOOP EXIT THEN ... LOOP
...как из одной задачи остановить выполнение другой задачи?
Например, так (работать будет только в ВинНТ/2000/ХР):
#( task1 VARIABLE t1-id Action: GetCurrentThreadId t1-id ! )#
#( task2 WINAPI: OpenThread KERNEL32.DLL Action: t1-id @ ?DUP IF 0 1 OpenThread ?DUP IF STOP THEN THEN )#
...как программно применить к задаче опцию NoActive или, наоборот, отменить ее действие?
Изнутри самой задачи:
\ активизируем CUR-NODE CF-ACTIVE SET-CRON-FLAG \ деактивизируем CUR-NODE CF-ACTIVE CLR-CRON-FLAG
Из другой задачи:
\ активизируем <task_name> @ CF-ACTIVE SET-CRON-FLAG \ деактивизируем <task_name> @ CF-ACTIVE CLR-CRON-FLAG
Обратите внимание, что программно оперируя опцией NoActive вы не вносите физических изменений в кронтаб-файл. Это означает, что вы меняете статус активности задачи только до следующего перечитывания кронтабов.
С помощью следующих слов вы можете проверить - установлена ли у задачи опция NoActive:
\ проверяем активность изнутри самой задачи: CF-ACTIVE? IF \ ... THEN \ проверяем активность из другой задачи: <task_name> @ CRON-FLAGS @ CF-ACTIVE AND? IF \ ... THEN
...как перехватывать и самостоятельно обрабатывать возникающие исключения?
nnCron предоставляет возможность в каждом конкретном случае перехватывать исключения самостоятельно и после этого решать, "что с ними делать".
Исключения перехватываются так:
['] word_name CATCH
['] - ищет следующее слово в словаре (в режиме компиляции) и компилирует
в определение его адрес xt (execution token) в виде числового литерала.
CATCH - берёт со стека xt, запоминает состояние стека (грубо говоря)
и выполняет этот самый xt. Если во время работы xt произойдёт исключение,
то дальше CATCH оно не уйдёт. Слово CATCH возвращает 0,
если исключений не возникло, и код ошибки в обратном случае.
Значит, в ситуации "приближенной к боевой" эта конструкция будет выглядеть так:
word_attributes ['] word_name CATCH ?DUP IF \ обработка ошибки \ на вершине стека будет лежать код ошибки \ а далее в стеке будет мусор \ в зависимости от параметров THEN
Пример:
S" from-path" S" to-path" ['] FCOPY CATCH ?DUP IF \ выводим в 'nncron.out' и на консоль код ошибки ." Copy error # " . CR \ удаляем мусор 2DROP 2DROP ELSE \ эта ветка может и отсутствовать ." Удачное копирование" CR THEN
Использовать CATCH напрямую можно только с "постфиксными" словами. Если же возникла необходимость обработать исключение префиксного слова, то на его основе нужно создать новое слово.
Пример:
#( task1 : copy1 FILE-COPY: "path-from" "path-to" ; \ ... Action: ['] copy1 CATCH ?DUP IF \ ... )#
Иногда, когда задача большая и ошибку могут вернуть сразу несколько операторов, помогает следующий трюк: помещаем все, что раньше было в разделе Action: в новое слово, и "сторожим" его с помощью CATCH.
Пример:
#( task2 NoActive : task-body \ помещаем все, что было в разделе Action: \ в новое слово task-body \ ... ; Action: \ выполняем новое слово, одновременно отлавливая ошибки ['] task-body CATCH ?DUP IF ." Error # " . CR THEN )#
...как расшифровать номера ошибок на форт-консоли, в лог-файле и nncron.out?
Чтобы консольные ошибки выводились в удобном для пользователя виде, а не в виде цифровых кодов (5, 2003, FILE ERROR # 3 и т. д.), скачайте и разархивируйте в каталог nnCron следующий файл: http://www.nncron.ru/download/spf_err.rar (~24k). Описание ошибок из лог-файла и nncron.out можно найти в этом же файле (по номеру ошибки).
...как перекодировать строку из кодировки WIN в кодировку OEM и наоборот?
В ядре nnCron определены "перекодирующие" слова OemToCharBuffA и CharToOemBuffA. Вот как с их помощью можно делать перекодировку строк:
#( test_recode NoActive \ определяем "перекодировочные" слова : WIN2OEM ( a u -- a u ) 2DUP SWAP DUP CharToOemBuffA DROP ; : OEM2WIN ( a u -- a u ) 2DUP SWAP DUP OemToCharBuffA DROP ; \ создаем буфер, в который скопируем строку для перекодировки CREATE RECODE_BUFFER 256 ALLOT Action: S" тестовая строка" RECODE_BUFFER PLACE \ сохраняем текст в кодировке OEM (ASCII): RECODE_BUFFER COUNT WIN2OEM S" c:\test_oem.txt" FWRITE \ сохраняем текст в кодировке WIN (ANSI): RECODE_BUFFER COUNT OEM2WIN S" c:\test_win.txt" FWRITE )#
Hиколас настоятельно рекомендует копировать строку в буфер и перекодировать ее там (как показано в примере), вместо того, чтобы преобразовывать кодировку прямо на месте хранения строки.
...как с помощью nnCron изменять атрибуты файлов?
Смотрим, что на этот счет сказано в WinAPI:
BOOL SetFileAttributes( LPCTSTR lpFileName, // file name DWORD dwFileAttributes // attributes );
Значит, можно делать, например, так:
#( test_file_attrib WINAPI: SetFileAttributesA Kernel32.dll NoActive Action: \ устанавливаем атрибут hidden: 2 S" c:\temp\test.txt" DROP SetFileAttributesA DROP )#
Вот расшифровка констант, которые можно употреблять вместо dwFileAttributes:
FILE_ATTRIBUTE_READONLY 1 FILE_ATTRIBUTE_HIDDEN 2 FILE_ATTRIBUTE_SYSTEM 4 FILE_ATTRIBUTE_DIRECTORY 16 FILE_ATTRIBUTE_ARCHIVE 32 FILE_ATTRIBUTE_NORMAL 128 FILE_ATTRIBUTE_COMPRESSED 2048
...как проверить условие на одной машине, а выполнить задачу на другой? Разумеется, на обеих машинах в сети запущено по nnCron'у.
Самое простое - через промежуточный файл, создаваемый на общедоступном сетевом диске.
Во-первых, можно использовать этот файл как флаг - создавать файл с одной машины, а "следить" за ним с другой.
Во-вторых, с помощью такого файла можно передать второй копии nnCron даже текст задачи, которая должна быть выполнена. Вот пример. В одной копии nnCron создаем файл под названием remote_task.spf с таким содержимым:
S" Hello" MsgBox
А на соседней машине выполняется такая задача:
#( remote_task WatchFile: remote_task.spf Action: 1000 PAUSE S" remote_task.spf" INCLUDED S" remote_task.spf" DELETE-FILE DROP )#
Не забывайте также про возможность запустить задачу из текстового файла с помощью ключа командной строки -runfile
...как узнать текущее разрешение экрана?
Существует слово WIN-RECT, которое возвращает четыре значения: координаты левого верхнего и правого нижнего углов указанного окна. В качестве аргумента оно принимает window handle этого окна. Значит, чтобы узнать разрешение экрана, достаточно узнать координаты окна Program Manager: последние два значения будут соответствовать текущему разрешению экрана.
Пример:
#( test_screen_resolution NoActive Action:
\ получаем window handle Program Manager WIN-EXIST: "Progman" IF \ выводим координаты окна Program Manager на консоль WIN-HWND WIN-RECT . . . . CR THEN )#
...как программно очистить корзину (Recycle Bin)?
1. Создаем файл clearbin.spf с таким содержимым:
WINAPI: SHEmptyRecycleBinA shell32.dll : main 7 0 0 SHEmptyRecycleBinA DROP ;
2. Определяем задачу:
#( clear_task \ Очищаем корзину по хоткею Ctrl+Alt+Shift+С AsLoggedUser LoadProfile WatchHotKey: "^@+c" Action: ShowNormal NormalPriority START-APP: %ModuleDirName%nncron.exe -wp -runfile clearbin.spf )#
Зачем такие сложности? Резонный вопрос. Для корректной очистки корзины нужна загрузка профиля пользователя, а без запуска отдельного процесса профиль как следует не загружается. Впрочем, если вы используете Win9х, то эта проблема вас не касается - вы можете прямо в теле задачи вызывать:
7 0 0 SHEmptyRecycleBinA DROP
Вот, кстати, константы, которые можно использовать при очистке корзины:
SHERB_NOCONFIRMATION 0x00000001 SHERB_NOPROGRESSUI 0x00000002 SHERB_NOSOUND 0x00000004
...как в цикле FOR-FILES: получить короткое имя файла (8.3)?
Для этого можно определить специальное слово (например, FOUND-SHORTFILENAME) и использовать его внутри цикла FOR-FILES:.
Пример:
<% : FOUND-SHORTFILENAME __FFB cAlternateFileName ASCIIZ> DUP 0= IF 2DROP FOUND-FILENAME THEN ; %> #( test_shortnames NoActive Action: FOR-FILES: "c:\temp\*" MSG: "%FOUND-FILENAME% : %FOUND-SHORTFILENAME%" ;FOR-FILES )#
...как запускать собственную задачу по двойному клику на иконке nnCron в системном трее?
Создать постфиксное слово (можно прямо в nncron.ini):
: launch-your-task S" your-task-name" SFIND IF EXECUTE LAUNCH ELSE 2DROP THEN ;
и отредактировать переменную в nncron.ini TrayIconDoubleClick:
TrayIconDoubleClick: launch-your-task
...как сконструировать собственное меню, которое бы появлялось при клике правой кнопкой мыши на иконке nnCron в системном трее?
Для этого нужно создать в каталоге nnCron текстовой файл menu.f и поместить в него следующее определение:
201 CONSTANT MI_ITEM1 202 CONSTANT MI_ITEM2 204 CONSTANT MI_ITEM31 205 CONSTANT MI_ITEM32 206 CONSTANT MI_ITEM33 : make-my-popup ( -- h ) POPUPMENU S" item1 " MI_ITEM1 MENUITEM S" item2 " MI_ITEM2 MENUITEM POPUP S" item31 " MI_ITEM31 MENUITEM MENUSEPARATOR S" item32 " MI_ITEM31 MENUITEM S" item33 " MI_ITEM31 MENUITEM S" item3" END-POPUP END-MENU ; : def-item-action S" item2" MsgBox ; \ задаем действия для каждого пункта меню : start-my-menu-item ( id -- ) CASE MI_ITEM1 OF S" item1" MsgBox ENDOF MI_ITEM2 OF def-item-action ENDOF MI_ITEM31 OF S" item31" MsgBox ENDOF MI_ITEM32 OF S" item32" MsgBox ENDOF MI_ITEM33 OF S" item33" MsgBox ENDOF ENDCASE ; : my-menu CronIcon hWnd @ SetForegroundWindow DROP make-my-popup >R \ делаем один из пунктов меню "дефолтным" (будет \ выполняться по двойному клику на иконке в трее) 0 MI_ITEM2 R@ SetMenuDefaultItem DROP 0 CronIcon hWnd @ CalcMenuYX ( TPM_RETURNCMD) 256 R@ TrackPopupMenuEx ?DUP IF start-my-menu-item THEN R> DestroyMenu DROP ;
После этого следует отредактировать nncron.ini следующим образом:
S" menu.f" INCLUDED TrayIconDoubleClick: def-item-action TrayIconRightButton: my-menu
В результате вы получите пример полноценного всплывающего меню, которое будет появляться при клике правой кнопкой мыши на иконке nnCron в системном трее. Обратите внимание, что "дефолтный" пункт меню выделен жирным шрифтом и выполняется при двойном клике мышью на икноке nnCron в трее.
...как запустить задачу с помощью ярлыка/шортката (*.lnk)?
Для этого следует использовать опцию командной строки -run <task_name>. Вот "пошаговая" инструкция:
1) Создайте задачу. Деактивируйте ее, если вы не хотите, чтобы задача выполнялась автоматически (NoActive):
#( test_task_shortcut NoActive Action: MSG: "Всем привет!" )#
2) Приступаем к созданию ярлыка/шортката: "кликаем" правой кнопкой мыши в нужном каталоге и выбираем New - Shortcut, после чего указываем местоположение 'nncron.exe' и немного редактируем содержимое поля Location of the item:
<путь_к_каталогу_nncron>\nncron.exe -run test_task_shortcut
Нажимаем Next и придумываем для нашего шортката подходящее имя. Скажем, test_task_shortcut. Нажимаем Finish.
3) Готово! Осталось сделать двойной щелчок левой кнопкой мыши на только что созданном шорткате, чтобы запустить задачу test_task_shortcut.
...как запускать программы с помощью ярлыков/шорткатов (*.lnk)?
Если не нужна авторизация, то так:
#( test_shortcut NoActive Action: 5 0 0 Z" c:\temp\cmd.exe.lnk" Z" open" 0 ShellExecuteA DROP 5 0 0 Z" c:\temp\notepad.exe.lnk" Z" open" 0 ShellExecuteA DROP )#
Для успешной авторизации задачу придется немного усложнить:
#( test_shortcut_authorized NoActive AsLoggedUser Action: START-APP: tm.exe 5 0 0 Z" c:\temp\cmd.exe.lnk" Z" open" 0 ShellExecuteA HALT START-APP: tm.exe 5 0 0 Z" c:\temp\notepad.exe.lnk" Z" open" 0 ShellExecuteA HALT )#
Есть еще один вариант запуска шорткатов с авторизацией (с использованием JScript). Обратите внимание на "прямые" слеши в пути к шорткату:
#( test_shortcut_authorized1 NoActive AsLoggedUser Action: <JScript> var WshShell = new ActiveXObject("WScript.Shell"); WshShell.Run("c:/temp/cmd.exe.lnk"); WshShell.Run("c:/temp/notepad.exe.lnk"); </SCRIPT> )#
...как скопировать указанный каталог, со всеми файлами и подкаталогами?
Проще всего воспользоваться утилитой nnBackup, которая была специально написана для подобных задач:
#( test_backup NoActive Action: START-APP: nnbackup.exe copy -i "c:\data" -o "d:\backup" -v -s )#
Эту же задачу можно решить и только средствами nnCron. Поскольку слово FILE-COPY: не создает промежуточных каталогов при копировании, их прийдется создавать самостоятельно:
#( test_backup1 NoActive Action: RECURSIVE FOR-FILES: "c:\data\*" IS-DIR? IF \ создаем промежуточные каталоги DIR-CREATE: "d:\backup\%FOUND-RELPATH%" ELSE \ копируем файлы FILE-COPY: "%FOUND-FULLPATH%" "d:\backup\%FOUND-RELPATH%" THEN ;FOR-FILES )#
...как перезапустить nnCron прямо из задачи?
Можно, например, так (перезапускаем nnCron ежедневно, в 23:59):
#( test_restart Time: 59 23 Action: SWHide StartIn: "d:\TOOLS\NNCRON" START-APP: %COMSPEC% /c net stop nncron && \ start/wait nncron.exe 5000 PAUSE BYE && \ net start nncron )#
...как узнать над каким элементом активного окна сейчас находится указатель мыши?
Для этого можно послать активному окну windows message WM_NCHITTEST и исследовать полученное числовое значение. Вот список возможных значений:
0 курсор вне текущего активного окна: в фоновой области экрана или на границе между окнами (HTNOWHERE). 1 курсор в клиентской области окна (HTCLIENT). 2 курсор в области заголовка окна (HTCAPTION). 3 курсор на пиктограмме системного меню (HTSYSMENU). 4 курсор в блоке изменения размеров окна (in a size box) (HTSIZE, HTGROWBOX). 5 курсор в панели меню (HTMENU). 6 курсор на горизонтальной полосе прокрутки (HTHSCROLL). 7 курсор на вертикальной полосе прокрутки (HTVSCROLL). 8 курсор на кнопке сворачивания окна (Minimize) (HTMINBUTTON, HTREDUCE). 9 курсор на кнопке разворачивания окна в полный экран (Maximize) (HTMAXBUTTON, HTZOOM). 10 курсор на левой вертикальной границе окна, чей размер можно изменить (HTLEFT). 11 курсор на правой вертикальной границе окна, чей размер можно изменить (HTRIGHT). 12 курсор на верxней горизонтальной границе окна, чей размер можно изменить (HTTOP). 13 курсор в левом верхнем углу окна, чей размер можно изменить (HTTOPLEFT). 14 курсор в правом верхнем углу окна, чей размер можно изменить (HTTOPRIGHT). 15 курсор на нижней горизонтальной границе окна, чей размер можно изменить (HTBOTTOM). 16 курсор в левом нижнем углу окна, чей размер можно изменить (HTBOTTOMLEFT). 17 курсор в правом нижнем углу окна, чей размер можно изменить (HTBOTTOMRIGHT). 18 курсор на рамке окна, чей размер нельзя изменить (HTBORDER). 20 курсор на кнопке Close (HTCLOSE). 21 курсор на кнопке Help (HTHELP). -1 курсор в окне которое закрыто другим окном, порожденным тем же потоком (HTTRANSPARENT). -2 курсор вне текущего активного окна: в фоновой области экрана или на границе между окнами. Этот код выдается, если при попытке кликнуть вне окна выдается звуковой сигнал (HTERROR).
Пример:
#( test_buttons \ appropriate message is shown when you hover your mouse over \ 'Minimize', 'Maximize' or 'Close' buttons in active window SingleInstance Action: BEGIN MOUSE-POS 16 LSHIFT OR \ converting x,y to lParam \ checking the cursor position: 0 132 GetForegroundWindow SendMessageA DUP 8 = \ cursor is over the Minimize button: IF DROP MSG: "Minimize Button!" ELSE DUP 9 = \ cursor is over the Maximize button: IF DROP MSG: "Maximize Button!" ELSE 20 = \ cursor is over the Close button: IF MSG: "Close Button!" THEN THEN THEN PAUSE: 100 AGAIN )#
Чтобы отслеживать щелчок мыши на заданном элементе активного окна, вы можете воспользоваться плагином keystate.spf, который позволяет узнать, нажата ли в данный момент указанная кнопка мыши.
Пример:
#( test_buttons_rightclick \ appropriate message is shown when you right-click on \ 'Minimize', 'Maximize' or 'Close' buttons in active window. \ Make sure that plug-in 'keystate.spf' is loaded. SingleInstance VARIABLE allowMB \ this flag allows to work with the current window Action: BEGIN VK_RBUTTON KEY-PRESSED? \ right mouse button IF allowMB @ \ first press? IF MOUSE-POS 16 LSHIFT OR \ converting x,y to lParam \ checking the cursor position: 0 132 GetForegroundWindow SendMessageA DUP 8 = \ cursor is over the Minimize button: IF DROP MSG: "Minimize Button!" ELSE DUP 9 = \ cursor is over the Maximize button: IF DROP MSG: "Maximize Button!" ELSE 20 = \ cursor is over the Close button: IF MSG: "Close Button!" THEN THEN THEN THEN ELSE \ the mouse button was released, set the flag to ON: allowMB ON THEN PAUSE: 100 AGAIN )#
Еще один практический пример: "...как прятать любое окно в трей, кликнув на кнопке Minimize правой кнопкой мыши?".
...как прятать любое окно в трей, кликнув на кнопке Minimize правой кнопкой мыши?
В эхе RU.NNCRON предложили такой вариант (не забудьте подключить плагины keystate.spf и win2tray.spf):
#( test_min2tray_mouseRB \ put the current window into system tray by \ right-clicking on the 'Minimize' button SingleInstance VARIABLE allowMB1 \ this flag allows to minimize the current window Action: BEGIN VK_RBUTTON KEY-PRESSED? \ right mouse button IF allowMB1 @ \ first press? IF MOUSE-POS 16 LSHIFT OR \ converting x,y to lParam \ checking the cursor position: 0 132 GetForegroundWindow SendMessageA 8 = \ if the cursor is on the Minimize button: IF WIN-TO-TRAY: "%GetForegroundWindow%" THEN allowMB1 OFF \ set flag to OFF THEN ELSE \ the mouse button was released, set the flag to ON: allowMB1 ON THEN PAUSE: 100 AGAIN )#