А знаете ли вы?..


  1. ...как опpеделить задачу, котоpая не будет отобpажаться в меню Start Task и Edit?
  2. ...как передать задаче аргументы из командной строки?
  3. ...как вести счет недель, т. е. запускать задачу, например только во второй понедельник месяца или третье воскресенье декабря?
  4. ...как узнать имя выполняемой задачи и имя кронтаб-файла, где эта задача находится?
  5. ...как вывести на экран сообщение с заданным текстом и заголовком?
  6. ...как запускать задачу только после загрузки/перезагрузки компьютера?
  7. ...как вpеменно заблокиpовать юзеpу ввод с мыши/клавиатуpы?
  8. ...как "приказать" nnCron вести единый лог-файл, а не создавать каждый день новый?
  9. ...как программно прекратить выполнение задачи (например, в случае ошибки)?
  10. ...как из одной задачи остановить выполнение другой задачи?
  11. ...как программно применить к задаче опцию NoActive или, наоборот, отменить ее действие?
  12. ...как перехватывать и самостоятельно обрабатывать возникающие исключения?
  13. ...как расшифровать номера ошибок на форт-консоли, в лог-файле и и в nncron.out?
  14. ...как перекодировать строку из кодировки WIN в кодировку OEM и наоборот?
  15. ...как с помощью nnCron изменять атрибуты файлов?
  16. ...как проверить условие на одной машине, а выполнить задачу на другой? Разумеется, на обеих машинах в сети запущено по nnCron'у.
  17. ...как узнать текущее разрешение экрана?
  18. ...как программно очистить корзину (Recycle Bin)?
  19. ...как в цикле FOR-FILES: получить короткое имя файла (8.3)?
  20. ...как запускать собственную задачу по двойному клику на иконке nnCron в системном трее?
  21. ...как сконструировать собственное меню, которое бы появлялось при клике правой кнопкой мыши на иконке nnCron в системном трее?
  22. ...как запустить задачу с помощью ярлыка/шортката (*.lnk)?
  23. ...как запускать программы с помощью ярлыков/шорткатов (*.lnk)?
  24. ...как скопировать указанный каталог, со всеми файлами и подкаталогами?
  25. ...как перезапустить nnCron прямо из задачи?
  26. ...как узнать над каким элементом активного окна сейчас находится указатель мыши?
  27. ...как прятать любое окно в трей, кликнув на кнопке Minimize правой кнопкой мыши?

...как оп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
)#