About nnCron

Program Overview
Graphical User Interface
License for Use and Distribution
Registration
Installing and Removing nnCron
History of Changes
Technical Support
Contact Information and Links
Copyrights


Program Overview

nnCron is an advanced and very powerful scheduler, scripting tool and automation manager. It will be useful to anyone seeking to automate most of his routine computer-related tasks.

Though nnCron is small in size, its capabilities are truly colossal. Besides possessing the conventional scheduler features (starting programs, displaying reminder messages and opening documents at specified time), nnCron also can:

  • start any program as a service
  • run tasks as if they were started by specified user
  • handle and restart so called missed tasks and reminders
  • shut down and hibernate the computer or put it into sleep mode at specified time
  • "wake up" the computer in order to run a task
  • display, hide, close, kill, minimize, maximize and hide specified windows to system tray
  • display messages on screen and write them in a log file
  • work with clipboard, files and registry
  • emulate keyboard input and mouse activities
  • dial and hang up
  • use the system speaker to make beeps of specified length and frequency
  • play audio files
  • sync system time
  • assign specified priority to a process
  • terminate any running process
  • restart automatically after fatal errors
  • keep track of files, flags, windows, processes, mouse activities, periods of idle time, keyboard shortcuts, getting online/off line, insertion of disk in a drive, presence of a host in network (ping), amount of free space on a disk, etc., etc.

nnCron allows to use VBScript/JScript scripting languages, as well as regular expressions when defining a task. It can execute programs written in Forth language (SP-Forth), it can be extended with plug-ins etc...

nnCron understands cron table format (Unix) and is managed with easy-to-edit plain text crontab files. There are at least two reasons why it is convenient to keep settings and data in text files:

  • they are easy to edit
  • settings and tasks won't be lost in case of emergency re-installation of the OS or nnCron

However, for those who prefer to work in a GUI environment, the program has a graphical shell which can be used to remove, add, edit and run tasks, set up reminders, change program settings. Furthermore, nnCron possesses advanced capabilities for working with command line arguments.

nnCron can be run as a system service or as a regular application. As nnCron has to execute important and even critical system tasks, it contains a special tool to ensure a higher level of viability, so called "crash guard" mode.

nnCron has several additional built-in tools which extend its capabilities even further:

  • WinSpy: a utility which permits to find out the current coordinates of mouse pointer, to establish the class of the object over which the mouse pointer hovers at the moment, to get information about coordinates of main window and child window.
  • Console: a tool for interaction with nnCron for those who know Forth language, and an indispensable assistant for those who just start learning this language. You can use Console to administrate nnCron remotely.

Works under Windows 95/98/ME/NT/2000/XP. Not resource-demanding.


Graphical User Interface

Right-click Pop-up Menu:

Add/Edit Task dialog box

Options dialog box:

Reminder window:

WinSpy window:

Detailed information about using Graphical User Interface can be found in Using the nnCron GUI section.


License for Use and Distribution

The nnCron program is distributed as try-before-you-buy. This means:

  • All copyrights to nnCron are exclusively owned by its developer, Nicholas Nemtsev.
  • Anyone may use this software during a test period of 30 days. After this test period of 30 days or less, if you wish to continue to use nnCron, you MUST register it.
  • Once registered, the user is granted a non-exclusive license to use nnCron, for any legal purpose, on one computer at a time. The registered nnCron software may not be rented or leased, but may be permanently transferred, if the person receiving it agrees to terms of this license. If the software is an update, the transfer must include the update and all the previous versions.
  • The nnCron unregistered trial version may be freely distributed, with exceptions noted below, provided the distribution package is not modified. No person or company may charge a fee for the distribution of nnCron without written permission from the copyright holder. The nnCron unregistered trial version may not be bundled or distributed with any other package without written permission of the copyright holder.

    • nnCron PROGRAM IS DISTRIBUTED "AS IS".
    NO WARRANTY OF ANY KIND IS EXPRESSED OR IMPLIED.
    YOU USE THE PROGRAM AT YOUR OWN RISK.
    THE AUTHOR WILL NOT BE LIABLE FOR DATA LOSS, DAMAGES, LOSS OF PROFITS OR ANY OTHER KIND OF LOSS WHILE USING OR MISUSING THIS SOFTWARE.

  • You may not use, copy, emulate, clone, rent, lease, sell, modify, decompile, disassemble, otherwise reverse engineer, or transfer the licensed program, or any subset of the licensed program, except as provided for in this agreement. Any such unauthorized use shall result in immediate and automatic termination of this license and may result in criminal and/or civil prosecution.
  • All rights not expressly granted here are reserved by Nicholas Nemtsev.
  • Installing and using nnCron signifies acceptance of the terms and conditions of the license.
  • If you do not agree with the terms of this license you must remove nnCron files from your storage devices and cease to use the product.

Thank you for using nnCron,
Nicholas Nemtsev.


Registration

If you want to continue using nnCron after the 30 day evaluating period, you can

Register it! (payment by credit card, bank/wire transfer, check or cash; quantity discounts)

Contact the author for educational discounts.


Installing and Removing nnCron

To start nnCron installation, double-click on the distribution file with your left mouse button. During the installation you will be asked to select the installation folder. Installation does not change any Windows system settings. All the files will be copied only to the folder you selected (except for the shortcuts which are automatically created in nnCron program group of Windows Start menu).

In Windows 9x/ME, nnCron creates an entry in the registry (HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Run) in the course of installation so that it starts automatically on the system startup. You can view and/or edit the list of your startup programs with the poorly documented Windows utility msconfig.exe. In WinNT/2000/XP nnCron is started as a system service on system startup - see Starting and Stopping nnCron. Crash Guard Mode.

In order to modify properties of a service, use Services dialog available under Administrative Options in Windows Control Panel. If you wish to remove the installed nnCron service, run batch file uninstall_svc.bat in the nnCron's home directory (it won't uninstall the application itself). You can also start nnCron without starting the service. In order to do that, use "-ns" key in the command line. To install nnCron service again, run install_svc.bat in the program's home directory.

The most convenient way to manually start nnCron service is to run batch file startnncron.bat. In order to unload nnCron from the memory you can run stopnncron.bat or click on Exit in nnCron pop-up menu (available by right-clicking the nnCron icon in system tray).

You can find shortcuts to all of the above-mentioned batch files in nnCron program group located in Windows Start menu.

To uninstall nnCron, go to Add or remove programs in the Control Panel. When updating nnCron to a newer version, you don't have to uninstall the previous installation—you can install the new version right over the previous one. nnCron's settings are stored in nncron.ini file, and the tasks themselves in crontab files. Keep these file when re-installing or updating nnCron or your operating system so that you don't have to fine-tune the program all over again. (See these notes for details).


History of Changes

History of changes in nnCron can be found in doc\history.txt file (in program's home directory).

This history has been maintained since version 1.01 (April 8th 2000).

Users are advised to check history.txt after installing updated versions of nnCron in order to be able to keep abreast of the latest changes.


Technical Support

If you have questions regarding nnCron and you cannot find answers in the available documentation, please subscribe to, and ask your questions in, nnCron mailing list. This mailing list was created to discuss problems related to nnCron, nnCron LITE and nnBackup. The developers post the news here, various bugs and new features are discussed here. The official language of this mailing list is English. To subscribe to the list, send a message to nncron-subscribe@nncron.ru.

There is also a newsgroup dedicated to nnCron, nnCron LITE and nnBackup named RU.NNCRON (fido7.ru.nncron). The official language of RU.NNCRON newsgroup is Russian, but messages in English are allowed as well.You can access RU.NNCRON newsgroup through your ISP's news server or through one of free public news servers, e.g.:
news.fido7.ru
news2.fido7.ru
news3.fido7.ru
news4.fido7.ru
ddt.demos.su
news.rt.ru

Those who prefer simpler solutions can access the news group directly in their Web browser:
http://www.fido-online.com or http://groups.google.com.

There is a nnCron Frequently Asked Questions collection:
http://www.nncron.ru/download/faq.zip

The most frequently asked questions regarding the Forth language (complete with answers) are collected in Forth first aid section. Advanced (or just curious) users are encouraged to read the Tips'N'Tricks chapter—a collection of poorly documented, or completely undocumented, or just curious nnCron features, solutions for nontrivial tasks and various handy hints and tips.

You are strongly encouraged to read these sections before writing a message to the mailing list, since they may contain a solution for your problem. It is also a good idea to have a look at example.tab file where you can find actual examples of many of nnCron's key words.

nnCron support e-mail: support@nncron.ru


Contact Information and Links

You can contact the nnCron's developers by writing to the following e-mail address:
Nicholas Nemtsev <nemtsev@nncron.ru>

All the questions regarding nnCron documentation should be addressed to
Valery Kondakoff <support@nncron.ru>

nnCron's advantages and shortcomings may be discussed in nnCron mailing list and in RU.NNCRON newsgroup (see also Technical Support).

You can also send your questions regarding nnCron to support@nncron.ru (but we suggest that you consult documentation and available FAQs prior to writing to us).

New versions of nnCron, nnCron LITE and nnBackup can be found at
http://www.nncron.ru/ (English)
http://www.nncron.ru/index_ru.shtml (Russian version)


Copyrights

Copyright (©) 2000 nnSoft

SP-Forth 3.75 (©) 1992-2000 A.Cherezov, http://www.forth.org.ru/

RegExp 4.0 (©) Cail Lomecb <ruiv@uic.nnov.ru>, http://www.uic.nnov.ru/~ruiv/


Introductory Course for Beginners

Introduction
Lesson 1: Creating a New Reminder
Lesson 2: Turning Off a Computer at a Specified Time
Lesson 3: Teaching Our Computer Some Good Manners
Lesson 4: Starting an Application with a Keyboard Shortcut
Lesson 5: Deleting Temporary Files Once a Week
Lesson 6: Starting a Task Manually
Lesson 7: Deactivating a Task


Introduction

So, you have installed and started nnCron and you are eager to try and see what it can do? Well, welcome to nnCron boot camp! Here we shall go through several short lessons during which we shall create several simple but handy tasks and learn how to use nnCron's GUI.

>> To Lesson 1


Lesson 1

Lesson One: Creating a New Reminder

Let's right-click on the nnCron icon in system tray and select New Reminder in the menu.

In the dialog box which appears after that, enter the text of reminder and the time when this reminder should be displayed. Voilà! Now you only have to press OK button and nnCron will start the countdown.

When your reminder appears on the screen, it will look somewhat like this:

>> To the next lesson


Lesson 2

Lesson 2: Turning Off a Computer at a Specified Time

Let's create a task which will be turning off our computer nightly at 01:00 a.m.

Right-click on nnCron icon in the system tray and select New Task in the menu. This will open New Task dialog box.

First of all, let's specify a name for our task in the window we just opened. In order to do that, let's type, for example, "PC off" in Task name field. Spaces between words will be automatically transformed into underscore symbols, for a task name cannot contain blank spaces..

On Time and Options tab, we specify when the task should be executed. For example, let us say that it will run daily (well, nightly, actually) at 01:00.

On the Action tab there is a a drop-down menu where we can select the action we want to be performed at the time we have just specified. Among numerous actions, listed in the drop-down menu, we select Shutdown. Then we click on Power off checkbox in order to instruct computer to turn off the power after shutting down the OS.

Now our task is ready to be run, but before we click OK, we could peek at the source text of the task. Let's go to Advanced tab:

>> To the next lesson


Lesson 3

Lesson 3: Teaching Our Computer Some Good Manners

In this lesson, we shall create a task that will display a polite greeting each time nnCron starts.

As usual, we begin with right-clicking the nnCron icon in the tray and selecting New Task in menu.

The we enter a name for our task in Task name field, e.g. "Hello_User"'.

Now we should specify the time when our task will be executed: at nnCron startup. To do that, we select the On event radio button on Time and Options tab and then we select On Startup in the drop-down menu that has just appeared.

On the Actions tab, we select Show message in drop-down menu and type something like "Welcome back, my dear %USERNAME%!" in Text of Message field.

Of course, when nnCron displays the message, it will replace %USERNAME% variable by the name under which your system knows you. As an addition benefit this task will let your computer to get acquainted with you! :)

Done! In order to have a look at the source text of just created task, we go to the Advanced tab. By the way, on this tab, you can not only study the task text, but you can correct any found error as well.

And here is how the result of our arduous work is going to look:

In the same way, you can set any message so that it is displayed at any specified time. For example, you could modify the task we have just created by selecting Once on the Time and Options tab and specifying your own birthday as the date when this task should be run. In this case, nnCron would join the loud and cheerful chorus of birthday greetings!.. :) And, by the way, you can even teach your computer to play "Happy birthday to you" as the message pops up! So, it is going to be a really well-mannered computer, isn't it?

>> To the next lesson


Lesson 4

Lesson 4: Starting an Application with a Keyboard Shortcut

It is very convenient to use nnCron as a keyboard shortcut manager.

In order to make sure that it is really so, we'll create a task which will start a dialer application each time you strike a certain combination of keys, but only in case if you are not yet connected to Internet..

So, let's start: We right-click the nnCron icon in the system tray and select New Task in menu.

In the Task name field, we type: "Inet_Dialer".

We want our task to start each time we press a certain combination of keys. In order to achieve that result, we select On event radio button and in the drop-down menu which appears after that, we select Hot Key. Now we have to specify the keys combination; for example, if we want to use Ctrl+Alt+i, we type "^@i" in the Hot key field. ('^' stands for 'Ctrl', '@' for 'Alt').

On the Action tab, we select Run application or open document in the drop-down menu and specify the path to our dialer application and (if necessary) command line keys.

Now we only have to make sure that the program will be executed only if we are not online yet. To do that, we go to the Condition tab. We select Online in the drop-down menu, check the Not checkbox (so that now the condition reads "Not online"), and in the Connection field we type the name of connection which we use to connect to our ISP.

That's it! As usual, we go to the Advanced tab to check the source text of our task.

>> To the next lesson


Lesson 5

Lesson 5: Deleting Temporary Files Once a Week

In this lesson we shall teach nnCron to perform some routine work: each Monday night it will remove from Windows temporary directory (c:\windows\temp) all files that more than 2 days old.

First of all, we right-click on the nnCron icon in system tray and select New Task in the menu.

In Task name field we type, for instance, "Temp_Cleanup".

On Time and Options tab we specify the schedule: weekly, 00:30, every Monday.

On the Action tab we select Purge directory from the drop-down menu, and specify what directory should be purged and the age of files, i.e. how old the files should be to be deleted.

As usual, we check the source text of our task on the Advanced tab.

>> To the next lesson


Lesson 6

Lesson 6: Starting a Task Manually

Now let's suppose we need to clean up the Windows temporary directory urgently and we don't want to wait till the Monday when the task we created in Lesson 5 will be executed.

Well, there's nothing to it. nnCron allows to start tasks "manually". Here's how: right-click on nnCron in the system tray, select Start Task and the name of task to be executed. In our case, it would be Temp_Cleanup.

>> To the next lesson


Lesson 7

Lesson 7: Deactivating a Task

Let's suppose that things has changed (as it happens all to often) and we no longer want some task to start automatically. But at the same time, we don't want to delete the task from a crontab file, for it may yet become useful in future.

For example, we no longer want our computer to shut down automatically each night. (Our task from Lesson 2 does just that, remember?) How can we stop it?

We right-click in nnCron icon in the system tray, and select Edit and then the task's name from the menu. In our case, that would be "PC_off".

On the Time and Options tab we unmark the Active checkbox and click OK.

That's it! Now the task becomes deactivated, i.e. it is no longer being executed automatically, but it is still present in the crontab file. If some time in the future we want to activate it again, all we will have to do is to mark Active checkbox on the Time and Options tab.

Now, that was the last lesson. If you made it to this point, you are officially nominated an nnCron Boot Camp Graduate. :) Well done!


Working with nnCron

Crontab File
Classic Mode (Syntax)
Extended Mode (Syntax)
Tasks
Cron Format
Starting and Stopping nnCron. Crash Guard Mode
Using nnCron GUI
nnCron Options
Tools
Plugins
 nnCron and Forth Programing Language
Working with Variables, Constants and Arrays
nnCron Predefined Variables
Working with Environment Variables


Crontab File

The "heart" of nnCron is a crontab file where all the data required to run a task are stored: time, events, commands and conditions on which commands are executed. Crontab file is an ordinary plain-text file. It can be created and/or edited in any available text editor.

Immediately after nnCron is installed, a crontab file named nncron.tab will be created in nnCron's home directory; it will be used as the default crontab. There are no limitations on number of crontabs that can be used simultaneously, so it may be a good idea to create several different crontabs to keep different types of tasks in different files; for example, I find it convenient to use crontab file nncron.tab for routine tasks, backup.tab for tasks that have to do with creating backup copies of files, hotkey.tab for tasks that are started with shortcut keys, and test.tab for various experiments and testing.

To view the list of active crontabs, open Options dialog box by doubleclicking nnCron icon in system tray. Use buttons Edit, Add, and Delete to add new crontabs or deactivate those you no longer use.

Starting times and frequency of actions are recorded in crontab files in so-called cron format, inherited from Unix systems.

Each minute, nnCron checks time of last modification of crontab files; if it notices that files were changed, it automatically "rereads" them. If you have manually changed some data in a crontab file and you don't want to wait while nnCron reloads it automatically, you can hasten reloading of crontab by typing in command line

nncron.exe -reload

or by selecting 'Reload crontabs' in menu which appears when you click right mouse button on nnCron icon in system tray.

If you used GUI to add or edit a task , crontab will be reloaded immediately, without waiting for the next minute. You can tune up nnCron crontabs-reloading behaviour using nncron.ini variable ReloadImmediately.

There are two versions of syntax used for recording data in crontab files: classic mode and extended mode. Note, please, that crontab line length should not exceed 512 characters.


Classic Mode (Syntax)

Classic mode syntax is very simple, but not very flexible; nevertheless, its capabilities are more then adequate for starting application at required times. Classic mode's obvious advantage is its compatibility with Unix crontab format.

In order to start an application in classic mode, one has just to specify the desired time of startup in cron format and (after a blank space) the command that should be executed:

<time_in_cron_format> <command>

Example:

# application 'chime.exe' is started at  12:15 every week day
15 12 * * 1-5 * c:\xxx\chime.exe
# the  pdf file named in the task is opened daily
# at 12:00 ad at  17:00
0 12,17 * * * * cmd /c "e:\home\re.pdf"
# the command file named in the task is executed every 5 minutes
*/5 * * * * * d:\fido\bat\blstbbs.cmd

Comments in classic mode begin with character '#' and continue until the end of line. Crontab file may contain any number of empty lines, which are ignored by the parser. Leading spaces and tab characters are also ignored.

It is possible to set values of environment variables in classic mode. Local environment variables (i. e. variables available only to application started by nnCron) are defined with word SET. System (global) environment variables, available to the entire software installed on a computer, are defined with word SYS-SET.

# local environment  variables
SET varname=string value to the end of line
# or
SET varname="string value"

# system (global) environment variables
SYS-SET varname=string value to the end of line
# or
SYS-SET varname="string value"

See Working with Environment Variables for a more detailed discussion of the subject.

Though the classic mode allows to start programs at any times and with any desired frequency, nnCron also supports another, more powerful mode. It is called Extended mode and provides numerous additional capabilities.


Extended Mode (Syntax)

Extended mode is the main and most powerful syntax mode used by nnCron. In extended mode, a user can create tasks with unique names; all tasks are started at user-specified times and allow to fine-tune both the actions performed in the task and conditions on which they are performed.

Definition of every task is started with the following construct:

#( <task_name>

When the crontab parser encounters this construct, it immediately switches to enhanced mode.

Another construct:

)#

denotes end of task definition and switches the crontab parser back to classic mode. In this way, both classic and extended modes can easily coexist in the same crontab file. The logic of this is very simple: anything in crontab that is within the following construct

#( task_name

)#

is treated as extended mode, and everything that is outside of this construct is treated as classic mode. Simplicity rules! :)

Example:

# starting a batch file every hour
0 * * * * * cmd /c "c:\xxx\my.bat"
# this is  classic mode

#( my_task
\ and this is extended mode already
\ displaying a message box after each 30 minutes
Time: */30 * * * * *
Action:
    TMSG: "30 minutes have passed" 3
)#

Extended mode parser ignores empty lines, so a task may include any amount of them. Leading blank spaces and tabs are ignored as well. Important notice: extended mode syntax requires that all key words of nnCron should be separated at least with one blank space or tab or placed on a separate lines.

Extended mode allows to "cut" long lines into any amount of short ones by placing character '\' (backslash) in the separation point. When parsing a task, the parser will "assemble" the complete line from several short ones. For example, the following two tasks are absolutely identical from the parser's viewpoint:

#( test_task
\ this is a comment
Action:
    \ and here are short lines which will be treated
    \ by the parser like a single long one
    START-APP: c:\very\very\long\\
path\to\the\file.exe \
-run my-script -exit \
-nowarning
)#

#( test_task1
\ this is a comment
Action:
    \ and this is a long string:
    START-APP: c:\very\very\long\path\to\the\file.exe -run my-script -exit -nowarning
)#

In any place within any task you can use a special Forth-style symbol meaning "comment until the end of line": \ (backslash). Please make sure you use a blank space after a comment symbol, for it is one of nnCron key words.

Attention, please: comment symbol used in classic mode (#) won't work in extended mode!

Example:

#( first_task
\ this is the first task of my own
NoLog                     \ option
Time: */15 * * * 1-5 *    \ time specifier
Action:                   \ action
    PLAY-SOUND: c:\winnt\media\chimes.wav
)#

Now let's talk about main advantage provided by the extended mode: the Task.


Tasks


Task (Introduction)

A task is a named construct which defines a certain job that should be performed by nnCron. A task defines both the operations to be performed (such as starting programs, operations with files, displaying onscreen messages etc.) and conditions under which these operations should be performed (time, absence or presence of specified files, absence or presence of a disk in a drive etc).

Each task is assigned a unique name which identifies the task and facilitates working with it. A task name should not contain any blank spaces.

As explained in section about the nnCron extended mode, each task starts with the following construct:

#( <task_name>

When crontab parser encounters this sequence, it immediately switches to extended mode. Task name length should not exceed 255 characters and may contain any alphanumeric letters. To mark the end of task, the following sequence is used:

)#

It switches the crontab parser back to classic mode.

A comment can be inserted anywhere in a task with the help of backslash character (\ ). In Forth, backslash means that any text till the end of this line should be treated as a comment (it works just like // (double slash) in C++ or JavaScript). Please don't omit placing a blank space after the comment symbol for it is one of the nnCron's key words.

Example:

#( first_task
    \ this is my first task
)#

This is an absolutely correct task as far as syntax is concerned. Its only fault is that it is useless in terms of functionality, because the body of first_task only contains a comment line.

Now, how a fully functional task would look? What would it consist of?

First of all, a task should contain a section defining the actions which should be performed by this task. Start of such a section is marked off with keyword Action:.

Example:

#( first_task
\ this is my first task
Action:     \ action
    \ playing a sound file
    PLAY-SOUND: c:\winnt\media\chimes.wav
)#

Section Action: can be preceded by other task components (in any desired order):

  • options for the entire task
  • time specifiers (Time:)
  • event specifiers
  • conditions for executing the task (Rule:)
  • user-defined variables and new Forth words
  • authorization parameters

In a most generic form, a typical task would look this way:

#( task_name
[\ comment to the end of line]
[options]
[authorization]
[time specifiers (Time:)]
[event specifiers]
[conditions for task execution (Rule:)]
actions (Action:)
    \ ... performing some useful actions
)#

Here is a slightly enhanced version of our first task. We have added option NoLog (so that task's execution would not be recorded in nnCron's log file) and a time specifier Time: */15 * * * 1-5 * (so that the tasks is executed each 15 minutes on weekdays):

#( first_task
\ this is my first task
NoLog                  \ option
Time: */15 * * * 1-5 * \ time specifier
Action:                \ action
    \ playing a sound file
    PLAY-SOUND: c:\winnt\media\chimes.wav
)#

A detailed discussion of all questions having to do with conditions and methods of starting a task can be found in section Starting a Task.


Task Options

Task options are placed in the beginning of the task definition (before Action: section) and affect the entire task. Task options modify task behavior, frequency of its execution and may even render the task inactive.

For any given task, a user can specify one or more options or use no options at all.

Options must be separated from each other and from other words with a blank space or tab character or started on a new line.

Examples:

#( test_option
\ deactivated task
NoActive
Time: * * * * * *
Action:
    \ ... performing some useful actions
)#

#( test_option1
\ options are separated by blank spaces
RunOnce NoDel
Action:
    \ ... performing some useful actions
)#

#( test_option2
\ each options is on a new line
RunOnce
NoDel
Action:
    \ ... performing some useful actions
)#

You can find the list of task options in nnCron Key Words - Task Options.


Authorization

By default, in WinNT/2000/XP nnCron is started as a service and runs tasks as though they were started by "user" SYSTEM. However, by "authorizing" a task, you can run it as any other user, with all the permissions that this user would have. To perform the authorization successfully, you have to know the username (login) and password of the user in whose name the task will be run, and this user must have the necessary privileges in the system.

The authorization instructions are placed in a task before the Action: section.

In order to run a task as a user who is currently logged on a system, use option AsLoggedUser.

nnCron has some features which make it possible to run all tasks, and even start nnCron's GUI, as a specific user. (See "Authorization Options").

nnCron has a convenient tool to prevent most of errors connected with user name, domain name, password and logon type: if you select Run as user checkbox on the Time and Options tab of "New Task" dialog box, it will become possible to perform a test login in order to find out any possible errors.

Examples:

#( as_user_task
User: john Password: privy Domain: my_domain LogonInteractive
Time: 0 10 * * * *
Action:
    START-APP: as-user-app.exe
)#

#( as_user_task1
User: john Password: privy
Time: 0 10 * * * *
Action:
    START-APP: as-user-app.exe
)#

See also Note.

In order to "authorize" a task, use the following key words:

  • Domain: <domain>
  • LogonBatch
  • LogonInteractive
  • LogonNetwork
  • Password: <password>
  • SecPassword: <abracadabra>
  • User: <user_name>

User: <user_name>

User name (login).

In Windows XP, it may be useful to make sure that you use the actual user name and not its alias. This can be verified in Control Panel -> System -> Advanced -> User Profiles -> Settings. Profile's name is the actual username of a user.

Password: <password>

User's password

SecPasword: <abracadabra>

Encrypted user password. Here you can find a detailed description of why an encrypted password is needed and where to get one.

Domain: <domain>

Your domain. This is an optional parameter.

LogonBatch
LogonInteractive
LogonNetwork

Type of logon. This is an optional parameter.

Note: Here is another example of running a task "as a user":

#( test_auth
LoadProfile
Time: START-TIME
User: "test_user" Password: "test" Domain: "vkondakoff"  \ LogonInteractive
Action:
    \ START-APP: WINWORD.EXE
    START-APP: C:\Program Files\Microsoft Office\Office10\WINWORD.EXE
)#

In this example, there are four points which deserve a special comment:

  • Word LogonInteractive can be safely omitted if nncron.ini has the line DefaultLogonType: LogonInteractive.
  • If an application is called without stating the full path (as in the line that was commented out), the application will be started by System. But if the full path is stated, then it will be run as by user "test_user". This has to do with some oddities in reading the registry branch HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths. (At least, Windows XP behaves in this fashion).
  • In Windows XP, one can login without stating one's password. In order to make it possible for nnCron to login without a password, you need to enter Local Security Settings and disable option Security Options -> Accounts: Limit local account use of blank passwords to console logon only. After that, you can omit field Password: for users without a password:
User: "empty_pass" Domain: "vkondakoff" LogonInteractive
  • В Win2000/XP, using option LogonBatch for some reason results in an error message Can't logon User. Error # 87. Use LogonInteractive instead.

See also:

  • DefaultDomain: "domain_name"
  • DefaultPassword: "sec_password"
  • DefaultUser: "username"
  • DefaultLoadProfile <ON/OFF>
  • DefaultLogonType: <logon_type>
  • LoadProfile
  • RunAsDefaultUser <ON/OFF>


Time Specifiers

As their name implies, time specifiers are used to specify when and how often a task should be executed. Time specifiers are placed in the beginning of a task before the Action: section.

In most cases, word Time: is used to specify the starting time and frequency of task execution.

Time: <time in cron format>

A task may contain more then one instance of word Time:; in this case, the action will be performed at each of the specified moments.

Actually, a task may contain no Time: section at all, which would have the same effect as an instruction to run the task each minute. Time: section is often omitted as unnecessary in task which are supposed to be started only manually. In this case, the task should deactivated with NoActive option.

Example:

#( test_task
\ task is started on nnCron startup and at the beginning of every hour
Time: START-TIME
Time: 0 * * * * *
Action:
    \ ... performing some useful actions
)#

#( test_task1
\ the task is started at 10:00 on weekdays and at 12:00 at weekends
Time: 0 10 * * 1-5 *
Time: 0 12 * * 6,7 *
Action:
    \ ... performing some useful actions
)#

#( test_task2
\  'Time:' section is absent, so the task
\ will be executed every minute
Action:
    \ ... performing some useful actions
)#

#( test_task3
\ task is going to be started manually, so 'Time:' section is not required
NoActive
Action:
    \ ... performing some useful actions
)#
  • Days: <dd>
  • Hours: <hh>
  • Minutes: <mm>
  • Months: <months>
  • Time: <time_in_cron_format>
  • Time: START-TIME
  • WeekDays: <week_days>
  • Years: <years>

Time: <time_in_cron_format>

This construct is used to specify at what time(s) a task will be executed. Time should be in "cron format", i. e.

Time: <Minutes> <Hours> <Days> <Months> <Weekdays> <Years>

Example:

\ each Monday at 11:10
Time: 10 11 * * 1 *
\ at the beginning of every hour
Time: 0 * * * * *

Time: START-TIME

Use this word to start a task immediately after nnCron startup.

Example:

#( test_start_time
\ displaying a message immediately after nnCron is started
Time: START-TIME
Action:
    TMSG: "nnCron is up!" 3
)#

See also description of "nonstandard" character '?' in nnCron's cron format and START-TIME? word.

Minutes: <mm>
Hours: <hh>
Days: <DD>
Months: <months>
Weekdays: <week_days>
Years: <years>

If the majority of fields in the argument of Time: is filled with asterisks (*), it will be perhaps more convenient to use "verbal notation", where you specify only those fields which contain some numerical values and omit asterisks.

Examples:

\ the same as  'Time: 30 * * * * *'
Minutes: 30
\ the same as  'Time: 0 12 * * 6,7 *'
Minutes: 0
Hours: 12
Weekdays: 6,7

Please note that when you are using this type of notation you cannot use more than one time specification.

Examples:

\ one cannot use more than one time specification
\ when using "verbal notation"
Minutes: 0
Minutes: 30 \ error!
\ one cannot use more than one time specification
\ when using "verbal notation"
Minutes: 0
Time: * 12 * * * * \ error!

See also:

  • DATE-INTERVAL: dd1.mm1.yyyy1-dd2.mm2.yyyy2[/days]
  • INTERVAL: hh1:mm1-hh2:mm2[/hh3:mm3]


Event Specifiers (Watch*)

In nnCron, one can cause a task to start at a specific event.

When you are creating a task, you can "tell" nnCron what events it is supposed to watch for; when this event happens, nnCron will start the task. You can use event specifiers together with time specifiers and conditions (rules), i. e. time and rules would be also checked before executing a task. (See also description of option Also). Specifiers are placed in the beginning of a task, before the Action: section.

Example:

#( test_watch
\ task will be started if all of these conditions are true:
\ file named  'test.sem' has been created or changed,
\ the current time is between  12:00 and 15:00 inclusive,
\ and you are online (i.e. there exists an active remote connection)
Time: * 12-15 * * * *
WatchFile: "c:\test.sem"
Rule: ONLINE?
Action:
    \ ... performing some useful actions
)#

A task can contain two or more event specifiers which are connected with logical OR, i. e. the action would be performed if at least one of the specified events takes place.

Example:

#( test_multiple_watch
\ task will be started if a file named  'test.sem' is been created or changed,
\ or if a window of Internet  Internet  Explorer is opened
\ or if the current time is between  18:00 and 20:00 inclusive
Time: * 18-20
WatchFile: "c:\1.sem"
WatchWinCreate: "*Internet Explorer"
Action:
    \ ... performing some useful actions
)#

Events of the same type cannot happen more frequently than it is specified in the parameter MonitorResponseTime: in nncron.ini. This parameter sets the minimum length of time (in milliseconds) between two consecutive events. By default, its value is 100 milliseconds, i.e. 1/10th of a second. If necessary, one can set a separate response time for each task. To do this, change the VALUE-variable MonitorResponseTime before a Watch* word you want to modify:

<time_in_ms> TO MonitorResponseTime

Redefining would also affect all the tasks located in crontab after this one, so it is advisable to restore the default value immediately after the Watch* word.

Example:

#( watch_task
MonitorResponseTime        \ saving the value in the stack
1000 TO MonitorResponseTime \ setting new value (1000 ms)
WatchDir: "c:\xxx\yyy"
TO MonitorResponseTime     \ restoring the old value
Action:
    MSG: "c:\xxx\yyy has been changed"
)#

You can find the list of task options in nnCron Key Words - Monitoring the Events (Watch*)


Conditions for Starting a Task (Rules)

It is possible to "tell" nnCron to check whether a certain condition exists before it starts to perform the actions listed in the task. Actions defined in Action: section will be executed only if this condition is found to be true. In order to check whether or not a condition is true, use word Rule:. In should be placed in the beginning of a task, before Action:.

Rule: <any sequence of Forth words returning a flag>

To reverse a rule, add after it "0=" (according to the rules of postfix notation, this means "equals to 0", i.e. FALSE) or "NOT:".

Rule: <any sequence of Forth words returning a flag> 0=

It is possible to use more than one Rule: construct in the same task. In this case, Rule: constructs are combined with logical "OR", in other words, the action will be performed if at least one of the conditions returns TRUE.

#( test_rule
\ the actions will be executed if either one of the first 2 checks
\  returns 'TRUE' or if "check3" returns 'FALSE'
Rule: <check1>
Rule: <check2>
Rule: <check3> 0=
Action:
    \ ... performing some useful actions
)#

A much more convenient way to achieve the same result is to combine several conditions within the same Rule: construct. In this case, words AND and OR are used as logical operators. Syntax of combined conditions follows the rules of postfix notation that is used in Forth language (<condition 1> <condition 2> <logical operator>):

\ Returns TRUE only if both conditions are true
Rule: <check1> <check2> AND
\ Returns TRUE if either or both of conditions are true
Rule: <check1> <check2> OR

Quite often it becomes necessary to use more complex combinations of conditions within a Rule: construct. The following example illustrates how these statements look in Forth language:

\ expression '(a OR b) AND c' :
a b OR c AND
\ expression 'a AND b AND c AND NOT d' :
a b AND c AND d NOT AND
\ expression '(a AND b AND c) OR (d AND (e OR f))' :
a b AND с AND d e f OR AND OR

Below is a list of some of predefined conditions which are convenient to use with word Rule: or in Action: section of a task (you can find all other conditions in "nnCron Key Words"):

  • DATE-INTERVAL: dd1.mm1.yyyy1-dd2.mm2.yyyy2[/days]
  • DISABLE-CRON?
  • FILE-EMPTY: "file_pattern"
  • FILE-EXIST: "file_pattern"
  • FILE-SIZE: "file_pattern"
  • HOST-EXIST: "hostname_or_ip_address"
  • IDLE: <seconds>
  • INTERVAL: hh1:mm1-hh2:mm2[/hh3:mm3]
  • LOGGEDON?
  • NHOST-EXIST: "hostname_or_ip_address" <num>
  • ONLINE?
  • ONLINE: "connection"
  • POP3-CHECK: "hostname-or-IP" "pop3user" "password"
  • PROC-EXIST: "proc_pattern"
    • PROC-FULLPATH
  • QUERY: "query_text"
  • TQUERY: "query_text" <timeout_in_sec> Yes/No
  • WIN-ACTIVE: "win_pattern"
  • WIN-EXIST: "win_pattern"


Action

Action: is the main section of a task. It defines the actions which should be performed by the task. Action: section is normally the last section of the task definition and is located after task options, authorization options, time specifiers, event specifiers and conditions for starting tasks.

In this section, you can use words of Forth programming language, user-defined words and any predefined words provided by nnCron.

Action: <any sequence of Forth words>

A list of nnCron's predefined words that can be used in Action: section can be found in nnCron's Key Words.


Starting a Task

As explained in preceding sections, task is a construct built in compliance with certain syntactic rules, defining the actions to be performed and conditions which should be present in order for these actions to be performed.

The actions are defined in Action: section of the task. And what about conditions? What tools can a user employ in order to start an application at the precise moment when it should be started? Within the task itself (i.e. while defining the task) a user has control over the following:

  • Options for the entire task
  • Time specifiers
  • Event specifiers
  • Conditions (rules) for starting a task

All these task components are described in detail in their respective chapters of this Help file. In addition nnCron provides the capability to start a task "from outside world", or manually.

  • Starting a Task Manually from nnCron GUI
  • Starting a Task from Command Line
  • Calling a Task from Another Task
  • Running a Task as a Separate Script

Starting a Task Manually from nnCron GUI

This is just as simple as it can be. Instructions for starting a task manually with the help of GUI can be found here.

Sometimes it becomes necessary to create a task a task which can be started only manually. To make sure that it never starts automatically, include option NoActive.

See also Note.

Starting a Task from Command Line

Start nnCron from command prompt with key -run <task_name>.

nncron.exe -run my_first_task

The task will be executed. If nnCron was already running when you were typing this command, the task will be started by existing instance of nnCron. If nnCron was not running, then this command will start nnCron, cause it to re-read crontabs, start the specified task and unload nnCron from the memory.

Of course, in order to be able to start a task from a command prompt, it is necessary for this task to be present in one of the active crontabs.

See also Note.

Sometimes it may be more convenient to use nnCron's capabilities to define and run Forth words right from the command line.

Calling a Task from Another Task

nnCron provides a capability to start executing Action: section of one task from the body of another task. In order to do this, it is necessary to place the callee task higher in the crontab (closer to beginning) than the caller task. It follows, then, that both tasks (of course) must be in the same crontab file.

Use nnCron's keyword <task-name> RUN in order to execute Action: section of the callee task as a subprogram, e.g. in the same thread as the rest of instructions of the caller task.

Example:

#( hello
\ ...
Action: MSG: "Hello, friend!"
)#

#( task2
\ ...
Action: hello RUN
)#

Please note, that word 'RUN' calls only 'Action:' section of the outer task, and not the entire task!

And if it becomes necessary to start an external task in its entirety (asynchronously, in a separate thread), with authorization and with check for all conditions (excluding time-conditions - Time:, OnceA* etc), you can use word <task-name> LAUNCH.

Example:

#( hello
\ ...
Action: MSG: "Hello, friend!"
)#

#( task2
\ ...
Action: hello LAUNCH
)#

Word LAUNCH is convenient to use in order to start a task from nnCron Console.

Running a Task as a Separate Script

A task can be defined in a separate file and executed as a script (or a batch file) afterwards. In order to run such a script file, type at the command prompt:

nncron.exe -runfile script_filename

In order to be able to run a script, it must contain Forth word main.

Example:

\ --- start of script file ----
: main
MSG: "Hello, WORLD!"
SEND-KEYS-DELAY: 100 100
SEND-KEYS: "$r{DELAY 1000}ping localhost -t{ENTER}"
5000 PAUSE
SEND-KEYS: "^c"
;
\ --- end of script file ------

Note: Please remember that by starting a task manually, you cancel all the conditions (Time:, Rule:, Watch*) defined in this task. Your instruction to "execute task manually" has an absolute priority over the rest of conditions! And if you need to check some conditions when starting a task manually, just put them inside the Action: section. For example, the following task will not check the condition when started manually:

#( test_rule
Rule: PROC-EXIST: "notepad.exe"
Action:
    MSG: "Notepad exists!"
)#

And the following task will check the condition even when started manually:

#( test_rule1
Action:
PROC-EXIST: "notepad.exe"
IF
    MSG: "Notepad exists!"
THEN
)#

See also:

  • How can I stop a running task (e.g. in case of an error)?
  • How can I stop a task from another task?
  • How can I make the task Active/NoActive programmatically?


Missed Tasks Handling

Besides possessing the conventional scheduler features (starting tasks at specified time or with specified frequency), nnCron provides the users an opportunity to manage so called missed tasks and reminders. Missed task is a task, which has not been ran at scheduled time because nnCron was not started or your PC was not turned on.

If your PC is not running 24 hours a day, you may want to use a special nnCron task option (RunMissed) when defining important tasks to launch the task at scheduled time or at the first opportunity if it was impossible to start the task at the scheduled time. If the task becomes missed, it will be started at the top of the first minute after nnCron startup. nnCron checks for missed tasks every crontab reloading.

Task option RunMissed and nncron.ini variable DefaultRunMissedTime: are used to manage missed tasks.

Let me show you an example. Let's assume, that user wants to delete temporary files on his local disks every Sunday at 23:30. There is how his task may looks like:

#( test_cleanup
Time: 30 23 * * 7 *
Action:
    START-APP: с:\utils\cleanup.exe
)#

There is one shortcoming of this task: temporary files will not be deleted for a two weeks if user's PC will be turned off on the next Sunday at 23:30. If the user does not want to wait for such a long time, he may want to turn on missed tasks handling:

#( test_cleanup1
RunMissed
Time: 30 23 * * 7 *
Action:
    START-APP: с:\utils\cleanup.exe
)#

Now, the task that was unable to start at Sunday, 23:30 will launch "at the first opportunity" - at the top of the first minute after nnCron startup, when user will turn his PC on: for example at Monday, 08:00.

There is an 'extended' RunMissed option: RunMissed: <hh:mm|days>. It allows you to specify maximum waiting time (in hours and minutes) that may elapse since this task was sheduled to run for the last time. The missed task will not be launched if specified waiting time value is smaller than the actual time elapsed since this task was sheduled to run for the last time.

Let's modify the previous example, to take all the benefits of RunMissed: <hh:mm|days> option. Now we want to start this task at specified time (every Sunday, 23:30) or at the first opportunity if the task becomes missed, but only if no more than 3 days are elapsed since the time the task was scheduled to run:

#( test_cleanup2
RunMissed: 3
Time: 30 23 * * 7 *
Action:
START-APP: с:\utils\cleanup.exe
)#

If the user turned his PC off at saturday evening and turned it on at tuesday the task will be executed immediately after nnCron startup. And if the user turns his PC at thursday or friday the task will not be launched because specified waiting time (3 days) is smaller that the actual time elapsed since this task was sheduled to run and nnCron will wait until the next scheduled time (next Sunday, 23:30).

You can use the RunMissed? word to check if the started task was missed and is started 'at the first opportunity' or it was started at the scheduled time. The word RunMissed? is mainly used to display a warning when launching missed task.

You can manage missed tasks handling using nnCron GUI: checkboxes to turn RunMissed option on/off and input fields to enter maximum waiting time are available in New Task, New Reminder

and Edit Task dialog boxes.

Info for the curious users: where nnCron stores the data that is needed for missed tasks handling?

nnCron stores all the data that is needed for missed tasks handling in a file etc\taskinfo.txt. Here is it's format:

Field | Description
TI-NAME | task name
TI-CRC32 | name+time crc32
TI-CREATION-TIME | time of crc32 creation
TI-WRITE-TIME | reserved for future use
TI-EXECUTION-TIME | time of task execution
TI-FLAG-SUCCESS | 1 if the task was launched successfully
TI-FLAG-EXIST | Special fileld, that is used for obsolete tasks removal. Should be set to 1.

Info for the curious users: how are time ranges handled during missed tasks management (say, Time: * 16-19 * * * *)?

First of all the latest assumed date when the task was scheduled to run for the last time is calculated. If there are several Time: constructs in the given task, we are choosing the time range with nearest (closest to the current time) right margin. Of course, if there is a single Time: construct, we are choosing the only available time range. Then we are comparing the assumed time when the task was scheduled to run with the left margin of the choosen time region. If the assumed time is smaller than the left margin of choosen time region, we are considering the task as missed and immediately starting it.

If the given task was never started before, we are examining the date when the task was created. Task creation time is compared with the right margin of the choosen time region. If the task creation time is smaller than the right margin of choosen time region, the task is considered missed as well and is immediately started.

See also:

  • ASSUMED-NEXT-TIME
  • ASSUMED-PREV-TIME
  • TASK-CREATION-TIME
  • TASK-EXECUTION-TIME


Cron Format

Cron format is a simple, yet powerful and flexible way to define time and frequency of various actions. nnCron make active use of cron format in both classic and extended modes.

Traditional (inherited from Unix) cron format consists of five fields separated by white spaces:

<Minute> <Hour> <Day_of_the_Month> <Month_of_the_Year> <Day_of_the_Week>

nnCron can use both traditional and "enhanced" version of cron format, which has an additional (6th) field: <Year>:

<Minute> <Hour> <Day_of_the_Month> <Month_of_the_Year> <Day_of_the_Week> <Year>

A user can select the format he would like to use by selecting or unselecting the Year field checkbox on General tab in Options dialog (which can be opened by doublecliking the nnCron icon in system tray). By default, nnCron uses the enhanced format.

The following graph shows what it consists of:

* * * * * *
| | | | | |
| | | | | +-- Year              (range: 1900-3000)
| | | | +---- Day of the Week   (range: 1-7, 1 standing for Monday)
| | | +------ Month of the Year (range: 1-12)
| | +-------- Day of the Month  (range: 1-31)
| +---------- Hour              (range: 0-23)
+------------ Minute            (range: 0-59)

Any of these 6 fields may be an asterisk (*). This would mean the entire range of possible values, i.e. each minute, each hour, etc. In the first four fields, nnCron users can also use "nonstandard" character ? (question mark), described here.

Any field may contain a list of values separated by commas, (e.g. 1,3,7) or a range of values (two integers separated by a hyphen, e.g. 1-5).

After an asterisk (*) or a range of values, you can use character / to specify that values are repeated over and over with a certain interval between them. For example, you can write "0-23/2" in Hour field to specify that some action should be performed every two hours (it will have the same effect as "0,2,4,6,8,10,12,14,16,18,20,22"); value "*/4" in Minute field means that the action should be performed every 4 minutes, "1-30/3" means the same as "1,4,7,10,13,16,19,22,25,28".

In Month and Day of Week fields, you can use names of months or days of weeks abbreviated to first three letters ("Jan,Feb,...,Dec" or "Mon,Tue,...,Sun") instead of their numeric values.

Examples:

* * * * * *                         Each minute

59 23 31 12 5 *                     One minute  before the end of year if the last day of the year is Friday

59 23 31 DEC Fri *                  Same as above (different notation)

45 17 7 6 * *                       Every  year, on June 7th at 17:45

45 17 7 6 * 2001,2002               Once a   year, on June 7th at 17:45, if the year is 2001 or  2002

0,15,30,45 0,6,12,18 1,15,31 * 1-5 *  At 00:00, 00:15, 00:30, 00:45, 06:00, 06:15, 06:30,
                                    06:45, 12:00, 12:15, 12:30, 12:45, 18:00, 18:15,
                                    18:30, 18:45, on 1st, 15th or  31st of each  month, but not on weekends

*/15 */6 1,15,31 * 1-5 *            Same as above (different notation)

0 12 * * 1-5 * (0 12 * * Mon-Fri *) At midday on weekdays

* * * 1,3,5,7,9,11 * *              Each minute in January,  March,  May, July, September, and November

1,2,3,5,20-25,30-35,59 23 31 12 * * On the  last day of year, at 23:01, 23:02, 23:03, 23:05,
                                    23:20, 23:21, 23:22, 23:23, 23:24, 23:25, 23:30,
                                    23:31, 23:32, 23:33, 23:34, 23:35, 23:59

0 9 1-7 * 1 *                       First Monday of each month, at 9 a.m.

0 0 1 * * *                         At midnight, on the first day of each month

* 0-11 * * *                        Each minute before midday

* * * 1,2,3 * *                     Each minute in January, February or March

* * * Jan,Feb,Mar * *               Same as above (different notation)

0 0 * * * *                         Daily at midnight

0 0 * * 3 *                         Each Wednesday at midnight

In extended mode, crontab notation may be abridged by omitting the rightmost asterisks.

Examples: (only for extended mode)

Full notation                         Abridged notation

* * * * * *

59 23 31 12 5 2003                    59 23 31 12 5 2003

59 23 31 12 5 *                       59 23 31 12 5

45 17 7 6 * *                         45 17 7 6

0,15,30,45 0,6,12,18 1,15,31 * * *    0,15,30,45 0,6,12,18 1,15,31

0 12 * * 1-5 *                        0 12 * * 1-5

* * * 1,3,5,7,9,11 * *                * * * 1,3,5,7,9,11

1,2,3,5,20-25,30-35,59 23 31 12 * *   1,2,3,5,20-25,30-35,59 23 31 12

0 9 1-7 * 1 *                         0 9 1-7 * 1

0 0 1 * * *                           0 0 1

* 0-11 * * * *                        * 0-11

* * * 1,2,3 * *                       * * * 1,2,3

0 0 * * * *                           0 0

0 0 * * 3 *                           0 0 * * 3

Both in classic and extended modes, nnCron users can use a "nonstandard" character "?" in the first four fields of cron format. It stands for time of nnCron startup, i. e. when a field is processed, startup time will be substituted for the question mark: minutes for Minute field, hour for Hour field, day of the month for Day of month field and month for Month field.

For example, if you write the following:

Time: ? ? * * * *

the task will be executed on nnCron startup and then will be executed daily at the same time (unless the user doesn't restart nnCron, of course): question marks will be "replaced" by nnCron startup time. For example, if nnCron was started at 8:25, question marks will be substituted this way:

Time: 25 8 * * * *

Some more examples:

\ task will be executed only on nnCron startup
\ (this has the sane effect  as "Time: START-TIME")
Time: ? ? ? ? * *

\ task will be executed on nnCron startup (e.g. at 10:15)
\ and then will be executed again each hour:
\ at 11:15, 12:15, 13:15 etc.
Time: ? * * * * *

\ task will be started each minute after nnCron startup until the next hour starts.
\ The next day, if nnCron has not been restarted in the meanwhile,
\it will be executed again each minute during the same hour.
Time: * ? * * * *

\ task will be executed daily,  every five minutes,
\ during the hour when nnCron was started.
Time: */5 ? * * * *


Starting and Stopping nnCron. Crash Guard Mode.

If nnCron is installed under Windows 9*/ME, it starts as a regular application. In Windows NT/2000/XP, nnCron is started by default as a system service.

nnCron home directory contains a batch file named startnncron.bat, which checks the version of operating system and automatically start nnCron in a an appropriate way: either as a service or as a regular application.

nnCron service can be run "in the name of" any registered user who has sufficient rights (see Note), in other words, service nnCron will use this user account to log in. To do this, select nnCron in the the Services window (Control panel - Aministrative Tools - Services - nnCron), open Properties dialogue, select This Account on LogOn tab and enter the user name and password of the required user.

If a user wants to run nnCron as a regular application under Windows NT/2000/XP, he can do this by starting nnCron from command line with key -ns:

nncron.exe Ns

In order to stop nnCron and unload it from memory, you can do any of the following:

  • Click Exit in the nnCron right-click menu
  • run batch file stopnncron.bat in the program's home directory
  • run the following command from command line: nncron.exe -stop (if nnCron was started as a regular application rather then as a service)

Suspended (Paused) Mode

nnCron provides the possibility to suspend its work without actually quitting the program. You can switch nnCron to suspended mode by using any of the following methods:

  • manually, by selecting Disable nnCron in right-click pop-up menu
  • programmatically, by using word DISABLE-CRON
  • by creating in nnCron home directory a flag file named disable

When in suspended mode, nnCron no longer executes any tasks (except tasks with HyperActive option, which are executed regardless of the operation mode, and except the case when nnCron was switched to suspended mode programmatically: in this case, nnCron continues to run the task which paused it, so that the same task could also "wake it up").

nnCron's icon in system tray will show if nnCron is in suspended mode or normal mode: in normal operation mode, it looks this [image], and in suspended mode, it looks this way: .

You can switch nnCron back to normal operation mode using any of the following methods:

  • by selecting Enable nnCron in right-click pop-up menu
  • programmatically, by using word ENABLE-CRON
  • by removing flag file disable from nnCron installed directory

Please note that flag file disable allows you to control nnCron's operation remotely.

See also description of word DISABLE-CRON?

Crash Guard Mode

Since nnCron's mission is to perform tasks which are important or even critical for the system, in has a special tool to increase its viability: so-called "Crash guard mode". For this purpose, it includes a special little utility nnguard.exe, which automatically restarts nnCron in case of a fatal error. In this way, we are trying to make sure that nnCron works uninterruptedly even on buggy and unstable systems.

To turn the crash guard mode on and off, you can either use the GUI or do it manually by editing nncron.ini.

It should be noted that nnCron writes technical information about its work into a text file named nncron.out, which is automatically deleted after the program was closed down correctly. If nnCron was closed incorrectly (because of a system error of a power failure), nncron.out will stay intact until the next time nnCron is started, and then this file get overwritten. If you don't want to lose those nncron.out files, then create a file named nodelout in nnCron home directory. When nnCron finds file nodelout in its home directory, it stops overwriting files nncron.out; instead, it renames them according to the mask %MM%-%DD%-%hh%-%mm%-nncron.out, so that you can check them later, at your convenience, and find out what exactly caused the error.

Note: in order to run nnCron not as System, but as а particular user, this user must have the following rights (see Control Panel - Administrative Tools - Local Security Settings - Local Policies - User Rights Assignment):

  • Replace a process level token
  • Act as part of the operating system
  • Bypass traverse checking

(user System has these rights by default).


Using GUI

Using nnCron GUI


nnCron Right-click Pop-up Menu

Since version 1.72, nnCron has been featuring Graphic user interface (GUI). With the help of GUI, nnCron users can add, remove, edit and run tasks, set up reminders, change programs settings—in other words, control the program just as freely as config file gurus.

Program tm.exe, located in nnCron home directory, is responsible for nnCron GUI. (Here you can find a description of command line parameters used with tm.exe).

All functions of nnCron GUI can be accessed through a pop-up menu which can be opened by clicking the right mouse button on nnCron icon in system tray (in this Help file, this menu is often referred to as "Right-click pop-up menu").

Options

Open the Options dialog box, which is used to change nnCron settings. Options dialog box is described in detail in nnCron Options.

Help

Use the nnCron Help system, i.e. the file you are reading right now. A user can himself specify which document should be opened when this menu item is selected. In order to do that, use the name of a specified file as a value of variable HelpFile in nncron.ini:

HelpFile: "d:\tools\help.chm"

Tools

Start one of additional tools of nnCron. nnCron tools are utilities which extend nnCron's capabilities and facilitate its use. nnCron tools are described in Tools section.

Start task

Manually start an existing task.

Various ways of starting a task, including manual start, are discussed in detail in Starting a Task

Please keep in mind that by starting a task manually, you cancel all conditions (Time:, Rule:, Watch*), specified in the task. Instruction "Start a task manually" has an absolute priority over any other conditions.

See also Note.

Edit

Open Edit Task dialog box where one can view and/or edit specific details of an existing task. Edit Task dialog box provides exactly the same capabilities as New Task window.

See also Note.

View Log

Open nnCron's log file in the text editor specified by the user. (See General Options section in nnCron Options).

Reload Crontabs

Cause nnCron to reload crontabs without waiting for it to do it automatically. This option is very convenient if you would like the changes, manually entered in crontab files, to be enabled immediately.

New Task

Open New task dialog box

New Reminder

Open New Reminder dialog box.

Disable nnCron/Enable nnCron

Switch nnCron to suspended mode (temporarily disable nnCron without closing the application) or restore normal mode (enable it again).

About nnCron

Display a message box with information about the current version of nnCron.

Exit

Exit nnCron.

Note: Some of the task names in Start Task and Edit menus are preceded by 2 dashes (--):

This means that option NoActive has been included in definitions of these tasks and, therefore, the tasks are not active and can only be started manually. Therefore, menus New Task and Edit could be used as a sort of a monitor which allows to see if certain task is currently active or not.


New Task;

New Task Dialog Box

New Task dialog box is a powerful and flexible tool allowing to create most complicated tasks. After you have specified a name for a task you are going to create and name of the crontab file where you are going to add this task, you can make use of the four additional tabs which correspond to main sections of a task:

  • Time and Options Tab
  • Action Tab
  • Condition Tab
  • Advanced Tab

Time and Options Tab

Time tab is where you specify when and how often a task should be executed.

First of all, you should select one of radio buttons that are used to set a time specifier (Once, Minutely, Hourly etc.); depending on your selection, the tab appearance will change and you will be offered most suitable options for the selection you have made.

Options On event and Cron time format should be mentioned specifically.

Option On event allows to specify an event that nnCron should watch for. As soon as the event takes place, the task will be started. Possible events include:

  • System startup
  • Changes in specified directories or files
  • Start of a specified process
  • A specified keyboard shortcut
  • Creation of a specified application window
  • Internet connection established

and many others.

Option Cron time format allows to use the convenient and powerful cron format in order to specify when and how often the task should be executed.

Lower on this tab you can specify various task option:

Run missed task

Sometimes tasks may have been missed because nnCron was not running. Select this checkbox if you want nnCron to run missed task 'at the first opportunity' - at the top of the first minute after nnCron startup. Using input field 'hh:mm/days' you can optionally specify maximum waiting time (in hours and minutes or days) that may elapse since this task was sheduled to run for the last time. The missed task will not be launched if specified value is smaller than the time elapsed since this task was sheduled to run for the last time. Missed tasks handling concept is described in more details in corresponding chapter.

Log file

If this checkbox is selected, nnCron will write information regarding task execution to the log file. If a task is executed very often, it might be a good idea to keep this option unselected in order to keep the log file free from junk information.

Remove after execution

If this option is selected, the task will be deleted from crontab file once it has been executed. This option is handy when you create a task which is only supposed to work once and will not be needed again.

Active

This checkbox activates/deactivates a task. It comes in useful when one needs to create a task which can only be started manually—in this case, this checkbox is unchecked. Another occasion to use this option is when you want to temporarily disable some task. Names of inactive tasks are preceded with two dashes (--) in Start Task and Edit menus.

Run as logged user

This is an authorization option. nnCron runs the task as a currently logged user.

Run as user

This is an authorization option. It allows nnCron to run a task as a specified user (if you use this option, you should fill in the required information in fields Name, Password, Domain, Logon type).

It is easy to make a mistake when filling this field, and then, of course, the task won't be executed correctly. To prevent an error, click Test logon button after you have filled the required fields: nnCron will perform a test logon and inform you of the results.

Load profile

This is an authorization option. It allows nnCron to load specified user profile when executing the task.

Action Tab

Action tab is where you define the job that a task is supposed to perform. This tab corresponds to Action: section of a task.

In the topmost drop-down menu you can see a list of some of the actions which nnCron can perform for you. These actions include:

  • Run application or open document
  • Show message
  • Play sound
  • Dial
  • Shutdown
  • Purge directory

and many others.

Appearance of the tab will change depending on your selection, and you will be asked to supply additional information suitable to the action you have just selected.

For example, if you want nnCron to start some application (which is the most frequently used option), you will be asked to supply the following information in fields provided for that purpose:

  • Application path
  • Parameters and startup folder (if required)
  • Application window options (an application window can be opened in the normal mode or it can be hidden, minimized or maximized)
  • Process priority (Normal, High, Realtime, Idle)

There are also some additional options for starting an application:

Prompt for confirmation

If this option is checked, a message box will be displayed each time an application is going to be started; it will query a user if he would like to run this application. The application will be started only if the user answers Yes.

As service

Application will be run as a service.

Wait for completion

nnCron will await for application to send a signal that it has completed its work (so-called return code). Only after nnCron receives the the return code it will go on to execute the next line in the task.

I would like to dwell a bit longer on action Run script. This action allows those users who are well versed in nnCron syntax or in Forth programing language to write the contents of Action: section manually, without wasting time on searching for necessary menus or filling fields. Don't you worry, you will also be able to use Run Script option after a thorough study of the documentation! :)

Condition tab

Condition tab is where you specify on which conditions a task will be or won't be started.

Some possible conditions are:

  • <without condition>
  • A specified file or folder exist
  • A specified window exist
  • Computer is online (connected to Internet)
  • A specified process exist
  • A user answered Yes to a query by nnCron

and many others.

Depending on your selection, the tab appearance will change and you will be offered most suitable options for the selection you have made.

Please note the Not checkbox beside the condition menu. If this checkbox is marked, the specified condition will be "inverted".

For example, if you selected "Window exists", then a task will be started only if the specified application window exists on the screen. Now let's invert the condition by checking the Not checkbox. Now the task will be started only if the specified window does not exist on the screen.

Advanced Tab

Additional tab serves both informational and practical purposes. Here you can cast a critical glance on the source code of a task you have just created and, if necessary, to modify it, to add some constructs that could not be added with the help of GUI, or remove some options that you deem unnecessary.


New Reminder

New Reminder Dialog Box

A reminder is a small message box which appears on the screen at a time specified by you, accompanied by a sound signal. Text of a reminder is entered when it is created. When a reminder is displayed, a user has an option to repeat the reminder later.

In the text field, enter the text you want to appear on your reminder, and select time and date when you want it to appear. When it appears, it is going to look somewhat like that:

Please note that you can choose to repeat the same reminder after a specified time.

Sometimes reminders may have been missed because nnCron was not running. Select 'Display missed reminder' checkbox if you want nnCron to run missed reminder 'at the first opportunity' - at the top of the first minute after nnCron startup.


nnCron Options


nnCron Options

nnCron provides numerous options for customizing program's interface and behavior. nnCron's settings are stored in configuration file nncron.ini which is located in nnCron's home directory. If you keep this file intact when reinstalling nnCron or your operating system, you will also keep intact all your settings.

You can change nnCron's settings either through GUI or by editing nncron.ini in your favorite text editor. Which method to use is just a matter of your personal preferences. (Attention, please: you have to restart nnCron after you finish editing cron.ini to enable configuration changes). A detailed description of variables used in nncron.ini can be found in a section suitably titled Variables Used in nncron.ini, and here we will concentrate on how to use the GUI to change nnCron's settings.

A double click on nnCron's icon in system tray will open Options dialog box. It consists of four parts, all of these parts are accessible via menu in the dialog's left-hand navigation pane:


General Options

Task files

List of active crontab files. By using buttons Edit, Add and Delete, you can add new files to the list or remove those which you no longer use. See also a detailed description of crontab files.

Log file

In this field you fill in the path to and name of the log file where nnCron records information about its current state, completed tasks, started applications and probable errors. If you would like nnCron to daily create a new log file which has the current date as its name, use in this field the default value. If you prefer a permanent log file, specify a "fixed" name, e.g. log\nncron.log.

Log time

This option allows you to set the date format used in log records. For example, I prefer to have each record preceded by current date, time and PID (process identifier):

%DD% %MMM% %hh%:%mm%:%ss% %ThreadId%

This is how it looks in the log file:

21 Jun 06:00:00 944 TASK: fido_purge_link
21 Jun 06:00:00 944 Start: sqpack.exe *
21 Jun 06:05:57 944 Start result: 0

Default editor

Use this option to specify which text editor should be used by default when a user selects "View Log" in menu or clicks on button "nncron.ini" in Options dialog box.

Allowed values:
1. default - this will cause nnCron to use the default Windows editor
2. Full path to any other text editor of your choice.

Backup path

Use this option to specify the directory where nnCron will save backup copies of crontab and ini files when they are edited.

Window mode

This option sets the default window mode in which nnCron will start applications (application window will be be displayed in normal mode, maximized, minimized, or hidden).

Allowed values:
Normal
Maximized
Minimized
Hidden

Default priority

Sets the default priority for applications started by nnCron.

Allowed values:
Normal
High
Realtime
Idle

Language

Use this option to select a language of your preference for nnCron's GUI.

Allowed values:
English
German
Russian

Show error messages

Select this checkbox if you want nnCron do display a warning message when it spots some error in its operation. Such messages are normally caused by syntax errors in task definitions.

Year field

Selecting this checkbox will cause nnCron to use enhanced cron formal with additional sixth field <Year>. If this option is left unselected, the regular five-field cron format will be used. For more information, see a detailed description of cron format.

Crash guard

Selecting this checkbox activates program nnguard.exe which causes nnCron to automatically restart after fatal errors. For additional information about the crash guard mode see Crash Guard Mode section in Starting and Stopping nnCron.


Interface Options

System tray icon

By selecting this checkbox you will cause nnCron's icon to be displayed in system tray.

For admins only

Select this checkbox if you want nnCron's icon in system tray to be visible only to users with administrator rights. Users with lower-level rights will not see the icon.

On left button double click
On right button click

Use these listboxes to define the action, that should be performed when double-clicking or right-clicking on nnCron system tray icon. There are several predefined words. Note, that you can use any other forth-words as well. This topic is explained in more details in "Variables Used in nncron.ini" chapter.

Menu items:

Options
Exit
Tools/Console
Reload crontabs

Checkboxes from this group determine whether or not the corresponding items are present in the Right-click pop-up menu which is displayed when you right-click nnCron's icon in system tray. You can unselect some checkboxes if you don't want these items to be present in the menu or to be visible to other users.

Open console at startup

This is a very convenient options. When it is selected, the Forth console is automatically started on nnCron startup. Therefore, frequent users of Forth console don't have to lose their time starting console manually each time they want to use it.


Authorization Options

Run all tasks "as user"

If you select this checkbox, nnCron will run all tasks as if they were started by a specified user. Be sure to enter the required data in fields Name, Password, and Domain. If necessary, you can select Load user profile checkbox to cause the desired user profile to be loaded with each task.

Run GUI "as user"

By selecting this checkbox, you will be able to start nnCron's GUI as if it was started by a specified user. Be sure to enter the required data in fields Name, Password, and Domain. If necessary, you can select Load user profile checkbox to cause the desired user profile to be loaded with GUI.


Plugins Options

List of Plugins

List of enabled (active) plugins. By using buttons Edit, Add and Delete, you can add new plugins to the list (thus enabling them) or remove those which you no longer use. See also a detailed description of plugins.


Tools


WinSpy

This utility allows you to find out the current coordinates of the mouse pointer, to find out class of the object over which the mouse pointer is currently located, to get information regarding size and coordinates of main and child windows and find out the window handle of a window. WinSpy also displays the text information contained in the current component. In addition, WinSpy can show you virtual key codes, which are generated, when you press a key on your keyboard.

Information provided by WinSpy can be used, for instance, in window key words (WIN-MOVE:, WIN-WAIT: etc.) or key words used to emulate mouse activity (MOUSE-MOVE: etc.). Virtual key codes can be used with a word WatchHotKey:.

To open WinSpy, select Tools - WinSpy in the menu which is opened by right-clicking on nnCron icon in the system tray.

You can also start WinSpy from command line by typing:

tm.exe WinSpy

If you want to copy to clipboard information provided by WinSpy about a certain window, do the following:

  1. Open the desired application window
  2. Start WinSpy
  3. Activate the field (Text, Class etc.), which contains the data you are going to copy. Do do this, just left-click in the field with your mouse or by repeatedly hitting TAB until the cursor is in the desired field.
  4. Now move the mouse so that the pointer is over the desired window (WinSpy's window is active)
  5. Select the text in the field (Shift+End)
  6. Now copy it to the clipboard (Ctrl+Ins)


Console

  • nnCron Console
  • Remote Console
  • Local Console
  • A Few Useful Words to Use with Console

For those who know Forth language, console is a tool allowing interactive communication with nnCron; for those who only starts to learn Forth, console is an indispensable assistant. In console you can use all Forth words, create new definitions and execute them etc. But please be careful: Forth allows you to do a lot of things, therefore it requires extreme care.

To start the console, right-click on nnCron icon in system tray and select Tools - Console in the menu. Console can also be started from command line.

If you want console to be started automatically at nnCron startup, open Options dialog window and check checkbox Open at startup on Interface page.

To end a console session and quit console type:

BYE

and press ENTER; or you can just click on the Close button in upper right corner of console.

nnCron console "remembers" all the commands you enter and can recall these commands and maintain command history list using pre set hotkeys. For example, you can press F7 to display the list of available commands in history. Press Up Arrow to recall the command you used before the one displayed. Press Down Arrow to recall the command you used after the one displayed etc... Take a look into description of built-in command doskey in your operating sysytem documentation for detailed list of available hotkeys.

Remote Console

Since nnCron version 1.88, one can use console even from remote computers. For this purpose, nnCron starts Remote Console server at each startup. Behavior of remote console server is modified with the following variables of nncron.ini:

  • RemConsole
  • RemConsolePort
  • RemAllowed
  • RemDisallowed

After you made sure you have right to connect from your address and that you know which port to connect to, start telnet and type in the command:

open <ip_address> <port>

for example:

open 127.0.0.1 2002

In this way, you will start a remote console sessions which is just the same as a local session.

Console can also be started and closed programmatically. In nnCron scripts which are started from command line with the help of -runfile key, one can use following words of Forth language:

CONSOLE - create a console window
START-QUIT - run word QUIT in a separate thread
QUIT - if a console is already running

Example:

: main
    CONSOLE
    ." Hello, World!" CR
    ." Press any key..." KEY DROP
;

When working with Forth console, please keep in mind that most of predefined prefix-type words in nnCron are intended to be used at compile-time rather then at run-time. Each task is automatically compiled when crontab is reloaded. So these words can be compiled, but cannot be used in console.

Here is a simple example. In a Forth console window, type the following line

MSG: "test"

and press ENTER. If you expect to see a message box saying "test", you are mistaken, for we used word MSG: at run-time and not at compile-time.

But if you compose a definition for a new word in console itself:

: test_message MSG: "test" ;

then press ENTER and and now try to execute this word,

test_message

then you will get your message box saying "test". Why? Well, it is because we compiled a new word by pressing ENTER after its definition, i.e. we used word MSG: only at compile time.

Besides that, you can use in console a postfix-type analogue of word MSG:

S" test" MsgBox

Most of predefined prefix words in nnCron have versions that use postfix positioning; you can safely use these postfix words in console.

Local Console

In order for nnCron console to work correctly, you must have TCP/IP protocol installed. If it is not installed on the computer where you are working, you can use so-called local console instead of the standard nnCron console. In order to be able to use the local console, set variable RemConsole in nncron.ini to OFF:

RemConsole OFF

In this case, a local console will be opened instead of standard nnCron console. The only limitation you will encounter in working with the local console is that is you shouldn't try to close it with Close button in upper right corner of console window.

The proper way to close a console window is to type the word bye in lower case:

bye

and press ENTER.

Don't to close local console by clicking on Close button in the upper right corner, for this will close nnCron itself!

A Few Useful Words to Use with Console:

. (period)

Grabs the value on the top of stack, removes it from the task and prints it to console.

Examples:

\ let's print to console the result of a check for existence of a file
FILE-EXIST: "c:\xxx\test.sem"
. CR
\ let's print to console the result of addition
2 3 + . CR

.S

Outputs all the contents of the stack without destroying it (i.e. leaving the stack in its former condition)

Example:

\ placing integers on stack and printing them to console
1 2 3 4 5 6 7 8 9 0 .S

ABRACADABRA

Clears the stack. Actually, any inexistent word can be used to clear the stack, including ABRACADABRA or CLEAR_DA_STACK or even simply qwefdawdflk. :)

Example:

\ placing integers on stack
1 2 3
\ clearing the stack
shg

We can also define a special word for clearing the stack. Let's call it 0SP.

: 0SP BEGIN DEPTH WHILE DROP REPEAT ;

Word DEPTH returns the number of elements on the stack. In this loop, we execute word DROP until word DEPTH returns 0 (which means that the stack is already empty).

Place this definition, for example, to plugin tools.spf, and you will always have word 0SP at your disposal.

."

This word prints to console a succeeding string from the current task followed a closing quotation mark.

Examples:

#( test_debug
NoActive
Action:
    ." Test string." CR
    ." Debug message." CR
)#

Here are examples of a construct which allows to print to console strings containing predefined nnCron variables:

\ prints to console: "Hello, name_of_current_user!"
S" Hello, %USERNAME%!" EVAL-SUBST TYPE
\ prints to console the title of currently active window
S" Title of active window: %ACTIVE-WINDOW%" EVAL-SUBST TYPE

CR

Types a carriage return in a console window.

Example:

." First string" CR ." Second string" CR

BYE

Closes console without closing nnCron. To close console, type in it:

BYE

and press ENTER.


Plugins

General Information about Plugins
http.spf
net.spf
process.spf
procwin.spf
ras.spf
sid.spf
system.spf
time.spf
timesync.spf
tools.spf
wakeup.spf
win2tray.spf
windows.spf


General Information about Plugins

Plugins are additional modules for nnCron; they are written in Forth language and are used to expand nnCron's capabilities by defining new Forth words. Plugins are plain text files with .spf extension which can be created, viewed and/or edited in any available text editor. nnCron distribution includes more than ten of various useful plugins which can be found in folder plugins in nnCron's home directory.

You can find more plugins at our web-site: http://www.nncron.ru/download.shtml. If you have created your own plugin and want to share it with other nnCron users, just send it to support@nncron.ru.

To view the list of active plugins, open Plugins window of Options dialog box (the latter can by opened by double-clicking on nnCron's icon in system tray). Buttons Edit, Add and Delete can be used to add new plugins and remove those you no longer use.

See also "Plugins".

After adding the plugin to Plugins list, you can use all the words defined in it in your tasks.


Plugin "http.spf"

File: http.spf
Author: Nicholas Nemtsev
Description: Additional words allowing to use HTTP protocol in order to monitor changes in remote files, retrieve the date of last modification and even download these files to a local computer.

New Words:

  • HTTP-CHANGED: <URL>
  • HTTP-GET: <URL>
  • HTTP-LM: <URL>
  • HTTP-RESULT
  • HTTPProxy: "proxy_server"
  • HTTPProxyPort: <port_number>
  • HTTPProxy-Authorization: username:password

HTTP-CHANGED: <URL> ( -- ?)

This word checks if a file located at the specified URL has changed since the last time when word HTTP-CHANGED: was executed. To perform this check, this word uses HTTP header Last-Modified. Word HTTP-CHANGED: will only work correctly if the remote HTTP server returns the Last-Modified header.

HTTP server responce code is written to user variable HTTP-RESULT.

When used for the first time, word HTTP-CHANGED: records the time of last modification in file etc\htime.txt, located in nnCron's home directory, and later compares the recorded time with those contained in HTTP header Last-Modified, returned by the remote server. If the times are different, word HTTP-CHANGED: returns TRUE (-1). Otherwise, it returns FALSE (0).

Please note that word HTTP-CHANGED: returns a flag. That means that it should be used with an IF ELSE THEN construct, or the value returned by FILE-CHANGE: should be explicitly cleared from the stack.

Example:

#( help_ru-notify
AsLoggedUser
OnceAHour
: help_ru S" http://www.nncron.ru/download/help_ru.zip" ;
Rule:
    ONLINE? DUP
    IF
       DROP
       HTTP-CHANGED: %help_ru%
    THEN
Action:
    QUERY: "%help_ru% is changed.%crlf%Download it?"
    IF
        S" help_ru.zip" DELETE-FILE DROP
        ShowMinimized
        START-APP: wget %help_ru%
    THEN
)#

There also exists a postfix version of HTTP-CHANGED:

S" http://www.nncron.ru/index.html" HTTP-CHANGED

HTTP-GET: <URL> ( -- a u ior)

Returns error code of an error (if there is one) and a string with contents of a specified URL, in other words, downloads the file to the local computer. HTTP-GET: is mainly used to download html-pages in order to further process them (e.g. to search for some keywords). HTTP-GET: does not support resuming downloads, so it is not recommended to use it for downloading data in binary format (the best way to download binary files is to use utilities specifically designed for that purpose). However, it is still possible to use word HTTP-GET: to download a binary file if such a necessity arises. HTTP server responce code is written to user variable HTTP-RESULT.

Example:

Action:
     S" http://www.nncron.ru/download/help_ru.zip" HTTP-GET 0=
     IF
        S" help_ru.zip" FWRITE
     ELSE 2DROP THEN

There also exists a postfix version of HTTP-GET:

S" http://www.nncron.ru/index.html" HTTP-GET

HTTP-LM: <URL> ( -- a u ior)

Returns error code of an error (if there is one) and a string containing HTTP header Last-Modified from a remote HTTP server, i.e. the time of last last modification of a remote file. HTTP server responce code is written to user variable HTTP-RESULT.

Example:

#( test_http_lm
NoActive
Action:
    HTTP-LM: "http://www.nncron.ru/download/help_ru.zip" 0=
    IF
        2DUP
        \ printing date of last modification to console
        TYPE CR
        \ displaying a message box with the same date
        MsgBox
    ELSE
        2DROP
        MSG: "Error in HTTP-response"
    THEN
)#

There also exists a postfix version of HTTP-LM:

S" http://www.nncron.ru/index.html" HTTP-LM

HTTP-RESULT

Contains HTTP server responce code (after HTTP-CHANGED:, HTTP-GET: and HTTP-LM:).

Here are the most useful codes:

200 - HTTP server reports that operation was successful
404 - HTTP server can not find a specified URL
etc... (you can find the entire list of HTTP server responce codes in your HTTP server documentation).

Response code 0 means, that the problem occured is not related to HTTP server. There are good chances that you are experiencing network problems. When receiving response code 0, it's a good idea to take a look at HTTP-GET: and HTTP-LM: own error codes.

Example:

#( test_http-result
NoActive
Action:
    HTTP-CHANGED: "http://www.nncron.ru/download/help.zip"
    HTTP-RESULT 200 <>
    IF
        DROP
        MSG: "There was an error: %HTTP-RESULT%"
    ELSE
        IF
            MSG: "help.zip was changed"
        THEN
    THEN
)#

HTTPProxy: "proxy_server"

Specifies the name of the proxy-server to use with the words, defined in http.spf plugin. See also: HTTPProxyPort:.

Пример:

HTTPProxy: "proxy.provider.ru"

HTTPProxyPort: <port_number>

Specifies the number of the proxy-server port (see HTTPProxy:). Default value: 3128.

Пример:

HTTPProxyPort: 3100

HTTPProxy-Authorization: username:password

Specifies username and password for authorization on the proxy-server (see HTTPProxy:).

Пример:

HTTPProxy-Authorization: user:password

URL is a string containing the full address (URL) of a remote file in compliance with HTTP protocol.

Examples:

HTTP-CHANGED: "http://www.nncron.ru/index.html"
HTTP-LM: "http://www.nncron.ru/download/help_ru.zip"

Don't omit placing a slash at the URL's end if you are addressing not a single file, but an entire directory or a default page, such as index.htm, index.html etc.:

HTTP-CHANGED: "http://www.nncron.ru/"
HTTP-CHANGED: "http://www.nbk.orc.ru/nncron/"


Plugin "net.spf"

File: net.spf
Author: Nicholas Nemtsev
Description: Additional capabilities for networking
System requirements: WinNT/2000/XP

New words:

  • %SESSIONSCOUNT%
  • %LOGGEDUSERCOUNT%
  • %SESSIONSERVERS%
  • %SESSIONSUSERS%

%SESSIONSCOUNT%

A variable containing a number of sessions.

Example:

MSG: "Currently there are %SESSIONSCOUNT% sessions"

%LOGGEDUSERCOUNT%

A variable containing the number of users that are currently logged on.

Example:

MSG: "Currently there are %LOGGEDUSERCOUNT% logged users"

%SESSIONSERVERS%

A variable containing a list of available servers. A blank space is used as a separator.

Example:

FILE-WRITE: "c:\temp\servers.txt"  " %SESSIONSERVERS% "

%SESSIONSUSERS%

A variable containing a list of users. A blank space is used as a separator.

Example:

FILE-WRITE: "c:\temp\users.txt"  " %SESSIONSUSERS% "


Plugin "process.spf"

File: process.spf
Author: Nicholas Nemtsev
Description: Assigning a specified priority to a process; tracing the moment when the process stops to load the CPU.

New words:

  • S" process-name" <priority-class> PRIORITY
  • S" process-name" <interval-sec> <min-usage> <max-count> PROC-WAIT-CPU-USAGE

    Priority classes:

    • NORMAL_PRIORITY_CLASS
    • IDLE_PRIORITY_CLASS
    • HIGH_PRIORITY_CLASS
    • REALTIME_PRIORITY_CLASS
    • BELOW_NORMAL_PRIORITY_CLASS
    • ABOVE_NORMAL_PRIORITY_CLASS

S" process-name" <priority-class> PRIORITY

Assigns to a process a specified priority from the list of priority classes .

Examples:

S" plugger.exe" HIGH_PRIORITY_CLASS PRIORITY
S" test.exe" IDLE_PRIORITY_CLASS PRIORITY

S" process-name" <interval-sec> <min-usage> <max-count> PROC-WAIT-CPU-USAGE

This postfix word pauses the execution of the task until the specified process stops to load the CPU. When the percentage of time that a process used the CPU becomes lower, than specified in PROC-WAIT-CPU-USAGE arguments, the task execution is resumed.

There is a description of PROC-WAIT-CPU-USAGE arguments:

  • S" process-name" - process name (name of the executable file)
  • interval-sec - time (in seconds) during which CPU usage should be monitored.
  • min-usage - processor time threshold value (in percents). The word PROC-WAIT-CPU-USAGE 'triggers' if the process uses less processor time, than is specified in min-usage.
  • max-count - the maximum allowed count of 'successive triggers'. The execution of the task should be resumed when there are more successive triggers than it is specified in max-count.

Let's examine the following code::

S" calculator.exe" 10 20 5 PROC-WAIT-CPU-USAGE

Explanation: pause the task and monitor the calculator.exe CPU time usage for every 10 seconds. Resume the task when the percentage of time that a process used the CPU becomes lower than 20% five time in a row.

Example:

#( test_proc-wait-cpu-usage
WatchHotKey: "^@r"
Action:
    START-APP: d:\tools\robosoft\robosoft.exe
    S" robosoft.exe" 2 1 3 PROC-WAIT-CPU-USAGE
    BEEP: 500 500
    \ ...
)#

This word only works in WinNT/2000/XP.


Plugin "procwin.spf"

File: procwin.spf
Author: Nicholas Nemtsev
Description: Stopping a process in a "gentle" way: before teminating a process (KILL), nnCron attemps to close all the open windows of this process.

New words:

  • PROC-CLOSE: "proc_pattern"

PROC-CLOSE: "proc_pattern"

Closes all the open windows first, and only after that terminates the process itself.

Examples:

PROC-CLOSE: xxxx.exe
PROC-CLOSE: winword.exe


Plugin "ras.spf"

File: ras.spf
Author: Nicholas Nemtsev
Description: Opens the default dialing program and starts dialing a remote connection. Connection is made "in the name" of the same user in whose name this task is executed.
System requirements: WinNT/2000/XP

New words:

  • DIAL-DLG: "ras_entry"

DIAL-DLG: "ras_entry"

Dials the specified remote connection. After completing its work, word DIAL-DLG: returns TRUE if the connection was successfully established.

Please note that word DIAL-DLG: returns a flag. That means that this word should be used with an IF ELSE THEN construct, or the value returned by DIAL-DLG: should be explicitely cleared from the stack.

Example:

#( download-task
\ when an Internet link is copied into a clipboard, start a
\ download manager and, if necessary, establish an Internet connection
User: "Nicholas" SecPassword: "sdfljwoer" LogonInteractive
WatchClipboard: "*"
\ creating a regular expression
: wget1-mask S" /(http)|(ftp)|(https):\/\/[^ ]+?\.(zip)|(rar)|(exe)|(pdf)|(gz)|(jpg)|(jpeg)|(txt)/i" ;
Rule: RE-MATCH: %CLIPBOARD% %wget1-mask%
Action:
RE-ALL: %CLIPBOARD% %wget1-mask%
\ querying the user with the help of a message box:
QUERY: "Download?%crlf%%$0%"
IF
    ONLINE? 0=
    IF
        \ dialing an Internet connection unless we already have one established
        DIAL-DLG: MyProvider
    ELSE
        TRUE
    THEN
    IF
        \ starting a download manager
        StartIn: e:\home\download
        ShowMinimized
        START-APP: E:\bin\wget\wget.exe %$0%
    THEN
THEN
;RE-ALL
)#


Plugin "sid.spf"

File: sid.spf
Author: Nicholas Nemtsev
Description: Coverts a user name into a SID string. SID (Security Identifier) is a unique number identifying a user or a user group.
System requirements: Win2000/XP

New words:

  • %SID: <user_name>%

%SID: <user_name>%

Coverts a user name into a SID string.

Use of postfix notation is allowed as well:

 S" Nicholas" SID

Example:

 REG-SZ: "HKEY_USERS\%SID: Nicholas%\Control Panel\Desktop\SCRNSAVE.EXE" "G:\WinNT\System32\DPMS.SCR"


plugin "system.spf"

File: system.spf
Author: Nicholas Nemtsev
Description: Additional words helping to monitor the use of system memory. They provide information about system memory use; based on this information, you can decide whether or not you need to use any memory management utilities.

New words:

  • MemLoad
  • TotalPhys
  • AvailPhys
  • TotalPageFile
  • AvailPageFile
  • TotalVirt
  • AvailVirt
  • GetVolID
  • GET-VOL-ID

MemLoad

Returns current memory usage (in percents)

Example:

#( test_memload
Action:
    MemLoad 90 >
    IF
        BALLOON: "MemLoad Warning" "More then  90%PERCENT% of available memory is used"
    THEN
)#

TotalPhys

Returns the amount of total physical memory in bytes.

Example:

\ outputting the value to nnCron console and to nncron.out
TotalPhys . CR

AvailPhys

Returns the amount of available physical memory in bytes.

Example:

\ outputting the value to nnCron console and to nncron.out
AvailPhys . CR

TotalPageFile

Total possible size, in bytes, of the paging file. Note that this number does not represent the actual physical size of the paging file on disk.

Example:

\ outputting the value to nnCron console and to nncron.out
TotalPageFile . CR

AvailPageFile

Size, in bytes, of space available in the paging file. The operating system can enlarge the paging file from time to time. The dwAvailPageFile member shows the difference between the size of current committed memory and the current size of the paging file—it does not show the largest possible size of the paging file.

Example:

\ outputting the value to nnCron console and to nncron.out
AvailPageFile . CR

TotalVirt

Total size, in bytes, of the user mode portion of the virtual address space of the calling process.

Example:

\ outputting the value to nnCron console and to nncron.out
TotalVirt . CR

AvailVirt

Size, in bytes, of unreserved and uncommitted memory in the user mode portion of the virtual address space of the calling process.

Example:

\ outputting the value to nnCron console and to nncron.out
AvailVirt . CR

GetVolID ( letter -- serial_number)

This postfix word takes drive-letter as an argument and returns single signed decimal number, that represents Volume ID (volume serial number) of the specified disk.

See also: GET-VOL-ID

GET-VOL-ID ( letter -- a u)

This postfix word takes drive-letter as an argument and returns a string, that represents Volume ID (volume serial number) of the specified disk (in HEX format). You can use such a string, for example, to identify specific compact-disk when it is inserted into CD-ROM drive.

GET-VOL-ID will return the string '0' if the program can not get Volume ID (disk is unreachable or compact-disc is not inserted into CD-ROM drive).

To place a drive-letter to a stack the words CHAR and [CHAR] are used. The word CHAR is used at run-time (in console, for example):

CHAR F GET-VOL-ID TYPE CR

And the word [CHAR] is used at compile-time (when defining tasks in your crontabs):

#( test_volid
NoActive
Action:
    \ printing drive F: Volume ID to console:
    [CHAR] F GET-VOL-ID TYPE CR
)#

Пример:

#( test_volid1
WatchDrive: "F"
Action:
    \ pausing for 20 seconds to let compact disk to 'spin up'
    PAUSE: 20000
    S" 35405AED" [CHAR] F GET-VOL-ID COMPARE 0=
    IF
        \ some useful action if the strings with Volume ID are the same
    THEN
)#


Plugin "time.spf"

File: time.spf
Author: Nicholas Nemtsev
Description: This plugin provides the capability to monitor time of creation of (last access to, or last modification of) a file with to-a-second accuracy. It also provides additional capability to monitor changes in files matching a certain mask and to create a list of modified files.

New words:

  • FILE-TIME: "filename"
  • FILE-ATIME: "filename"
  • FILE-WTIME: "filename"
  • FTIME-
  • FILE-CHANGE: "file_mask"
  • FCH-CH-LIST

FILE-TIME: "filename"
FILE-ATIME: "filename"
FILE-WTIME: "filename"

These words are used to get, respectively, creation time/last access time/last modification time of the specified file. The values are returned in FILETIME format.

Examples:

#( test_file_time1
\ if file "1.sem" was created earlier than "2.sem",
\ perform some useful operations
Action:
FILE-TIME: "C:\1.sem" FILE-TIME: "C:\2.sem" FTIME- 0>
IF
    \ ... performing some useful actions
THEN
)#

There also exist a postfix versions of these words:

S" c:\temp\test.txt" FILE-TIME
S" c:\temp\test.txt" FILE-ATIME
S" c:\temp\test.txt" FILE-WTIME

Additional methods of working with date and of conversion of dates between various formats are described in detail in Working with Dates and Time.

FTIME-

This word is used to compare the time when a file was created (or last accessed or modified) with that of another file or with the current time. It returns the difference (in seconds) between two dates in FILETIME format.

Examples:

\ file test.txt was created earlier than 10 minutes ago
FT-CUR FILE-TIME: "test.txt" FTIME- 600 >

Additional methods of working with date and of conversion of dates between various formats are described in detail in Working with Dates and Time.

FILE-CHANGE: "file_mask"

When used for the first time, word FILE-CHANGE: creates a list of files matching a specified mask, taking note of the last modification time; when this word is called later, it compares the data in the list with the current state of files and returns TRUE if one or more files has been changed. If none of the files has been changed, word FILE-CHANGE: returns FALSE.
The list of monitored files is saved in nnCron's home directory and is named etc\filechange.txt. Deleted files are not taken into account, in other words, they are not considered to be changed.
Word FILE-CHANGE: can be used with modifier RECURSIVE, which is placed before the word.

Please note that word FILE-CHANGE: returns a flag. That means that this word should be used with an IF ELSE THEN construct, or the value returned by FILE-CHANGE: should be explicitely dropped from the stack.

Examples:

#( test_file_time3
\ Every 10 minutes, checking for changes in all text files
\ in directory 'c:\xxx'. Displaying a message if any changes found.
Time: */10
Action:
FILE-CHANGE: "c:\XXX\*.txt"
IF
    TMSG: "Files were changed!" 5
THEN
)#

#( test_file_time_3_recursive
\ Every 10 minutes, checking for changes in all text files
\ in directory 'c:\xxx' and all of its subdirectories
\ Displaying a message if any changes found.
Time: */10
Action:
RECURSIVE
FILE-CHANGE: "c:\XXX\*.txt"
IF
    TMSG: "Files were changed!" 5
THEN
)#

FCH-CH-LIST

A list of modified files which is built during the execution of FILE-CHANGE:.

Examples:

#( test_file_time4
\ Checking for changes in all text files every 10 minutes
\ in directory 'c:\xxx'. Displaying a message if any changes found.
\ Printing the list of modified files to console
: type-node NodeValue ASCIIZ> TYPE CR ;
Time: */10
Action:
FILE-CHANGE: "c:\XXX\*.txt"
IF
    TMSG: "Files were changed" 5
    ['] type-node FCH-CH-LIST DoList
THEN
)#

#( test_file_time5
\ Every 10 minutes checking for changes in all text files
\ in directory 'c:\xxx'. Saving the list of modified files to
\ 'log\list.log' and displaying the list in a message box
: log-list NodeValue ASCIIZ> S" log\list.log" LOG ;
Time: */10
Action:
FILE-CHANGE: "c:\XXX\*.txt"
IF
    ['] log-list FCH-CH-LIST DoList
    TMSG: "Changed files:%crlf%%FILE: log\list.log%" 10
    FILE-DELETE: "log\list.log"
THEN
)#

#( test_file_time6
\ Every 10 minutes, checking for changes in all text files
\ in directory 'c:\xxx'. Passing names of all modified files
\ to word "START-APP:" as parameters for starting notepad.exe
: write-files NodeValue ASCIIZ> S" c:\changed_files.log" FAPPEND
  crlf S" c:\changed_files.log" FAPPEND
;
VARIABLE list-file
CREATE list-contents 258 ALLOT
Time: */10
Action:
FILE-CHANGE: "c:\XXX\*.txt"
IF
    \ writing the list of all the changed files
    ['] write-files FCH-CH-LIST DoList
    \ reading the list one line at a time
    S" c:\changed_files.log" R/O OPEN-FILE-SHARED THROW list-file !
    BEGIN list-contents 1+ 255 list-file @ READ-LINE THROW WHILE
        list-contents C!
        \ processing each line: passing each filename as
        \ command line parameter
        START-APP: notepad.exe %list-contents COUNT%
    REPEAT
    DROP
    list-file @ CLOSE-FILE DROP
    FILE-DELETE: "c:\changed_files.log"
THEN
)#


Plugin "timesync.spf"

File: timesync.spf
Author: Nicholas Nemtsev
Description: Provides a capability to synchronize system clock with a specified precise time server using NTP protocol. A list of NTP servers is provided here.

New words:

  • TP-SYNC: <server_name>
  • TP-SYNC-RESULT
  • TP-SYNC-DELAY

TP-SYNC: <server_name>

This command starts the process of time synching. Use a name of an NTP server as a parameter.

Example:

#( time_adjust
\ a simple example of time synchronization
OnceADay
Rule: ONLINE?
Action:
    TP-SYNC: time.nist.gov
    TP-SYNC-RESULT 0<>
    IF
        CLEAR-ONCE
        MSG: "Can't synchronize time"
    ELSE
        TMSG: "Time was synchronized. Server response delay: %TP-SYNC-DELAY%" 10
    THEN
)#

#( time_adjust1
\ an advanced example of time synchronization
0 VALUE hh0
0 VALUE mm0
0 VALUE ss0
0 VALUE s_hh
0 VALUE s_mm
0 VALUE s_ss
OnceADay
Rule: ONLINE?
Action:
GET-CUR-TIME
Hour@ TO hh0 Min@ TO mm0 Sec@ TO ss0
TP-SYNC: time.nist.gov
<time> @ UT>TIME 2DROP DROP TO s_hh TO s_mm TO s_ss
TP-SYNC-RESULT 0<>
IF
    LOG: timesync.log "*** %YYYY%-%MMM%-%DD%  %hh0%:%mm0%:%ss0% %TP-SYNC-DELAY% (%s_hh%:%s_mm%:%s_ss%)"
    TQUERY: "Can't synchronize time.%crlf%Continue synchronization?" 10 Yes
    IF CLEAR-ONCE THEN
ELSE
    GET-CUR-TIME
    LOG: timesync.log "%YYYY%-%MMM%-%DD%  %hh0%:%mm0%:%ss0% -> %hh%:%mm%:%ss%  %TP-SYNC-DELAY%"
    TMSG: "Time is synchronized%crlf%%YYYY%-%MMM%-%DD%%hh0%:%mm0%:%ss0% -> %hh%:%mm%:%Ss% (server time %s_hh%:%s_mm%:%s_ss%)" 5
THEN
)#

TP-SYNC-RESULT

Variable TP-SYNC-RESULT allows to check if the time sinchronization was successfull. It countains 0 if sinchronization was successful, and it contains winsock error code if there was an error while trying to connect to the NTP server.
Use it after word TP-SYNC:.

TP-SYNC-DELAY

Variable TP-SYNC-DELAY contains response time of the NTP server (in milliseconds).
Use it after TP-SYNC:.

List of available NTP servers:

time.nist.gov
clock.psu.edu
finch.cc.ukans.edu
ntp.css.gov
ntp.lth.se
ntp.maths.tcd.ie
ntp0.cornell.edu
ntp-1.ece.cmu.edu
ntp-2.ece.cmu.edu
ntp2a.mcc.ac.uk
Rolex.PeachNet.EDU
salmon.maths.tcd.ie
sundial.columbia.edu
time.nrc.ca
timelord.uregina.ca
timex.cs.columbia.edu
Timex.PeachNet.EDU


Plugin "tools.spf"

File: tools.spf
Author: Nicholas Nemtsev
Description: Miscellaneous helper-words: searching a word in nnCron dictionary, printing to console a list of tasks and a list of crontabs.

New words:

  • WORDS-LIKE <part_of_searched_word>
  • TABS
  • TASKS

WORDS-LIKE <part_of_searched_word>

This word searches the nnCron dictionary for all the words whose names contain the argument <part_of_searched_word> used with word WORDS-LIKE, and prints to console the list of all found words. It is used in console.
Its most frequent use is to search for some word if you only can recall a part of it.

Example:

In the console window, enter "WORDS-LIKE" followed by a part of the word you are searching for. For example, command

WORDS-LIKE DAY

would return: CRON-WDAY CRON-DAY WEEKDAYS PURGE-DAYS WEEK-DAY DAY+ WDAYS DAYS.
Please note that the search is case sensitive, therefore, commands

WORDS-LIKE DAY

and

WORDS-LIKE Day

would produce different results.

TASKS

Prints to console a list of all existing tasks. Use in console.

TABS

Prints to console a list of available crontabs. Use in console.


Plugin "wakeup.spf"

File: wakeup.spf
Author: Nicholas Nemtsev
Description: Provides the capability to "wake up" a computer from energy-saving modes such as hibernation (provided, of course, that the computer hardware and software support such modes).
During the entire period while computer is "asleep", words WakeAfter: and WakeAt: function practically in the same way as word PAUSE: . That means that all the task key words that follow after WakeAfter: or WakeAt: will be executed immediately after the computer wakes up.

New words:

  • WakeAfter: <hh:mm>
  • WakeAt: <hh:mm>

WakeAfter: <hh:mm>

Sets "relative" time for a computer to wake up. As the argument for this word, state the length of time (in "hh:mm" format) after which the computer should wake up . Variables (% %) can also be used as an argument.

Examples:

#( wakeup_task
\ timer is set up at the moment the computer switches to hibernation mode
WatchSuspend
Action:
\ computer will wake up in 8 hours 30 minutes
WakeAfter: 08:30
\ this message box will be displayed after the computer has woke up
TMSG: "I'm ready!" 3
)#

SET wake_time=10:00
#( wakeup_task1
\ timer is set up nightly at midnight
Time: 0 0
Action:
\ computer will wake up in 10 hours
WakeAfter: %wake_time%
\ this message box will be displayed after the computer has woke up
TMSG: "I'm ready!" 3
)#

WakeAt: <hh:mm>

This command wakes up a computer at a specified time. In the argument, use format hh:mm. Variables (% %) can also be used in the argument.

Example:

#( another_wakeup_task
\ timer is set up at the moment the computer switches to hibernation mode
WatchSuspend
Action:
\ computer will wake up at 10:00
WakeAt: 10:00
\ this message box will be shown after the computer has woke up
TMSG: "I'm ready!" 3
)#

SET wakeat_time=09:00
#( another_wakeup_task1
\ timer is set up at the moment the computer switches to hibernation mode
WatchSuspend
Action:
\ computer will wake up at 09:00
WakeAt: %wakeat_time%
\ this message box will be shown after the computer has woke up
TMSG: "I'm ready!" 3
)#


Plugin "win2tray.spf"

File: win2tray.spf
Author: Nicholas Nemtsev
Description: Additional words for manipulating icons in the system tray; they allow to minimize to tray either a particular window or all windows matching a specified mask; to find out if a particular window is minimized to tray; to add any desired icons to system tray (as well as modify or delete them); to use icons in tray to show if Web sites are accessible or not, etc.

New Words:

  • WIN-TO-TRAY: "win_pattern"
  • ADD-TI
  • DEL-TI
  • ADD-HOST
  • DEL-HOST-ICONS
  • MODIFY-TI
  • IN-TRAY?
  • TRAY-LIST

WIN-TO-TRAY: "win_pattern"

Minimizes a window matching the specified pattern to the system tray .
Word WIN-TO-TRAY can be preceded by modifier ALL:. In this case, all windows matching the pattern will be minimized to the system tray.

Examples:

\ Minimizing to tray a window of  Internet Explorer
WIN-TO-TRAY: "*Internet Explorer"
\ Minimizing to tray all opened  windows of  Internet Explorer
ALL WIN-TO-TRAY: "*Internet Explorer"

There also exists a postfix version of this word:

S" win_pattern" WIN-TO-TRAY

ADD-TI ( a u hicon -- id )

This postfix word can be used to add a desired icon to system tray and to specify the text which should appear when a user hovers his mouse over the icon.

Word ADD-TI has the following arguments: a string that should appear in a hint when a mouse pointer is placed over the icon, and so-called icon handle, i.e. the icon which should appear in the tray. To create a icon handle, you can "preload" an icon from a file:

S" iconname.ico" LoadIcon

or else you can use one of the numerous Windows constants:

32512 0 LoadIconA

Here is a list of some numerical values of icon constants which you can use:

IDI_APPLICATION | 32512
IDI_ERROR | 32513
IDI_QUESTION | 32514
IDI_WARNING | 32515
IDI_ASTERISK | 32516

Word ADD-TI returns an ID of the icon it creates; you can use this ID later to delete or modify the icon (see DEL-TI, MODIFY-TI)

Example:

#( test_long_proc
NoActive
VARIABLE icon_id
Action:
    \ creating an icon in the tray (IDI_WARNING)
    S" nnCron: long process started" 32515 0 LoadIconA ADD-TI
    \ saving icon's  ID in a variable
    icon_id !
    \ ... working
    \ deleting the icon
    icon_id @ DEL-TI
)#

See also Note.

DEL-TI ( id -- )

This postfix word removes an earler created icon from the system tray. It uses the icon's ID (which was received when the icon was created) as its argument.

Example:

#( test_icon
\ creating an icon in the tray
\ (loading the icon from a specified file)
NoActive
VARIABLE my_icon_id
Action:
    S" New Icon" S" ico\my_icon.ico" LoadIcon ADD-TI
    my_icon_id !
    \ ... working
    \ removing the icon from system tray
    my_icon_id @ DEL-TI
)#

Note: it would be a good idea to remove an icon from the tray in the same task which created it in the first place: an icon exists as long as exists the thread which created it. If the task which created a particular icon is completed, the icon becomes a kind of a ghost which disappears when a mouse pointer passes over the system tray. However, it is possible to add an icon to train in the main nnCron thread (from nncron.ini). Then it would be possible to remove the icon from any task.

MODIFY-TI ( a u hicon id -- )

This postfix word can be used to modify an existing icon in the system tray or to change the hint which appears when a mouse is passed over the icon.

Word MODIFY-TI uses the following arguments: a string which will appear in the hint, icon handle, and icon's ID.

Example:

#( test_tray_icons
NoActive
VARIABLE tray_icon_id
Action:
    \ creating an icon in the tray (IDI_APPLICATION)
    S" nnCron: task started" 32512 0 LoadIconA ADD-TI
    \ saving its ID
    tray_icon_id !
    \ ... working
    \ ... changing the icon in tray (IDI_WARNING)
    S" nnCron: task continued" 32515 0 LoadIconA
    tray_icon_id @ MODIFY-TI
    \ ... working
    \ removing the icon
    tray_icon_id @ DEL-TI
)#

ADD-HOST ( a u -- )

This word adds to the system tray an icon which shows whether or not a specified network computer or Web site is available at the moment. The icon will look like this [image] if the host is accessible, or like this [image] if the host is not accessible. A host is considered to be accessible if it can be pinged. By placing the mouse pointer over this icon you can display a hint with the host name. When you quit nnCron, this icon is automatically removed from the system tray. To manually remove this icon from the tray use the word DEL-HOST-ICONS.

Example:

#( test_add-host
WatchLogon: "*"
Action:
    S" strauss" ADD-HOST
    S" www.nncron.ru" ADD-HOST
)#

DEL-HOST-ICONS

This word removes from system tray all the icons added by word ADD-HOST.

Example:

#( test_del-host-icons
WatchLogoff: "*"
Action:
    DEL-HOST-ICONS
)#

IN-TRAY? ( hwnd -- ? )

This word allows to find out if a specified window is minimized to the tray.
Word IN-TRAY? accepts window handle of a window as its argument, and it returns a flag: TRUE (-1) ifa window is minimized to tray and FALSE (0) if it is not.

Example:

#( test_in_tray
NoActive
Action:
    \ starting Notepad
    START-APP: notepad.exe
    PAUSE: 1000
    \ getting  window handle of Notepad
    WIN-EXIST: "*Notepad"
    IF
        \ checking if Notepad's window is minimized to tray
        WIN-HWND IN-TRAY?
        IF
            MSG: "Notepad is minimized to tray"
        ELSE
            MSG: "Notepad is not minimized to tray"
        THEN
        \ minimizing Notepad's window to tray
        WIN-TO-TRAY: "*Notepad"
        PAUSE: 1000
        \ again checking Notepad's window is minimized to tray
        WIN-HWND IN-TRAY?
            IF
                MSG: "Notepad is minimized to tray"
            ELSE
                MSG: "Notepad is not minimized to tray"
            THEN
    THEN
)#

TRAY-LIST

A list of window handles of windows which has been minimized to the system tray. A detailed discussion of how to work with lists can be found in "Forth First Aid".


Plugin "windows.spf"

File: windows.spf
Author: Nicholas Nemtsev, Valery Kondakoff
Description: Additional words, providing a capability to monitor hidden windows (e.g. those hidden by command WIN-HIDE :), minimized windows and topmost windows. Control of windows' transparency (Win2000/XP).

New words:

  • <window_handle> MINIMIZED?
  • <window_handle> TOPMOST?
  • <window_handle> VISIBLE?
  • WIN-TRANSPARENCY: "win_pattern" <transparency_level>

<window_handle > MINIMIZED?

Returns TRUE only if the specified window is currently minimized.

Example:

\ restore minimized window
WIN-EXIST: "*Internet Explorer"
    IF
        WIN-HWND MINIMIZED?
        IF
            WIN-RESTORE: "*Internet Explorer"
        THEN
    THEN

<window_handle > TOPMOST?

Returns TRUE if the specified window is currently topmost (displayed over all other windows).

Example:

#( test_topmost
\ toggle specified window topmost/notopmost status using hotkey
WatchHotKey: "$q"
Action:
    WIN-EXIST: "*Notepad*"
    IF
        WIN-HWND TOPMOST?
        IF
            WIN-NOTOPMOST: "*Notepad*"
        ELSE
            WIN-TOPMOST: "*Notepad*"
        THEN
    THEN
)#

<window_handle> VISIBLE?

Returns FALSE if the window was processed by WIN-HIDE command or minimized to the system tray. Otherwise, returns TRUE.

Example:

\ show window if it was hidden
WIN-EXIST: "*Internet Explorer"
    IF
        WIN-HWND VISIBLE? 0=
        IF
            WIN-SHOW: "*Internet Explorer"
        THEN
    THEN

WIN-TRANSPARENCY: "win_pattern" <transparency_level>

This word is used to control "transparency" of windows matching a specified mask (except for console windows). The transparency level is specified in numbers ranging from 0 (window is not transparent, flag LAYERED is off) to 255 (window is completely transparent).
Restarting a window will cancel the effect of WIN-TRANSPARENCY:.

Word WIN-TRANSPARENCY: will only work in operating systems which support window transparency, i.e. Windows 2000/XP.

Example:

\ making a window of Notepad half-transparent:
WIN-TRANSPARENCY: "*Notepad" 50
\ making a window of Notepad completely transparent:
\ it still exists on the screen, but it is invisible:
WIN-TRANSPARENCY: "*Notepad" 255
\ canceling the effect of  WIN-TRANSPARENCY:
WIN-TRANSPARENCY: "*Notepad" 0


Plugin winlirc.spf

File: winlirc.spf
Author: Nicholas Nemtsev
Description: Allows to start a task when specific command is received from WinLIRC. WinLIRC is a program which monitors IR (infrared) port and transmits the text of a buttons, which are pressed on remote control unit from TV, audio-system or other infrared remote controls.

New words:

  • WatchLirc: <command_pattern>

WatchLirc: <command_pattern>

WatchLirc: is an event specifier, that receives WinLIRC commands and compares it with a specified command_pattern - mask of a button title, which is pressed on remote control unit. Command_pattern may include wildcard characters * and ? or regular expressions enclosed in slashes: /<regexp>/.

The word WatchLirc: is triggered when WinLIRC command matches a specified command_pattern.

Examples:

\ triggered when any WinLIRC command was received
WatchLirc: "*"
\ triggered when WinLIRC 'play' command was received
WatchLirc: "play"
\ triggered when WinLIRC 'stop' command was received
WatchLirc: "stop"
\ triggered when any numerical WinLIRC command was recived
WatchLirc: "/\d+/"

Using WatchLirc: word you can assign different actions to different buttons of your remote control unit.

Examples:

#( winlirc_play
WatchLirc: "play"
Action:
    START-APP: your_player.exe -play favorite.mp3
)#

#( winlirc_shutdown
WatchLirc: "stop"
Action:
    FORCE-POWEROFF
)#

#( winlirc_go_online
WatchLirc: "0"
Action:
    ONLINE: "MyConnection" 0=
    IF
        RASUser: "login"
        RASPassword: "password"
        DIAL: "MyConnection" 5 30
    THEN
)#


nnCron and Forth Programing Language

nnCron is written in SP-Forth, which is an implementation of Forth programing language. Therefore, use of Forth has become an integral part of nnCron's make-up. Right within a task, a user is allowed to create variables and arrays, use any existing Forth words and create new ones. Actually, if one wants, he can use "pure Forth" within a task. Extended mode syntax also borrows many of its features from Forth.

Forth is a very powerful, and hence, somewhat dangerous tool. Careless use of Forth may crash nnCron or even destabilize the entire system. nnCron provides an option to put certain restrictions on how far one can go when manually writing task code: see description of variable SyntaxRestriction used in nncron.ini.

nnCron documentation contains answers to frequently asked questions about Forth, and the present section provides only elementary information, the basics of Forth which are difficult to do without when actively using nnCron. Use of variables, constants and arrays is discussed in a separate chapter.

In your experiments with Forth, you can use the Forth console which is one of nnCron's built-in tools: this will greatly facilitate understanding of how Forth works. Examples of nnCron tasks using branching, variables and Forth words can be found in file titled example.tab.

  • Forth Syntax
  • Postfix Notation
  • Using Stack
  • Flow of Control (Branching)
  • Creating and Using New Words
  • Double Numbers

Forth Syntax

Forth syntax is very simple: it is considered one of the simplest in the entire history of programing.

In short, it can be described as follows: "A Forth program is a set of words with spaces between them". "Word" in Forth is a name assigned to a definition. In other words, a Forth word is an analogue of a function (method) in other programing languages. Words are executed in the order in which they are placed in the source text. For example, a hypothetical program emulating behavior of a typical workaholic (all work and no rest):

WAKE_UP BREAKFAST EAT WORK DINNER EAT WORK SLEEP

Forth programing adds up, essentially, to performing operations with words. Even signs of arithmetical operations (e.g.+, -, *), symbol of "comment till the end of line" (\) and even symbols of start and end of a task definition (" #( " and " )# ") are Forth words in their own right. Therefore, make sure to separate all words with spaces.

Example:

\ the line below is incorrect:
\ there is no space after the "comment" word
\Error!

\ the first lime of the task below
\ also contains an error: there is no space
\ between the task name
\ and the word marking the task beginning
#(task_name \ error!
\ ...
)#

Postfix Notation.

Forth uses so-called postfix notation (it is also called reverse Polish notation). In this type of notation, operators (logical or arithmetical) are placed after the values on which the operation is performed.

For example, an operation of adding two numbers would look in postfix notation like this:

2 3 +

In order to make postfix notation seem more logical to you, you can read this example in this way: "Let's take number 2 and number 3 and add them up". (I suppose that you have figured out the result? Yes, it is 5!). :)

Using Stack

The reason why Forth uses postfix notation is because it is convenient to use with "stack", which is an area of memory in which data are placed and removed according to LIFO principle (last in, first out). The simplest way to imagine a stack is to see it as a pile of numbers placed one upon the other.

For example, let's take the following string:

2 3 +

It actually means that numbers 2 and 3 are placed on stack and added, and 5 remains on stack.

Here is a little more complex example:

4 3 2 1 + - +

What will happen here? I will try to explain it you step by step: words "+" and "-" (and in Forth, these arithmetical signs are words in their own right) work with two uppermost elements of stack. We put on stack 4, 3, 2 and 1. Therefore, we have 2 and 1 on the top of the stack. It is these two numbers that are added by the first "postfix" plus sign:

 4 3 2 1 + - +

After the first addition, we have three numbers remaining on the stack: 4, 3, and the sum we have just obtained: 3. The "postfix" minus sign also applies to the two topmost elements of the stack, therefore, now we subtract 3 from 3 (3-3):

4 3 3 - +

Now we have only two numbers on the stack: 4 and 0, and they are added by the next plus. The end result is 4:

4 0 +

Well, how do you like it? Slightly paraphrasing Aristotle, we could say that roots of study are bitter, but its fruit is sweet!. :)

Flow of Control (Branching)

Postfix notation also appears in frequently used IF THEN constructs. Instead of more traditional forms:

IF <condition> THEN <action_if_TRUE>
IF <condition> THEN <action_if_TRUE> ELSE <action_if_FALSE>

we have the following constructs in Forth:

<condition> IF <action_if_TRUE> THEN
<condition> IF <action_if_TRUE> ELSE <action_if_FALSE> THEN

The general rule of branching in Forth is as follows: after IF, we write everything that should be done if a check on the condition returns TRUE (-1), and after ELSE we write everything that should be done if a check on the condition returns FALSE (0).
THEN just signifies that the end of construct.
ELSE is not an obligatory element, one could just use IF THEN.

Example:

FILE-EXIST: "test.txt"  \ condition
IF MSG: "exist!"        \ this will be done if the specified file exists
ELSE MSG: "not exist!"  \ this will be done if the specified file does not exist
THEN

Sometimes it is more convenient to use another type of construct then IF ... ELSE ... THEN: this is CASE ... OF ... ENDOF ... ENDCASE construct, which is usually used when it is necessary to select one of several known values:

<value_on_stack>
CASE
    <a possible_value> OF action (value on stack equals the possible value) ENDOF
    <a possible_value> OF action (value on stack equals the possible value) ENDOF
    \ ...
    <a possible_value> OF action (value on stack equals the possible value) ENDOF
    <a possible_value> OF action (value on stack equals the possible value) ENDOF
    DUP OF <a possible_value> OF action (value on stack equals none of the  possible values) ENDOF
ENDCASE

Example:

#( test_case
NoActive
Action:
    START-APPW: program.exe
    \ placing on stack the return code of a program
    ExitCodeProc
    \ displaying a message depending on the return code
    CASE
        \ return code 0
        0 OF MSG: "Everything okay!" ENDOF
        \ return code 1
        1 OF MSG: "I can't be bothered getting started!" ENDOF
        \ return code 2
        2 OF MSG: "Leave me alone!" ENDOF
        \ любые return code
        DUP OF MSG: "Unknown error!" ENDOF
    ENDCASE
)#

Creating and Using New Words

Creating of new Forth words is very much like creating variables, but the syntax is different:

: <name_of_word> <body of word> ;

Have you noticed the spaces after ":" and before ";"? Yes, colon and semicolon are Forth words too! :) I hope, now you understand why names of variables, new words and tasks cannot contain spaces? (I will give the answer to this question, just in case: from the viewpoint of Forth, a space is a separator of words. If a name contains a space, it will be treated by Forth as two different identifiers).

Example:

\ let's create a new word "x2" which would multiply by  2
\ the uppermost value on the stack:
: x2 2 * ;
\ now let's test word "x2" in action:
2 x2   \ now the stack contains the result of multiplying  2 * 2
16 x2  \ now the stack contains the result of multiplying  16 * 2

New words can be defined not only through numbers, but also by using earlier defined words.

Example:

\ if word "x2" is already defined, we can
\ create a new word which, for example, will
\ subtract4 from the result produced by "x2".
\ let's call the new word "x2minus4"
: x2minus4 x2 4 - ;
\ let's test  "x2minus4" in action:
8 x2minus4  \ now the stack contains the result
            \ of expression  (8 * 2) - 4
1 x2minus4 \ now the stack contains the result
            \ of expression  (1 * 2) - 4

New Forth words should be created in the beginning of a task (before Action: section), and they can be used inside this section. Let's convert the above example to an nnCron task:

#( words_task
NoActive \ we are going to start this task manually
\ creating two new words
: x2 2 * ;
: x2minus4 x2 4 - ;
Action:
    \ displaying the result of "3 x2"
    MSG: "3 x2 = %3 x2%"
    \ displaying the result of "6 x2minus4"
    MSG: "6 x2minus4 = %6 x2minus4%"
    \ displaying the result of "1 x2minus4"
    MSG: "1 x2minus4 = %1 x2minus4%"
)#

New Forth words created by you are global, i. e. they can be "seen" from other tasks and are shared by all instances of any given task. In order to avoid unnecessary confusion, please make sure that all names of new words are unique.

Double Numbers

Some of words used in Forth and in nnCron return so called double numbers, i. e. numbers which require 64 bits to represents them instead of 32 bits. A double number takes the same amount of space in stack as two usual numbers.

Forth has special words for handling double-numbers, e.g.:

D. | output a double number to console
D+ | add two double numbers
D- | subtract one double number from another (d1 - d2)
DNEGATE | revert the sign of a double number
D< | put on stack TRUE if d1 is less then d2
D= | put on stack TRUE if d1 equals d2
D0= | put on stack TRUE if d equals zero

Literal double numbers are written with a period in the end. You can convert single number to a double number using the special word S>D. To convert a double number to a single number, use word D>S.

Examples:

\ adding two double numbers
1000000. 2000000. D+

\ comparing  two double numbers and displaying a message
10240. 90000. D<
IF MSG: "File size exceeds 10kb"
ELSE MSG: "File size less then 10kb"
THEN

\ checking if two double numbers are equal
150000. 150000. D=
IF MSG: "Equal!"
ELSE MSG: "Not equal"
THEN


Working with Variables, Constants and Arrays

Active usage of nnCron often requires to store various data for long periods of time. Variables, constants and arrays can be used for this purpose. Beside allowing to use all the tools for handling variables, constants and arrays provided by Forth programing language (SP-Forth), nnCron also privides some convenient tools of its own.

  • Variables
  • Self-fetching Variables (VALUE)
  • Constants
  • Arrays
  • File and Registry Variables
  • Visibility Scope of Variables, Constants and Arrays

Variables

Variables inteneded for storing numerical values are created (declared) with word VARIABLE:

VARIABLE <var_name>

Variable should be declared in the beginning of a task, before the Action: section; operations of assigning/fetching values to and from variables should be performed inside of Action: section. When a variable is created, it is assigned a value of 0.

Example:

#( test_variable
NoActive
VARIABLE my_var
Time: * * * * * *
Action:
    \ ... working with value of my_var
)#

In order to assign a value to a variable, use word ! (exclamation point) :

<var_value> <var_name> !

Example:

\ now variable my_var contains  a numerical value of 12
12 my_var !

To get (retreive) a value from a variable, use word @:

<var_name> @

Example:

\ adding 10 to the value of  my_var (12)
\ the sum is 22
my_var @ 10 +

Example:

#( variable_task
NoActive   \ we are going to start this task manualy
\ creating two variables
VARIABLE first_var
VARIABLE second_var
Action:
    \ assigning value of  18 to first_var
    18 first_var !
    \ adding  4 to the value of first_var
    \ and storing the result in second_var
    \ (4 + 18 = 22)
    4 first_var @ + second_var !
    \ diaplaying the value of second_var
    MSG: "second_var = %second_var @%"
)#

There are also special words ON and OFF which facilitate use of variables with IF ... ELSE ... THEN construct . Word ON sets the value of a variable to -1, and OFF to 0:

\ setting  first_var to -1
first_var ON
\ setting  first_var to 0
first_var OFF

Example:

#( test_variable2
NoActive
\ creating a  variable is_it_true?
VARIABLE is_it_true?
Action:
    \ assigning a value of -1 to is_it_true?
    is_it_true? ON
    \ fetching the value of this variable
    \ checking it with a conditional construct
    is_it_true? @
    IF
        MSG: "TRUE!"
    ELSE
        MSG: "FALSE!"
    THEN
    \ assigning a value of 0 to is_it_true?
    is_it_true? OFF
    \ fetching the value of this variable
    \ checking it with a conditional construct
    is_it_true? @
    IF
        MSG: "TRUE!"
    ELSE
        MSG: "FALSE!"
    THEN
)#

See also Variables, Constants and Arrays Visibility Scope

Self-fetching Variables (VALUE)

Another way to create a somewhat different type of numerical variables (so-called self-fetching variables) is to use word VALUE:

<initial_value> VALUE <var_name>

As you can see, a self-fetching variable is assigned some value at the moment when it is created:

10  VALUE first_var
100  VALUE second_var

One of the convenient features of self-fetching variables is that you can fetch their values without using a special word. All that you need to do in order to place a value of a self-fetching variable on stack is just to use its name in a program:

#( test_value_var
NoActive
\ declaring a variable bingo and setting its value to 21
21 VALUE bingo
Action:
    \ displaying its value
    MSG: "You are a winnner - %bingo%!"
)#

To assign a value to a self-fetching variable, use word TO. Here is and example of its use:

<new_var_value> TO <var_name>

Example:

#( test_value_var1
NoActive
\ declaring a variable counter_var and setting its value to 0
0 VALUE counter_var
Action:
    \ displaying its value
    MSG: "Initial value = %counter_var%"
    \ assigning a new value to it ( 5)
    5 TO counter_var
    \ displaying the new value of our variable
    MSG: "New value = %counter_var%"
)#

See also Variables, Constants and Arrays Visibility Scope

Constants

Sometimes it is necessary to create a "variable" whose numerical value should not change later. Such a "variable" is called a constant.

To create a constant, use a special word CONSTANT:

<const_value> CONSTANT <const_name>

All that you need to do in order to place a value of a constant on stack is just to use its name in a program:

#( test_constant
NoActive
\ creating a constant one_o_one and setting its value to 101
101 CONSTANT one_o_one
Action:
    \ displaying the value of our constant
    MSG: "One-O-One = %one_o_one%"
    \ using the constant in an arithmetical operation
    MSG: "One-O-One - 1 = %one_o_one 1 -%"
    \ displaing the constant again,
    \ to make sure it has not changed
    MSG: "One-O-One = %one_o_one%"
)#

See also Variables, Constants and Arrays Visibility Scope

Arrays

Array is a special type of structure that allows to store multiple values under a single name. One of the traditional uses for arrays in nnCron is to temporarily store strings in them. Methods of handling strings are described in detail in "Forth First Aid".

In order to create an array, use word CREATE:

CREATE <array_name>

To allocate a required memory space for the new massive, use word ALLOT.

Example:

#( test_array
NoActive
\ creating an array test_arr  256 byte in size
CREATE test_arr 256 ALLOT
Action:
    \ placing a string to our array
    S" this is our string" test_arr PLACE
    \ reading a string from the array
    \ and displaying it
    MSG: "Array contents: %test_arr COUNT%"
)#

Of course, arrays can be used to store any kind of values, not just strings. It is even possible to initialize arrays right at the monent of their creation, e.g.:

\ сreating an array containing five integers
CREATE numbers 1 , 2 , 3 , 4 , 5 ,

It is not a purpose of nnCron documentation to provide a more detailed desription of using arrays. For additional information, consult documentation of Forth programing language.

See also Variables, Constants and Arrays Visibility Scope

File and Registry Variables

The main drawback of variables, constants and arrays discussed above is that they store their values in computer memory, and, therefore, these values will be lost after the computer is turned of or after nnCron is unloaded from the memory. But what if we want to save a value of a variable, constant or array during the period when computer is off or nnCron is not running?

Just for this purpose nnCron provides a number of words for creating string variables which are not affected by restart of a computer or of nnCron. These are so-called file variables and registry varibiables, i. e. variables which store their values not in computer memory, but in special files and registry keys.

fVAR <var_name> (file variable)
regVAR <var_name> (registry variable)

When file/registry variable is created, it is initialized with an empty string. To store your string in such a variable, use word TO. To access the current value of a variable, just use its name in a program:

#( test_persistent_var
NoActive
\ creating a file variable and a registry variable
fVAR file_var
regVAR reg_var
Action:
    \ assigning string values to variables
    S" first string" TO file_var
    S" second string" TO reg_var
    \ displaying both variables on screen
    MSG: "There are %file_var% and %reg_var%"
)#

As told above, file and registry variables are used to store strings, but if you want to use them to store numbers rather then strings, you can use special words which convert a number to a string and vice versa (coverting numbers to strings and strings to numbers is discussed in detail in "Forth First Aid"):

\ converting a number to a string and storing it in a file variable
N>S TO file_var
\ reading a string from a file variable and converting it to string
file_var S>NUM

If we want to get a complete idea about using file and registry variables, we have yet to talk about out where they are stored. Each file variable is stored in a file with the same name; this files are located in subdirectory var of the nnCron installed directory. Registry variables store their values in registry keys which have the same name as variables and are located in a registry branch HKEY_LOCAL_MACHINE\SOFTWARE\nnSoft\var\.

If it is necessary to change storage locations of file and registry variables, there are special words which can be used for that purpose:

FileVarPath! ( a u -- )
RegVarPath! ( a u -- )

These words specify the path to directory or registry branch where file/registry variables should be stored. Don't forget a backslash (\) at the end of the specified path.

S" c:\temp\var\" FileVarPath!
S" HKEY_LOCAL_MACHINE\SOFTWARE\var\" RegVarPath!

Please note that these words are intended for use in nncron.ini. They cannot be used in tasks.

uFileVarPath! ( a u -- )
uRegVarPath! ( a u -- )

These words specify the path to directory or registry branch where file/registry variables should be stored. Don't forget a backslash (\) at the end of the specified path.

S" c:\temp\var\" uFileVarPath!
S" HKEY_LOCAL_MACHINE\SOFTWARE\var\" uRegVarPath!

These words are intended for use in tasks.

If required, you can delete unnecessary file or register variables with words FILE-DELETE:/REG-DELETE-KEY:.

See also Variables, Constants and Arrays Visibility Scope

Visibility Scope of Variables, Constants and Arrays

All variables (VARIABLE, VALUE), constants (CONSTANT) and arrays(CREATE ... ALLOT) are global, they can be seen from other tasks and are shared by all instances of any given task. Therefore, in order to avoid unnecessary confusion, one should take a great care to ensure that all variable names are unique.

Here are some details for most curious ones: although theoretically all variables are global, each unique task will work with its own variable. Constructs of %VAR-NAME @% type, however, will always return the value of variable which was used last.

Example:

#( t1
VARIABLE V1
Action:
    1 V1 !
    MSG: "%V1 @%"
)#

#( t2
VARIABLE V1
Action:
    2 V1 !
    MSG: "%V1 @%"
)#

Now, a question: what message will contain the message box displayed by the first task?

It depends on whether or not the second one has been executed. If it has, the first one will output 2, otherwise, it will output 0 (the initial value of all variables).

It is possible to create arrays and variable which will be unique for each instance of a task (there will be as many variables as there are instances of task running). In order to achieve this result, create variables with these words:

USER var1
USER-CREATE var2 256 USER-ALLOT
USER-VALUE var3

You can also allocate memory using word ALLOCATE. In this case each task will also have its own buffer:

#( vars
NoActive
USER buf
Action:
    256 ALLOCATE THROW buf !
    ACTIVE-WINDOW buf @ PLACE
    5000 PAUSE
    MSG: "%buf @ COUNT%"
)#


nnCron Predefined Variables

%hh% | current hour (00-23)
%mm% | current minute (00-59)
%ss% | current second (00-59). nnCron automatically updates the value of this variable once a minute; use the word GET-CUR-TIME to update it manually
%MM% | month (01-12)
%MMM% | month (Jan-Dec)
%DD% | day of a month (01-31)
%WW% | day of a week (Mo-Su)
%WD% | day of a week (1-7, where 1 is Monday, and 7 is Sunday)
%YYYY% | year (4 digit)
%YY% | year (last 2 digit)

%crlf% | carriage return followed by line feed
%QUOTE% | quotation mark (")
%% | percent sign (%)
%PERCENT% | percent sign (%)
%FILE: filename% | inserts the contents of a file filename. There also exists a postfix version of this word: S" filename" FILE.

%FOUND-FILENAME% | name of a found file (see FOR-FILES:)
%FOUND-FULLPATH% | full path and name of a found file (see FOR-FILES:)
%FOUND-RELPATH% | path and name of a found file relative to the directory where search is performed (see FOR-FILES:)

%WIN-TITLE% | window title (see "Working with Application Windows")
%ACTIVE-WINDOW% | title of the active window (see "Working with Application Windows")
%FOUND-WINDOW% | title/class of a found window (see "Working with Application Windows")
%FOUND-CHILD-WINDOW% | title/class of a found child window (see FOR-CHILD-WINDOWS:)

%FOUND-PROC% | the name of the found process (see "Working with processes")
%FOUND-PID% | the PID of the found process (see "Working with processes")

%n esPICK%
         - inserting the n-th value from the stack

%n esPICKS%

 - inserting the string from the stack. The starting address of the string should be the n-th value on the stack and the counter should be the n-th value on the stack minus one (n-1)

Note: the stack numbering starts with zero (0), so the value on top of the stack is always the value 0. After %n esPICK% and %n esPICKS% usage the stack is cleared up to the n-th value plus 1 (n+1) , so the n-th value plus 1 (n+1) becomes the topmost value on the stack.

Examples:

#( test_esPICK
NoActive
Action:
\ placing three values on the stack (the current year, month and day):
Year@ Mon@ Day@
\ displaying these values in a message:
MSG: "The current date: %0 esPICK%-%1 esPICK%-%2 esPICK%"
)#

#( test_esPICK1
NoActive
Action:
\ placing three values on the stack (the current year, month and day):
Year@ Mon@ Day@
\ displaying these values in a messages (one by one):
MSG: "Current day: %0 esPICK%"
MSG: "Current month: %0 esPICK%"
MSG: "Current year: %0 esPICK%"
)#

#( test_esPICKS
NoActive
Action:
\ placing two strings on the stack:
S" first string" S" second string"
\ displaying these strings in a message:
MSG: "%1 esPICKS% and %3 esPICKS%"
)#

#( test_esPICKS1
NoActive
Action:
\ placing two strings on the stack:
S" first string" S" second string"
\ displaying these strings in a messages (one by one):
MSG: "The second string: %1 esPICKS%"
MSG: "The first string: %1 esPICKS%"
)#

%COMSPEC% | name or the command interpreter (command.com in Win9* and cmd.exe in WinNT/2000/XP)
%CLIPBOARD% | current contents of the Windows clipboard
%USERNAME% | name of the current logged in user
%CONNECTION% | a list of all active remote connections (conn1, conn2, ...)
%LAST-CONNECTION% | name of the last remote connection (e.g. for WatchDisconnect)
%ModuleDirName% | the full path to the directory, where nnCron is installed
%CHAR X FREE-SPACE% | amount of free space on disk X: (in kilobytes). For example, for C: drive it will be %CHAR C FREE-SPACE%, for D: drive—%CHAR D FREE-SPACE% etc.
%$0% %$1% .... %$15% | variables used in regular expressions
%ExitCodeProc% | exit code (error level) of an application. Used after execution of START-APPW:
%ThreadId% | number of a thread in which a task is started, task process identifier
%WATCH-PROC-ID% | contains process identifier (PID). This variable is filled after words WatchProc:/WatchProcStop: have been used. It is used as an argument for words used to handle processes.
%DRIVE-LETTER% | contains the inserted/removed removable data storage device letter. This variable is filled after words WatchDrive:/WatchDriveRemove: have been used.
%TempFile% | contains a unique string which is built in this way: <running number >.<ThreadId>.<TickCounter>, e.g.: 5.120.5434173 6.968.5439611 7.544.5446721 8.1100.5451629 Such a string maybe conveniently used, for example, as a unique file name.
%PrevTempFile% | contains the previous %TempFile%

PROC-ID | process identifier (PID) of an application started by nnCron. It is used as an argument for words handling processes. This variable is filled after each time an applications is started successfully (see START-APP:, START-APPW:, QSTART-APP:).
WIN-HWND | contains window handle of a window. It is filled after most of command having to do with windows (and WIN-EXIST: as well).
WIN-CHILD-HWND | contains window handle of a child window. This variable is filled inside of the FOR-CHILD-WINDOWS: loop.

Special folders (variables which return path and name of user folders will contain empty strings unless a user profile is loaded):

%FOLDER-APP-DATA% | Application data folder
%FOLDER-COMMON-DESKTOP% | Common desktop for all users
%FOLDER-COMMON-STARTMENU% | Common Start menu
%FOLDER-COMMON-PROGRAMS% | Common Programs menu
%FOLDER-DESKTOP% | Desktop
%FOLDER-FAVOURITES% | Favorites
%FOLDER-PERSONAL% | Personal Folder
%FOLDER-STARTMENU% | Start menu
%FOLDER-PROGRAMS% | Programs menu
%FOLDER-RECENT% | Documents menu (within Start menu)
%FOLDER-SENDTO% | "Send to" menu
%FOLDER-STARTUP% | Startup menu
%FOLDER-TEMPLATES% | Templates folder
%FOLDER-TEMP% | Temp folder (for temporary files)
%FOLDER-WINDOWS% | Windows folder
%FOLDER-SYSTEM% | System folder

Besides, any environment variables, e.g. %PATH%, and any Forth words can also be used as nnCron variables, but in this case an expression must return a string ( addr u) or a 32-bit integer ( n).

Example:

\ the number of milliseconds since system startup,
\ will be inserted to a string
MSG: "%GetTickCount%"


Working with Environment Variables

nnCron can set environment variables and use them in its work. nnCron is actually a fully-functional manager of environment variables, and it can set both local environment variables (available only to programs started by nnCron) and system (global) environment variables, available to the all the software installed on your computer.

Environment variables defined in crontabs are totally independent of the system, and this is their main advantage. For example, in Windows NT/2000/XP, nnCron is run by SYSTEM, and variables of "user" SYSTEM may be different from variables set for a current user. And if the variables are defined in crontabs, they are not affected by this problem and you won't have reenter them after reinstalling your system.

System environment variables, created by nnCron, can be used in tasks, *.cmd and *.bat files, as well as any other programs. Local environment variables can be used in those command and batch files and programs which are started by nnCron.

  • How to Set System Environment Variables
  • How to Set Local Environment Variables
  • How to Use Environment Variables in Tasks

How to Set System Environment Variables

System (global) environment variables are set with word SYS-SET.

SYS-SET varname=string value until the end of line
# or
SYS-SET varname="string value"

You can use word SYS-SET in any place of crontab with one condition: it must be outside of any task definitions.

# declaring a local variable
SYS-SET PC_NAME=your friendly PC
#( pc_hello
Time: START-TIME
Action:
    \ displaying a message box
    MSG: "This is %PC_NAME%!"
)#

System environment variables are used for storing permanent, rarely changed values (e.g. paths to programs and system directories or global macrosubstitutions). System variables are reset each time crontabs are reloaded.

It must be noted that deleting a system variable from a crontab won't automatically remove it from system settings. Values of system environment variables are stored in system registry (HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Session Manager\Environment), and you should remove obsolete values manually or use a special system tool System Properties - Advanced - Environment Variables (Windows 2000 and Windows XP).

How to Set Local Environment Variables

Local environment variables are set with word SET.

SET varname=string value until the end of line
# or
SET varname="string value"

You can use word SET in any place of crontab with one condition: it must be located outside of any task definitions.

# declaring a local variable
SET PC_NAME=your friendly PC
#( pc_hello
Time: START-TIME
Action:
    \ displaying a message box
    MSG: "This is %PC_NAME%!"
)#

Local environment variables are much more flexible then system (global) variables. They are reloaded, (in other words, re-set) each time any program is started by nnCron. This allows a user to set values which are difficult to set with the standard means provided by a command interpreter. For example, you can set date, time or another changing factor an environment variable:

SET CURTIME=%hh%:%mm%
SET CURDATE=%DD%.%MM%.%YY%
SET WEEKDAY=%WD%

As you can see, nnCron allows to use its own variables when setting values of environment variables. Therefore, it is even possible to create "dynamic" environment variables, whose values will change as conditions change.

For example, one can declare a variable MYHOST containing a name of a host available at the moment:

# declaring an environment variable
SET MYHOST=%MyHost%
<%
    \ creating a new word
    : MyHost
        \ checking if the first host is accessible
        HOST-EXIST: "HOST1"
        IF
            \ the first host is accessible,
            \ returning its name
            S" \\HOST1\DIR1"
        ELSE
            \ checking if the second host is accessible
            HOST-EXIST: "HOST2"
            IF
                \ the second host is accessible,
                \ returning its name
                S" \\HOST2\DIR2"
            ELSE
                \ no hosts are accessible,
                \ returning an empty string
                S" "
            THEN
        THEN
   ;
%>

For this purpose, we created word MyHost, which returns a name of an available host. If none of the specified hosts can be accessed at the moment, word MyHost returns an empty string.

Since environment variables declared with word SET are set anew each time a new application is started, string SET MYHOST=%MyHost% means that at the moment when any application starts, the value of environment variable MYHOST will be equal to the result returned by MyHost, i. e. a name of a host accessible at the moment or an empty string.

Please note that values of variables are "calculated" right at the moment when they are addressed, so it would be not a good idea to use constructs like the one below:

SET PATH="%PATH%;c:\xxx"

it will cause the value of PATH to become longer and longer each time PATH is addressed.

Additional information regarding local environment variables:

Inside a task (and in Forth Console) a value of an environment variable can be accessed with the help of word ENV ( aname u1 -- aval u2)

 S" PATH" ENV TYPE CR

There also exists word SETENV ( aval u1 aname u2 -- ior )

 S" c:\dos;c:\bin" S" PATH" SETENV THROW

How to Use Environment Variables in Tasks

Although the methods used to set local and system (global) variables are different, both types of variables are used in the same way in tasks. The general rule is as follows: in order to access a value of a variable, one just has to place its name between %...% characters.

Examples:

\ displaying a message box with a value of a variable
MSG: "WINDIR=%WINDIR%"
\ writing a value of a variable to a file
FILE-WRITE: "c:\temp\test.txt" "%SCITE_HOME%"

Environment variables set on system level outside of nnCron (e.g. in autoexec.bat), can be used in tasks in the same way.


nnCron Commands

nnCron Key Words

Starting Applications and Opening Documents
Task Options
Monitoring the Events (Watch*)
Messages, Reminders, Hints
Working with Application Windows
Operations with Files and Directories
Working with Processes
Working with Dates and Time
Working with Sounds
Working with Dial-up (RAS)
Working with Event Logs (WinNT/2000/XP)
Performance Monitoring
Mouse Activity Emulation
Keyboard Input Emulation
Working with Windows Registry
Regular Expressions Support
Power Management and Turning off the Computer
Checking Your OS Version
Integrating JScript and VBScript in Your Tasks
Miscellaneous Key Words


Starting Applications and Opening Documents

  • START-APP: <command to the end of line>
  • START-APPW: <command to the end of line>
  • QSTART-APP: <command to the end of line>

    Options for Running Applications and Opening Documents:

    • AboveNormalPriority
    • AsService
    • BelowNormalPriority
    • HighPriority
    • IdlePriority
    • NormalPriority
    • RealtimePriority
    • ShowMaximized
    • ShowMinimized
    • ShowNoActivate
    • ShowNormal
    • StartIn: "dir_path"
    • StartPos: <x> <y>
    • StartSize: <xsize> <ysize>
    • SWHide
    • Title: "console_title"
    • WaitFor: <hh:mm>
    • WaitFor: <ms>

START-APP: <command until the end of line>

Starts an application and proceeds to the next line of current task without waiting for the application to be closed.

Arguments of word START-APP: may include path to the desired program or document, name of the executable file and all required command line parameters. If the argument contains a name of a document rather than that of an executable file, nnCron will open this document in a program which is the registered program for files of this type.

Examples:

#( test_start_app
\ starting Internet Explorer on every week day at 10:00 A.M.
Time: 0 10 * * 1-5 *
Action:
START-APP: C:\Program Files\Internet Explorer\iexplore.exe
\ after Internet Explorer has been started, nnCron proceeds to
\execute the remainder of the task
)#

#( test_start_app1
\ starting backup copying on Mondays and Thursdays at 2:30 A.M.
Time: 30 2 * * 1,4 *
Action:
START-APP: nnbackup.exe sync -i d:\fido -o g:\backup\fido -s -v -e -da
)#

There also exists a postfix version of this word:

S" app_name" START-APP

Attention, please: you cannot use the postfix word START-APP in console. To start an application from console use the word StartApp ( si a u -- ?):

0 S" app_name" StartApp DROP

See also "Options for Running Applications and Opening Documents" , PROC-WAIT-IDLE.

START-APPW: <command to the end of line>

This word works similarly to START-APP:, but after starting an application it awaits for its completion, i.e. the next line in the task will be executed only after the application has been stopped.

Example:

#( test_start_appw
\ starting Internet Explorer on every week day at 10:00 A.M.
Time: 0 10 * * 1-5 *
Action:
START-APPW: C:\Program Files\Internet Explorer\iexplore.exe
\ the remainder of task will not be executed
\ until Internet Explorer window is closed by the user
)#

Word START-APPW: permits to access the errorlevel code returned by the program which it started. The errorlevel number is stored in variable ExitCodeProc.

Example:

\ display a message if  errorlevel number  is not equal to zero
START-APPW: xxx.exe
ExitCodeProc 0 <> IF MSG: "Error %ExitCodeProc%!" THEN

Besides the standard set of options running applications, you can use option WaitFor: <ms or hh:mm> before START-APPW:; this option will terminate the application if it has not completed its work during specified period of time.

There also exists a postfix version of this word:

S" app_name" START-APPW

Attention, please: you cannot use the postfix word START-APPW in console. To start an application from console use the word StartAppWait ( si a u -- ?):

0 S" app_name" StartAppWait DROP

See also "Options for Running Applications and Opening Documents" .

QSTART-APP: <command to the end of line>

This word works similarly to START-APP:, but before starting an application, it will display a dialog box asking: "Would you like to run application?". The application will be started only if the user selects Yes.

Example:

#( test_start_app
\ every week day at 5:30 P.M., asking user's permission
\ to start Internet Explorer
Time: 30 17 * * 1-5 *
Action:
    QSTART-APP: C:\Program Files\Internet Explorer\iexplore.exe
)#

See also "Options for Running Applications and Opening Documents", PROC-WAIT-IDLE.

Options for Running Applications and Opening Documents

There are certain options for running applications and opening documents which can be used with words START-APP:, START-APPW: и QSTART-APP:; these options determine how applications will be started and how documents will be opened. Options should be separated by a blank space, a tabulation symbol or a newline symbol. They are placed before words which they modify.

StartIn: "dir_path" | Sets the directory in which the application will be started.
ShowNormal
SWHide
ShowMaximized
ShowMinimized
ShowNoActivate

Options for displaying application window:

  • Start in normal mode
  • Hide program window
  • Maximize
  • Minimize
  • Do not make the window active when starting application
StartPos: <x> <y> | Specifies the absolute position of a window (in pixels)
StartSize: <xsize> <ysize> | Specifies window size (in pixels)
HighPriority
IdlePriority
NormalPriority
RealtimePriority
AboveNormalPriority
BelowNormalPriority

Sets a process's priority.

Works only in WinNT/2000/XP, and words AboveNormalPriority and BelowNormalPriority - only in Win2000/XP.
AsService

Starts an application as a service. This means that the program started in this way will not be terminated on user log-off. Option AsService permits nnCron to perform functions of utility SRVANY.EXE fromWinNT Res. Kit.

Works only in WinNT/2000/XP.
Title: "console_title" | Sets a console window's title immediately on the application's startup. Works only with console windows..

WaitFor: <ms>
WaitFor: <hh:mm>

Terminates an application if it has not completed its work or been closed by a user during a specified period of time.

Works only with word START-APPW:.

Example:

#( backup_fido_and_tools
\ NoActive
Time: 30 2 * * 1,4 *
Action:
    StartIn: "\tools\nnbackup"
    ShowMinimized NormalPriority
    START-APPW: nnbackup.exe sync -i d:\fido -o g:\backup\fido -s -v -e DA
    LOG: "log\nncron.log" " > Exit Code: %ExitCodeProc% > FIDO backup"

    StartIn: "\tools\nnbackup"
    ShowMinimized NormalPriority
    START-APPW: nnbackup.exe sync -i d:\tools -o g:\backup\tools -s -v -e DA -x *.lck
    LOG: "log\nncron.log" " > Exit Code: %ExitCodeProc% > Tools backup"
)#


Task Options

  • Also
  • AsLoggedUser
  • HyperActive
  • LoadProfile
  • NoActive
  • NoDel
  • NoLog
  • NoRunAs
  • OnceADay
  • OnceAHour
  • OnceAMonth
  • OnceAWeek
    • CANCEL
    • CLEAR-ONCE
  • RunMissed
  • RunMissed: <hh:mm|days>
  • RunOnce
  • SingleInstance
    • GET
    • RELEASE

Also

Connects specifiers Time: and Watch* with logical OR operator (by default, they are treated as combined with logical AND).

Example:

#( test-mailbox
\this task will be executed each hour or when the user presses "Alt-Ctrl+F12"
Time: 0 * * * * *
Also
WatchHotKey: @^{F12}
Rule: POP3-CHECK: "hostname" "pop3user" "password"
Action:
    START-APP: e:\win\the bat!\thebat.exe /CHECKALL
)#

AsLoggedUser

This option tells nnCron to execute a task as a currently logged user. A task with this option can be executed only if there is a user who is authorized (logged) on this system.

Example:

#( interactive-job
AsLoggedUser
Time: 0 10 * * * *
Action:
    START-APP: c:\msoffice\winword.exe
)#

Use this option when nnCron is started as a system service (using System account). Don't use AsLoggedUser if you are running nnCron not as a system service, but as a regular application (see also Starting and Stopping nnCron).

Hyperactive

A task with this option will be executed not only in normal mode, but in suspended mode as well.

Example:

#( test_hyperactive
HyperactiveTime: */5
Action:
    MSG: "Running in normal and suspended mode!"
)#

LoadProfile

This option is used to load user profile when launching processes (START-APP:, START-APPW:).
When performing task authorization, use this option for applications which require user profile (Outlook Express, The Bat!, Internet Explorer etc.)

NoActive

Deactivates the task
This option is also used in tasks which are intended to be started manually.

NoDel

This word tells nnCron not to remove from crontab file a task containing option RunOnce.
If a task contains both RunOnce and NoDel, it will be executed each time the crontab is reloaded.

Example:

#( every_crontab_reload
\ the task is executed on each reloading of crontab
RunOnce NoDel
Action:
    TMSG: "Crontab was reloaded!" 3
)#

NoLog

This option forbids to make records about execution of the task in a log file.
It is convenient to use this option in tasks which are triggered too often or with "secret" tasks which shouldn't be disclosed by record in a log file.

NoRunAs

Cancels authorization for this particular task if nnCron is set to run all tasks as as specified user (variable RunAsDefaultUser in nncron.ini).

OnceAHour
OnceADay
OnceAWeek
OnceAMonth

These options tell nnCron to run a task only once during an hour, day, week or month, respectively.

Example:

#( daily-task
\ the task is executed only once a day at system startup
Time: START-TIME
OnceADay
Action:
    START-APP: backup.bat
)#

No matter how many time a computer is going to be reloaded during a day, the above task will be executed only once. You can also set time limits, e.g.:

Time: * 12-16 * * * *
OnceADay

This task will be executed once on any given day, if the computer is working between 12:00 and 16:59. (And it will be started only once, even if the computer is reloaded. You cannot achieve the same result by using option RunOnce).

Information about the "worked-out" programs is recorded in file etc\once.txt nnCron's installed directory.
Sometimes it may be necessary to cancel option OnceA* in the task itself, e.g. so that time count is started anew after rebooting the system. For this purpose, you can use words CANCEL or CLEAR-ONCE, which removes the effect of OnceA* option from the current task.

Example:

#( test_clear_once
Time: START-TIME
OnceADay
Action:
    START-APP: backup.bat
    \ clearing 'OnceA*' option if specified file exists
    FILE-EXIST: "c:\more_backups.sem"
    IF CLEAR-ONCE THEN
)#

RunMissed
RunMissed: <hh:mm|days>

Sometimes tasks may have been missed because nnCron was not running. RunMissed option tells nnCron to run missed task 'at the first opportunity' - at the top of the first minute after nnCron startup. Missed tasks handling concept is described in more details in corresponding chapter.

Example:

#( test_missed
\ the task will start at the specified time or
\ at the top of the first minute after nnCron startup
\ (if nnCron was not running at 12:00)
RunMissed
Time: 0 12 16 5 * 2003
Action:
    \ ...
)#

The 'extended' option RunMissed: <hh:mm|days> allows you to specify maximum waiting time (in hours and minutes) that may elapse since this task was sheduled to run for the last time. The missed task will not be launched if specified waiting time value is smaller than the actual time elapsed since this task was sheduled to run for the last time.

Example:

#( test_missed1
\ the task will start at the specified time or
\ at the top of the first minute after nnCron startup
\ (if nnCron was not running at 12:00 and maximum
\ waiting time do not exceeds 3 hours and 30 minutes)
RunMissed: 03:30
Time: 0 12
Action:
    \ ...
)#

#( test_missed2
\ the task will start at the specified time or
\ at the top of the first minute after nnCron startup
\ (if nnCron was not running at sunday, 12:00 and
\ maximum waiting time do not exceeds 3 days)
RunMissed: 3
Time: 0 12 * * 7
Action:
    \ ...
)#

Note, please, that you can use RunMissed: 0 syntax to disable missed tasks handling.

When you are using plain RunMissed option (instead of extended RunMissed: <hh:mm|days>) the value of nncron.ini variable DefaultRunMissedTime: is used as RunMissed argument (360 hours or 15 days).

You can manage missed tasks handling using nnCron GUI: checkboxes to turn RunMissed option on/off and input fields to enter maximum waiting time are available in New Task, New Reminder

and Edit Task dialog boxes.

See also: RunMissed?

RunOnce

A task with this option will only be executed once, after which it will be deleted from the crontab file.
Deleted tasks are automatically saved by the program in a special inactive crontab file deleted.tab which is located in nnCron's installed directory.
This option is mainly used in reminders (see Reminder:).

SingleInstance

This option prevents simultaneous execution of two or more instances of the same task. While a task with SingleInstance option is being executed, no other instance of the same task cannot be started, and any attempt to start it will be suppressed.

In order to prevent a simultaneous execution of several different tasks (and two or more instances of the same task as well), one can use words GET и RELEASE. GET takes hold of a specified semaphore, and RELEASE releases it. These words use address of a variable (which is left on the stack after the variable has been used in the task) as their parameter. The succeeding tasks will be started, but they will be actually executed only after the preceding task releases the semaphore.

Example:

#( test_task1
\ Messages "task1" and "task2" will never appear at the same time.
VARIABLE SEM1
Action:
    SEM1 GET
    MSG: "task1"
    SEM1 RELEASE
)#

#( test_task2
Action:
    SEM1 GET
    MSG: "task2"
    SEM1 RELEASE
)#


Monitoring the Events (Watch*)

  • WatchBatteryLow
  • WatchClipboard: "text_pattern"
  • WatchConnect
  • WatchCPUUsage: <CPUUsage%> <seconds>
  • WatchDir: "dir_path" [flag] [modifiers]
  • WatchDisconnect
  • WatchDrive: <drv_letter>
  • WatchDriveRemove: <drv_letter>
  • WatchEventLog: "log_name"
  • WatchFile: "file_path"
  • WatchFileDelete: "file_path"
  • WatchHotKey: "hotkey"
  • WatchLogoff: "username_pattern"
  • WatchLogon: "username_pattern"
  • WatchProc: "proc_pattern"
  • WatchProcStop: "proc_pattern"
  • WatchRegistryKey: "key_path" [flag] [modifiers]
  • WatchQuerySuspend
  • WatchResume
  • WatchResumeAuto
  • WatchShutdown
  • WatchSuspend
  • WatchWinActivate: "win_pattern"
  • WatchWinCreate: "win_pattern"
  • WatchWinDestroy: "win_pattern"
  • WatchWindow: "win_pattern"

WatchFile: "file_path"
WatchFileDelete: "file_path"

The word WatchFile: is triggered when the specified file appears (is created) or when its contents is modified.
If the specified file exists at the moment of nnCron startup, the task will be started if the file has been changed since the moment when nnCron was unloaded from memory.

The word WatchFileDelete: is triggered when the specified file is deleted (renamed, moved).

Examples:

WatchFile: "c:\flags\urgent.sem"
WatchFile: "c:\xxx\test.flg"
WatchFileDelete: "c:\flags\del.sem"
WatchFileDelete: "c:\xxx\xxx.flg"

Words WatchFile:/WatchFileDelete: can also work with filename masks, but with one limitation: they looks for the first file in the specified directory that matches a mask, and tests just this one file for modification. In other words, if a directory contains more than one file matching a specified mask, WatchFile:/WatchFileDelete: may ignore the fact of creation/modification/deletion of another file matching this mask.

Example:

#( test_watchfile
WatchFile: "c:\xxx\*.sem"
Action:
    MSG: "flag detected"
)#

WatchDir: "dir_path" [flag] [modifiers]

Flag (optional):
WatchSubtree
Modifiers (optional):
WATCH-CHANGE-ATTRIBUTES notify of changes to the attributes
WATCH-CHANGE-DIR-NAME notify of changes to the directory name
WATCH-CHANGE-FILE-NAME notify of changes to the file names within directory
WATCH-CHANGE-LAST-WRITE notify of changes to the last modification date (is triggered when new file is created, or existant file is changed, but in not triggered when a file is deleted)
WATCH-CHANGE-SECURITY notify of changes to the access rights
WATCH-CHANGE-SIZE notify of changes to the size

This word is triggered by changes in a specified directory. The modifiers listed above allow a user to specify very precisely which parameters should be watched for changes.

Flag WatchSubtree instructs nnCron to monitor not only a specified directory, but all of its subdirectories as well.

Examples:

\ monitoring all the changes in  'c:\xxx'
WatchDir: "c:\xxx"

\ monitoring changes of access rights in  'c:\xxx'
WatchDir: "c:\xxx"
WATCH-CHANGE-SECURITY

\ monitoring changes of size of  'c:\xxx'
\ and all its subdirectories
WatchDir: "c:\xxx"
WatchSubtree
WATCH-CHANGE-SIZE

\ monitoring changes of file names, directory names
\ and attributes in 'c:\xxx'
WatchDir: "c:\xxx"
WATCH-CHANGE-FILE-NAME
WATCH-CHANGE-DIR-NAME
WATCH-CHANGE-ATTRIBUTES

\ monitoring changes of file names, directory names
\ and attributes in 'c:\xxx' and all its subdirectories
WatchDir: "c:\xxx" WatchSubtree
WATCH-CHANGE-FILE-NAME
WATCH-CHANGE-DIR-NAME
WATCH-CHANGE-ATTRIBUTES

Directory, that does not exists can also be specified as an argument for a word WatchDir:. In this case WatchDir: enters a loop, waiting for specified directory to be created and triggers when directory becomes available. Self-fetching variable MonitorDirTimeout sets the time (in ms) between every loop iteration. The default MonitorDirTimeout value is 60000 ms (60 seconds).

WatchConnect
WatchDisconnect

These words are triggered, respectively, by connecting to and disconnecting from your ISP. WatchConnect is also triggered on nnCron startup if an active remote connection exists at that moment.

These words only work in WinNT/2000/XP.

WatchClipboard: "text_pattern"

This word is triggered if the contents of Windows clipboard matches the specified mask.

In text_pattern, you can use either a usual mask (containing characters * and ?) or regular expressions inside of forward slashes: /<regexp>/.

Examples:

\ will be triggered by  any changes in the clipboard contents
WatchClipboard: "*"
\ will be triggered if  a name of any executable file
\ (e.g. 'nncron.exe') is copied to the clipboard
WatchClipboard: "*.exe*"
\ will be triggered if a text containing some number
\ is copied to the clipboard
WatchClipboard: "/.*\d+.*/"

WatchWinCreate: "win_pattern"
WatchWinActivate: "win_pattern"
WatchWinDestroy: "win_pattern"

These words are triggered when a window whose title matches the specified pattern is created (opened), activated or closed, respectively.

Example:

#( test_watchwin
\ the task would be executed
\ if a window of Notepad is opened,
\ or if a window of Opera browser is
\ or if a window of Internet Explorer is closed
WatchWinCreate: "*Notepad"
WatchWinActivate: "Opera*"
WatchWinDestroy: "*Internet Explorer"
Action:
    \ ... performing some useful actions
)#

See also Note.

WatchWindow: "win_pattern"

This word is triggered whenever a window appears whose title matches a specified pattern and/or when when a window's title is changed to another one matching this pattern.

Example:

#( test_watchwindow
WatchWindow: "*white*"
Action:
    \ ... performing some useful actions
)#

Let's analyze this task. We have set a window title pattern (*white*) to watch for. Now, if there appears a window with a title containing substring "white", or if its title is changed in such a way that the new title contains substring "white", word WatchWindow: will be triggered. For example, WatchWindow: will be triggered if there appears a window titled 'white.txt - Notepad'. WatchWindow: will be also triggered if the title is changed into 'black_and_white.txt - Notepad' (for the new title contains 'white'). If the title is changed to 'black.txt - Notepad', WatchWindow: won't be triggered, for the new title does not contain the substring we are watching for.

It follows, then, that if a window title is changed and the new title does not contain the specified substring, WatchWindow: won't be triggered. If the original title is restored (the one containing this substring), WatchWindow: will be triggered again.

See also Note.

WatchDrive: <drv_letter>
WatchDriveRemove: <drv_letter>

These words are working with different removable data storage devices (removable hard disk drives, USB drives, CD/DVD-ROM drives etc).

The word WatchDrive: is triggered when removable device is connected to your PC (at the moment when specified disk drive letter appears in My Computer folder) or when specified CD/DVD-ROM drive tray is closed.

The word WatchDriveRemove: is triggered when removable device is disconnected from your PC (at the moment when specified disk drive letter disappears from My Computer folder) or when disk is removed from the specified CD/DVD-ROM drive. WatchDriveRemove: is triggered also when closing empty CD/DVD-ROM drive tray, because the system reports, that there is no disk in specified drive.

Use the specified disk drive letter as an argument to the words WatchDrive:/WatchDriveRemove:. If you want to work with all the inserted/removed drives, you can use * mask as well. After WatchDrive:/WatchDriveRemove: words have been used the variable %DRIVE-LETTER% is filled with a letter of currently inserted/removed drive.

Examples:

#( test_watchdrive
WatchDrive: "E"
Action:
    START-APP: explorer.exe d:\backup
)#

#( test_watchdriveremove
WatchDriveRemve: "E"
Action:
    POWEROFF
)#

#( test_watchdrivemask
WatchDrive: "*"
Action:
    S" G" DRIVE-LETTER COMPARE 0=
    IF
        MSG: "drive G inserted"
    ELSE
        S" H" DRIVE-LETTER COMPARE 0=
        IF
            MSG: "drive H inserted"
        ELSE
            MSG: "unexpected drive (%DRIVE-LETTER%) inserted"
        THEN
    THEN
)#

Note, please: in order for these words to work properly with CD/DVD-ROM drives, option Autorun must be set to on. In Windows NT/2000/XP this option is toggled on/off in the registry: HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Cdrom.

See also: CD-TRAY-EJECT: <drv_letter>, CD-TRAY-CLOSE: <drv_letter>, IS-CD-PRESENT: <drv_letter>

WatchEventLog: "log_name"

This word is triggered when new entries in WinNT/2000/XP event logs were found. See Working with Event Logs chapter for details.

WatchProc: "proc_pattern"
WatchProcStop: "proc_pattern"

These words are triggered, respectively, by starting or stopping the process specified in the argument. Please note that word WatchProc: (unlike WatchProcStop:) cannot take process identifier (PID) as its argument.

Example:

#( test_proc
\ the task will be started both when the process "wget.exe" is started
\ and when it is ended "wget.exe"
WatchProc: "wget.exe"
WatchProcStop: "wget.exe"
Action:
    \ ... performing some useful actions
)#

After words WatchProc:/WatchProcStop: have been used, variable %WATCH-PROC-ID% will contain a string with process identifier (PID).

Example:

#( test_watchprocstop
WatchProc: notepad.exe
Action:
    MSG: "PID = %WATCH-PROC-ID%"
)#

WatchRegistryKey: "key_path" [flag] [modifiers]

Flag (optional):
WatchSubtree
Modifiers (optional):
REG-CHANGE-ATTRIBUTES notify of changes to the attributes of the key, such as the security descriptor information.
REG-CHANGE-NAME notify of changes to the key name
REG-CHANGE-LAST-SET notify of changes to the key last modification date
REG-CHANGE-SECURITY notify of changes to the key access rights

This word is triggered by changes in a specified Registry key. The modifiers listed above allow a user to specify very precisely which parameters should be watched for changes.

Flag WatchSubtree instructs nnCron to monitor not only a specified Registry key, but all of its subkeys as well.

Examples:

\ monitoring all the changes of the key
WatchRegistryKey: "HKEY_LOCAL_MACHINE\SOFTWARE\test"

\ monitoring changes of access rights
WatchRegistryKey: "HKEY_LOCAL_MACHINE\SOFTWARE\test"
REG-CHANGE-SECURITY

\ monitoring changes of the key name and changes of the names
\ of all the subkeys
WatchRegistryKey: "HKEY_LOCAL_MACHINE\SOFTWARE\test"
WatchSubtree
REG-CHANGE-NAME

\ monitoring changes of the key name and changes of access rights
WatchRegistryKey: "HKEY_LOCAL_MACHINE\SOFTWARE\test"
REG-CHANGE-NAME
REG-CHANGE-SECURITY

WatchLogoff: "username_pattern"
WatchLogon: "username_pattern"

These words are triggered, respectively, when a user tries to log off (end his session) or log on the local computer. They take as their arguments masks of user names.

Examples:

WatchLogon: "vkondakov"
\ will be triggered when either user Admin or user Administrator log on the system
WatchLogon: "Admi*"
\ will be triggered when any user ends his session
WatchLogoff: "*"

WatchShutdown - on the attempt to shut down the computer.
WatchSuspend - on switching the computer to Hibernate or Standby modes.
WatchQuerySuspend - when applications are queried before switching to Hibernate or Standby modes.
WatchBatteryLow - when the system sends a message that the batteries are low.

These words are triggered by attempts to shut down the computer or switch it to Hibernate or Standby modes etc., as described above. It should be noted that nnCron has no means to stop or suspend the process of shutting the system down or switching it to Hibernate mode, so that if a long task is started on such an event, it may be interrupted before it is complete. Event specifiers WatchShutdown, WatchSuspend etc. were created in order to be used in shorter tasks, e.g. setting up a timer (e.g. setting a period of time after which the computer should wake up) or creating a flag file.

See also WatchLogoff:

WatchResume
WatchResumeAuto

These words are triggered when the system returns to normal energy consuming after being in Hibernate or Standby modes.

The word WatchResume is triggered, when the system returns to normal mode forced by some user activity (mouse moving or pressing of any key) - for example, after resuming from StandBy mode and when user activity is detected after resuming from Hibernate mode.
WatchResumeAuto is triggered, when the system returns to normal working mode after being in Hibernate or Standby modes regardless of presence or lack of user activity.

Examples:

#( test_watchresume
\ will be triggered after resuming from StandBy
\ and when user activity will be first detected
\ after resuming from Hibernate
WatchResume
Action:
    BEEP: 50 500
    PAUSE: 100
    BEEP: 50 500
)#

#( test_watchresumeauto
\ will be triggered after resuming from StandBy
\ and after resuming from Hibernate
WatchResumeAuto
Action:
    BEEP: 50 500
    PAUSE: 100
    BEEP: 50 500
)#

#( test_watchresumecombined
\ will be triggered once after resuming from StandBy
\ and twice after resuming from Hibernate (right after
\ resuming and when user activity will be first detected)
WatchResume
WatchResumeAuto
Action:
    BEEP: 50 500
    PAUSE: 100
    BEEP: 50 500
)#

WatchHotKey: "hotkey"

This word is triggered by pressing a specified "hotkey" (keyboard shortcut), consisting of one or more keys pressed together. It may be advisable to create hotkeys by combining such keys as CTRL, SHIFT, ALT or WIN with one of the alphanumerical keys. If a shortcut consists of two or more keys, they are considered to be pressed simultaneously. The order of keys and case of alphabetical keys does not matter (^@w и @W^ are the same thing).
A detailed description of symbolic designations of various keys can be found here.

Examples:

WatchHotKey: "$9"   \ 'WIN + 9'
WatchHotKey: "^@f"  \ 'CTRL + ALT + F'
WatchHotKey: "@+z"  \ 'ALT + SHIFT + Z'
WatchHotKey: "^+w"  \ 'CTRL + SHIFT + W'
WatchHotKey: "w^+"  \ 'CTRL + SHIFT + W'

Virtual key codes can be used as an argument to WatchHotKey: as well. Use WinSpy to find a virtual key code of a specified key. Place the virtual key code inside the curly braces.

Examples:

WatchHotKey: "{0x74}"    \ 'F5'
WatchHotKey: "^@{0x7B}"  \ 'CTRL + ALT + F12'
WatchHotKey: "^+{0x47}"  \ 'CTRL + SHIFT + G'

Attention, please: you can't use virtual key codes, when specifying modifiers-keys (CTRL, SHIFT, ALT, WIN).

Note: Words of WatchWin*: group ignore console windows. This limitation is imposed by the operating system. At the same time, word WIN-EXIST: can work correctly with both with normal and console windows. Therefore, you can attempt to monitor console windows with the help periodical use of WIN-EXIST:.

See also:

  • WatchCPUUsage: <CPUUsage%> <seconds>


Messages, Reminders, Hints

  • BALLOON: "balloon_title" "balloon_text"
  • ERR-MSG: "msg_text"
  • HINT: "hint_text"
  • HINTW: "hint_text"
  • HINT-OFF
  • MSG: "msg_text"
  • QUERY: "query_text"
  • REMINDER: "reminder_text"
  • THINT: "hint_text" <time_in_sec>
  • THINTW: "hint_text" <time_in_sec>
  • TMSG: "msg_text" <time_in_sec>
  • TQUERY: "query_text" <timeout_in_sec> Yes/No

    Hint displaying options

    • HINT-POS: x y
    • HINT-SIZE: w h

MSG: "msg_text"

Displays a message box with a specified text.

User-defined variables and nnCron's predefined variables can be used in text of a message. To add a quotation mark character and percent sign character to the text of a message, use variables %QUOTE% and %PERCENT% respectively. By using variable %FILE: filename%, you can display contents of a specified file in a message box.

After a message box has been displayed, execution of the task is suspended until the user clicks OK button.

Examples:

MSG: "Work is 100%PERCENT% complete"
MSG: "Hello, %USERNAME%!"
MSG: "Isn't it time to go home?"

There also exist a postfix version of this command:

S" Hello, world!" MsgBox
\ converting number on the stack ('115') to a string
\ and displaying it on screen
115 N>S MsgBox

TMSG: "msg_text" <time_in_sec>

This word works similarly to MSG, but it displays a message only for a specified time (in seconds), after which it closes the message and resumes execution of the task. A user can close the message before this time has elapsed by clicking OK button.

Examples:

\ this message is displayed for three seconds
TMSG: "Everything's ready!" 3
\ this message is displayed for five second
TMSG: "Hello, %USERNAME%!" 5

There also exist a postfix version of this word:

S" Hello, world!" 3 TimeMsgBox

ERR-MSG: "msg_text"

Works just like MSG, but contains an error icon instead of information icon.

ERR-MSG is best used to warn a user that something has gone wrong.

QUERY: "query_text"

This word displays a query message box with a specified question. If the user answers affirmatively (clicks YES), QUERY: returns TRUE (-1).

Example:

#( test_query
\ every weekday, at 18:00 querying the user
\ and turning off the computer if he answers YES
Time: 0 18 * * 1-5 *
Rule: QUERY: "Shutdown your PC?"
Action:
    POWEROFF
)#

TQUERY: "query_text" <timeout_in_sec> Yes/No

Similar to QUERY:, but waits for the user's response during a specified number of seconds. If user does not respond, the value specified in the last argument will be used as the answer (Yes or No).

Example:

#( test_tquery
\ every weekday, at 18:00 querying the user
\ and turning off the computer if the user  answers YES
\ or if he does not respond within 30 seconds
Time: 0 18 * * 1-5 *
Rule: TQUERY: "Shutdown your PC?" 30 Yes
Action:
    POWEROFF
)#

REMINDER: "reminder_text"

Displays a message accompanied by a sound signal and provides an option to repeat it after a certain number of minutes.

Sometimes reminders may have been missed because nnCron was not running. Select 'Display missed reminder' checkbox if you want nnCron to run missed reminder 'at the first opportunity' - at the top of the first minute after nnCron startup (see this chapter for details).

HINT: "hint_text"

Displays a small hint message and proceeds with execution of the task, regardless of user's reaction.

You can move a hint to any place on the screen by simply dragging it with your mouse.

A hint can be closed either manually (by right-clicking on it and selecting Close from context menu) or programmatically from the task, by using word HINT-OFF.

See also Hint Options.

HINT-OFF

Closes a hint message

HINTW: "hint_text"

Similar to HINT, but suspends execution of the task until the user closes hint message manually or until it is closed with HINT-OFF.

See also Hint Options.

THINT: "hint_text" <time_in_sec>

Displays a hint during a specified period of time (in seconds). A user can close the hint earlier by clicking on it. Task execution is not suspended.

See also Hint Options.

THINTW: "hint_text" <time_in_sec>

Displays a hint during a specified period of time (in seconds), suspending execution of the task. After the time expires, the hint automatically closes and execution of task is resumed. The user can close the hint at any time by clicking on it.

See also Hint Options.

Hint Options

You can use the following options before words HINT:, HINTW:, THINT: and THINTW: to control size and position of hint box:

HINT-POS: x y | specify position of hint box
HINT-SIZE: w h | specify dimensions of hint box

Example:

HINT-POS: 100 100 HINT-SIZE: 100 100
THINT: "This is a hint" 5

BALLOON: "balloon_title" "balloon_text"

Displays a small hint message with a specified title and text and proceeds with execution of the task regardless of the user reaction. The balloon hint appears near nnCron icon in system tray.

A hint can be closed by clicking on it or on Close button in the upper right corner. If a hint is not closed manually, it will disappear by itself after some time.
Word BALLOON: can be used only in Win2000/XP.

Example:

#( test_backup
NoActive
Action:
    BALLOON: "Attention!" "Task %QUOTE%%CUR-TASK-NAME%%QUOTE% has been started"
    BEEP: 250 500
)#

You can customize BALLOON: behaviour using the following variables:

BalloonTime

Sets the time (in ms), after which balloon hint will be closed by the system. The system enforces minimum and maximum timeout values (10000 ms and 30000 ms, respectively). Values that are too large are set to the maximum value and values that are too small default to the minimum value. Thus, you can control the time in the range from 10000 ms to 30000 ms. Default value - 10000 ms.
BalloonIcon

Sets the icon, that will be displayed in balloon hint:

  • 0 - no icon
  • 1 - Asterisk icon ( [image])
  • 2 - Warning icon ( [image])
  • 3 - Error icon ( [image])

Default value - 1.

Example:

#( test_backup1
NoActive
Action:
    \ in the case of error
    30000 BalloonTime !
    3 BalloonIcon !
    BALLOON: "Error!" "Error in task %QUOTE%%CUR-TASK-NAME%%QUOTE%"
    BEEP: 250 500
)#

There also exist a postfix version of this command:

S" title" S" text" BALLOON

Note: if BALLOON: seems not to work on your PC (Win2000/XP) check the following registry path: HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced. The value EnableBalloonTips need to be set to dword:00000001.

See also: TrayIconBalloonClick:, OnBalloonClick.

See also:

  • QSTART-APP: <command to the end of line>


Working with Application Windows

  • GetForegroundWindow
  • SendMessageA
  • WIN-ACTIVATE: "win_pattern"
  • WIN-ACTIVE: "win_pattern"
  • WIN-CLICK: "win_pattern" "button_pattern"
  • WIN-CLOSE: "win_pattern"
  • WIN-EXIST: "win_pattern"
  • WIN-HIDE: "win_pattern"
  • WIN-MAXIMIZE: "win_pattern"
  • WIN-MINIMIZE: "win_pattern"
  • WIN-RESTORE: "win_pattern"
  • WIN-POS
  • WIN-RECT
  • WIN-RESIZE
  • WIN-NOTOPMOST: "win_pattern"
  • WIN-SEND-KEYS: "win_pattern" "key_code_string"
  • WIN-SET-TITLE: "win_pattern" "new_window_title"
  • WIN-SHOW: "win_pattern"
  • WIN-TERMINATE: "win_pattern"
  • WIN-TOPMOST: "win_pattern"
  • WIN-MOVE: <x> <y>
  • WIN-MOVER: <x> <y>
  • WIN-WAIT: <time_in_ms>
  • FOR-WINDOWS: "win_pattern" <...> ;FOR-WINDOWS
  • FOR-CHILD-WINDOWS: "win_pattern" <...> ;FOR-CHILD-WINDOWS
  • ALL
  • WIN-HWND
  • %ACTIVE-WINDOW%
  • %WIN-TITLE%
  • %FOUND-WINDOW%

GetForegroundWindow

Returns window-handle of the active application window; window-handle can be used with the majority of "window" key words (see also win_pattern, WIN-HWND, WIN-CHILD-HWND).

Example:

WIN-SET-TITLE: "%GetForegroundWindow%" "new_title"

SendMessageA ( u u u u -- u )

The Windows operating system allows you to send special control messages to a specified window. These messages are called Windows Messages. Different windows can handle different messages - consult API of the specified program to learn which messages can you send to it's windows. Special win32-function SendMessage is used to send Windows Messages. Here is the description of this function:

LRESULT SendMessage(
   HWND hWnd, // handle of destination window
   UINT Msg, // message to send
   WPARAM wParam, // first message parameter
   LPARAM lParam // second message parameter
);

SendMessageA is a postfix version of SendMessage function, that you can use in nnCron. This means, that if you know the Window Handle of a specified window, you can send Windows Messages to that window right from your tasks. Note, please, that SendMessageA is a postfix word, thus the arguments are passed to it in reverse order:

<lParam> <wParam> <Msg> <hWnd> SendMessageA

Value, that was returned by SendMessageA stays on the stack. Delete this value if you are not planning to use it in your task.

Examples:

\ clicking 'play' button in WinAmp
0 40045 273 WIN-HWND SendMessageA DROP
\ clicking 'next' button in WinAmp
0 40048 273 WIN-HWND SendMessageA DROP
\ getting current WinAmp state (play, stop, pause)
104 0 1024 WIN-HWND SendMessageA IF ... ELSE ... THEN
\ setting Miranda state to 'online'
0 171144 273 WIN-HWND SendMessageA DROP
\ setting Miranda state to 'do not disturb'
0 171146 273 WIN-HWND SendMessageA DROP

WIN-CLICK: "win_pattern" "button_pattern"

"Clicks" on a specified button in a specified window.

Word WIN-CLICK: can be used with modifier ALL, which is placed before it.

WIN-CLOSE: "win_pattern"

Sends instruction WM_CLOSE to a specified window, i.e. emulates a single click with left mouse button on the "diagonal cross" in the upper right corner of the window.

Word WIN-CLOSE: can be used with modifier ALL, which is placed before the word.

WIN-HIDE: "win_pattern"

Hides a specified window. The program will still be running, but its window will no longer be seen on screen. In order to make the window reappear, use word WIN-SHOW:.

Word WIN-HIDE: can be used with modifier ALL, which is placed before the word.

WIN-SHOW: "win_pattern"

Causes the windows that has been hidden with WIN-HIDE: and windows of applications started with option SWHide to be displayed on the screen.

Word WIN-SHOW: can be used with modifier ALL, which is placed before the word.

WIN-TERMINATE: "win_pattern"

Terminates the process which created a specified window.

Word WIN-TERMINATE: can be used with modifier ALL, which is placed before the word.

WIN-ACTIVATE: "win_pattern"

Activates a specified window.

Example:

#( test_win_activate
\ activates window of  Notepad application, using
\ a regular expression as a mask
NoActive
Action:
    WIN-ACTIVATE: "/.*notepad/i"
)#

It should be noted that while nnCron is running, variable %ACTIVE-WINDOW% always contains the title of currently active window.

WIN-ACTIVE: "win_pattern"

Returns TRUE (-1) if a specified window is active

WIN-EXIST: "win_pattern"

Returns TRUE (-1) if a specified window exists.

There also exists a postfix version of this word:

S" pattern" WIN-EXIST?

See also Note.

WIN-MINIMIZE: "win_pattern"
WIN-MAXIMIZE: "win_pattern"
WIN-RESTORE: "win_pattern"

These words, respectively, minimize, maximize and restore a specified window..

Words WIN-MINIMIZE:, WIN-MAXIMIZE: and WIN-RESTORE: can be used with modifier ALL, which is placed before them.

<win-hwnd> WIN-POS ( h -- x y )

A postfix word that takes as its argument window handle of a required window and returns two values which are coordinates of the upper left corner of this window.

Example:

#( test_position
NoActive
VARIABLE x
VARIABLE y
Action:
    WIN-EXIST: "nnCron: Options"
    IF
        BEEP: 250 500
        WIN-HWND WIN-POS  y ! x !
        TMSG: "%FOUND-WINDOW% x=%x @% y=%y @%" 2
    THEN
)#

<win-hwnd> WIN-RECT ( h -- r b y x )

A postfix word that takes as its argument window handle of a required window and returns four values, which are the coordinates of the upper left and lower right corners of this window.

Example:

#( test_rect_position
NoActive
VARIABLE x
VARIABLE y
VARIABLE b
VARIABLE r
Action:
    WIN-EXIST: "nnCron: Options"
    IF
        BEEP: 250 500
        WIN-HWND WIN-RECT x ! y ! b ! r !
        TMSG: "%FOUND-WINDOW% x=%x @% y=%y @% b=%b @% r=%r @%" 2
    THEN
)#

<w> <h> WIN-RESIZE

A postfix word which resizes the active window. It uses height and width of this window (in pixels) as its arguments.

Examples:

600 400 WIN-RESIZE
800 800 WIN-RESIZE

WIN-TOPMOST: "win_pattern"

Places a specified window above all other windows. A window to which word WIN-TOPMOST: has been applied will stay above all other windows even after it loses the focus. To restore window's "normal" properties, just close it and then open it again or use WIN-NOTOPMOST: word.

Example:

#( test_win_topmost
\ by pressing hot keys  "CTRL+ALT+t",
\ the currently active window is placed
\ above of the rest of windows.
WatchHotKey: "^@t"
Action:
    WIN-TOPMOST: "%ACTIVE-WINDOW%"
)#

WIN-NOTOPMOST: "win_pattern"

Cancel effect of WIN-TOPMOST:. By using WIN-TOPMOST: and WIN-NOTOPMOST: together, you can hold a window above all other windows for a required period of time and then restore its "normal" properties.

Example:

#( test_win_notopmost
\ placing the specified window on top of the rest of windows,
\ performing required action and canceling the effect of "WIN-TOPMOST:"
NoActive
Action:
    WIN-TOPMOST: "*Notepad"
    \ ... performing required operations
    WIN-NOTOPMOST: "*Notepad"
)#

WIN-SEND-KEYS: "win_pattern" "key_code_string"

Activates a specified window and sends to it a sequence of key codes.

Example:

#( test_win_send_keys
\ starting Notepad, making its window active
\ and typing word  "test"
NoActive
Action:
    START-APP: notepad.exe
    PAUSE: 1000
    WIN-SEND-KEYS: "/.*notepad/i" "test"
)#

Sometimes it becomes necessary to specify key codes for keyboard shortcut consisting of two or more keys that should be pressed simultaneously (e.g. CTRL is pressed and then, while it is being held down, ALT and G are pressed too). In this case, you should first indicated the first key that is being pressed and held down, and and state the remaining key codes after it in parentheses.

Examples:

\ "CTRL+s"
WIN-SEND-KEYS: "^(s)"
\ "CTRL+SHIFT+a"
WIN-SEND-KEYS: "^(+a)"
\ "SHIFT+F12"
WIN-SEND-KEYS: "+({F12})"

Pauses between individual "keystrokes" and SEND-KEYS: constructs can be specified by using word SEND-KEYS-DELAY:.

See also Keyboard Input Emulation.

WIN-SET-TITLE: "win_pattern" "new_window_title"

Changes a title of a specified window. This word is frequently used to create unique titles for each of several simultaneously running instances of the same program .

Example:

#( test_set_title
NoActive
Action:
    START-APP: notepad.exe
    PAUSE: 500
    WIN-SET-TITLE: "%GetForegroundWindow%" "first instance of Notepad "
    START-APP: notepad.exe
    PAUSE: 500
    WIN-SET-TITLE: "%GetForegroundWindow%" "second instance of Notepad "
)#

WIN-MOVE: <x> <y>

Moves the active window to a new position with absolute coordinates x and y (in pixels).

You can use WinSpy utility to find out the required coordinates.

Examples:

\ activating Notepad"s window and moving it to location
\ with coordinates 100, 100
WIN-ACTIVATE: "*Notepad"
WIN-MOVE: 100 100
\ and now moving it to the upper left corner of the screen
WIN-MOVE: 0 0

WIN-MOVER: <x> <y>

Moves the active window to the specified amount of pixels from the current position.

Arguments of word WIN-MOVER: can take both positive and negative values:

  • If x has a positive value, the pointer will be moved to the right.
  • If x has a negative value, the pointer will be moved to the left.
  • If y has a positive value, the pointer will be moved down.
  • If y has a negative value, the pointer will be moved up.

You can use WinSpy utility to find out the required coordinates.

Examples:

\ activating Notepad"s window and moving it
\ 100 pixels to the right and  100 pixels down
WIN-ACTIVATE: "*Notepad"
WIN-MOVER: 100 100
\ moving the window 250 pixels to the right
\ and 100 pixels up
WIN-MOVER: 250 -100
\ moving the window 250 pixels to the right
WIN-MOVER: 250 0

WIN-WAIT: <time_in_ms>

Specifies the time during which nnCron will wait for the active window to get ready.

For example, if an application performs after startup some lengthy operation and its window does not react to user's actions, you can specify the time (in milliseconds) during which nnCron will wait for the active window to become ready.

If the active window becomes free before the specified time has expired, nnCron will immediately execute the next line of the task. Otherwise, it will execute it only after the entire period of waiting time has expired.

Example:

\ starting a slowly-starting program
START-APP: "xxx.exe"
PAUSE: 1000
\ waiting for 30 seconds for it to get ready
WIN-WAIT: 30000
\ ... performing some operations with the window

FOR-WINDOWS: "win_pattern" <...> ;FOR-WINDOWS

Provides possibility to perform operations not on just a single window, but entire groups of windows matching a certain mask: commands specified in the body of "FOR-WINDOWS:" loop will be applied to each of these windows. Actually, definitions of all the "WIN*" words are based on this loop.

It works in this way: if there are five files matching a certain mask, then FOR-WINDOWS: loop will be automatically executed five times and each time value of variable %FOUND-WINDOW% will be renewed. (Variable %WIN-TITLE% can be used instead of %FOUND-WINDOW%, they both refer to the same thing). Value of variable WIN-HWND, which contains window handle of the currently processed window, is also renewed with each loop.

Example:

#( test_for_windows
\ closing all found windows of Internet Explorer
NoActive
Action:
    FOR-WINDOWS: "*Internet Explorer"
        PAUSE: 300
        WIN-CLOSE: "%FOUND-WINDOW%"
    ;FOR-WINDOWS
)#

Therefore, with each iteration of the loop you get access to title of the next window matching the mask. Now it only remains to perform the required action with this window (close, move or minimize it etc.), or to perform a new check in order to decide what to do with this particular window.

Possibility to perform an additional check before performing actions with a window is the main difference between word FOR-WINDOWS: and modifier ALL.

Example:

#( test_for_windows1
\ displaying a query message box and closing
\ all found windows of Internet Explorer
NoActive
Action:
    FOR-WINDOWS: "*Internet Explorer"
        QUERY: "Close window %FOUND-WINDOW%?"
        IF
            WIN-CLOSE: "%FOUND-WINDOW%"
        THEN
    ;FOR-WINDOWS
)#

FOR-CHILD-WINDOWS: "win_pattern" <...> ;FOR-CHILD-WINDOWS

Provides possibility to perform operations on groups of child windows whose title matches a specified mask. Before you can use FOR-CHILD-WINDOWS:, variable WIN-HWND must contain the window handle of the window whose child windows we are going to work with.

Most of "WIN*" words, word WIN-EXIST: and loop FOR-WINDOWS:, when used, cause this variable to be set correctly.

FOR-CHILD-WINDOWS: loop sets its own variable WIN-CHILD-HWND which contains a window handle of a child window.

Examples:

\ after word "WIN-EXIST:",  variable  "WIN-HWND"
\ is assigned a proper value
WIN-EXIST: "xxx"
IF
    FOR-CHILD-WINDOWS: "yyy"
        \ ... performing some operations on child windows
    ;FOR-CHILD-WINDOWS
THEN

\ in each  "FOR-WINDOWS:" loop, variable "WIN-HWND"
\ contains  current window's window handle
FOR-WINDOWS: "xxx"
    \ ... performing operations
    FOR-CHILD-WINDOWS: "yyy"
        \ ... performing some operations on child windows
    ;FOR-CHILD-WINDOWS
;FOR-WINDOWS
#( test_for_child_windows
\ outputting to a log file  names of all
\ child windows of program"Xnews"
NoActive
Action:
    \ using word "WIN-EXIST:" to properly
    \ set the value of variable "WIN-HWND"
    WIN-EXIST: "*Xnews*"
    IF
        \ Using the class of child windows
        \ as argument  of " FOR-CHILD-WINDOWS:"
        \ You can look up the class in "WinSpy" utility
        FOR-CHILD-WINDOWS: "TGroupsWindow"
            LOG: "log\nncron.log" "%FOUND-CHILD-WINDOW%"
        ;FOR-CHILD-WINDOWS
    THEN
)#

ALL

Nearly all "WIN*" key words can be preceded by modifier ALL.

When this modifier is used, the command will be executed for all windows whose titles match a specified mask.

Examples:

\ minimizing all open windows of  "Internet Explorer"
ALL WIN-MINIMIZE: "*Internet Explorer"
\ closing all  found windows of "Command Prompt"
ALL WIN-CLOSE: "/(Command Prompt)|(.*?cmd.exe)/i"

Note: after most of "WIN*" key words (as well as WIN-EXIST :), variable WIN-HWND will contain the window handle of corresponding window, and variable %FOUND-WINDOW% - will contain this window's title. (%WIN-TITLE% is a synonym for %FOUND-WINDOW%).

#( task-move-window
\ displaying a query message box
\ and moving the specified window to the desired screen location
Action:
    WIN-EXIST: "*Internet*"
    IF
        QUERY: "Move "%FOUND-WINDOW%" to (0,0)?"
        IF
            WIN-ACTIVATE: "*Internet*"
            PAUSE: 100
            WIN-MOVE: 0 0
        THEN
    THEN
)#

win_pattern is a mask of a window title or window class. Mask of a window title may include wildcard characters * and ? or regular expressions enclosed in slashes: /<regexp>/. Window handle of a required window (either in decimal or in hexadecimal form) can also be used in win_pattern. WinSpy utility can be used to find out the class, exact title and window handle of a required window.

Example:

\ window title mask
WIN-HIDE: "Calculator"
\ regular expression (based on a window title)
WIN-HIDE: "/calculator/i"
\ window class
WIN-HIDE: "SciCalc"
\ window handle  (decimal form)
WIN-HIDE: "592738"
\ window handle  (hexadecimal form)
WIN-HIDE: "0x90B62"

See also:

  • WatchWindow: "win_pattern"
  • WatchWinCreate: "win_pattern"
  • WatchWinActivate: "win_pattern"
  • WatchWinDestroy: "win_pattern"


Operations with Files and Directories

  • DIR-CREATE: "path"
  • DIR-DELETE: "path"
  • DIR-EMPTY: "path"
  • DIR-SIZE: "path"
    • RECURSIVE
  • FILE-APPEND: "filename" "text"
  • FILE-COPY: "from_filename" "to_filename"
  • FILE-CREATE: "filename"
  • FILE-CROP: "filename" <max_size_in_kb> <size_after_crop>
  • FILE-ACCESS-DATE: "path"
  • FILE-CREATION-DATE: "path" (FILE-DATE: "path")
  • FILE-WRITE-DATE: "path"
  • FILE-DELETE: "filename"
    • RECURSIVE
  • FILE-EMPTY: "file_pattern"
  • FILE-EXIST: "file_pattern"
  • FILE-MOVE: "from_filename" "to_filename"
  • FILE-RENAME: "old_filename" "new_filename"
  • FILE-SIZE: "file_pattern"
  • FILE-WRITE: "filename" "text"
  • ONLYDIR
  • ONLYNAME
  • PURGE-OLD: "path\mask" <days>
  • PURGE-OLDA: "path\mask" <days>
  • PURGE-OLDW: "path\mask" <days>
    • RECURSIVE
    • WITHDIRS
  • FOR-FILES: "path\mask" <...> ;FOR-FILES
    • ACCESS-DATE
    • CREATION-DATE
    • CUR-DATE
    • DATE-
    • FF-EXIT
    • FILESONLY
    • IS-ARCHIVE?
    • IS-DIR?
    • IS-HIDDEN?
    • IS-READONLY?
    • IS-SYSTEM?
    • RECURSIVE
    • SKIPERRORS
    • TODEPTH
    • WRITE-DATE

FILE-COPY: "from_filename" "to_filename"

This word copies a specified file. If the target directory already contains the file with specified name, the old file will be overwritten (unless it is used by another application ). If you don't change the filename when copying a file, then it would be sufficient to specify the receiving directory (without filename) in the argument to_filename.
This command does not support operations with file masks and it cannot be used to delete a directory. To process several files, use FOR-FILES: loop.

Examples:

FILE-COPY: "c:\xxx\test.txt" "c:\xxx\new.txt"
FILE-COPY: "c:\xxx\test.txt" "d:\backup\another_test.txt"
\ copying file  test.txt to directory  c:\yyy\
FILE-COPY: "c:\xxx\test.txt" "c:\yyy\"
\ copying file  test.txt to file  backup
FILE-COPY: "c:\xxx\test.txt" "c:\backup"

If an error occurs during execution of this command, you can find out the error number by using GetLastError word.

There also exists a postfix version of this word:

S" from_filename" S" to_filename" FCOPY

FILE-MOVE: "from_filename" "to_filename"

This word moves a specified file. If you don't change the filename when moving a file, then it would be sufficient to specify the receiving directory (without filename) in the argument to_filename.
This command does not support operations with file masks and it cannot be used to delete a directory. To process several files, use FOR-FILES: loop.

Examples:

FILE-MOVE: "c:\xxx\test.txt" "c:\xxx\new.txt"
FILE-MOVE: "c:\xxx\test.txt" "d:\backup\test.txt"
\ moving file  test.txt to directory  c:\yyy\
FILE-MOVE: "c:\xxx\test.txt" "c:\yyy\"
\ moving file  test.txt to file  backup
FILE-MOVE: "c:\xxx\test.txt" "c:\backup"

If an error occurs during execution of this command, you can find out the error number by using GetLastError word.

There also exists a postfix version of this word:

S" from_filename" S" to_filename" FMOVE

FILE-RENAME: "old_filename" "new_filename"

Renames a specified file. If you use this word just to move a file without changing its filename, then it would be sufficient to specify the receiving directory (without filename) in the argument to_filename. Unlike "FILE-MOVE:" word, this command can rename (move) directories, but only within the same drive.

Examples:

FILE-RENAME: "c:\xxx\test.txt" "c:\xxx\new.txt"
FILE-RENAME: "c:\xxx" "c:\yyy" \ only within the same drive
\ moving file  test.txt to directory  c:\yyy\
FILE-RENAME: "c:\xxx\test.txt" "c:\yyy\"
\ renaming file  test.txt to  backup
FILE-RENAME: "c:\xxx\test.txt" "c:\backup"

If an error occurs during execution of this command, you can find out the error number by using GetLastError word.

There also exists a postfix version of this word:

S" old_filename" S" new_filename" FRENAME

FILE-SIZE: "file_pattern"

Returns the size of a specified file (double number). To get the aggregate size of all files in a directory use the word DIR-SIZE:.

Examples:

\ checking file size and displaying a message
10240. FILE-SIZE: "c:\test.txt" D<
IF MSG: "File size exceeds 10kb"
ELSE MSG: "File size less then 10kb"
THEN
#( test_file_size
\ the action will be executed if the file size is less than 10 kb
Rule: 10240. FILE-SIZE: "c:\test.txt" D<
Action:
    \ ... performing some useful actions
)#

#( test_file_size1
\ displaying a message if a specified file
\ is greater than 100kb
NoActive
Action:
    102400. FILE-SIZE: "c:\fido\sessions.log" D<
    IF
        MSG: "File size exceeds 100 kb!"
    THEN
)#

#( test_delete_empty
\ recursively deleting from a specified folder
\ all the files whose size equals  0
 NoActive
 Action:
     RECURSIVE
     FOR-FILES: "c:\xxx\*.*"
         0. FILE-SIZE: "%FOUND-FULLPATH%" D=
         IF FILE-DELETE: "%FOUND-FULLPATH%" THEN
     ;FOR-FILES
)#

There also exists a postfix version of this word:

S" filename" FSIZE

FILE-DELETE: "filename"

Deletes a specified file. Supports masks of filenames. If you want to delete all files matching a specified mask not just in main directory, but in all its subdirectories as well, use modifier RECURSIVE before word FILE-DELETE:

This word cannot be used to delete a directory. If you want to delete a directory rather then a file, use DIR-DELETE.

Example:

FILE-DELETE: "c:\xxx\test.txt"
FILE-DELETE: "c:\xxx\*.txt"
RECURSIVE FILE-DELETE: "c:\xxx\*.txt"

If an error occurs during execution of this command, you can find out the error number by using GetLastError word.

There also exists a postfix version of this word:

S" filename" FDELETE

You shouldn't use with this word the standard method of getting an error code (GetLastError), because FILE-DELETE: works with masks and always returns error #18 (There are no more files. ERROR_NO_MORE_FILES).

However, if you want to get an error code after deleting a file, you can use a standard Forth word DELETE-FILE ( c-addr u -- ior )

Example:

S" myfile.txt" DELETE-FILE ?DUP IF ." Error # " . CR THEN

FILE-EMPTY: "file_pattern"

Returns TRUE (-1) if a file is empty or if it doesn't exist.

FILE-EXIST: "file_pattern"

Returns TRUE (-1) if a specified file or directory exists.

There also exists a postfix version of this word:

S" file_pattern" EXIST?

FILE-CREATE: "filename"

Creates an empty new file with a specified name. Creates all the intermediate directories if necessary. If you want to create a directory rather then a file, use DIR-CREATE:.

Examples:

\ creates an empty file named  'test.txt' in the root directory of C: drive
FILE-CREATE: "c:\test.txt"
\ creates an empty file named  'test.txt' in  'c:\xxx\yyy\zzz'
\ all the  intermediate directories which do not exist will be created.
FILE-CREATE: "c:\xxx\yyy\zzz\test.txt"

If an error occurs during execution of this command, you can find out the error number by using GetLastError word.

There also exists a postfix version of this word:

S" filename" FCREATE

FILE-WRITE: "filename" "text"

Writes content of argument "text" into a specified file, removing the file's previous content.

It is possible to use user-defined variables and nnCron's predefined variables in arguments of word FILE-WRITE. To write into a file quotation mark character and per cent sign character, use variables %QUOTE% and %PERCENT% respectively. You can use variable %FILE: filename% to write to a file content of another file.

Examples:

FILE-WRITE: "c:\xxx\test.txt" "Last update: %hh%:%mm%"
FILE-WRITE: "c:\xxx\test.txt" "%USERNAME% was there!"
FILE-WRITE: "c:\xxx\test.txt" "Content of another file:%crlf%%crlf%%FILE: c:\yyy\source.txt%"

If an error occurs during execution of this command, you can find out the error number by using GetLastError word.

There also exists a postfix version of this word:

S" filename" S" text" FWRITE

FILE-APPEND: "filename" "text"

This word is similar to FILE-WRITE:, but it does not overwrite the target file's content, but appends the new information in the end of file.

Examples:

FILE-APPEND: "c:\xxx\test.txt" "Message was sent at: %hh%:%mm%%crlf%"
FILE-APPEND: "c:\xxx\test.txt" "Content of another file:%crlf%%FILE: c:\yyy\source.txt%"

If an error occurs during execution of this command, you can find out the error number by using GetLastError word.

There also exists a postfix version of this word (FAPPEND):

S" text" S" filename" FAPPEND

DIR-CREATE: "path"

Creates a specified directory and, if necessary, all the intermediate directories.

If an error occurs during execution of this command, you can find out the error number by using GetLastError word.

DIR-DELETE: "path"

Deletes a specified directory or a directory tree.
Use with care: a specified catalog or a tree will be deleted even if they are not empty.

Example:

DIR-DELETE: "c:\xxx"

If an error occurs during execution of this command, you can find out the error number by using GetLastError word.

DIR-SIZE: "path"

Returns the aggregate size of all files in a directory (a double number).

Example:

#( test_dir_size
\ displaying a message if aggregate size of files
\ in directory  c:\cpp exceeds 100kb (without subdirectories)
NoActive
Action:
    102400. DIR-SIZE: "c:\cpp" D<
    IF
        MSG: "Dir size exceeds 100 kb!"
    THEN
)#

In order to find out a size of a directory including all the subdirectories, place modifier RECURSIVE before DIR-SIZE:.

Example:

#( test_dir_size1
\ displaying a message if aggregate size in directory 'c:\cpp'
\ exceeds 100kb (including files in all  subdirectories)
NoActive
Action:
    102400. RECURSIVE DIR-SIZE: "c:\cpp" D<
    IF
        MSG: "Dir size exceeds 100 kb!"
    THEN
)#

There also exists a postfix version of this word:

S" dirname" DIR-SIZE

DIR-EMPTY: "path"

Returns "TRUE" if a specified directory is empty and "FALSE" if it contains at least on file or subdirectory.
Please note that DIR-EMPTY returns "TRUE" even if a specified directory does not exist.

ONLYDIR

Receives a string with full file path and file name (S" fullpath" ONLYDIR) and returns a string, containing file path only (without a file name). For example, when receiving a string 'd:\tools\nnbackup\nnbackup.exe', this word will return 'd:\tools\nnbackup'.

Attention please: you can use this word when defining a task, but you can not use it in console!

Example:

#( test_filename
NoActive
Action:
    FILESONLY
    FOR-FILES: "C:\TEMP\*"
        MSG: "Full filename: %FOUND-FULLPATH%%crlf%\
Path only: %FOUND-FULLPATH ONLYDIR%"
    ;FOR-FILES
)#

See also: ONLYNAME

ONLYNAME

Receives a string with full file path and file name (S" fullpath" ONLYNAME) and returns a string, containing file name only (without a file path). For example, when receiving a string 'd:\tools\nnbackup\nnbackup.exe', this word will return 'nnbackup.exe'.

Attention please: you can use this word when defining a task, but you can not use it in console!

Example:

#( test_filename1
NoActive
Action:
    FILESONLY
    FOR-FILES: "C:\TEMP\*"
        MSG: "Full filename: %FOUND-FULLPATH%%crlf%\
Name only: %FOUND-FULLPATH ONLYNAME%"
    ;FOR-FILES
)#

See also: ONLYDIR

FOR-FILES: "path\mask" <...> ;FOR-FILES

This word can be used to perform operations not just on single files, but entire groups of files matching a specified filename mask; commands included in the body of FOR-FILES loop will be applied to each of these files.

Example:

#( test_for_files
\ removing all the files with  "*.txt" extension in directory  "c:\xxx"
NoActive
Action:
    FOR-FILES: "c:\xxx\*.txt"
        FILE-DELETE: "%FOUND-FULLPATH%"
    ;FOR-FILES
)#

It works in this way: if there are five files matching a certain mask, then FOR-FILES: loop will be automatically executed five times and each time values of the following variables will be renewed:

%FOUND-FILENAME% | name of a file matching the search pattern (e.g. test.txt)
%FOUND-FULLPATH% | full path and name of file matching the search pattern (e.g. 'c:\xxx\yyy\test.txt')
%FOUND-RELPATH% | path and name of file matching the search pattern, relative to the directory where search is performed (e.g. 'yyy\test.txt')

That means that on each iteration of the loop you get access to the name of the next file matching a specified mask, and now it only remains to perform the required action with this file (i.e. remove, move or rename it etc.) or to perform another check in order to decide what to do with this particular file.

Here is the list of checks which can be performed in the body of FOR-FILES: loop (use word "0=", to reverse the condition):

IS-DIR? | Returns 'TRUE' if a directory is found
IS-HIDDEN? | Returns 'TRUE' if a file with attribute hidden is found
IS-READONLY? | Returns 'TRUE' if a file with attribute read-only is found'
IS-SYSTEM? | Returns 'TRUE' if a file with attribute system is found
IS-ARCHIVE? | Returns 'TRUE' if a file with attribute hidden is found'

Example:

\ all the file and subdirectories inside the directory "c:\xxx" match the pattern used here,
\ but due to additional checks, we will only  process subdirectories
\ and  files with attributes "hidden" and "read-only"
FOR-FILES: "c:\xxx\*"
    \ checking if the found file is a directory
    IS-DIR?
    IF
        \ ... commands for performing operations with directories, including those with  "hidden" and "read-only" attributes
    ELSE
        \ checking if the found file has attribute "hidden"
        IS-HIDDEN?
        IF
            \ ... commands for performing operations with hidden files
        ELSE
            \ checking if the found file has attribute "read-only"
            IS-READONLY?
            IF
                \ ... commands for performing operations with read-only files
            THEN
        THEN
    THEN
;FOR-FILES

Besides, the body of FOR-FILES: loop can contain instructions for performing operations with dates of file creation and modification and last access (take a look at "Working with Dates and Time"):

CREATION-DATE | Date of creation of a found file
ACCESS-DATE | Date of last access to found file
WRITE-DATE | Date when a found file was written
CUR-DATE | System date
DATE- | Difference between two dates ( date1-date2 ). Returns the difference between two dates in days.

Example:

#( test_for_files1
\ removes from directory "c:\xxx" all files
\ created more than ten days ago
NoActive
Action:
    FOR-FILES: "c:\xxx\*"
        \ working only with files, ruling directories out
        IS-DIR? 0=
        IF
            CUR-DATE CREATION-DATE DATE- 10 >
            IF
                FILE-DELETE: "%FOUND-FULLPATH%"
            THEN
        THEN
    ;FOR-FILES
)#

The following modifiers can be used before FOR-FILES:

RECURSIVE | Working with a specified directory and all its subdirectories
TODEPTH | Searching the "deep levels" of a directory tree. There are two ways to perform a search in a directory tree: 1. First a current (upper-level) directory is processed, and after that all the subdirectories (this method is used by default). 2. First all the subdirectories are searched, and then the current directory. To do this, one should use TODEPTH.
FILESONLY | Instructions in the body of FOR-FILES: are performed on files only, and not on directories.
SKIPERRORS | Ignore file access errors when moving through a directory tree

Examples:

#( test_for_files2
\ removing all the files and directories in directory "c:\xxx".
\ word FILE-DELETE: deletes files,
\ and word DIR-DELETE: deletes directories
NoActive
Action:
    RECURSIVE
    FOR-FILES: "c:\xxx\*"
        \ checking if the found file is a directory
        IS-DIR?
        IF
            DIR-DELETE: "%FOUND-FULLPATH%"
        ELSE
            FILE-DELETE: "%FOUND-FULLPATH%"
        THEN
    ;FOR-FILES
)#

#( test_for_files3
\ deleting all files with zero length from directory c:\zzz and all its subdirectories
\ deleting files only, but not the directories.
NoActive
Action:
    RECURSIVE FILESONLY
    FOR-FILES: "c:\zzz\*.*"
        FILE-SIZE: "%FOUND-FULLPATH%" D0=
        IF
            FILE-DELETE: "%FOUND-FULLPATH%"
        THEN
    ;FOR-FILES
)#

If necessary, you can always exit FOR-FILES: loop by using word FF-EXIT.

Example:

#( test_for_files4
\ displays messages with names of all
\ text files in directory C:\TEMP\
\ exits the loop when file exit.txt is found
NoActive
Action:
    FOR-FILES: "C:\TEMP\*.txt"
        MSG: "%FOUND-FILENAME%"
        \ matching name of each found file against name "exit.txt"
        RE-MATCH: "%FOUND-FILENAME%" "/exit.txt/i"
        \ if name is the same, leaving the loop
        IF FF-EXIT THEN
    ;FOR-FILES
    BEEP: 250 500
)#

FILE-CROP: "filename" <max_size> <size_after_crop>

Permits to control size of text files. Removes beginning of a specified file so that its size does not exceed the value of size_after_crop. File will be cropped only if its size is greater than the value of max_size.

Values of max_size и size_after_crop are in kilobytes.

This word is used mostly to control size of log files.

Example:

\ log file  sessions.log will be cropped down to  500 kb
\ if it was greater than 1000 kb when FILE-CROP was called
FILE-CROP: "c:\fido\sessions.log" 1000 500
\ log file  nncron.log will be cropped down to  50 kb
\ if it was greater than 100 kb when FILE-CROP was called
FILE-CROP: "log\nncron.log" 100 50

There also exists a postfix version of this word:

S" filename" <max_size> <size_after_crop> FCROPkb

PURGE-OLD: "path\mask" <days>
PURGE-OLDW: "path\mask" <days>
PURGE-OLDA: "path\mask" <days>

These words remove all the files which match a specified mask and are older then a specified number of days. PURGE-OLD: checks the file creation date, PURGE-OLDW: checks the date when a file was last written into and PURGE-OLDA: checks the date when a file was last accessed.

Use modifier RECURSIVE to delete all files in the specified directory and all its subdirectories.

If value of days is set to -1, then all files will be deleted from a directory.

Examples:

\ deleting all files more than 3 days old from Windows Temp directory
PURGE-OLD: "c:\windows\temp\*" 3
\ deleting from the specified directory and all its subdirectories all text files
\ which were last written into more that 10 days ago
RECURSIVE
PURGE-OLDW: "c:\drafts\*.txt" 10
\ removing all files from Windows Temp directory
PURGE-OLD: "c:\windows\temp\*" -1

By default, words of PURGE-OLD*: group remove only files, but by using modifier WITHDIRS, you can delete both files an directories older than a specified number of days. Please be careful when using it: directories older than a specified period of time will be deleted with all their content!

Example:

\ removing ALL files and directories
WITHDIRS
PURGE-OLD: "c:\windows\temp\*" -1

FILE-CREATION-DATE: "path" (you can also use word FILE-DATE: "path")
FILE-ACCESS-DATE: "path"
FILE-WRITE-DATE: "path"

These words return numeric values of date of creation of a file, date of last access and date when the file was last modified (these values are resented in a special binary DATE-format). These three words can be used to perform operations with these three types of dates.

Current system time can be placed on stack with the help of word CUR-DATE. Word DATE- returns the difference (in days) between 2 dates. Methods of handling dates and of their conversion between different formats are described in chapter Working with Dates and Time.

Examples:

#( test_file_date
\ removing file new.txt if it was created more than 30 days ago
NoActive
Action:
    CUR-DATE
    FILE-CREATION-DATE: "c:\xxx\new.txt"
    DATE- 30 >
    IF
        FILE-DELETE: "c:\xxx\new.txt"
    THEN
)#

There also exists a postfix version of these words:

S" filename" FCDATE
S" filename" FADATE
S" filename" FWDATE

See also:

  • FREE-SPACE: <drv_letter>
  • WatchDir: "dir_path" [flag] [modifiers]
  • WatchFile: "file_path"
  • WatchFileDelete: "file_path"


Working with Processes

  • FOR-PROCS: "proc_pattern" <...> ;FOR-PROCS
    • %FOUND-PROC%
    • %FOUND-PID%
  • KILL: "proc_pattern"
  • kill
  • ProcActiveTime
  • PROC-EXIST: "proc_pattern"
    • PROC-FULLPATH
  • PROC-FULLNAME
  • PROC-NAME
  • PROC-TIME: "proc-pattern"
  • PROC-WAIT-IDLE

FOR-PROCS: "proc_pattern" <...> ;FOR-PROCS

This is a special cycle which can be used to perform operations not just on single processes, but entire groups of processes matching a specified mask; commands included in the body of FOR-PROCS loop will be applied to each of these processes.

It works in this way: if there are, for example, five processes matching a certain mask, then FOR-PROCS: loop will be automatically executed five times and each time values of the variables %FOUND-PROC% and %FOUND-PID% will be renewed; these variables contains a name of last found process and its Process ID (PID) respectively.

Example:

#( test_for_processes
\ printing to console names of all running processes
NoActive
Action:
    FOR-PROCS: "*.exe"
        FOUND-PROC TYPE CR
    ;FOR-PROCS
)#

That means that on each iteration of the loop you get access to the name and PID of the next process matching a specified mask, and now it only remains to perform the required action with this process (e.g. stop it or assign a desired priority etc.) or to perform another check in order to decide what to do with this process.

Example:

#( test_for_processes1
\ displaying a query and ending, one by one,
\ all found processes of Internet Explorer
NoActive
Action:
    FOR-PROCS: "iexplore.exe"
        QUERY: "End process %FOUND-PROC%?"
        IF
            KILL: "%FOUND-PID%"
        THEN
    ;FOR-PROCS
)#

KILL: "proc_pattern"

This word terminates a specified process. It can take as its argument a mask of a process name (which is normally the same as the name of the executable file which is used to start this process) or a string containing numerical process identifier (PID), which is stored in predefined variable PROC-ID immediately after a program has been started.

By using a process identifier as an argument, you can terminate a particular process even if there are several instances of the same program running, i. e. there are several processes with the same name. Please note that variable PROC-ID is filled each time a when a program is successfully started by words START-APP, START-APPW or QSTART-APP, but if the process we want to stop was started by word START-APPW, you shouldn't use the value stored in PROC-ID, for in this case this variable would contain PID of the process which was already stopped.

KILL: can also be used with predefined variable %WATCH-PROC-ID%, in which words WatchProc:/WatchProcStop: store the PID of the process they have found.

Examples:

\ using process name
KILL: "opera.exe"
KILL: "notepad.exe"
KILL: "*pad.exe"
\ using process identifier (PID)
KILL: "2121"
KILL: "%PROC-ID%"

#( test_proc_id
NoActive
VARIABLE my_notepad_id
Action:
    START-APP: notepad.exe
    PAUSE: 1000
    START-APP: notepad.exe
    PROC-ID my_notepad_id !
    PAUSE: 1000
    START-APP: notepad.exe
    \ ... something useful here
    \ terminating the second instance of Notepad
    KILL: "%my_notepad_id @%"
)#

There also exists a postfix version of this word:

S" opera.exe" KILL
S" 2121" KILL

kill ( pid -- )

This postfix word terminates a process accepting its PID as an argument. Since word kill takes a number as its argument, you won't have to convert a number returned by PROC-ID or WATCH-PROC-ID into a string:

386 kill
PROC-ID kill
my_proc_id @ kill

PROC-TIME: "proc_pattern"

Puts on stack the time (number of seconds) during which a specified process has been working.

Works only in WinNT/2000/XP.

ProcActiveTime ( pid -- ms)

Puts on stack the time (double number - number of milliseconds) during which the specified process has been working. Takes a PID as its argument.

Example:

#( test_proctime
NoActive
Action:
    S" notepad.exe" PROC-EXIST? ?DUP
    IF
        \ printing the time of work to console
        ProcActiveTime D>S . CR
    ELSE
        MSG: "Notepad is not started!"
    THEN
)#

PROC-EXIST: "proc_pattern"

Returns TRUE (-1) if there exists a process matching a specified pattern. As an argument for PROC-EXIST: one should normally use the name of the executable file that starts a process.

Example:

Rule: PROC-EXIST: "winword.exe"

A process can be identified not only by the file name, but also by full path to the application file. In order to do that, use option PROC-FULLPATH. If the process name contains at least one backslash ('\'), nnCron will automatically try to identify it by the full path to its executable file.

Example:

Rule: PROC-FULLPATH PROC-EXIST: "C:\PROGRAM FILES\OPERA\opera.exe"
Rule: PROC-EXIST: "C:\PROGRAM FILES\OPERA\opera.exe"

If you want to find out PID of a process, use postfix word PROC-EXIST?

Example:

\ puts on stack PID of 'winword.exe'
S" winword.exe" PROC-EXIST?

PROC-FULLNAME ( pid - a u)
PROC-NAME ( pid - a u)

These postfix words get Process ID (PID) as their arguments and return a string with full/short process name. PROC-NAME returns a short process name (usually a name of the executable file, like notepad.exe), and PROC-FULLNAME returns the name of the executable file together with the full path to this file (c:\windows\system32\notepad.exe).

Example:

#( test_procname
WatchProc: "notepad.exe"
Action:
\ printing process short name to the console
WATCH-PROC-ID PROC-NAME TYPE CR
\ displaying a message with process full name
MSG: "%WATCH-PROC-ID PROC-FULLNAME%"
)#

PROC-WAIT-IDLE ( pid -- )

This postfix word pauses the task until the specified process becomes idle. For example, you can use PROC-WAIT-IDLE when launching an application (START-APP:) if you want to make sure the application is fully loaded into computer memory before the task resumes it's work.

Example:

#( test_start_app
NoActive
Action:
    START-APP: your_prog.exe
    \ pausing the task until your_prog.exe is
    \ fully loaded into computer memory
    PROC-ID PROC-WAIT-IDLE
    \ resuming the task
    \ ...
)#

proc_pattern is a process's name or name mask. Normally, a process name is the same as the name of executable file which is used to start this process. However, one can also use a full path to the executable file as a process name. In masks of process names or paths to executable files, you can use wildcard characters '*' and '?', or regular expressions between slashes: /<regexp>/.
If a mask contains at least one backslash ('\'), it will be compared with the full path of executable file.
Process identifiers also can be used as values for proc_pattern. (See PROC-ID, %WATCH-PROC-ID%).

Examples:

\ process name
PROC-EXIST: "notepad.exe"
\ mask of  process name
PROC-EXIST: "notepad*"
PROC-EXIST: "*pad.exe"
\ masks of process names taking in account the full path
PROC-EXIST: "*\notepad*"
PROC-EXIST: "c:\*\notepad.exe"
\ regular expression
PROC-EXIST: "/(note)|(word)pad.exe/i"
\ process identifier
PROC-EXIST: "1116"
PROC-EXIST: "%WATCH-PROC-ID%"
PROC-EXIST: "%my_proc_id @%"

See also:

  • HighPriority
  • IdlePriority
  • NormalPriority
  • RealtimePriority
  • AboveNormalPriority
  • BelowNormalPriority
  • PRIORITY
  • PROC-CLOSE: "proc_pattern"
  • PROC-ID
  • WatchProc: "proc_pattern"
  • WatchProcStop: "proc_pattern"
  • %WATCH-PROC-ID%


Working with Dates and Time

Beside the traditional date formats (YMD, YMDHMS, in strings or numerical representation), nnCron also uses two other methods of date representation: DATE и FILETIME.

DATE is number which in binary representation looks like this: yyyyyyyyyyymmmmddddd, i. e. five last bits represent a day of the month, four preceding bits represent a month, and all the remaining bits are used to record a year. Therefore, DATE only contains information about a year, month and day, but not about hours, minutes or seconds. DATE format is used, for example, by such words as FILE-CREATION-DATE:, FILE-ACCESS-DATE:, FILE-WRITE-DATE:, as well as words used inside of FOR-FILES: loop (CREATION-DATE, ACCESS-DATE, WRITE-DATE).

FILETIME permits to access not just values of year, month and day of the month, but also hours, minutes, seconds and milliseconds. FILETIME is a double number which contains the number of 100-nanosecond intervals from January 1st 1601 to the specified moment. FILETIME format is used, for example, by words from plugin time.spf (FILE-TIME:, FILE-ATIME:, FILE-WTIME:). We are strongly recommending using FILETIME format when working with dates and time.

If necessary, you can convert dates between formats YMD, DATE and FILETIME.

  • ASSUMED-NEXT-TIME
  • ASSUMED-PREV-TIME
  • CUR-DATE
  • DATE>S
  • DATE>YMD
  • DATE-
  • DATE-INTERVAL: dd1.mm1.yyyy1-dd2.mm2.yyyy2[/days]
  • DAY+
  • DAYS
  • Day@
  • Days@
  • FT-
  • FT-CUR
  • FT>DATE
  • FT>DAY
  • FT>DD.MM.YYYY/hh:mm:ss
  • FT>HOUR
  • FT>MIN
  • FT>MS
  • FT>SEC
  • FT>YMDHMS
  • GET-CUR-TIME
  • GetTickCount
  • Hour@
  • INTERVAL: hh1:mm1-hh2:mm2[/hh3:mm3]
  • Min@
  • Mon@
  • MonLength
  • MONNAMES
  • SD.M.Y>Day
  • SDD.MM.YYYY
  • SH:M>Min
  • Sec@
  • START-TIME?
  • TASK-CREATION-TIME
  • TASK-EXECUTION-TIME
  • TimeMin@
  • TimeSec@
  • WDay@
  • WDAYS
  • WEEK-DAY
  • YMD>DATE
  • YMDHMS>FT
  • Year@

ASSUMED-NEXT-TIME ( -- d t= | -- f= )
ASSUMED-PREV-TIME ( -- d t= | -- f= )

When used inside the task these words give you an access to the information about the dates, when this task was scheduled to run for the next and the last time.

The word ASSUMED-NEXT-TIME returns TRUE flag and assumed date when the task is scheduled to run for the next time or single FALSE flag if nnCron can't determine the date. The word ASSUMED-PREV-TIME returns TRUE flag and assumed date when the task was scheduled to run for the last time (even when this time was missed) or single FALSE flag if nnCron can't determine the date.

Both words are returning time in FILETIME format.

Examples:

#( test_assumed_time
\ printing assumed time of the next scheduled
\ task run to console every 2 minutes
Time: */2
Action:
    ASSUMED-NEXT-TIME
    IF
        FT>DD.MM.YYYY/hh:mm:ss TYPE CR
    THEN
)#

#( test_assumed_time1
\ creating special words and printing assumed times
\ of the last and the next scheduled task run to
\ console every 3 minutes
: FT. FT>DD.MM.YYYY/hh:mm:ss TYPE ;
: ?FT. IF FT. ELSE ." none" THEN ;
Time: */3
Action:
   ASSUMED-NEXT-TIME ?FT. CR
   ASSUMED-PREV-TIME ?FT. CR
)#

CUR-DATE ( -- u )

Puts on stack the value of current date (in DATE format). This word is used to compare various dates, e.g. date of creation of (last access to, last modification of) a file with the current date (details).

DATE>S ( u -- a u )

Converts a date from DATE format to a string "DD-MM-YYYY".

Examples:

\ printing the current date to console
CUR-DATE DATE>S TYPE

#( test_message
NoActive
Action:
    \ displaying a current date in a message box
    MSG: "Current date: %CUR-DATE DATE>S%"
)#

DATE- ( u1 u2 -- u )

Returns a difference (in days) between two dates in DATE format.

Examples:

\ placing the current date on stack
CUR-DATE
\ converting "December 31 2002" to  DATE format
2002 12 31 YMD>DATE
\ calculating the difference between these two dates (in days)
DATE- . CR

DATE-INTERVAL: dd1.mm1.yyyy1-dd2.mm2.yyyy2[/days]

Returns TRUE (-1) if the current date belongs to a specified interval.
The third parameter is optional, and it is only used if you want to check for this condition periodically. It sets the interval between consecutive checks (in days).

See also: INTERVAL: hh1:mm1-hh2:mm2[/hh3:mm3]

DAY+ ( y m d days -- y1 m1 d1 )

This word "adds" or "subtracts" any desired number of days to/from a date in YMD format (taking in account the number of days in each month of a year and number of months in a year) and returns the resulting date in the same format.

Example:

\ adding one day to "December 31 2002",
\ printing to console the result: 1 1 2003 ("January 1st 2003").
2002 12 31 1 DAY+ . . . CR

To "subtract" any desired number of days from a date in YMD format, just use a negative value when specifying number of a days to subtract.

Example:

\ subtracting one day from "December 31 2002",
\ printing to console the result: 30 12 2002 ("December 30th 2002").
2002 12 31 -1 DAY+ . . . CR

DAYS ( y m d -- days )

Puts on stack the number of days from the starting point of Gregorian calendar to the specified date. Accepts a date in YMD format as its argument.

Example:

\ printing to console the total number
\ of days before January 1st, 2003
2003 1 1 DAYS . CR

Days@

Puts on stack the number of days from the starting point of Gregorian calendar to the current date.

FT-

Returns a difference between two dates in FILETIME format. To convert the result (for example) to seconds, use word FT>SEC.

Example:

\ noting the current time twice and placing on stack
\ the difference in seconds
FT-CUR
10000 PAUSE
FT-CUR FT- FT>SEC D>S . CR

FT-CUR

Converts the current date and time to FILETIME format.

Example:

#( test_file_time
\ if file '1.sem' was created more then 2 minutes ago,,
\ we'll do something useful
Action:
FT-CUR FILE-TIME: "C:\1.sem" FTIME- 120 >
IF
    \ ... doing the required job
THEN
)#

FT>DAY
FT>HOUR
FT>MIN

These words convert the specified date and time in FILETIME format to number of days, hours or minutes respectively.

FT>DD.MM.YYYY/hh:mm:ss ( d - a u)

This word converts the specified date and time in FILETIME format to a string "DD.MM.YYYY/hh:mm:ss".

Пример:

\ printing to console current date and time (31.03.3003/14:40:47)
FT-CUR FT>DD.MM.YYYY/hh:mm:ss TYPE CR

FT>MS
FT>SEC

These words convert the specified date and time in FILETIME format to number of milliseconds or seconds respectively. They return a double number .

GET-CUR-TIME

"Renews" the current time value. nnCron does this automatically once a minute, so that the number seconds remains the same during the entire minute. Use GET-CUR-TIME to forcibly renew the number of seconds.

Examples:

\ each second during a minute
\ writing the precise current time to a log file:
#( test_cur_time
NoActive
Action:
    60 0 DO
    GET-CUR-TIME
    LOG: "log\idle.log" "%hh%:%mm%:%ss% - current time"
    PAUSE: 1000
    LOOP
)#

\ printing to console the exact value of the current second
GET-CUR-TIME Sec@

GetTickCount

Puts on stack the number of milliseconds since startup of operating system.

Example:

\ the task will be started
\ if the OS was started less then 90 seconds ago
Rule: GetTickCount 90000 <

INTERVAL: hh1:mm1-hh2:mm2[/hh3:mm3]

Returns TRUE (-1) if the current time belongs to a specified interval.
The third parameter is optional, and it is only used if you want to check for this condition periodically. It sets the interval between consecutive checks (in hours and minutes).

\ this rule will return  'TRUE' at 10:00, 10:45 and 11:30
\ (i.e. with  intervals of 45 minutes)
Rule: INTERVAL: 10:00-12:00/00:45
\ this rule will return 'TRUE' at  10:00, 11:01, 12:02 and 13:03
\ (.e. with  intervals of 61 minute)
Rule: INTERVAL: 10:00-14:00/01:01

Examples:

#( test_interval
WatchConnect
Rule: INTERVAL: 10:00-18:00
Action:
    \ ... performing some useful actions
)#

#( test_interval1
\ performing the action each 30 minutes, from 10:00 to 18:00 inclusive
Rule: INTERVAL: 10:00-18:00/00:30
Action:
    MSG: "Half an hour has passed!"
)#

See also: DATE-INTERVAL: dd1.mm1.yyyy1-dd2.mm2.yyyy2[/days]

FT>DATE
FT>YMDHMS
DATE>YMD
YMD>DATE
YMDHMS>FT

These words convert dates between formatsYMD (YMDHMS), DATE and FILETIME.

Examples:

\ FILETIME в DATE
FT-CUR FT>DATE
\ FILETIME в YMDHMS
FT-CUR FT>YMDHMS
\ DATE в YMD
CUR-DATE DATE>YMD
\ YMD в DATE
2002 12 31 YMD>DATE
\ YMDHMS в FILETIME
2002 12 31 0 0 0 YMDHMS>FT

Sec@
Min@
Hour@
Day@
Mon@
WDay@
Year@

This words put on stack the value of the current second, minute, hour, day, month, day of the week, and year respectively. Please note that to receive a correct value for seconds you will have to use word GET-CUR-TIME.

Example:

\ placing on stack the current date in YMD format
Year@ Mon@ Day@
\ placing on stack the current date in YMDHMS format
Year@ Mon@ Day@ Hour@ Min@ GET-CUR-TIME Sec@

MonLength ( year month -- days-of-month )

Returns the number of days in a specified month. This word uses the year and the number of desired month as its arguments.

Example:

\ printing to console the number of days in February 2003
2003 2 MonLength . CR

WDAYS
MONNAMES

These predefined arrays contain shortened names of days of week and of months. WDAYS contains characters "MonTueWedThuFriSatSun", and MONNAMES contains characters "JanFebMarAprMayJunJulAugSepOctNovDec". You can use these arrays to access a name of a day of week (or of a month) by their number. Please not that numbering of days of a week starts with Monday (in other words, Monday is considered to be the first day of a week, and Sunday the seventh).

Examples:

\ printing to console the name of the 1st month
1 1- 3 * MONNAMES COUNT DROP + 3 TYPE CR
\ printing to console the name of the 12th month
12 1- 3 * MONNAMES COUNT DROP + 3 TYPE CR
\ printing to console the name of the third day of week
3 1- 3 * WDAYS COUNT DROP + 3 TYPE CR
\ printing to console the name of the fifth day of week
5 1- 3 * WDAYS COUNT DROP + 3 TYPE CR

SD.M.Y>Day ( addr u -- days )

This word receives a string describing a date in DD.MM.YYYY format and returns (puts on stack) the number of days from the starting point of Gregorian calendar to the specified date.

Example:

\ printing to console the total number
\ that has passed before  31.12.2002
S" 31.12.2002" SD.M.Y>Day . CR

SDD.MM.YYYY ( addr u -- y m d )

Converts a string (in DD.MM.YYYY format) into a date in YMD format.

Example:

\ converting string "31.12.2002" to 3 numbers (YMD)
\ and printing them to console
S" 31.12.2002" SDD.MM.YYYY . . . CR

SH:M>Min

This word takes as its argument a string describing time in HH:MM format and converts it to a number equal to the number of minutes.

Examples:

\ converting strings "1:20" and "01:20"
\ into number of minutes (80)
S" 1:20" SH:M>Min . CR
S" 01:20" SH:M>Min . CR

START-TIME?

Checks if the current time is the top of the first minute after nnCron startup. Returns TRUE (-1) if current time is the top of the first minute after nnCron startup and FALSE (0) otherwise. This word should be used for example to avoid task start on nnCron startup.

Example:

#( test_nostartup
\ this task will be started every
\ minute but not on nnCron startup
Rule: START-TIME? 0=
Action:
    \ ...
)#

TASK-CREATION-TIME ( -- d t= | -- f=)
TASK-EXECUTION-TIME ( -- d t= | -- f=)

When used inside the task these words give you an access to the information about the date, when this task was created (to be more specific, this is the date of the last modification of the Time: field) and the date when this task was executed for the last time.

The word TASK-CREATION-TIME returns TRUE flag and the date when the task was created or single FALSE flag if nnCron can't determine the date. The word TASK-EXECUTION-TIME returns TRUE flag and the date when the task was executed for the last time or single FALSE flag if nnCron can't determine the date.

Both words are returning time in FILETIME format.

Examples:

#( test_task_time
\ printing the time when the task was
\ created to console every 2 minutes
Time: */2
Action:
    TASK-CREATION-TIME
    IF
        FT>DD.MM.YYYY/hh:mm:ss TYPE CR
    THEN
)#

#( test_task_time1
\ creating special words and printing the times
\ when the task was created and executed for the
\ last time to console every 3 minutes
: FT. FT>DD.MM.YYYY/hh:mm:ss TYPE ;
: ?FT. IF FT. ELSE ." none" THEN ;
Time: */3
Action:
   TASK-CREATION-TIME ?FT. CR
   TASK-EXECUTION-TIME ?FT. CR
)#

TimeMin@ ( -- CurrentTime_in_minutes )
TimeSec@ ( -- CurrentTime_in_seconds )

This words put on stack the current time in minutes or seconds respectively (the number of minutes/seconds since the last midnight).

Examples:

\ printing to console the current time in minutes/seconds
TimeMin@ . CR
TimeSec@ . CR

WEEKDAY ( y m d -- wd[1-7] )

This word takes a date in YMD format and returns (puts on stack) the corresponding number of day of a week (1 ... 7, 1 being Monday).

Example:

\ printing to console the number of day of a week
\ which was December 31, 2002
2002 12 31 WEEKDAY . CR

See also:

  • %DD%
  • %hh%
  • %mm%
  • %MMM%
  • %ss%
  • %WW%
  • %WD%
  • %YYYY%
  • %YY%
  • ACCESS-DATE
  • CREATION-DATE
  • FILE-ACCESS-DATE:
  • FILE-ATIME:
  • FILE-CREATION-DATE:
  • FILE-TIME:
  • FILE-WRITE-DATE:
  • FILE-WTIME:
  • ProcActiveTime
  • WRITE-DATE


Working with Sounds

  • BEEP: <length_in_ms> <frequency_in_hz>
  • MIXER+
  • MIXER-DOWN
  • MIXER-MUTE
  • MIXER-STATE
  • MIXER-UNMUTE
  • MIXER-UP
  • MIXER-VOLUME!
  • MIXER-VOLUME@
  • PLAY-SOUND: "path_of_wav_file"
  • PLAY-SOUNDW: "path_of_wav_file"

BEEP: <length_in_ms> <frequency_in_hz>

Causes your computer to beep using internal speaker. You can specify the beep's length (in milliseconds) and frequency (in hertz).

Example:

\ making a 500 Hz beep half a second long
BEEP: 500 500

You can use a postfix version of this word (BEEP) in order to be able to pick up length and frequency values directly from the stack:

<length_in_ms> <frequency_in_hz> BEEP

In this way, you can create some curious and funny sound effects for various events:

Examples:

10 1 DO 100 I 100 * BEEP LOOP
50 3000 DO
30 I BEEP I 17 / NEGATE
+LOOP

MIXER+ ( % -- )

This postfix word increases or decreases volume of the sound (Volume Control applet) by specified number of percents. To increase the volume use positive value, to decrease the volume use negative value. You can find the current volume value using the word MIXER-VOLUME@.

Examples:

\ increase the volume by 10%
10 MIXER+
\ decrease the volume by 30%
-30 MIXER+

MIXER-DOWN ( % -- )
MIXER-UP ( % -- )

Postfix words to decrease/encrease volume of the sound (Volume Control applet) by specified number of percents. You can find the current volume value using the word MIXER-VOLUME@.

Examples:

\ increase the volume by 10%
10 MIXER-UP
\ decrease the volume by 30%
30 MIXER-DOWN

MIXER-MUTE
MIXER-UNMUTE

Postfix words to mute/unmute volume of the sound (Volume Control applet).

MIXER-STATE ( -- ? )

Postfix word which returns TRUE (-1) if sound is unmuted (the Mute checkbox in Volume Control applet was not set) and FALSE (0) if sound is muted (the Mute checkbox in Volume Control applet was set).

Example:

\ unmuting the sound if it was muted
\ and increasing the volume by 50%
MIXER-STATE 0=
IF
    MIXER-UNMUTE
THEN
50 MIXER-UP

MIXER-VOLUME! ( % -- )

Postfix word which set the current sound volume (Volume Control applet) to a specified value in percents.

Примеры:

\ set volume to 10%
10 MIXER-VOLUME!
\ set volume to 90%
90 MIXER-VOLUME!

MIXER-VOLUME@ ( -- % )

Postfix word which puts on the stack the current sound volume value (Volume Control applet). The value is counted in percents.

Example:

\ printing  the current volume value to console:
MIXER-VOLUME@ . CR

PLAY-SOUND: "path_of_wav_file"

Plays a .wav file in asynchronous mode: task is not suspended while the .wav file is being played.

Example:

#( test_play_sound
NoActive
Action:
    PLAY-SOUND: "c:\my.wav"
)#

PLAY-SOUNDW: "path_of_wav_file"

Plays a .wav file in synchronous mode: task is suspended until the .wav file has been played.

Example:

#( test_play_soundw
NoActive
Action:
    PLAY-SOUNDW: "c:\my.wav"
    \ ... the next line will be executed only after
    \  the .wav file has been played to the end
)#


Working with Dial-up (RAS) and Your Internet Connection

  • CALL_DIAL
  • CALL_HANGUP
  • DIAL: "ras-entry" <number of attempts> <pause between attempts in seconds>
    • RASError
  • HANGUP
  • HANGUP: "ras-entry"
  • HOST-EXIST: "hostname_or_ip_address"
  • NHOST-EXIST: "hostname_or_ip_address" <num>
  • ONLINE?
  • ONLINE: "connection"
  • POP3-CHECK: "hostname-or-IP" "pop3user" "password"
  • RASDomain: "domain"
  • RASPassword: "dialup-password"
  • RASPhone: "phone"
  • RASSecPassword: "dialup-secure-password"
  • RASUser: "dialup-login"

RASUser: "dialup-login"

Sets user name (login) for a dial-up connection.

RASPassword: "dialup-password"

Sets password for a dial-up connection.

RASSecPassword: "dialup-secure-password"

Sets secure (encrypted) password for a dial-up connection. Here you can find a detailed description of what secure password is and how to get one .

RASPhone: "phone"

Specifies a phone number to dial. This parameter optional. If it is omitted, then nnCron will use the default phone for the dial-up connection specified in command DIAL:.

Example:

RASPhone: "1234567"

To force pulse dialing, use prefix P before the phone number.

Example:

RASPhone: "P1234567"

RASDomain: "domain"

Specifies a domain name for a dial-up connection. This parameter is optional. If it is omitted, nnCron will use the default domain for the dial-up connection specified in command DIAL:.

DIAL: "ras-entry" <number of attempts> <pause between attempts in seconds>

Initiates the dial-up process using the specified dial-up connection. Second and third arguments of word DIAL: specify, respectively, the number of attempts and the pause (in seconds) between attempts.

Dial error code is recorded into variable RASError.

Example:

#( test_dial
\ Dial-up a connection at 10:00 am on each week day
\ unless the computer is already online,
\ using remote connection 'MyConnection'.
Time: 0 10 * * 1-5 *
Action:
    \ checking if an Internet connection already exists
    ONLINE: "MyConnection" 0=
    IF
        RASUser: "login"
        RASPassword: "password"
        \ five dialing attempts with 30 seconds intervals between attempts
        DIAL: "MyConnection" 5 30
    THEN
)#

HANGUP: "ras-entry"

Breaks up a specified dial-up connection.

Example:

#( test_dial1
\ Dialing up a connection each hour  on every week day
\ unless the computer is already online,
\ using remote connection 'MyConnection'.
\ After connection is established, receiving the mail,
\ and disconnecting.
Time: 0 * * * 1-5 *
Action:
    \ checking if an Internet connection already exists
    ONLINE: "MyConnection" 0=
    IF
        RASUser: "login"
        RASPassword: "password"
        \ five dialing attempts with 30 seconds intervals between attempts
        DIAL: "MyConnection" 5 30
    THEN
    ONLINE: "MyConnection"
    IF
        START-APPW: getmail.bat
        HANGUP: "MyConnection"
    ELSE
        MSG: "Can't establish connection."
    THEN
)#

HANGUP

Breaks up any dial-up connection.

CALL_DIAL
CALL_HANGUP

Special words for users of EServ2. They are used to start dial-up or hang up while using EServ2.

HOST-EXIST: "hostname_or_ip_address"
NHOST-EXIST: "hostname_or_ip_address" <num>

These words return TRUE (-1) if a specified server is accessible (can be pinged).
HOST-EXIST: pings the server 3 times, and in NHOST-EXIST:, the number of ping-attempts is specified by the user.
By default, the ping-timeout is set to 3000 ms. You can set your own ping-timeout by modifying the VALUE-variable PING-TIMEOUT.

Example:

#( test_host_exist
\ Checking the accessibility of http://www.nncron.ru every midnight.
\ Starting 'my_app.exe' if the server can be pinged.
\ Setting ping-timeout to 5000 ms.
5000 TO PING-TIMEOUT
Time: 0 0
Rule: HOST-EXIST: "www.nncron.ru"
Action:
    START-APP: my_app.exe
)#

ONLINE?

Returns TRUE (-1) if any remote connection (dial up or VPN) is currently active

ONLINE: "connection"

Returns TRUE (-1) if a specified remote connection is active. As an argument, one should use the name of an actually existing connection as displayed in Dial-Up Networking (Network and Dial-up Connections) window.

POP3-CHECK: "hostname-or-IP" "pop3user" "password"

Returns the number of messages available in specified mailbox. Returns FALSE (0) if a specified mailbox is empty or not accessible using POP3 protocol.

There also exists a postfix version of this word:

S" hostname-or-ip" S" pop3user" S" password" POP3-CHECK

See also:

  • ADD-HOST
  • HTTP-CHANGED: <URL>
  • HTTP-GET: <URL>
  • HTTP-LM: <URL>
  • WatchConnect
  • WatchDisconnect


Working with Event Logs (WinNT/2000/XP)

  • FOR-NEW-EVENTS ... FOUND-EVENT ... ;FOR-NEW-EVENTS
  • FOUND-EVENT
  • WatchEventLog: "log_name"

FOR-NEW-EVENTS ... ;FOR-NEW-EVENTS

After WatchEventLog: triggers, you can use FOR-NEW-EVENTS ... ;FOR-NEW-EVENTS to loop through the list of new event records. FOUND-EVENT buffer is used to access the "body" of each event record.

Example:

#( test_watch_event
WatchEventLog: "System"
Action:
FOR-NEW-EVENTS
    ." New System event detected" CR
;FOR-NEW-EVENTS
)#

#( test_watch_event1
WatchEventLog: "System"
Action:
FOR-NEW-EVENTS
    ." New System event detected=" FOUND-EVENT evEventID @ . CR
;FOR-NEW-EVENTS
)#

FOUND-EVENT ( -- a)

Address of a buffer, which contains the binary information about an event record. You can use this buffer inside the FOR-NEW-EVENTS ... ;FOR-NEW-EVENTS loop.

Here are the fields, that are accessible in FOUND-EVENT:

Name | Size | Description
evLength | 1 CELLS | Size of this event record, in bytes.
evReserved | 1 CELLS | Reserved
evRecordNumber | 1 CELLS | Record number of the record
evTimeGenerated | 1 CELLS | Time at which this entry was submitted. This time is measured in the number of seconds elapsed since 00:00:00 January 1, 1970, Universal Coordinated Time.
evTimeWritten | 1 CELLS | Time at which this entry was received by the service to be written to the logfile. This time is measured in the number of seconds elapsed since 00:00:00 January 1, 1970, Universal Coordinated Time.
evEventID | 2 bytes | Event identifier
evEventType | 2 bytes | Type of event
evNumStrings | 2 bytes | Number of strings present in the log (at the position indicated by StringOffset)
evEventCategory | 2 bytes | Category for this event
evReservedFlags | 1 CELLS | Reserved
evClosingRecordNumber | 1 CELLS | Reserved
evStringOffset | 1 CELLS | Offset of the description strings within this event log record
evUserSidLength | 1 CELLS | Size of the UserSid member, in bytes
evUserSidOffset | 1 CELLS | Offset of the security identifier (SID) within this event log record
evDataLength | 1 CELLS | Size of the event-specific data (at the position indicated by DataOffset), in bytes
evDataOffset | 1 CELLS | Offset of the event-specific information within this event log record, in bytes

More detailed description of all of the fields is available in MSDN (see EVENTLOGRECORD structure).

Use the word @ to access the fields, which are marked as 1 CELLS and the word W@ to access the fields, which are marked as 2 bytes.

Example:

#( test-found-event
WatchEventLog: "Security"
Action:
FOR-NEW-EVENTS
    FOUND-EVENT evRecordNumber @ . CR
    FOUND-EVENT evEventType W@ . CR
;FOR-NEW-EVENTS
)#

#( test-found-event1
\ printing all the description strings to console
WatchEventLog: "Security"
Action:
FOR-NEW-EVENTS
    FOUND-EVENT evStringOffset @ FOUND-EVENT +
    FOUND-EVENT evNumStrings W@ 0 ?DO
        ." String " I . ." =" ASCIIZ> 2DUP TYPE CR + 1+
    LOOP
    DROP
;FOR-NEW-EVENTS
)#

Here are additional words to simplify the work with FOUND-EVENT buffer:

Name | Comment | Description
evComputername | ( a -- a1) | computer name (use ASCIIZ> to convert null-terminated string to au-string)
evNString | ( a # -- a1) | address of an #th string. String numbering begins with 0. (Use ASCIIZ> to convert null-terminated string to au-string).
evSourceName | ( a -- a1) | event source string (use ASCIIZ> to convert null-terminated string to au-string)
evStrings | ( a -- a1) | description strings (use ASCIIZ> to convert null-terminated string to au-string)
evStrings2String | ( a -- a1 u1) | combines all the description strings, replaces intermediate zeroes with blank spaces and returns the entire string
evUserSid | ( a -- a1 u1) | SID

Example:

#( test-evlog
WatchEventLog: "Security"
Action:
FOR-NEW-EVENTS
    ." evSourceName =" FOUND-EVENT evSourceName ASCIIZ> TYPE CR
    ." evComputername =" FOUND-EVENT evComputername ASCIIZ> TYPE CR
;FOR-NEW-EVENTS
)#

#( test-evlog1
\ printing entire description string to console
WatchEventLog: "Security"
Action:
FOR-NEW-EVENTS
    ." evStrings2String =" FOUND-EVENT evStrings2String TYPE CR
;FOR-NEW-EVENTS
)#

WatchEventLog: "log_name"

Modifiers (optional):
EVENTLOG-AUDIT-SUCCESS - notify of Audit Success event records
EVENTLOG-AUDIT-FAILURE - notify of Audit Failure event records
EVENTLOG-ERROR-TYPE - notify of Error event records
EVENTLOG-WARNING-TYPE - notify of Warning event records

This word is triggered when new event records in WinNT/2000/XP event logs are available. You can pass "Application", "System" or "Security" as "log_name" parameter.

The modifiers listed above allow a user to specify very precisely which event records should be watched.

After WatchEventLog: is triggered, the user can start a loop FOR-NEW-EVENTS ... ;FOR-NEW-EVENTS to traverse through all new event records in specified events log.

Example:

#( test-watchevent
WatchEventLog: "Security"
Action:
FOR-NEW-EVENTS
    ." EVENT RECORD= " FOUND-EVENT evEventID @ . CR
;FOR-NEW-EVENTS
)#

#( test-watchevent1
\ printing entire FOUND-EVENT buffer to console
WatchEventLog: "Application"
EVENTLOG-AUDIT-FAILURE
Action:
FOR-NEW-EVENTS
    ." EVENT RECORD=" CR FOUND-EVENT DUP @ DUMP CR CR
;FOR-NEW-EVENTS
)#


Performance Monitoring

  • CPU-USAGE
  • (CPU-USAGE)
  • IDLE: <seconds>
  • PROC-CPU-USAGE
  • (PROC-CPU-USAGE)
  • WatchCPUUsage: <CPUUsage%> <seconds>

CPU-USAGE ( -- %)
(CPU-USAGE) ( ms -- %)

Monitors the CPU usage for one second. The resulted value (in percents) is placed on a stack.

Example:

#( test_cpuusage
\ printing CPU usage to console once a minute
Action:
CPU-USAGE . ." %" CR
)#

Use (CPU-USAGE) word if you want to set the time (in ms) during which CPU usage should be monitored.

Example:

#( test_cpuusage1
\ printing CPU usage to console once a minute
Action:
\ monitoring CPU usage for 10 seconds
10000 (CPU-USAGE) . ." %" CR
)#

You can change the value of the VALUE-variable CpuMeasurementTime as well (default value - 1000 ms).

Example:

#( test_cpuusage2
\ printing CPU usage to console once a minute
Action:
CpuMeasurementTime		 \ placing the old value to the stack
5000 TO CpuMeasurementTime \ setting new value (5000 ms)
\ monitoring CPU usage for 5 seconds
CPU-USAGE . ." %" CR
TO CpuMeasurementTime      \ reverting to old value
)#

These words only work in WinNT/2000/XP.

IDLE: seconds

Returns TRUE (-1) if computer's idle time is greater then or equal to a specified amount of seconds. A computer is considered idle when its user gives no signs of activity, i.e. does not move or click the mouse and doesn't press keys on the keyboard. User's activity can be emulated: see sections "Keyboard Input Emulation" and "Mouse Activity Emulation".

To access the idle time counter, use word GetIdleTime, which puts on stack the computer's idle time in milliseconds.
It should be noted that the counter incrementation will start only after word IDLE: is been used in some task or after idle time counting has been initiated specifically:

<%
InitIdleHook
%>

#( test_idle
RunOnce NoDel
Action:
    60 0 DO
    LOG: "log\idle.log" "Idle time: %GetIdleTime%"
    PAUSE: 1000
    LOOP
)#

Operating system may interfere with operation or the word IDLE: If a console window is open (e.g. Command Prompt, FAR etc.), Windows "ignores" user's actions and idle time counter goes on despite of user's activities.
When a console window is open, Window 9* ignores only keyboard input, but it correctly processes actions performed with the mouse. Win2000 ignores both.

PROC-CPU-USAGE ( a u -- %)
(PROC-CPU-USAGE) ( a u ms -- %)

Monitors the CPU usage produced by specified process for one second. The resulted value (in percents) is placed on a stack. Use the name of an executable file to specify the name of the process. If the specified process does not exists the words PROC-CPU-USAGE/(PROC-CPU-USAGE) return 0.

Example:

#( test_proccpuusage
\ printing CPU usage produced by 'notepad.exe'
\ to console once a minute
Action:
S" notepad.exe" PROC-CPU-USAGE . ." %" CR
)#

Use (PROC-CPU-USAGE) word if you want to set the time (in ms) during which CPU usage should be monitored.

Example:

#( test_proccpuusage1
\ printing CPU usage produced by 'notepad.exe'
\ to console once a minute
Action:
\ monitoring CPU usage for 10 seconds
S" notepad.exe" 10000 (PROC-CPU-USAGE) . ." %" CR
)#

You can change the value of the VALUE-variable CpuMeasurementTime as well (default value - 1000 ms).

Example:

#( test_proccpuusage2
\ printing CPU usage produced by 'notepad.exe'
\ to console once a minute
Action:
CpuMeasurementTime		 \ placing the old value to the stack
5000 TO CpuMeasurementTime \ setting new value (5000 ms)
\ monitoring CPU usage for 5 seconds
S" notepad.exe" PROC-CPU-USAGE . ." %" CR
TO CpuMeasurementTime      \ reverting to old value
)#

These words only work in WinNT/2000/XP.

WatchCPUUsage: <CPUUsage%> <seconds>

This word is triggered when CPU usage exceeds the specified level (in percents) for a specified time (in seconds).

Example:

#( test_watchcpuusage
WatchCPUUsage: 95 10
Action:
MSG: "CPU usage exceeds 95%% for 10 seconds!"
)#

This word only works in WinNT/2000/XP. You should set nncron.ini variable PerfMonitor to ON for this word to works properly.

See also:

  • PROC-WAIT-CPU-USAGE


Mouse Activity Emulation

  • MOUSE-MOVE: <x> <y>
  • MOUSE-MOVER: <x> <y>
  • MOUSE-MOVEW: <x> <y>
  • MOUSE-LBDN
  • MOUSE-LBUP
  • MOUSE-LBCLK
  • MOUSE-LBDCLK
  • MOUSE-POS
  • MOUSE-RBDN
  • MOUSE-RBUP
  • MOUSE-RBCLK
  • MOUSE-RBDCLK

MOUSE-MOVE: <x> <y>

Moves the mouse pointer to screen position "x,y"; values of x and y are in pixels, "0,0" being the upper-left corner of the active window.

You can use WinSpy utility to find out the current absolute coordinates of the mouse pointer.

Examples:

\ moving mouse pointer to screen position "400, 400"
MOUSE-MOVE: 400 400
\ moving mouse pointer to the upper left corner of the screen
MOUSE-MOVE: 0 0

MOUSE-MOVER: <x> <y>

Moves the mouse pointer to a specified position relative to the current mouse position.

Arguments of word MOUSE-MOVER: can take both positive and negative values:

  • If x has a positive value, the pointer will be moved to the right.
  • If x has a negative value, the pointer will be moved to the left.
  • If y has a positive value, the pointer will be moved down.
  • If y has a negative value, the pointer will be moved up.

You can use WinSpy utility to find out the current absolute coordinates of the mouse pointer.

Examples:

\ moving the mouse pointer 100 pixels to the right
\ and 100 pixels down
MOUSE-MOVER: 100 100
\ moving the mouse pointer 250 pixels to the right
\ and 100 pixels up
MOUSE-MOVER: 250 -100
\ moving the mouse pointer 250 pixels to the right
MOUSE-MOVER: 250 0

MOUSE-MOVEW: <x> <y>

Moves the mouse pointer to the position "x,y" the in currently active window relative to the upper left corner of this window.

Example:

\ moving the mouse pointer to the upper left corner of active window
MOUSE-MOVEW: 0 0
\ moving the mouse pointer to the position 100 pixels to the right
\ and 100 pixels down from the upper left corner of active window
MOUSE-MOVEW: 100 100

MOUSE-LBDN
MOUSE-LBUP
MOUSE-LBCLK
MOUSE-LBDCLK

These key words emulate, respectively, the following actions of left mouse button: pressing the button, releasing the button, left click, and left doubleclick.

Examples:

\ moving the mouse pointer to a required position
\ and double-clicking with the left button
MOUSE-MOVE: 600 500
MOUSE-LBDCLK
\ pressing the left button, waiting for 4 seconds
\ and releasing the button
MOUSE-LBDN
PAUSE: 4000
MOUSE-LBUP

MOUSE-POS

This is a postfix word which puts on stack two numbers which are the current coordinates of the mouse pointer.

Example:

\ printing to console coordinates
\ of the mouse pointer (for instance:  404 657):
MOUSE-POS . . CR

MOUSE-RBDN
MOUSE-RBUP
MOUSE-RBCLK
MOUSE-RBDCLK

These key words emulate various actions of right mouse button. They work similarly to the corresponding words for the left button.

See also:

  • WIN-CLICK: "win_pattern" "button_pattern"
  • WIN-MOVE: <x> <y>
  • WIN-MOVER: <x> <y>


Keyboard Input Emulation

  • SEND-KEYS: "key_code_string"
  • SEND-KEYS-DELAY: <between_keystrokes_in_ms> <between_SEND-KEYS_in_ms>

SEND-KEYS: "key_code_string"

Sends one or several key codes to the active window, in other words, emulates keyboard input. Command SEND-KEYS: can be used both to use a keyboard shortcut (hotkey) in the active window (e.g. CTRL+S in order to save a file) as well as for just "typing" some text in text editors and in various input fields.

Section "Key Codes" contains detailed explanations of how to use key codes as arguments of word SEND-KEYS:

Examples:

\ typing word test
SEND-KEYS: "test"
\ typing 12345 on one line and  67890 on the next one
SEND-KEYS: "12345{ENTER}67890"

Sometimes it becomes necessary to specify key codes for a keyboard shortcut consisting of two or more keys that should be pressed simultaneously (e.g. CTRL is pressed and then, while it is being held down, ALT and G are pressed too). In this case, you should first indicate the first key that is being pressed and held down, and state the remaining key codes after it in parentheses.

Examples:

\ SHIFT+e+c
SEND-KEYS: "+(ec)"
\ CTRL+SHIFT+a
SEND-KEYS: "^(+a)"
\ CTRL+ALT
SEND-KEYS: "^(@)"
\ WIN+F1
SEND-KEYS: "$({F1})"

Pauses between individual "keystrokes" and SEND-KEYS: constructs can be set with word SEND-KEYS-DELAY:. A delay (pause) in milliseconds between two keystrokes can also be specified by using the following expression:

{DELAY time-in-ms}

Example:

#( test_send_keys
\ typing 12345, making a one-second delay
\ and then typing 67890.
NoActive
Action:
    WIN-ACTIVATE: "*Notepad"
    SEND-KEYS: "12345{DELAY 1000}67890"
)#

#( test_send_keys1
\ starting  Calculator and making some simple calculations.
Time: 0 12 * * * *
Action:
    START-APP: calc.exe
    PAUSE: 500
    WIN-ACTIVATE: "Calculator"
    PAUSE: 100
    SEND-KEYS: "1{+}2{ENTER}{DELAY 2000}*3{ENTER}"
)#

Using SEND-KEYS:, you can even switch the keyboard layout and type in several installed input languages. Notice, please, that you should watch the active keyboard layout for currently active GUI-application when typing in alternative languages. If standard (EN) keyboard layout was active before SEND-KEYS: usage, you can emulate typing of your native letters just by switching the keyboard layout and using the corresponding latin letters as an argument for SEND-KEYS:

\ 'EN' is the active keyboard layout.
\ We are using 'ALT+SHIFT' to switch the keyboard layout.
WIN-ACTIVATE: "*Notepad"
PAUSE: 500
SEND-KEYS: "+(t)est @(+)ntcn @(+)test"

If the alternative keyboard layout was active prior to SEND-KEYS: usage, you should use your native characters as an argument to SEND-KEYS:

\ 'RU' is the active keyboard layout.
\ We are using 'ALT+SHIFT' to switch the keyboard layout.
WIN-ACTIVATE: "*Notepad"
PAUSE: 500
SEND-KEYS: "+(t)est @(+)тест @(+)test"

Thus, you can define a task like this:

#( test_typing
\ setting keyboard layout to 'RU'
: KeysToRUS SEND-KEYS: "@(+1)" ;
\ setting keyboard layout to 'EN'
: KeysToENG SEND-KEYS: "@(+2)" ;
Action:
   PAUSE: 1000
   KeysToRUS
   SEND-KEYS: "+(Э)то тест - "
   KeysToENG
   SEND-KEYS: "This is a test"
)#

You can determine the active keyboard layout for GUI-application using the kbd_layout.spf plugin.

Limitations: You cannot use key PrtScr (PRINTSCREEN) in keyboard shortcuts. Besides, you won't be able to use SEND-KEYS: to "press" CTRL+ALT+DELETE.

SEND-KEYS-DELAY: <between_keystrokes_in_ms> <between_SEND-KEYS_in_ms>

Sets delay (in milliseconds) after each "keystroke" and after each subsequent SEND-KEYS: (WIN-SEND-KEYS:) construct. Allows to emulate "slow typing".

Affects all the subsequent SEND-KEYS: (WIN-SEND-KEYS:) constructs within current task.

Example:

#( test_send_keys_delay
NoActive
Action:
    START-APP: notepad.exe
    1000 PAUSE
    WIN-ACTIVATE: "*Notepad"
    500 PAUSE
    SEND-KEYS-DELAY: 500 0
    SEND-KEYS: "Typing slowly..."
)#

See also:

  • WIN-SEND-KEYS: "win_pattern" "key_code_string"


Working with Windows Registry

  • REG-SZ: "registry_path" "string_value"
  • REG-DWORD: "registry_path" <number>
  • REG-DELETE-KEY: "registry_path"
  • REG-DELETE-VALUE: "registry_path"
  • <buffer> GET-REG: "registry_path"

REG-SZ: "registry_path" "string_value"

Adds a string value to a key specified in registry path. (If the key does not exist, it will be created).

Example:

#( test_reg_sz
NoActive
Action:
    REG-SZ: "HKEY_LOCAL_MACHINE\SOFTWARE\test\first" "test string value"
)#

REG-DWORD: "registry_path" <number>

Adds a numerical value to the key specified in registry path. (If this key does not exist, it will be created).

DWORD (double word) is a 32-bit value, 8 hexadecimal digits.

Example:

#( test_reg_dword
NoActive
Action:
    REG-DWORD: "HKEY_LOCAL_MACHINE\SOFTWARE\test\second" 16
)#

There also exists a postfix version of this word (it is convenient to use it when working with variables):

S" HKEY_LOCAL_MACHINE\SOFTWARE\test\first" 16 REG-DWORD
S" HKEY_LOCAL_MACHINE\SOFTWARE\test\first" first_var @ REG-DWORD

REG-DELETE-KEY: "registry_path"

Deletes a specified key and all of its subkeys from the registry.

Example:

#( test_reg_delete_key
NoActive
Action:
    REG-DELETE-KEY: "HKEY_LOCAL_MACHINE\SOFTWARE\test"
)#

REG-DELETE-VALUE: "registry_path"

Deletes a specified value from Windows registry. Can be used with both string and numerical values.

Example:

#( test_reg_delete_value
NoActive
Action:
    REG-DELETE-VALUE: "HKEY_LOCAL_MACHINE\SOFTWARE\test\first"
    REG-DELETE-VALUE: "HKEY_LOCAL_MACHINE\SOFTWARE\test\second"
)#

<buffer> GET-REG: "registry_path"

Gets and records a specified value from the registry into a buffer created by the user.

String values should be placed in arrays, and numerical values in variables.

Examples:

#( test_get_reg
NoActive
CREATE reg_value 256 ALLOT
Action:
    reg_value GET-REG: "HKEY_LOCAL_MACHINE\SOFTWARE\test\first"
    MSG: "We have extracted a string value: %reg_value ASCIIZ>%"
)#

#( test_get_reg1
NoActive
VARIABLE reg_variable
Action:
    reg_variable GET-REG: "HKEY_LOCAL_MACHINE\SOFTWARE\test\second"
    MSG: "We have extracted a numerical value: %reg_variable @%"
)#

Word ASCIIZ> separates address of zero-terminated string into an address and a character count.

Some comments:

1) We would like to point out that editing Windows registry (especially removing keys whose purpose you don't know), is a rather dangerous activity, therefore we suggest that you create a backup copy of the registry.

2) One shouldn't use nnCron to access any entries in HKEY_CURRENT_USER subtree. nnCron is run by "user" SYSTEM and cannot access this branch, because from the viewpoint of user SYSTEM, branches of other users are located in subtree HKEY_USERS. In Win2000/XP, you can use plugin sid.spf to access user's branches in subtree HKEY_USERS.

See also:

  • WatchRegistryKey: "key_path" [flag] [modifiers]


Regular Expressions Support

  • RE-MATCH: "text" "/regexp/"
  • RE-ALL: "text" "/regexp/" <...> ;RE-ALL

RE-MATCH: "text" "/regexp/"

This words returns TRUE if it finds a matching string is found when comparing argument text with a regular expression.

Example:

#( test_re_match
\ with the help of a regular expression, let's find
\ in directory  'c:\xxx' all the files whose names start
\ with characters  'vk_'  followed by 3 digits,
\ e.g., 'vk_123test.txt', 'vk_324.gif', vk_647999.pdf' etc.
NoActive
Action:
    FOR-FILES: "c:\xxx\*"
        RE-MATCH: "%FOUND-FILENAME%" "/vk_\d\d\d.*/i"
        IF
            \ ... performing the required actions
        THEN
    ;FOR-FILES
)#

A postfix version of this word also exists:

S" text" S" /regexp/" RE-MATCH

Detailed description of regular expressions' syntax can be found here.

See also Notes.

RE-ALL: "text" "/regexp/" <...> ;RE-ALL

This words is used to execute a loop for each match found. The loop will be repeated as many times as there are matches.

Example:

#( test_re-all
\ word "nnCron" contains 3 instances of "n",
\ therefore, the loop will be executed 3 times
NoActive
Action:
    RE-ALL: "nnCron" "/n/"
        MSG: "n"
    ;RE-ALL
)#

Detailed description of regular expressions' syntax can be found here.

See also Notes.

Note 1: When working with regular expressions, use variable $0 to access the entire sequence, and variables $1 - $15 to access "remembered" matching groups of characters: $1 - first matching group, $2 - second matching group etc.

Example:

#( test_regexp
NoActive
Action:
    RE-MATCH: "Firstname Lastname" "/(.*) (.*)/"
    IF
        MSG: "$0 = %$0%" \ $0 = Firstname Lastname
        MSG: "$1 = %$1%" \ $1 = Firstname
        MSG: "$2 = %$2%" \ $2 = Lastname
    THEN
)#

Note 2: Besides being used in words RE-MATCH: и RE-ALL:, regular expressions are also used in nnCron for creating masks for words which perform operations with window names.


Turning Your Computer on/off, Power Management

  • FORCE-LOGOFF
  • FORCE-POWEROFF
  • FORCE-REBOOT
  • FORCE-SHUTDOWN
  • LOGGEDON?
  • LOGOFF
  • MONITOR-ON
  • MONITOR-OFF
  • MONITOR-LOW
  • POWEROFF
  • POWER-HIBERNATE
    • POWER-FORCE
  • POWER-SUSPEND
    • POWER-FORCE
  • REBOOT
  • SCREENSAVER-ON
  • SCREENSAVER-ON?
  • SCREENSAVER-OFF
  • SHUTDOWN

POWER-SUSPEND

Puts the system to Standby mode.

To accelerate switch to Suspend mode, use POWER-FORCE immediately before POWER-HIBERNATE.

POWER-HIBERNATE

Puts computer to hibernate mode.

To accelerate switch to Hibernate mode, use POWER-FORCE immediately before POWER-HIBERNATE.

MONITOR-ON
MONITOR-OFF
MONITOR-LOW

These key words, respectively, turn on the monitor, turn it off and switch it to reduced power consumption mode, .

SCREENSAVER-ON
SCREENSAVER-OFF

Starts/stops the screen saver.

SCREENSAVER-OFF only works in WinNT/2000/XP. However, you can usually turn off a screen saver by emulating a mouse movement (see "Mouse Activity Emulation).

SCREENSAVER-ON?

Returns TRUE (-1) if screen saver is started.

SHUTDOWN
FORCE-SHUTDOWN

Shuts down Windows to the point of "It is now safe to turn off your computer ". Word FORCE-SHUTDOWN ignores system queries regarding saving changes in open applications and forces the operating system to shut down.

REBOOT
FORCE-REBOOT

Reboots the system. Word FORCE-REBOOT ignores system queries regarding saving changes in open applications and forces the operating system to reboot.

POWEROFF
FORCE-POWEROFF

Shuts the system down and turns off the power. Word FORCE-POWEROFF ignores system queries regarding saving changes in open applications and forces the operating system to shut down and turns power off.

LOGOFF
FORCE-LOGOFF

Logs off the current user (works in 9x/ME and works in NT/2000/XP if nnCron is running as a regular application rather then as a service). Word FORCE-LOGOFF ignores system queries regarding saving changes in open applications and forcibly logs off the current user.

LOGGEDON?

Returns TRUE (-1) if a user is logged on locally.

See also:

  • WakeAfter: <hh:mm>
  • WakeAt: <hh:mm>
  • WatchQuerySuspend
  • WatchResume
  • WatchResumeAuto
  • WatchShutdown
  • WatchStandby
  • WatchSuspend
  • WatchLogoff: "username_pattern"
  • WatchLogon: "username_pattern"


Checking Your OS Version

  • DllGetVersion
  • GET-VER
  • Win2k?
  • Win95?
  • Win98?
  • Win9x?
  • WinME?
  • WinNT?
  • WIN-VER
  • WinVerBuild
  • WinVerMajor
  • WinVerMinor
  • WinVerPlatform
  • WinVerServicePack
  • WinVersionString
  • WinXP?

DllGetVersion ( a u -- major minor build)

Puts three values on stack (major, minor and build) which you can use to retrieve the full version number of specified dll. (This word will work only if dll support versioning).

GET-VER ( -- minor major platform)

Puts three values on stack:

  • platform
Value | Meaning
1 | Windows9*/ME
2 | WinNT/2000/XP
  • major
Value | Meaning
3 | Windows NT 3.51
4 | Windows 95
4 | Windows 98
4 | Windows ME
4 | Windows NT 4.0
5 | Windows 2000
5 | Windows XP
5 | Windows .NET Server
  • minor
Value | Meaning
51 | Windows NT 3.51
0 | Windows 95
10 | Windows 98
90 | Windows ME
0 | Windows NT 4.0
0 | Windows 2000
1 | Windows XP
2 | Windows .NET Server

With these values, you can retrieve the full version number of OS installed on your computer.

Example:

#( test_win_version
NoActive
0 VALUE ver_minor
0 VALUE ver_major
0 VALUE ver_platform
: platform
    ver_platform 2 =
    IF
        ver_major 4 =
        IF
            S" NT"
        ELSE
            ver_minor 0 =
            IF S" 2000" ELSE S" XP" THEN
        THEN
    ELSE
        S" 9x"
    THEN ;
Action:
    GET-VER TO ver_platform TO ver_major TO ver_minor
    MSG: "Windows %platform% %ver_major%.%ver_minor%
)#

Win2k?

Returns TRUE (-1) if nnCron has been started in Win2000 or WinXP, and returns FALSE (0), if it is run in Win9x/ME/NT.

Win95?
Win98?
WinME?
WinXP?

Returns TRUE (-1) if nnCron has been started in Win95, Win98, WinME or WinXP respectively .

Win9x?

Returns TRUE (-1) if nnCron has been started in Win9x or WinME, and returns FALSE (0), if it is run in WinNT/2000/XP.

WinNT?

Returns TRUE (-1) if nnCron has been started in WinNT/2000/XP, and returns FALSE (0), if it is run in Win9x/ME.

WIN-VER ( -- major )

Puts on stack a numeric value of Windows version.

Value | Meaning
3 | Windows NT 3.51
4 | Windows 95
4 | Windows 98
4 | Windows ME
4 | Windows NT 4.0
5 | Windows 2000
5 | Windows XP
5 | Windows .NET Server

WinVerBuild ( -- n)
WinVerMajor ( -- n)
WinVerMinor ( -- n)
WinVerPlatform ( -- n)

Gets the system values (build, major, minor and platform) which you can use to retrieve the full version number of OS installed on your computer. See descriptions of these values.

WinVerServicePack ( -- a u)

Returns the string with the name of the currently installed service pack in your operating system.

Example:

\ printing installed service pack name to console
WinVerServicePack TYPE CR

WinVersionString ( -- a u)

Returns the string with the full version of your operating system (OS name, build number and service packs installed).

Example:

MSG: "%WinVersionString%"


Integrating JScript and VBScript in Your Tasks

  • <VBScript> ... </SCRIPT>
  • <JScript> ... </SCRIPT>

<VBScript> ... </SCRIPT>
<JScript> ... </SCRIPT>

You can use these constructs in order to integrate scripting languages VBScript and JScript, respectively, in your own tasks. Scripts in these languages may include nnCron's predefined variables surrounded by two percent signs (%).

Example:

#( jscript-calc
Time: 0 12 * * * *
Action:
    <JScript>
        var WshShell = WScript.CreateObject("WScript.Shell");
        WshShell.Run("calc");
        WScript.Sleep(100);
        WshShell.AppActivate("Calculator");
        WScript.Sleep(100);
        WshShell.SendKeys("2{+}2{*}3=");
    </SCRIPT>
)#

Version 2.0 of Windows Script Host (WSH) should be installed on your computer in order for this example to run correctly..

If you are using Windows 2000/XP or Windows ME, version 2.0 of WSH is already installed on your system. If you are using Windows 95, 98 or Windows NT 4.0, you probably have obsolete version 1.0. To update your WSH to version 5.6 or newer, go to Microsoft Windows Script Technologies Web site.


Miscellaneous Key Words

  • CD-TRAY-EJECT: <drv_letter>
  • CD-TRAY-CLOSE: <drv_letter>
  • CLIPBOARD: "text"
  • CRON-LOG
  • CUR-TASK-NAME
  • DISABLE-CRON
  • DISABLE-CRON?
  • ENABLE-CRON
  • FREE-SPACE: <drv_letter>
  • GetLastError
  • HIDE-ICON
  • IS-CD-PRESENT: <drv_letter>
  • LOG: "filename" "message"
  • PAUSE: <hh:mm>
  • PAUSE: <time_in_ms>
  • RANDOM
  • RES
  • RunMissed?
  • SHOW-ICON
  • TRAY-REFRESH
  • WINAPI: <function_name> <dll_name>

CD-TRAY-EJECT: <drv_letter>
CD-TRAY-CLOSE: <drv_letter>

Ejects/closes the tray of a specified CD-ROM drive.

See also: WatchDrive: <drv_letter>, WatchDriveRemove: <drv_letter>, IS-CD-PRESENT: <drv_letter>

IS-CD-PRESENT: <drv_letter>

Returns TRUE (-1) if there is a disk in the specified CD-ROM drive and returns FALSE (0) if the specified CD-ROM drive is empty.

Example:

#( test_cd_present
WatchShutdown
Action:
    IS-CD-PRESENT: "d"
    IF
        ERR-MSG: "Remove disk from CD-ROM drive!"
    THEN
)#

There also exists a postfix version of this word. To be used at run-time (in console, for example):

CHAR D IS-CD-PRESENT

To be used at compile-time (when defining tasks in your crontabs):

[CHAR] D IS-CD-PRESENT

See also: WatchDrive: <drv_letter>, WatchDriveRemove: <drv_letter>, CD-TRAY-EJECT: <drv_letter>, CD-TRAY-CLOSE: <drv_letter>

PAUSE: <time_in_ms>
PAUSE: <hh:mm>

Suspends a task for a specified length of time.

Examples:

#( test_pause
Time: 30 7 * * * *
Action:
    START-APP: d:\tools\vmtdial\vmtdial.exe -h
    \ waiting for three seconds
    PAUSE: 3000
    WIN-CLOSE: "*VMT Dialer*"
)#

#( test_pause1
WatchFile: "c:\xxx.sem"
Action:
    PAUSE: "00:30"
    \ ... executing the job 30 minutes after the flag file was spotted
)#

Word PAUSE can also be used in with postfix-type notation (i.e. "<time_in_ms> PAUSE" ), but in this case time may be specified only in milliseconds.

Example:

\ a pause five seconds long
5000 PAUSE
\ a pause  one minute long
60000 PAUSE

LOG: "filename" "message"

Appends contents of message into the log file specified in filename.

There also exists a postfix version of this word:

S" message" S" filename" LOG

S" message" CRON-LOG

Writes the message into the cronlog specified in variable Cronlog: in nncron.ini. The string passed as a parameter to word CRON-LOG may contain nnCron's predefined variables.

Example:

S" test message" CRON-LOG
S" message from %USERNAME%" CRON-LOG

CLIPBOARD: "text"

Places the contents of argument text in the clipboard.

There also exists a postfix version of this word:

S" text" CLIPBOARD!

See also: CLIPBOARD, WatchClipboard:

FREE-SPACE: <drv_letter>

Returns the amount of free space (in kilobytes) on a specified drive.

Example:

\ returns "TRUE" if  C: drive has
\ less then 10 megabyte free space
\ and "FALSE" if C: drive has more
\ then 10 megabyte free space
FREE-SPACE: C 10000 <

There also exists a postfix version of this word:

\ for use in console:
CHAR <drv_letter> FREE-SPACE
\ for use in crontabs:
[CHAR] <drv_letter> FREE-SPACE
\ or
%CHAR <drv_letter> FREE-SPACE%

HIDE-ICON
SHOW-ICON

These key words, respectively, hide nnCron icon in system tray if it is visible and show the icon if it is hidden

HIDE-ICON is executed after a certain delay.

CUR-TASK-NAME ( -- a u )

When used within a tasks definition, this word returns the name of the current task.

Example:

#( test_taskname
NoActive
Action:
    MSG: "Current task name: %CUR-TASK-NAME%"
)#

DISABLE-CRON
ENABLE-CRON

Word DISABLE-CRON switches nnCron to suspended mode. Word ENABLE-CRON, does the opposite thing: it causes nnCron to return to the normal operation mode.

It is important to note that while nnCron is in suspended mode, the task which suspended nnCron still remains active (as well as tasks with HyperActive option). This allows you to wake up nnCron programmatically from the same task.

Example:

#( test_suspend
\ when flag file "disable.flg" appears,
\ we'll switch nnCron to suspended mode for 10 minutes
WatchFile: "C:\TEMP\disable.flg"
Action:
    BEEP: 250 500
    DISABLE-CRON
    PAUSE: 00:10
    ENABLE-CRON
)#

DISABLE-CRON?

Returns TRUE (-1) if nnCron is in suspended mode, and returns FALSE (0) if nnCron is in normal mode. For example, you could use this word to start a task only if nnCron is in suspended mode.

Example:

#( test_suspend?
RunOnce NoDel
HyperActive
Rule: DISABLE-CRON?
Action:
    MSG: "nnCron is disabled!"
)#

GetLastError

This word is calling Win32 API GetLastError() function. If there was an error during execution of last command, it returns the error number, and if there was no error, it returns 0.

Word GetLastError can be used with following key words: START-APP:, START-APPW:, FILE-CREATE ( -COPY, -MOVE, -RENAME, -CROP, -WRITE, -APPEND), DIR-CREATE (-DELETE) etc.

Example:

#( test_error
NoActive
Action:
    FILE-DELETE: "c:\xxx\test.sem"
    GetLastError
    IF MSG: "FILE-DELETE error: %GetLastError%" THEN
)#

GetLastError shouldn't be used with word FILE-DELETE: (details).

RANDOM ( range -- random )

This postfix word generates random numbers using an implementation of the function RAN4, described in the second edition of "Numerical Recipes in C". This word takes a number as its argument, that sets an upper limit for random numbers. The random numbers will range from 0 to the argument value - 1. So, if you call RANDOM with an argument 1000, the random numbers will range from 0 to 999.

Random numbers generator is initialized with a special word START-SEQUENCE ( dcounter dseq# ), that takes two double length arguments. The top of stack specifies which sequence to generate numbers from. The second on stack specifies the starting position within that sequence. When launching a task, unique values are automatically assigned to these arguments, but you can assign them manually, by using, for example, the number of milliseconds since startup of operating system (GetTickCount):

GetTickCount DUP 2DUP START-SEQUENCE

Examples:

\ random numbers will range from 0 to 510
511 RANDOM

#( test_random
WatchHotKey: "${F5}"
Action:
    \ START-SEQUENCE was set automatically
    \ displaying random number (range from 0 to 99) in a message:
    MSG: "Random: %100 RANDOM%"
    \ printing random number (range from 0 to 99) to console:
    100 RANDOM . CR
)#

#( test_random_manual
WatchHotKey: "${F6}"
Action:
    \ setting START-SEQUENCE manually
    GetTickCount DUP 2DUP START-SEQUENCE
    \ displaying random number (range from 0 to 99) in a message:
    MSG: "Random: %100 RANDOM%"
    \ printing random number (range from 0 to 99) to console:
    100 RANDOM . CR
)#

RES ( n -- a u )

This posrfix word uses a number as its argument and returns a corresponding string from active language resource file (see also: Language:).

Example:

#( test_predefined_string
NoActive
Action:
    \ displaying 'Buy nnCron Now!' string in your language
    MSG: "%19 RES%"
)#

#( test_predefined_string1
NoActive
Action:
    \ dislaying full name of a current weekday
    MSG: "%159 WDay@ + RES%"
)#

RunMissed?

Returns TRUE (-1) if the started task was missed and is started 'at the first opportunity' and returns FALSE (0) if the task was started at the scheduled time. You can use the RunMissed? word to display a warning when launching missed task.

Example:

#( test_runmissed
Time: 0 0
Rule: RunMissed? IF TQUERY: "Missed task. Launch it?" 5 Yes THEN
Action:
    \ ...
)#

TRAY-REFRESH

Refreshes system tray and removes "lost" icons, which can remain in system tray after the application was closed from nnCron.

Example:

#( test_close_miranda
NoActive
Action:
    PROC-CLOSE: "miranda32.exe"
    TRAY-REFRESH
)#

WINAPI: <function_name> <dll_name>

This word allows you to import win32-functions from external DLLs to nnCron by specifying function name and the name of dll-file, where the function resides.

WINAPI: MoveFileA KERNEL32.DLL
WINAPI: RasDialDlgA RASDLG.DLL
WINAPI: NetSessionEnum NETAPI32.DLL

During the import the function is converted to a new postfix word, that you can use in all of your tasks. Function arguments are reversed to comply with postfix notation.

Before the import:

your_function(1, 2, "string", 4);

After the import:

4 Z" string" 2 1 your_function

Value, that was returned by imported function stays on the stack. Delete this value if you are not planning to use it in your task.

Example:

#( convert_to_lower_case
NoActive
WINAPI: CharLowerBuffA USER32.DLL
CREATE convert_buf 256 ALLOT
Action:
    S" My TeSt StRiNg" convert_buf PLACE
    MSG: "Not converted: %convert_buf COUNT%"
    convert_buf COUNT SWAP CharLowerBuffA DROP
    MSG: "Converted: %convert_buf COUNT%"
)#

OnBalloonClick

The USER-variable OnBalloonClick "overrides" the value of nncron.ini variable TrayIconBalloonClick: for the current task (and only for the current task). Thus, for current task you can define a specific action, that should be performed when clicking on a BALLOON: hint.

Example:

#( test_balloonclick
NoActive
: my-click
  \ some useful activity:
  MSG: "You have destroyed my Balloon!"
;
Action:
    ['] my-click OnBalloonClick !
    BALLOON: "Test" "Click me!"
)#

#( test_balloonclick1
NoActive
Action:
    [NONAME
    \ more useful activity:
    BEEP: 50 500 PAUSE: 200 BEEP: 50 500
    NONAME] OnBalloonClick !
    BALLOON: "New test" "Click me now!"
)#


Additional Information

Variables Used in nncron.ini
Command Line Keys for nncron.exe and tm.exe
Key Codes (for Use with Words WatchHotKey: and SEND-KEYS:)
Regular Expressions
Tips-'N'-Tricks
Forth First Aid
Troubleshooting


Variables Used in nncron.ini

Note: To restore the default values of all variables listed in nncron.ini, do the following:

  • unload nnCron from computer's memory
  • rename file nncron.ini or move it from nnCron's home directory
  • restart nnCron

After this, a new nncron.ini will be generated, where all variables will have their default values.

  • : CRONTAB-ERROR ... ;
  • : REMINDER-SOUND ... ;
  • BackupPath: "folder_name"
  • CompleteTaskTimeout: <time_in_ms>
  • Console <ON/OFF>
  • Cronlog: "filename"
  • Crontab: "filename"
  • DefaultDomain: "domain_name"
  • DefaultLoadProfile <ON/OFF>
  • DefaultLogonType: <logon_type>
  • DefaultOpenMode: <mode>
  • DefaultPassword: "sec_password"
  • DefaultPriority: <priority>
  • DefaultRunMissedTime: <hh:mm>
  • DefaultUser: "username"
  • DialOnce <ON/OFF>
  • Editor: "filename"
  • GUIAsUser <ON/OFF>
  • GUIDomain: "domain_name"
  • GUILoadProfile <ON/OFF>
  • GUIPassword: "sec_password"
  • GUIUser: "username"
  • Guard <ON/OFF>
  • HelpFile: "filename"
  • INCLUDE "filename"
  • IconForAdminsOnly <ON/OFF>
  • ItemConsole <ON/OFF>
  • ItemExit <ON/OFF>
  • ItemOptions <ON/OFF>
  • ItemReload <ON/OFF>
  • ItemSuspend <ON/OFF>
  • Language: <language_name>
  • LogTimeFormat: "time_format"
  • Log2StdOut <ON/OFF>
  • MenuHotKey: "hotkey"
  • MonitorResponseTime: <time_in_ms>
  • QueryStartAnswer: <Yes/No>
  • QueryStartTimeout: <time_in_sec>
  • PerfMonitor <ON/OFF>
  • ReloadImmediately <ON/OFF>
  • RemAllowed: <ip_address_mask>
  • RemConsole <ON/OFF>
  • RemConsolePort: <port_number>
  • RemDisallowed: <ip_address_mask>
  • RunAsDefaultUser <ON/OFF>
  • ShowErrorMsg <ON/OFF>
  • SyntaxRestriction <ON/OFF>
  • SysTrayIcon <ON/OFF>
  • TrayIconDoubleClick: <forth_word>
  • TrayIconRightButton: <forth_word>
  • WatchProcDelay: <time_in_ms>
  • WatchWinCreateDelay: <time_in_ms>
  • YearField <ON/OFF>

Crontab: "filename"

Activates a crontab. File nncron.ini may contain more then one "Crontab:" variable: there may be as many of them as there are activated crontabs.

Crontab: "hotkey.tab"
Crontab: "vk.tab"
Crontab: "test.tab"
Crontab: "%YYYY%.tab"

Editor: "filename"

Specifies the text editor which will be used when the user selects View log in the right-click menu or clicks on nncron.ini button in Options dialog box.

By the way, there exists a special nnCron syntax highlight scheme for a free open-source text editor SciTE. Syntax highlighting can be flexibly modified. I recommend it to all! Additional information can be found on the SciTE web-site (http://www.scintilla.org). There also exists an add-on enabling syntax highlight for nnCron and Forth in the internal editor of FAR file manager (http://www.farmanager.com).

Allowed values:

  • Editor: "default"
  • Editor: "filename"
Editor: "d:\tools\scite\scite.exe"

Language: <language_name>

Specifies the language to be be used in nnCron's GUI. nnCron's language resource files are located in res subdirectory. New and updated language resource files can be downloaded from our Translation page (http://www.nncron.ru/translation.shtml).

Allowed values:

  • Language: English
  • Language: German
  • Language: Russian

etc...

Language: English

Cronlog: "filename"

Specifies the name of nnCron's log file.

Cronlog: "log\nncron.log"

LogTimeFormat: "time_format"

Specifies the format for writing information into log file.

LogTimeFormat: "%DD% %MMM% %hh%:%mm%:%ss% %ThreadId%"

YearField <ON/OFF>

Specifies whether or not the Year field should be included in the cron format used by nnCron.

Allowed values:

  • YearField ON
  • YearField OFF
YearField ON

CompleteTaskTimeout: <time_in_ms>

Specifies the length of time (in milliseconds) during which nnCron will await for completion of a running task when reloading crontab files. If a task is not completed during the specified time, it will be forced to stop.

CompleteTaskTimeout: 10000

QueryStartTimeout: <time_in_sec>

Specifies the length of time (in seconds) during which nnCron will await for user's answer to a query about starting an application (QSTART-APP:). If the user does not react during the specified time, nnCron will itself decide whether or not the application should be started (see QueryStartAnswer:).

QueryStartTimeout: 30

QueryStartAnswer: <Yes/No>

Specifies nnCron's default answer to a query regarding starting an application (QSTART-APP:) if the user did not react during the time specified in QueryStartTimeout: variable.

Allowed values:

  • QueryStartAnswer: Yes
  • QueryStartAnswer: No
QueryStartAnswer: Yes

PerfMonitor <ON/OFF>

This variable turns on/off the special set of words for system performance monitoring. There are some of these words:

  • WatchCPUUsage: <CPUUsage%> <seconds>

Allowed values:

  • PerfMonitor ON
  • PerfMonitor OFF
PerfMonitor OFF

ReloadImmediately <ON/OFF>

ReloadImmediately ON - reload changed crontabs located in nnCron home directory imediately.
ReloadImmediately OFF - check for crontabs changes once in a minute (at 30 seconds).

Allowed values:

  • ReloadImmediately ON
  • ReloadImmediately OFF
ReloadImmediately ON

DefaultOpenMode: <mode>

Specifies the default mode in which applications will be started by nnCron (application window can be opened in in following modes: normal, maximized, minimized or hidden).

Allowed values:

  • DefaultOpenMode: ShowNormal
  • DefaultOpenMode: ShowMinimized
  • DefaultOpenMode: ShowMaximized
  • DefaultOpenMode: SWHide
DefaultOpenMode: ShowNormal

DefaultPriority: <priority>

Specifies the default priority which nnCron assigns to applications launched by it.

Allowed values:

  • DefaultPriority: HighPriority
  • DefaultPriority: IdlePriority
  • DefaultPriority: NormalPriority
  • DefaultPriority: RealtimePriority
DefaultPriority: NormalPriority

DefaultRunMissedTime: <hh:mm|days>

Manages launching of missed tasks: specifies maximum waiting time (in hours and minutes or days) that may elapse since this task was sheduled to run for the last time. The missed task will not be launched if DefaultRunMissedTime: value is smaller than the time elapsed since this task was sheduled to run for the last time.

DefaultRunMissedTime: 360:00

DefaultLogonType: <logon_type>

Defines the default logon type.

Allowed values:

  • DefaultLogonType: LogonBatch
  • DefaultLogonType: LogonInteractive
  • DefaultLogonType: LogonNetwork
DefaultLogonType: LogonInteractive

SysTrayIcon <ON/OFF>

Specifies whether or not the nnCron icon will be displayed in system tray.

Allowed values:

  • SysTrayIcon ON
  • SysTrayIcon OFF
SysTrayIcon ON

TrayIconDoubleClick: <forth_word>
TrayIconRightButton: <forth_word>
TrayIconBalloonClick: <forth_word>

These variables defines the action, that should be performed when double-clicking or right-clicking on nnCron system tray icon or clicking on a BALLOON: hint. There are several predefined words, which can be used as an arguments to TrayIconDoubleClick:, TrayIconRightButton: and TrayIconBalloonClick:. Note, that you can use any other forth-words as well.

Predefined words, which can be used with TrayIconDoubleClick:, TrayIconRightButton: and TrayIconBalloonClick:

  • options (show the 'Options' dialog window)
  • add-new-task (show the 'New Task' dialog window)
  • open-help (open the help file)
  • add-reminder (open the 'New Reminder' dialog window)
  • about (open the 'About' window)
  • show-log (open the nnCron log-file)
  • buy (go to the nnCron registration page)
  • winspy (open the WinSpy window)
  • START-CONSOLE (open the Console window)
  • reload-crontab (reload crontabs)
  • menu (load the nnCron pop-up menu)
  • NOOP (perform no actions)
TrayIconDoubleClick: options
TrayIconRightButton: menu
TrayIconBalloonClick: NOOP

See also the answers on a following questions: "How can I start my own task by double-clicking on nnCron system tray icon?" and "How can I create my own pop-up menu which is shown when right-clicking on nnCron system tray icon?".

IconForAdminsOnly <ON/OFF>

Allows to make the nnCron's icon in system tray visible only to users with administrator rights. If the value of this variable is set to ON, then users with lower-level rights will not see the icon in the tray.

Allowed values:

  • IconForAdminsOnly ON
  • IconForAdminsOnly OFF
IconForAdminsOnly OFF

MonitorResponseTime: <time_in_ms>

Specifies the minimal period of time between two events (Watch*). This is discussed in greater detail in Event Specifiers section.

MonitorResponseTime: 100

: CRONTAB-ERROR ... ;

Word CRONTAB-ERROR is called each time when a syntax error is spotted in a crontab file. By modifying the definition of CRONTAB-ERROR, you can change contents of the error message. CRONTAB-ERROR to a certain degree parallels functions of variable ShowErrorMsg, therefore, it can be used as an auxiliary tool: e.g. to play a specific sound in order to warn about an error, to create a flag file each time an error is spotted, or do something else. Word CRONTAB-ERROR may be safely deleted from nncron.ini.

: CRONTAB-ERROR ( a u -- )
WinNT? IF 10 1 DO 100 I 100 * BEEP LOOP ELSE 1 1 BEEP THEN
ERR-MSG: "CRONTAB ERROR!!!.%crlf%%crlf%TASK FILE: %CUR-TAB-FILENAME COUNT%%crlf%TASK: %CUR-TASK-NAME%%crlf%Line: %CURSTR @%"
;

: REMINDER-SOUND ... ;

Word REMINDER-SOUND specifies the sound which should be played when a Reminder message is displayed.

: REMINDER-SOUND 500 500 BEEP ;

or:

: REMINDER-SOUND PLAY-SOUND: "%Windir%\media\tada.wav" ;

BackupPath: "folder_name"

Specifies the directory where nnCron stores backup copies of crontab files and ini files after they have been modified.

BackupPath: "backup"

WatchWinCreateDelay: <time_in_ms>

Specifies the delay time (in milliseconds) before execution of WatchWinCreate:. Such a delay is necessary because many windows have no title when they have been just created, so they cannot be found by their titles.

WatchWinCreateDelay: 100

WatchProcDelay: <time_in_ms>

Specifies the delay time (in milliseconds) before execution of WatchProc: and WatchProcStop:.

WatchProcDelay: 1000

Console <ON/OFF>

Specifies whether or not the Forth console should be started automatically on nnCron startup.

Allowed values:

  • Console ON
  • Console OFF
Console OFF

ItemConsole <ON/OFF>
ItemExit <ON/OFF>
ItemOptions <ON/OFF>
ItemReload <ON/OFF>
ItemSuspend <ON/OFF>

These variables respectively specify whether or not the Right-click pop-up menu should contain the following items: "Tools/Console", "Exit", "Options", "Reload Crontabs" and "Disable nnCron/Enable nnCron".

Allowed values: ON or OFF

ItemExit ON
ItemOptions ON
ItemConsole ON
ItemReload ON
ItemSuspend ON

Guard <ON/OFF>

Specifies whether or not application nnguard.exe (which is responsible for so-called Crash guard mode, in which nnCron automatically restarts after fatal errors) should be used. More detailed description of the Crash guard mode can be found here.

Allowed values:

  • Guard ON
  • Guard OFF
Guard ON

INCLUDE "filename"

Activates specified plugins. Several instanced of INCLUDE can be used in nncron.ini—as many as there are enabled plugins.

INCLUDE "plugins\tools.spf"
INCLUDE "plugins\windows.spf"
INCLUDE "plugins\time.spf"
INCLUDE "plugins\win2tray.spf"
INCLUDE "plugins\wakeup.spf"
INCLUDE "plugins\procwin.spf"
INCLUDE "plugins\timesync.spf"

DialOnce <ON/OFF>

DialOnce ON: when this variable is on, nnCron won't attempt to re-dial a connection if a remote connection already exists (function RasDial will not be called). So it enough to call word HANGUP just once in order to hang up (break the connection).

Allowed values:

  • DialOnce ON
  • DialOnce OFF
DialOnce ON

DefaultUser: "username"
DefaultPassword: "sec_password"
DefaultDomain: "domain_name"
DefaultLoadProfile <ON/OFF>

Sets authorization parameters (login, password, domain) for running all tasks as a particular user. (See RunAsDefaultUser). Variable DefaultLoadProfile specifies whether user profile should be loaded. Use an encrypted password as a value of variable DefaultPassword:.

DefaultUser: "test_user"
DefaultPassword: "h4jk2sdhl=="
DefaultDomain: ""
DefaultLoadProfile OFF

RunAsDefaultUser <ON/OFF>

Specifies whether or not all tasks should be run as the default user (using the data specified in Default* group of variables).

Allowed values:

  • RunAsDefaultUser ON
  • RunAsDefaultUser OFF
RunAsDefaultUser OFF

GUIUser: "username"
GUIPassword: "sec_password"
GUIDomain: "domain_name"
GUILoadProfile <ON/OFF>

Sets authorization parameters (login, password, domain) for running nnCron's GUI as a particular user. (See GUIAsUser). Variable GUILoadProfile specifies whether a user profile should be loaded. Use an encrypted password as a value for variable GUIPassword:.

GUIUser: "test_user"
GUIPassword: "h4jk2sdhl=="
GUIDomain: ""
GUILoadProfile OFF

GUIAsUser <ON/OFF>

Specifies whether or not to run the nnCron GUI as the user specified in GUI* group of variables.

Allowed values:

  • GUIAsUser ON
  • GUIAsUser OFF
GUIAsUser OFF

ShowErrorMsg <ON/OFF>

Specifies whether or not the errors written to log file should be accompanied by an alert message box. If necessary, the time of waiting for user response can be changed (it is set to 30 by default). To do this, change the value of variable ShowErrorTime:

10 ShowErrorTime !

Allowed values:

  • ShowErrorMsg ON
  • ShowErrorMsg OFF
ShowErrorMsg ON

SyntaxRestriction <ON/OFF>

This word can be used to put a restriction to what words and constructs can be used in the beginning of a task (After '#(' and before Action: or Rule:). If SyntaxRestriction is ON, then only a limited number of words can be used in the beginning section of a task (Time:, Watch*, task options, comment sign). Thus, the system can be safeguarded against actions of inexperienced users, for user errors may crash nnCron or even destabilize the entire system.
To overcome this restriction, experienced users can use words <( and )>. Any words can be used between the parentheses (even if SyntaxRestriction is on). But in this case, make sure you know what you are doing.

Allowed values:

  • SyntaxRestriction ON
  • SyntaxRestriction OFF
SyntaxRestriction OFF

HelpFile: "filename"

Specifies which help file is will be opened when a user clicks on Help in menu.

HelpFile: "F:\My Documents\NNCRON\help_ru.chm"

Log2StdOut <ON/OFF>

This word is used to toggle ON/OFF the mode in which all the errors written to log file are duplicated to standard output. When this mode is ON, all the information sent to log file will be duplicated on Forth console.

Allowed values:

  • Log2StdOut ON
  • Log2StdOut OFF
Log2StdOut OFF

RemConsole <ON/OFF>

Allows/disallows use of Remote Console instead of regular Forth console. If RemConsole is set to OFF, Remote Console server is not started, and a local console is used instead of standard nnCron's console. For example, Remote Console may have to be disallowed on systems where TCP/IP (which is required for Remote console to work) is not installed.

Allowed values:

  • RemConsole ON
  • RemConsole OFF
RemConsole ON

RemConsolePort: <port_number>

Sets the number of port which Remote Console server will listen.

RemConsolePort: 2002

RemAllowed: <ip_address_mask>
RemDisallowed: <ip_address_mask>

Sets IP addresses which are allowed or disallowed to connect to Remote Console server. nncron.ini may contains several instances of variables RemAllowed or RemDisallowed. As arguments, you can use address masks and nonexistent addresses.

The general rule is as follows: one can connect from all addresses named in RemAllowed, except for addressees specified in RemDisallowed.

For example, let us allow connection from 127.0.0.1 (localhost), and in RemDisallowed we shall specify a nonexistent IP address; this would have the following effect: No specific addresses are disallowed, but only addresses specified in RemAllowed: will be allowed to connect

RemAllowed: 127.0.0.1
RemDisallowed: x.x.x.x

Extending the list of "allowed" addresses:

RemAllowed: 127.0.0.*
RemAllowed: 127.127.15.15
RemAllowed: 127.63.63.3
RemDisallowed: x.x.x.x

Allowing connection from all IP addresses and disallowing connection from 127.0.0.13, 127.0.0.14 and 127.13.13.*:

RemAllowed: *
RemDisallowed: 127.0.0.13
RemDisallowed: 127.0.0.14
RemDisallowed: 127.13.13.*

MenuHotKey: "hotkey"

Sets the keyboard shortcut (hotkey) that will bring nnCron pop-up menu on-screen. Hotkeys are defined using the same syntax as in WatchHotKey:

MenuHotKey: "^@n"


Command line keys for "nncron.exe" and "tm.exe"

  • nncron.exe
  • tm.exe
  • Executing Forth Words in Command Line (Oneliners)

nncron.exe:

-install | Install nnCron service (WinNT/2000/XP)
-remove | Remove nnCron service (WinNT/2000/XP)
-q | Do not display confirmation message box after installing/removing the service (this key should be placed before "-install/-remove") (WinNT/2000/XP)
-ns | Launch nnCron as a regular application (not as a service)
-debug | Run nnCron in debug mode (some additional information will be written to nncron.out file)
-v | Display nnCron version and build number
-ep your_password | Generate an encrypted password. As the task source text is stored without any protection in a plain-text crontab file, nnCron provides an option to use your password in tasks in what I call "sort-of-protected" encrypted form. To generate this type of a password, start nncron.exe in command line followed with parameters "-ep <your password>". After that, the program will display a message box with your password in encrypted form. It should be used in SecPassword: constructions. I'm calling this type of passwords "sort-of-protected" because the encryption algorithm is a very simple one and can be rather easily cracked by an expert. WinNT/2000/XP, though, allows to control access rights to individual files and directories, so if you wish you can protect crontab files from outsiders (just be sure to grant access to these files to those users whose user names are used with "run as user" option). See also Authorization section
-stop | Stop nnCron (handy for Win95/98 users)
-reload | Immediately reload modified crontab
-run task-name | Run the task specified in argument. More detailed discussion of this key can be found here.
-runfile <filename> | Execute the specified file as a script; the file should contain Forth word main. A more detailed description of this key can be found here.
-wp | Do not load the plugins when nnCron starts. Use this key in conjunction with -runfile option if you want nnCron to start faster.
-hi | Hide the nnCron icon in system tray
-si | Display the nnCron icon in system tray
-ini <filename> | Specifies the file containing nnCron settings (nncron.ini by default)
-out <filename> | Specifies the file which will receive the technical information output (nncron.out by default)
-? | Show nnCron Help (see also Help Menu Item).

tm.exe

tm.exe is the nnCron's GUI. This is the dialog which appears when you doubleclick on the nnCron's icon in system tray. This dialog permits to set and change nnCron's basic parameters as well as add/edit tasks in crontab files. Here is the list of command line parameters used by tm.exe:

tm.exe | Running tm.exe without additional parameters will result in displaying a dialog box for adding a task into the default crontab file
tm.exe About | Display About the Program dialog box
tm.exe Console <host> <port> | Start Remote Console and attempt to connect the specified address using the specified port
tm.exe EditTask "crontab filename" task_name | Display Edit Task dialog box which allows you to edit the specified task
tm.exe Hint [some text] | Display a small "hint" message (looking somewhat like Windows tooltips) with the specified text
tm.exe Message [first line\second line...] | Display a message box with the specified text
tm.exe NewReminder "crontab filename" [first line\second line...] | Display New Reminder dialog box which allows you to add the specified text to the specified crontab file
tm.exe NewTask ["crontab filename"] | Display New Task dialog box which allows you to add a new task to the specified crontab file
tm.exe Options | Display Options dialog box
tm.exe Reminder "crontab filename" once|* [first line\second line...] | Display a Reminder box containing the specified text and allowing you to set the repetition options.
tm.exe TimeHint seconds [some text] | Display a small "hint" message (looking somewhat like Windows tooltips) with the specified text, which will disappear after the specified period of time
tm.exe WinSpy | Start WinSpy utility

Executing Forth Words in Command Line (Oneliners)

Beside possessing standard capabilities for working with for command line keys, nnCron also provides its users an interesting capability to define and execute Forth words right in command line. This is similar to so-called oneliners used in Perl.

Oneliner is a line of program code that can be executed in command line.

The rules are as follows:

  • Only postfix words can be executed (athough you can create new postfix word, containing several prefix words if you want to)
  • You cannot directly use loops and flow control constructs (e.g. IF ... ELSE ... THEN). However, it doesn't prevent you from defining a new word right in command line, and this definition may contain both loops and IF ... ELSE ... THEN constructs
  • You cannot execute words which output information to stdout
  • In order to compete execution of program code from command line use word BYE

Examples:

Displaying a message box with test message:

nncron.exe S" test message" MsgBox BYE

Now we'll create a file, write into it the current user's user name, display the text from the file in a message box and, to complete the task, make our computer to emit a touching beep. Of course, all this is just one long command line:

 nncron.exe S" oneliner.txt" FCREATE S" %USERNAME%" EVAL-SUBST S" oneliner.txt" FAPPEND S" oneliner.txt" FILE 3 TimeMsgBox 250 500 BEEP BYE

Now a more interesting example. In a single long command line we shall create and execute a new word which will inform us whether we are online:

nncron.exe : test_online ONLINE? IF S" we are online!" 3 TimeMsgBox ELSE S" we are offline!" 3 TimeMsgBox THEN ; test_online BYE

Please also keep in mind that you can include in onliners entire pieces of code from external files (S" filename" INCLUDED).

Oneliners can also be used in *.cmd and *.bat files for checking for various conditions. nnCron will return errorlevel 0 if the condition is FALSE, and -1 if it is TRUE.

Examples:

Checking if we are connected to the Internet:

start /wait nncron.exe ONLINE? HALT

An example of using a prefix word:

start /wait nncron.exe : online? ONLINE: "ISP" ; online? HALT


Key Codes (for Use with Words 'WatchHotKey:' and 'SEND-KEYS:')

This section explains how to use various key codes with words WatchHotKey:, SEND-KEYS: and WIN-SEND-KEYS:.

In order to use any alphanumeric key as an argument for these words, you can just use the corresponding character in quotation marks (case-sensitive). For example, letters A, b and f all correspond to their respective keys. You can use several letters together: e.g. string AbC corresponds to pressing A, b and C.

The plus sign (+), caret (^), at sign (@), dollar sign ($) have special meanings. Normally, they are used to represent functional keys SHIFT, CTRL, ALT and WIN, respectively. To use these characters in an argument as characters and not as symbols for functional keys, you have to place them inside of curly braces ({+}, {^}, {@}, {$}). If you have to use braces in a parameter of one of the above words, use double braces ( {{ and }} ), and use {QUOTE} for a quotation mark.

Examples:

SEND-KEYS: "A"
SEND-KEYS: "qwe"
SEND-KEYS: "Valery Kondakoff"
SEND-KEYS: "support{@}nncron.ru" \ support@nncron.ru
SEND-KEYS: "2 {+} 2"          \ 2 + 2
SEND-KEYS: "{QUOTE}Micro{$}oft{QUOTE} Company" \ "Micro$oft" Company

As mentioned above, keys SHIFT, CTRL and ALT are represented by special characters:

Key | Code
ALT | @
CTRL | ^
SHIFT | +

Microsoft Natural Keyboard or any other compatible keyboard includes two additional keys: the Windows logo key (WIN) and the Application key (APP):

Key | Code
APP | {APP}
WIN | $

To specify characters that aren't displayed when you press a key, such as ENTER or TAB, and keys that represent actions rather than characters, use the codes shown below:

Key | Code
BACKSPACE | {BACKSPACE}, {BS}, or {BKSP}
BREAK | {BREAK}
CAPS LOCK | {CAPSLOCK}
DEL or DELETE | {DELETE} or {DEL}
DOWN ARROW | {DOWN}
END | {END}
ENTER | {ENTER}
ESC | {ESC}
HELP | {HELP}
HOME | {HOME}
INS or INSERT | {INSERT}
LEFT ARROW | {LEFT}
PAGE DOWN | {PGDN}
PAGE UP | {PGUP}
PRINT SCREEN | {PRTSC}
RIGHT ARROW | {RIGHT}
SCROLL LOCK | {SCROLLLOCK}
TAB | {TAB}
UP ARROW | {UP}
F1 | {F1}
F2 | {F2}
F3 | {F3}
F4 | {F4}
F5 | {F5}
F6 | {F6}
F7 | {F7}
F8 | {F8}
F9 | {F9}
F10 | {F10}
F11 | {F11}
F12 | {F12}
F13 | {F13}
F14 | {F14}
F15 | {F15}
F16 | {F16}

You can also use the numpad keys, wich are located in the right side of your keyboard (so called grey keys):

Key | Code
+
         {ADD}
. {DECIMAL}
/ {DIVIDE}
* {MULTIPLY}
NUM LOCK | {NUMLOCK}
- {SUBTRACT}
0 | {NUMPAD0}
1 | {NUMPAD1}
2 | {NUMPAD2}
3 | {NUMPAD3}
4 | {NUMPAD4}
5 | {NUMPAD5}
6 | {NUMPAD6}
7 | {NUMPAD7}
8 | {NUMPAD8}
9 | {NUMPAD9}

nnCron can handle multimedia keys, that are available on several extended keyboards. We are expecting these keys to work smoothly with SEND-KEYS:, but currently we have not such a keyboard and we can't test how these keys will work with WatchHotKey:. Anyway, here are the multimedia key codes:

Code | Code | Code | Code
{BROWSER_BACK} | {VOLUME_MUTE} | {MEDIA_NEXT_TRACK} | {LAUNCH_MAIL}
{BROWSER_FORWARD} | {VOLUME_DOWN} | {MEDIA_PREV_TRACK} | {LAUNCH_MEDIA_SELECT}
{BROWSER_REFRESH} | {VOLUME_UP} | {MEDIA_STOP} | {LAUNCH_APP1}
{BROWSER_STOP} |  | {MEDIA_PLAY_PAUSE} | {LAUNCH_APP2}
{BROWSER_SEARCH} |  |  |
{BROWSER_FAVORITES} |  |  |
{BROWSER_HOME} |  |  |

Examples:

SEND-KEYS: "First line.{ENTER}Second line."\ two  lines
SEND-KEYS: "Temp{BS}{BS}st" \ Test
WatchHotKey: "^@s"          \ CTRL + ALT + s
WatchHotKey: "$5"           \ WIN + 5


Regular Expressions

Regular expressions (regexps, REs) are a powerfull tool for creating templates which can be used for searching and comparing any symbols and strings (even the most complex) in a text.

How such template is composed? This is done with the help of special characters, metacharacters and character classes (sets). A regular expression is a simple string and any characters in it wich are not special (reserved) characters are treated as themselves.

Special characters are subdivided in three groups:

  • characters of the first group match a certain character class (set): e.g. expression "\w" matches any letter
  • characters of the second class, unlike the first one, don't have a length (so-called zero-width characters): e.g. "^" matches start of a line, "\b" matches a start of a word
  • third class includes operators. Operators are applied to metacharacters, common characters and to other operators.

One can group up any expression (by enclosing it in parentheses) and apply an operator to the entire group.

Syntax of regular expression in nnCron is the same as in Perl, with a few minor differences in certain extended operators.

Syntax

All regexps should be enclosed between forward slashes (/.../). Parameters may be placed after the ending slash:

/.../i | - ignore case differences.
/.../x | - ignore whitespace characters and newline characters (for convenience).
/.../s | - treat the regular expression as a single line (regard the special character "." (period) as "any character, including newline character").

Examples:

\ matches only word 'Valery'
/Valery/
\ matches words  'VALERY', 'valery', 'Valery' etc.
/Valery/i
\ matches  'foobar', 'foobar barfoo'
/foobar/
\ matches  'foobar', 'FOOBAR', 'foobar and two other foos'
/ FOO bar /ix
\ matches 'Valery%crlf%Kondakoff'
/Valery.*Kondakoff/s

All characters in a regular expression are consecutively (left to right) compared with the target string. All characters which are not special characters or operators listed below are treated as themselves and checked for a simple match.

Special Characters

^ | Start of a line
$ | End of a line
. | Any character except for newline character (if used without parameter " /.../s")
[ ... ] | Any character of set inside the brackets. Inside square brackets, other special characters won't work, but metacharacters can be used. You can use two characters with a hyphen between them to designate a range of characters: e.g. [a-f] would match any of the following characters: a, b, c, d, e, f.
[^ ... ] | None of the characters listed in square brackets. Inside of square brackets, other special characters won't work, but meta characters can be used. You can use a hyphen between two characters to designate a sequence of characters (inclusive) between these two: e.g. [^0-9] would match any character except 0, 1, 2, 3, 4, 5, 6, 7, 8, 9.
\# | This would match the character (#) following the backslash (except for characters a-z and 0-9). E.g. sequence "\\" would mean "\" , "\." would match character "." (stop), "\$" would match "$" и т. д.
\b | Start of word
\B | End of a word
\xNN | A character with ASCII hex code NN (\x20 would be a blank space, \x4A - J, \x6A - j, etc.)
\n | 0x10 (lf)
\r | 0x13 (cr)
\t | 0x09 (tab)
\s | A whitespace character (tab/space /cr/lf)
\S | Not a whitespace character
\w | A word character (letters, digits, _)
\W | A non-word character
\d | A digit
\D | Not a digit
\u | An uppercase character
\l | A lowercase character

Examples:

\ matches word  'help' followed by a stop
/help\./
\ matches words 'cats', 'cars' etc.
/ca.s/
\ matches  'testing', 'tester', but not 'the test'
/^test/
\ matches 'see me', but not 'meter' or 'me and you'
/me$/
\ matches one of the vowels
/[aeiou]/
\ matches one letter or digit
/[a-z0-9]/
\ matches 'footer', 'footing', 'a foot', but not 'afoot'
/\bfoot/
\ matches 'afoot', 'foot.' (stop is not considered a part of the word)
\ doesn't  match 'footing'
/foot\B/
\ matches whole word 'foot' only
/\bfoot\B/
\ matches words 'q2w', 'r5t' etc.
/\D\d\D/

Extended Special Characters

Unlike ordinary special characters, extended ones are not compatible with Perl:

\N Reference to a subpattern withing the same regular expression, where N is the number of the required subpattern. This operator has certain limitations: it will only work if the referenced supbattern does not contain any repetition operators.

Example:

\ matches phrases 'man to man', '
\ hand to hand', '100 to 100' etc.
(\b\w+\B) to \1

Operators

Operators cannot be used by themselves, they should be preceded by a character or meta character which they affect. If an operator is preceded by some expression enclosed in parentheses, it affects the entire contents of parentheses

( ... ) | Group characters into a single pattern and remember it
| | Preceding or following pattern (logical OR)
* | Zero or more times
+ | One or more times
? | 0 or 1 times the preceding pattern
{n} | To repeat n times
{n,} | To repeat n or more times
{n,m} | To repeat n to m times

Examples:

\ matches words 'cat' или 'mouse'
/(cat)|(mouse)/

\ matches words 'dogs', 'doggie'
/dog(s|gie)/
\ matches 'ma', 'maaa', 'maaaaaaa'
/ma+/
\ matches 'm', 'maaa'
/ma*/
\ matches 'yada yada yada'
/(yada ){2,}/
\ matches 'fooandbar', 'foobar'
/foo(and)?bar/

If you add charahter "?" after an operator, this will turn a greedy operator into a non-greedy one. For example, a greedy "*" will become non-greedy when replaced by "*?". Greedy operators try to match as much a possible, and non-greedy ones match little as possible.

Extended Operators

?#N | Lookbehind operator . N is the number of characters to look for.
?~N | No lookbehind
?= | Lookahead
?! | No lookahead

Please note that although the last two operators exist in Perl, they are used there in this way: (?=foobar). In nnCron, this operator looks like this: (foobar)?=.

Examples:

\ matches any word followed by a tab character,
\ the tab character itself not  included with the mathing characters
/\w+(\t)?=/
\ matches any instance of 'foo' which is not followed by 'bar'
/foo(bar)?!/
\ matches any instance of 'bar' not preceded by 'foo'
/(foo)?#3bar/

More examples:

\ matches "foobar", "bar"
/(foo)?bar/
\ matches only "foobar"
/^foobar$/
\ matches "foobar", "for", "far"
/f[obar]+r/
\ any number with a decimal point
/([\d\.])+/
\ matches "foofoofoobarfoobar", "bar"
/((foo)|(bar))+/


Tips-'N'-Tricks

  1. How can I define a task so that it is not displayed in Start Task and Edit menus?
  2. How can I pass arguments from command line to a task?
  3. How can I count weeks, e.g. start a task only on the second Monday of every month or on the third Sunday of December?
  4. How can I find out the name of the task which is currently being executed and the name of the crontab file where this task is located?
  5. How can I display a message box with a specified title and message?
  6. How can I "tell" nnCron that a certain task should be started only after startup/restart of my computer?
  7. How can I temporarily block mouse and keyboard input?
  8. How can I block a workstation (WinNT/2000/XP) using the means provided by nnCron?
  9. How can I "instruct" nnCron to keep a single log file and not to create a new one every day?
  10. How can I stop a running task (e.g. in case of an error)?
  11. How can I stop a task from another task?
  12. How can I make the task Active/NoActive programmatically?
  13. How can I intercept exceptions so that I can handle them myself?
  14. How can I find out the meaning of error numbers that I see on Forth console, log file and in nncron.out?
  15. How can I change a string's encoding from WIN to OEM and vice versa?
  16. How can I use nnCron to change attributes of a file?
  17. How can I check a condition on one computer in a network and execute a task on another one (provided, of course, that a copy of nnCron is running on both computers)?
  18. How can I find out the current display resolution?
  19. How can I programmatically empty the recycle bin?
  20. How can I find short name of the file (8.3) when I'm inside the FOR-FILES: loop?
  21. How can I start my own task by double-clicking on nnCron system tray icon?
  22. How can I create my own pop-up menu which is shown when right-clicking on nnCron system tray icon?
  23. How can I launch a task using windows shortcut (*.lnk)?
  24. How can I launch a program using windows shortcut (*.lnk)?
  25. How can I copy all the files and all the subdirectories tree?
  26. How can I restart nnCron right from the given task?

How can I define a task so that it is not displayed in Start Task and Edit menus?

Name a task this way: CLASSIC-TASK-#-ххх.

#( CLASSIC-TASK-#-xxx
NoActive
Action:
    MSG: "CLASSIC-TASK-#-xxx"
)#

Instead of "ххх", you can put any characters except for blank spaces (e.g. CLASSIC-TASK-#-ABCD, CLASSIC-TASK-#-123456 or CLASSIC-TASK-#-my_task). You can start such a task manually from a command prompt:

nncron -run CLASSIC-TASK-#-my_task

How can I pass arguments from command line to a task?

It can be done if you start a task with key -runfile:

nncron.exe -runfile <file_name>

Everything that follows the file name in command line is treated as an arguments and can be read by Forth construct BL WORD (blank space is used as a delimiter). Here is an example which displays a consecutive series of message boxes with all found arguments of command line:

\ ---begin 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---
\ start: nncron.exe -wp -runfile args.spf one two three four

Besides, nnCron has word get-string, which performs all the "menial" work when parsing an argument: if a string is surrounded by quotation marks, then everything inside the quotation marks is treated as an argument; otherwise, only that part of the string which precedes the first encountered blank space will be considered an argument.

Example:

\ ---begin of args1.spf---
CREATE str1 256 ALLOT
: main
    get-string str1 PLACE
    MSG: "%str1 COUNT%"
;
\ ---end of args1.spf---
\ start:
\ nncron.exe -wp -runfile args1.spf "Very long argument in quotes"

How can I count weeks, e.g. start a task only on the second Monday of every month or on the third Sunday of December?

\ here is 2nd Monday of each January (08:00)
Time: 0 8 8-14 Jan Mon *
\ and here is 3rd Sunday of each December (08:00)
Time: 0 8 15-21 Dec Sun *

The same trick can be also used for the first (1-7) and fourth (22-28) week, but it won't work for the last week of the month. Here you should invent something more complicated. But the value of the day of the month is easily accessible (Day@), and so is the value of the day of the week (WDay@). So you can get as complicated as you wish—and please also keep in mind word OnceAWeek.

How can I find out the name of the task which is currently being executed and the name of the crontab file where this task is located?

Name of task:

%CUR-NODE CRON-NAME @ COUNT%

Name of crontab file:

%CUR-NODE CRON-FILENAME @ COUNT%

To get the task name from the task itself, use word CUR-TASK-NAME ( -- a u ).

How can I display a message box with a specified title and message?

This is very simple:

0 S" Title" DROP S" Message" DROP 0 MessageBoxA DROP

How can I "tell" nnCron that a certain task should be started only after startup/restart of my computer?

Solution of this problem consists of two simple steps:

1) We must make sure first that on each startup a special flag file is created. For example, we can place in Startup folder a link to a batch file containing the following line:

echo started > c:\started.sem

2) Now it only remains to write the task itself:

#( after_system_start
WatchFile: "c:\started.sem"
Action:
    FILE-DELETE: "c:\started.sem"
    \ after this, we perform all the required action
)#

Voilà! Now this task will be started only after system startup. And, unlike the tasks which are started with the help of word START-TIME, our task will be started immediately after startup, without waiting for a new minute to begin.

Here is another method: word GetTickCount puts on stack the time that has passed since the system startup (in milliseconds). Therefore, we can check this time and if it is less then a minute or two, that would mean that the system has just started.

Example:

#( system_restart
Time: START-TIME
Rule: GetTickCount 90000 <
Action:
    \ here we perform all the required actions
)#

If a computer starts slowly, we might want to increase the length of time to which we compare GetTickCount (90000 - 150000).

How can I temporarily block mouse and keyboard input?

Here's how:

WINAPI: BlockInput USER32.DLL
: BlockTheInput TRUE BlockInput DROP ;
: UnblockTheInput FALSE BlockInput DROP ;

But this will only work in Windows 9*/2000/XP. Besides, it has been found that in Win9*, the above construct doesn't just block the user's activities, but also blocks key words SEND-KEYS: and (apparently) MOUSE* as well. Be careful!

Example:

#( test_hint
WINAPI: BlockInput USER32.DLL
: BlockInput TRUE BlockInput DROP ;
: UnblockInput FALSE BlockInput DROP ;
Action:
    BlockInput
    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
    UnblockInput
    THINT: "User input unblocked!" 3
)#

Please note also that the user input will be only blocked for the time or execution of the task which has called BlockTheInput. As soon as the task is completed, the user input is automatically unblocked.

How can I block a workstation (WinNT/2000/XP) using the means provided by nnCron?

For example, in this fashion:

#( test_lock_workstation
NoActive
WINAPI: LockWorkStation USER32.DLL
Action:
    LockWorkStation DROP
)#

How can I "instruct" nnCron to keep a single log file and not to create a new one every day?

To do this, you should change values of variables Cronlog and (optionally) LogTimeFormat in nncron.ini:

\ path of log
Cronlog: "log\nncron.log"
 \ log time pattern
LogTimeFormat: "%DD% %MMM% %hh%:%mm%:%ss% %ThreadId%"

Here is how information in the log will look:

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

By the way, the single log can be "cut down" from time to time with the help of word FILE-CROP:.

How can I stop a running task (e.g. in case of an error)?

Use word EXIT (it belongs to Forth kernel), which is used to exit the current word. It can be used because Action: also is a Forth word.

#( test_exit
NoActive
Action:
    \ ... doing something useful
    \ and checking for any errors:
    FILE-EXIST: "error.log"
    IF
        \ there is an error,
        \ deleting the file and stopping the task
        FILE-DELETE: "error.log"
        EXIT
    THEN
    \ ... if there are no errors, going on with our work
)#

Attention, please: word EXIT cannot be used within DO ... LOOP construct. To exit both a loop and a task, use UNLOOP EXIT: construct

DO ... IF UNLOOP EXIT THEN ... LOOP

How can I stop a task from another task?

For example, this way (it will only work in Windows NT/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
)#

How can I make the task Active/NoActive programmatically?

From inside the current task:

\ activating
CUR-NODE CF-ACTIVE SET-CRON-FLAG
\ deactivating
CUR-NODE CF-ACTIVE CLR-CRON-FLAG

From the another task:

\ activating
<task_name> @ CF-ACTIVE SET-CRON-FLAG
\ deactivating
<task_name> @ CF-ACTIVE CLR-CRON-FLAG

Note, please: you are not changing the crontab physically, when programmatically setting or clearing NoActive task option. Thus, the task keeps it's new active/non-active status until you reload crontabs for the next time.

Using the following words you can check if the task is active or not:

\ checking if the task is active from the task itself
CF-ACTIVE?
IF
    \ ...
THEN
\ checking if the task is active from another task
<task_name> @ CRON-FLAGS @ CF-ACTIVE AND?
IF
    \ ...
THEN

How can I intercept exceptions so that I can handle them myself?

nnCron provides a possibility to intercept any exception and decide afterwards what you are going to do with them.

This is how exceptions are intercepted :

['] word_name CATCH

['] looks up the following word in a dictionary (in compilation mode) and compiles its address xt (execution token) into the definition as a numeric literal.
CATCH takes xt from the stack, "remembers" state of the stack (broadly speaking) and executes this xt. If an exception arises while xt is being executed, it won't go anywhere beyond CATCH. World CATCH returns 0 if there are no exceptions, and error code if there was one.

Therefore, in a "real-life" situation this will look somewhat like this:

word_attributes ['] word_name CATCH ?DUP
IF  \ processing the error
    \ error code will be on top of the stack
    \ and below it there will be some garbage,
    \ depending on parameters
THEN

Example:

S" from-path" S" to-path" ['] FCOPY CATCH ?DUP
IF
    \ writing error code to 'nncron.out' and to the console
    ." Copy error # " . CR
    \ removing the garbage
    2DROP 2DROP
ELSE
    \ this branch doesn't have to exist, actually
    ." Copied successfully" CR
THEN

You can only use CATCH directly with "postfix" words. If it is necessary to process an exception of a "prefix" word, you should first create a new postfix word based on this "prefix" word.

Example:

#( task1
: copy1 FILE-COPY: "path-from" "path-to" ;
\ ...
Action:
    ['] copy1 CATCH ?DUP
    IF \ ...
)#

Sometimes, when a task is large and there are several operators that can throw an exception, the following trick can help: we can place the entire content of Action: section into a new word and use CATCH to "watch" it.

Example:

#( task2
NoActive
: task-body
    \ placing the content of  Action: section
    \ into a new word task-body
    \ ...
 ;
 Action:
    \ executing the new word and catching the mistakes at the same time
    ['] task-body CATCH ?DUP IF ." Error # " . CR THEN
)#

How can I find out the meaning of error numbers that I see on Forth console, log file and in nncron.out?

If you want the errors to be displayed on console in user-friendly (verbose) format rather then as numerical codes (5, 2003, FILE ERROR # 3 etc.), download and extract to nnCron home directory the following file: http://www.nncron.ru/download/spf_err.rar (~24k). Here you can also find descriptions of errors recorded in log file and nncron.out (you can look them up by error number).

How can I change a string's encoding from WIN to OEM and vice versa?

nnCron's kernel contains definitions of "recoding" words OemToCharBuffA and CharToOemBuffA. Here is how you can use them to change encoding of a string:

#( test_recode
NoActive
\ defining "recoding" words
: WIN2OEM ( a u -- a u ) 2DUP SWAP DUP CharToOemBuffA DROP ;
: OEM2WIN ( a u -- a u ) 2DUP SWAP DUP OemToCharBuffA DROP ;
\ creating a buffer to place a string
\ whose encoding is going to be changed
CREATE RECODE_BUFFER 256 ALLOT
Action:
    S" a test string" RECODE_BUFFER PLACE
     \ printing the string to console
    RECODE_BUFFER COUNT WIN2OEM TYPE CR
    \ displaying the string content in a message box:
    MSG: "%RECODE_BUFFER COUNT WIN2OEM%"
)#

Nicholas strongly recommends to copy a string to a buffer and change its encoding there (as in above example), instead of changing encoding right where the the string is stored.

How can I use nnCron to change attributes of a file?

Let's look up what Windows API says about this:

BOOL SetFileAttributes(
LPCTSTR lpFileName, // file name
DWORD dwFileAttributes // attributes
);

That means, for example, that we can do the following :

#( test_file_attrib
WINAPI: SetFileAttributesA Kernel32.dll
NoActive
Action:
    \ setting the "hidden file" attribute:
    2 S" c:\temp\test.txt" DROP SetFileAttributesA DROP
)#

Here is a list of constants (with their values) that can be used instead of 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

How can I check a condition on one computer in a network and execute a task on another one (provided, of course, that a copy of nnCron is running on both computers)?

The simplest way to do this is to use an intermediate file created on a shared network drive accessible from both computers.

In the first place, you can use this file as a flag: one computer is used to create it, and the other one to watch for it.

You can also use such a file to pass to the second copy of nnCron the text of the task to be executed. Here is an example: one copy of nnCron creates a file named remote_task.spf with the following content:

S" Hello" MsgBox

And on the second computer, the following task is being executed:

#( remote_task
WatchFile: remote_task.spf
Action:
    1000 PAUSE
    S" remote_task.spf" INCLUDED
    S" remote_task.spf" DELETE-FILE DROP
)#

Please also keep in mind that it is possible to run a task stored in a text file by using command line key -runfile

How can I find out the current display resolution?

Word WIN-RECT returns four values which are coordinates of upper left and lower right corners of a specified window. This word takes the window handle of this window as its argument. Therefore, to learn the display resolution you only have to learn the coordinates of Program Manager window: the last two values will show the current display resolution.

Example:

#( test_screen_resolution
NoActive
Action:
    \ getting window handle of Program Manager
    WIN-EXIST: "Progman"
    IF
        \ printing the coordinates of Program Manager window to console
        WIN-HWND WIN-RECT . . . . CR
    THEN
)#

How can I programmatically empty the recycle bin?

1. Create a file clearbin.spf with the following contents:

WINAPI: SHEmptyRecycleBinA shell32.dll
: main 7 0 0 SHEmptyRecycleBinA DROP ;

2. Define a task:

#( clear_task
\ Clearing the recycle bin on hotkey combination Ctrl+Alt+Shift+С
AsLoggedUser
LoadProfile
WatchHotKey: "^@+c"
Action:
    ShowNormal NormalPriority
    START-APP: d:\tools\nncron\nncron.exe -wp -runfile clearbin.spf
)#

Why all these complexities? Well, a user profile should be loaded in order to empty the recycle bin correctly, and a user profile will not load properly without starting a separate thread. However, if you are using Windows 9х, this problem does not affect you, for you can use the following construct right within a task:

 7 0 0 SHEmptyRecycleBinA DROP

By the way, here are some constants you can use in emptying the recycle bin:

SHERB_NOCONFIRMATION 0x00000001
SHERB_NOPROGRESSUI   0x00000002
SHERB_NOSOUND        0x00000004

How can I find short name of the file (8.3) when I'm inside the FOR-FILES: loop?

You can define a special word (say, FOUND-SHORTFILENAME) and use it inside the FOR-FILES: loop.

Example:

<%
: 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
)#

How can I start my own task by double-clicking on nnCron system tray icon?

Just create a postfix word (you can do this right in nncron.ini):

: launch-your-task
  S" your-task-name" SFIND IF EXECUTE LAUNCH ELSE 2DROP THEN
;

and edit the value of nncron.ini variable TrayIconDoubleClick:

TrayIconDoubleClick: launch-your-task

How can I create my own pop-up menu which is shown when right-clicking on nnCron system tray icon?

Create a plain text file menu.f in nnCron home directory and place the following definitions inside this file:

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 ;

\ setting the action for each menu item
: 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

   \ setting one of the menu item as 'default' (should be
   \ executed by double-clicking on nnCron tray icon)
   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
;

Now just edit your nncron.ini like this:

S" menu.f" INCLUDED
TrayIconDoubleClick: def-item-action
TrayIconRightButton: my-menu

That's all! Now you have an example of fully-functional multilevel pop-up menu, that will be shown by right-clicking on nnCron tray icon. Note, please, that the default menu item (the bold one) will be executed by double-clicking on nnCron tray icon as well.

How can I launch a task using windows shortcut (*.lnk)?

This is rather easy if you use the -run <task_name> command line option. Here is the procedure:

1) Create a task. Mark this task NoActive if you don't want this task to be executed automatically:

#( test_task_shortcut
NoActive
Action:
    MSG: "Hi there!"
)#

2) Now create windows shortcut in the desired location: mouse right-click - New - Shortcut and browse to 'nncron.exe'. Edit the Location of the item field like this:

<path_where_nncron_is_installed>\nncron.exe -run test_task_shortcut

Press Next and give the meaningful name for the newly created shortcut (test_task_shortcut for example). Press Finish.

3) That's it. Your shortcut is ready! Double-click it with your mouse to run test_task_shortcut task.

How can I launch a program using windows shortcut (*.lnk)?

It is not difficult at all:

#( 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
)#

The example will look slightly different if you need to authorize the task:

#( 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
)#

There is another one example of launching an application from the windows shortcut with authorization. This example uses JScript. Note the forward slashes in shortcut paths:

#( 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>
)#

How can I copy all the files and all the subdirectories tree?

The easiest solution is to use the nnBackup utility, which was created especially for this purpose:

#( test_backup
NoActive
Action:
    START-APP: nnbackup.exe copy -i "c:\data" -o "d:\backup" -v -s
)#

On the other hand, the problem can be solved by using nnCron as the only available tool. Since FILE-COPY: does not create subdirectories when copying files, you need to have nnCron create them as shown:

#( test_backup1
NoActive
Action:
    RECURSIVE
    FOR-FILES: "c:\data\*"
        IS-DIR?
        IF
            \ creating intermediate directories
            DIR-CREATE: "d:\backup\%FOUND-RELPATH%"
        ELSE
            \ copying files
            FILE-COPY: "%FOUND-FULLPATH%" "d:\backup\%FOUND-RELPATH%"
        THEN
    ;FOR-FILES
)#

How can I restart nnCron right from the given task?

Take a look at the example (restarting nnCron every night, at 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
)#


Forth First Aid

  1. Where can I find more information about Forth programming language?
  2. Where can I use pure Forth in crontabs? Can you give more details?
  3. How can I declare a variable or define a word outside of a particular task, e.g. in the very beginning of a crontab file?
  4. Which string types are used in SP-Forth?
  5. What means does Forth provide to check if two strings are identical?
  6. What other "advanced" ways of working with strings are there?
  7. How to convert a number to a string and vice versa?
  8. What means does Forth provide for creating a simple loop?
  9. How can I "insert" a numerical variable into a text string so that I could use it, for example, in MSG: or in SEND-KEYS:?
  10. And what about a double number? Is it possible to "insert" it into a string, too?
  11. Did I get it right that within a string (between quotation marks) one can place a pair of percent signs ("%%") and insert any sequence of Forth words between them?
  12. How can I see the list of all Forth words in nnCron's dictionary?
  13. Hmmmm... And how can I find the word I need (I only can recall a part of it)?
  14. How can I use value of a variable (or current value on the stack) as a parameter of some word?
  15. How to write data to a file or read from one?
  16. How can I handle lists?

Where can I find more information about Forth programming language?

Here are some useful links for beginners:

  • Forth Tutorial - http://www.softsynth.com/pforth/pf_tut.htm
  • An Introduction to Forth Using StackFlow - http://www.taygeta.com/forth_intro/stackflo.html
  • Build Your Own Forth - http://www.figuk.plus.com/byof.htm
  • JForth - http://home.tampabay.rr.com/jforth/TableOfContents.html (three chapters are quite good: Beginning Forth Tutorial, Intermediate Forth Tutorial and Advanced Forth Tutorial).
  • Summary of Forth Style Conventions - http://www.taygeta.com/forth_style.html
  • A small reference text on basic Forth words (in Russian) - http://www.nncron.ru/download/spf_help.zip

Don't forget to check onine version of Starting Forth, a great book by Leo Brodie - http://home.iae.nl/users/mhx/

There is a newsgroup, COMP.LANG.FORTH, which is dedicated to Forth language.

Where can I use pure Forth in crontabs? Can you give more details?

"Pure" Forth can be used immediately after word "#( task-name". And word ")#" returns nnCron to classic mode. Therefore, you can define any Forth words between "#(" and ")#"

Example:

#( task1
: x1 .... ;
: x2 .... ;
: x3 .... ;
Action:
    x1 x2 x3
)#

#( task2
Action:
    x3 x2 x1
)#

How can I declare a variable or define a word outside of a particular task, e.g. in the very beginning of a crontab file?

Outside of "#(" and ")#", you can use any Forth words or expression by using them within "<% ... %>" construct. This type of construct can be located in any place of a crontab, including its beginning.

Example:

<%
VARIABLE x
VARIABLE y
: z .... x @ .... y ! ;
%>

#( task1
Action: z
)#

Which string types are used in SP-Forth?

1) Character string (au-string):

The strings of this type are most often used strings in SP-Forth. Such a string is specified by a cell pair ( a u -- ) representing its starting address and length in characters. Use a S" xxx" syntax to create character string. For example, after you enter in console

S" my first string"

and press <ENTER>, two values will be placed on the stack - the address of the first character of the newly created string and the number of its characters.

Most of nnCron words, that are working with strings are expecting for character string as their argument. For example, you can use the word TYPE ( a u -- ) to print character string to the console:

S" my first string" TYPE

Pay attention to the fact, that the length of a strings created using S" xxx" syntax can not exceeds 255 characters.

2) Zero-terminated string (az-string):

These strings are used when calling API functions and when the string length can exceed 255 characters: the length of zero-terminated strings is not limited.

Use Z" xxx" or S" xxx" DROP syntax to create zero-terminated string:

Z" null-terminated string"
S" null-terminated string" DROP

Special words are available to convert character string to zero-terminated string and vice-versa:

  • S>ZALLOC ( a u -- az ) - takes a character string, allocates enough memory and records this string with ending zero to the allocated memory; it returns the address of the newly created string. The character count is not stored. In other words, one can record strings of any length (they may be as long as the system would allow).
  • ASCIIZ> ( az -- a u ) - converts zero-terminated string to character string by separating zero-terminated string address to an address and length in characters.
#( test_count
NoActive
Action:
    \ converting character string to a zero-terminated string:
    S" test string" S>ZALLOC
    \ separating string address to an address and length in characters:
    ASCIIZ>
    \ displaying the string in a message:
    MsgBox
)#

3) Counted string (ac-string):

Counted string is a sequence of bytes, that represents the string contents. The first byte in this sequence holds the string length in characters (binary
representation of the number of data characters). This byte is called length character. Counted string in memory is identified by the address of its length character. This string type was widely used in early Forth implementations. Currently there are not too many words, that are expecting for counted strings as their arguments. The length of counted strings can not exceeds 255 characters.

Use C" xxx" syntax to create counted string. In addition, counted string can be created by using the word PLACE

C" counter string"
S" your string" buffer_name PLACE

You can convert counted string to a character string using the word COUNT ( a -- a u ), that separates counted string address to an address and length in characters.

#( test_count1
NoActive
Action:
    \ creating counted string:
    С" test string"
    \ converting counted string to a character string
    \ and printing it to console:
    COUNT TYPE CR
)#

#( test_count2
NoActive
CREATE my_strbuffer 256 ALLOT
Action:
    \ creating counted string:
    S" test string" my_strbuffer PLACE
    \ printing buffer address to console:
    my_strbuffer . CR
    \ separating address to an address and length in characters
    \ and printing character string to console:
    my_strbuffer COUNT TYPE CR
    \ displaying character string in a message:
    MSG: "%my_strbuffer COUNT%"
)#

What means does Forth provide to check if two strings are identical?

You can use word COMPARE which returns 0 if compared objects are identical.

Example:

S" first string" S" second string" COMPARE 0=
IF MSG: "Strings are the same"
ELSE MSG: "Strings are different"
THEN

What other "advanced" ways of working with strings are there?

This is a very difficult question to answer, for there are so many possible answers. To make the answer as precise as possible, let me use you some examples.

Example 1:

#( forth_strings
\ creating 2 strings up to  255 characters each
\ with static memory allocation
CREATE str1 256 ALLOT
CREATE str2 256 ALLOT
Action:
    \ Word PLACE puts a string into specified location
    S" This is a first string" str1 PLACE
    \ Displaying a message with the first string. Using word COUNT
    \  to convert  an address into address with string length.
    MSG: "%str1 COUNT%"
    \ +PLACE adds another string to the specified string
    S" , and this is an addition to it..." str1 +PLACE
    MSG: "%str1 COUNT%"
    \ removing 5 leftmost characters from str1
    \ and placing the result to str2
    str1 COUNT 5 /STRING str2 PLACE
    MSG: "%str2 COUNT%"
    \ removing 5 rightmost characters from str1
    \ and placing the result to str2
    str1 COUNT 5 - 0 MAX str2 PLACE
    MSG: "%str2 COUNT%"
    \ placing the first 10 characters from str1 to str2
    str1 COUNT 10 MIN str2 PLACE
    MSG: "%str2 COUNT%"
    \ placing to str2 the last 10 characters from str1
    str1 COUNT DUP 10 - 0 MAX /STRING str2 PLACE
    MSG: "%str2 COUNT%"
    \ placing 10 characters from  str1 to str2,
    \ starting with the 10-th character
    str1 COUNT 10 /STRING 10 MIN str2 PLACE
    MSG: "%str2 COUNT%"
)#

Example 2:

#( forth_strings1
\ creating 4 strings up to  255 characters each
\ with static memory allocation
CREATE str_1 256 ALLOT
CREATE str_2 256 ALLOT
CREATE str_3 256 ALLOT
CREATE str_4 256 ALLOT
\ A new word,  StringReplace str2 str1 str3 str4,
\ Searches  str_1 for substrings matching  str_3,
\ and if it finds anything, it replaces all found matches by
\ на str_4. The result is placed to str_2.
\ If no matches are found, it places
\ the entire str_1 to str_2, without any modifications
\ The example is not uneversal in that it was written to process
\ a particular phrase.
: StringReplace ( -- )
  str_2 0!
  str_1 COUNT
  BEGIN OVER SWAP str_3 COUNT SEARCH WHILE
  >R SWAP 2DUP - str_2 +PLACE
  str_4 COUNT str_2 +PLACE
  R> str_3 C@ /STRING
  REPEAT
  str_2 +PLACE
  DROP
;
\ Another new word: StringReplace str str str str
\ It can function in the same way
\ that the preceding one, but it is universal
\ because it uses local variables, i.e..
\ it doesn't have to use  str_1, str_2  etc.
: StringReplace2 { a2 a1 u1 a3 u3 a4 u4 \ rest -- a2 u2 }
  a2 0!
  a1 u1
  BEGIN OVER SWAP a3 u3 SEARCH WHILE
  TO rest SWAP 2DUP - a2 +PLACE
  a4 u4 a2 +PLACE
  rest u3 /STRING
  REPEAT
  a2 +PLACE
  DROP
;
Action:
    \ placing a long phrase into str_1
    S" This string is not a very good sample. " str_1 PLACE
    S" But not just a sample." str_1 +PLACE
    \ defining a search phrase
    S" not" str_3 PLACE
    \ defining a replacement phrase
    S" " str_4 PLACE
    StringReplace str_2
    MSG: "%str_2 COUNT%"
    str_2 S" test test test" S" es" S" ouris" StringReplace2
    MSG: "%str_2 COUNT%"
)#

Example 3:

#( forth_strings2
VARIABLE position
\ New word. It is used to search a string for matches
\ with another string and (if any found) to return the position
\  of the first character of this  match.
\ Position numbering starts with 1. If the substring is not found,
\ it returns 0. Of course, it is also possible to start the position count from 0
\ and to return -1 if nothing is found
: StringGetPos { a1 u1 a2 u2 -- pos}
a1 u1 a2 u2 SEARCH IF DROP a1 - 1+ ELSE 2DROP 0 THEN ;
Action:
    \ comparing the strings and writing the result
    \ into variable position
    S" 123456789" S" 567" StringGetPos position !
    \ displaying the result (should be 5)
    MSG: "Position: %position @%"
)#

There are many other words that are used to work with strings. For example:

\ returns 0 if the strings are identical
S" str1" S" str2" COMPARE
\ returns 0 if the strings are identical (not case-sensitive)
S" str1" S" Str2" ICOMPARE
\ returns TRUE if a match is found
S" str1" S" ?tr*" WC-COMPARE
\ the same as SEARCH, but not case-sensitive
S" xxxstryyu" S" STR" ISEARCH

How to convert a number to a string and vice versa?

Number to string:

nnCron has word N>S. Here is its definition:

: N>S ( u -- addr u) DUP >R ABS S>D <# #S R> SIGN #> ;

It is used in this way:

100 N>S \ produces string 100

Similar results can be obtained with the help of construct S>D <# #S #>, and in this case one can specify how many characters should be converted, add necessary characters to the string, and convert characters with a sign:

101 S>D <# #S #> \ produces string 101
101 S>D <# # # # # # #> \ produces string 00101
-101 DUP ABS S>D <# #S ROT SIGN #> \ produces string -101
101 S>D <# # 58 HOLD #S #> \ produces string 10:1

Notes:

  • words <# and #> mark start and end of formatting;
  • word # converts one digit in the current numbering system;
  • word #S converts the entire number;
  • word SIGN inserts a minus sign into output string if the 3-rd number on the stack is negative;
  • word HOLD inserts into the current position any symbol whose ASCII code is currently on stack.

To get a string representation of a number in hexadecimal form, word N>H:

200 N>H \ produces string  C8

String to number:

For this purpose, use S>NUM. It is used in this way:

S" 128" S>NUM \ produces number 128

Example:

#( test_int_to_string
\ picking  IP addresses one by one, in order,  starting with 128.128.128.1
\ and ending at 128.128.128.10
NoActive
CREATE STR 256 ALLOT
VARIABLE NUMBER
Action:
    BEGIN
    S" 128.128.128." STR PLACE
    NUMBER @ 1 + NUMBER !
    NUMBER @ N>S STR +PLACE
    TMSG: "%STR COUNT%" 1
    \ instead of just displaying a resulting  IP address,
    \ you could, for example, "feed" it to HOST-EXIST:
    NUMBER @ 10 =
    UNTIL
)#

What means does Forth provide for creating a simple loop?

If you know in advance how many times the loop should be repeated, then best way to do it would be to use DO ... LOOP construct (definite loop):

10 0 DO <body of the loop> LOOP

Here 10 is the limit and 0 is the index (a number which is incremented by 1 with each iteration). To access the index from the body of the loop, use word "I" (please note that this is an uppercase letter "i", not a slash or vertical bar)—it puts the current value of the index into data stack .

The loop will be executed over and over until the index becomes equal to the limit. Therefore, the above loop will be executed 10 times.

Example:

Action:
    3 0 DO
        \  message  will be displayed 3 times
        TMSG: "Inside the loop" 1
        \ numbering starts with 0, index equals 1
        I 1 =
        \ displaying another message
        IF TMSG: "Second loop" 1 THEN
    LOOP

To cause the index to be incremented by any other number then 1, use word +LOOP:

50 0 DO <body of the loop> 5 +LOOP \ incrementing by 5

To force an exit from a definite loop, use word LEAVE:

Action:
5 0 DO
    \ message will be displayed four times
    TMSG: "Inside the loop" 1
    \ exiting the loop after the fourth iteration
    I 3 = IF LEAVE THEN
LOOP

If the number of iterations is not known, you can use the BEGIN ... UNTIL construct (indefinite loop, which is repeated until a specified condition is met). It is used in the following way:

BEGIN <body of the loop> <condition> UNTIL

Such a loop will be executed at least one time and then its iterations will go on until a certain condition becomes true:

Action:
    BEGIN
        \ repeating this message
        TMSG: "Warning! xxx.txt not exist!" 3
        \ until the following file appears
        FILE-EXIST: "c:\xxx.txt"
    UNTIL

Here is another type of a indefinite loop (or loop with a condition):

BEGIN <condition> WHILE <body of the loop> REPEAT

The loop is repeated until the condition is true.

And here is an example showing you how you can display a value of index (I) without creating an additional variable:

3 0 DO
    I S>D <# 0 HOLD #S S" I=" HOLDS #> 1 TimeMsgBox
LOOP

How can I "insert" a numerical variable into a text string so that I could use it, for example, in MSG: or in SEND-KEYS:?

Here's how:

%VARIABLE_NAME @%

Now this variable's value can be displayed in a message (MSG, TMSG) and/or printed with SEND-KEYS etc.

Example:

VARIABLE MyVariable \ creating a variable
Action:
    13 MyVariable ! \ setting the value of  MyVariable  to 13
    MSG: "MyVariable = %MyVariable @%"
    START-APP: "notepad"
    PAUSE: 1000
    BEGIN \ starting a loop
        SEND-KEYS: "%MyVariable @% {DELAY 300}"
        MyVariable @ 1 - MyVariable !
        MyVariable @ 0 =
    UNTIL \ ending  the loop
    SEND-KEYS: "{ENTER}That's the end, folks!"

Please keep in mind that you can also insert into a text string any Forth word which return a string ( -- addr u) or a 32-bit integer ( -- n). In order to do that, you just have to surround the word by percent signs.

Example:

\ the number of milliseconds since system startup,
\ is inserted into a string
MSG: "%GetTickCount%"

And what about a double number? Is it possible to "insert" it into a string, too?

Sure. Here is an example of this:

#( test_dir_size
NoActive
2VARIABLE size
Action:
    RECURSIVE DIR-SIZE: "c:\cpp" size 2!
    MSG: "c:\cpp size = %size 2@ <# #S #>%"
)#

Handling double numbers is discussed here.

Did I get it right that within a string (between quotation marks) one can place a pair of percent signs ("%%") and insert any sequence of Forth words between them?

Yes, you got it right. "%...%" construct is dynamically processed, that is to say, when the prefix string is parsed, the sequence between "% % " signs is analyzed separately and word EVALUATE is applied to this substring. Please note that if you use postfix notation you will have to use word EVAL-SUBST in order to "unfold" contents of "%...%" construct.

Example:

\ creating a buffer
CREATE buf_ex 256 ALLOT
Action:
\ placing a string to this buffer
S" example" buf_ex PLACE
\ printing the string to console including the contents of  buf_ex
S" string containing %buf_ex COUNT% buffer" EVAL-SUBST TYPE CR
\ displaying a message with the same string
MSG: "string containing %buf_ex COUNT% buffer"

To your information: if a Forth word or a variable returns a string, you can skip the %...% altogether when using postfix notation:

\ "prefix" notation:
MSG: "%USERNAME%"
\ postfix notation:
USERNAME MsgBox
\ of course, you can do it this way too  (but less efficiently):
S" %USERNAME%" EVAL-SUBST MsgBox

How can I see the list of all Forth words in nnCron's dictionary?

That is very simple: open FORTH console, enter command WORDS and hit <ENTER>. But be prepared to see a list of about 3000 words! :)

And the following task will send the entire dictionary to nncron.out so that you can study it later:

#( words-task
NoActive
Action:
    WORDS
)#

(The console must be closed).

Hmmmm... And how can I find the word I need (I only can recall a part of it)?

It is just for such an occasion that nnCron's developer has defined word WORDS-LIKE in plugin tools.spf.

How can I use value of a variable (or current value on the stack) as a parameter of some word?

Since nnCron 1.89rc2 there are special words to use numbers and strings from the stack as a parameters:%n esPICK% and %n esPICKS%.

Besides that, each prefix-type word (ХХХ:) has a corresponding postfix word (either ХХХ, or some other name). And it is these postfix words that should be used when the current value on the stack is used as an argument.

Examples:

BEEP: 1000 500 -> var_name @ var_name1 @ BEEP
WIN-SHOW: "xxx" -> S" xxx" WIN-SHOW
WIN-HIDE: "xxx" -> S" xxx" WIN-HIDE
\ ...
FILE-APPEND: "file" "xxx" -> S" xxx" S" file" FAPPEND
FILE-WRITE: "file" "xxx" -> S" xxx" S" file" FWRITE
FILE-COPY: "file1" "file2" -> S" file1" S" file2" FCOPY

Prefix words of "ХХХ:" type were introduced expressly in order to save users the trouble of puzzling out how to use the reverse Polish notation.

How to write data to a file or read from one?

You can easily write text data to a file using features provided by nnCron. Read the Help sections discussing such words as LOG:, FILE-WRITE:, FILE-APPEND:...

As to reading an entire text file, the simplest way to do this is as follows:

S" file-name" FILE

or even

FILE: filename

The first method is convenient when you have to get the file's name form a variable, and the second one is for use between percent signs (% %), so it takes as its parameter (file name) the sequence of characters to the end of the line.

\ first method
: 2nd-file S" %JT%\test.txt" EVAL-SUBST FILE ;
Action:
    FILE-APPEND: "%JT%\new.txt" "%2nd-file%"

\ second method
MSG: "%FILE: test.txt%"

Example:

#( test_read_from_file
NoActive
\ reading 64 characters from file  test.txt
\ and placing them to array  file_contents.
\ displaying a message with the content of array.
CREATE file_contents 256 ALLOT
Action:
    PAD 64 S" test.txt" FREAD file_contents PLACE
    MSG: "%file_contents COUNT%"
)#

To read information from a file line by line, we'll need to use SP-Forth word READ-LINE. Here is its description:

READ-LINE ( c-addr u1 fileid -- u2 flag ior ): read the next line from the file specified in fileid into memory address c-addr. No more then u1 characters will be read. String buffer c-addr must have length of minimum u1+2 characters (including end of line characters). If the action is successful, flag will be "true" and ior will equal zero. If end of line is reached before u1 characters has been read, then u2 is a number of actually read characters without "end of line" characters. If u1=u2, end of line has been reached already.

#( test_read_by_line
NoActive
\ Reading  file test.txt line by line (in a loop)
\ into array  list-contents
\ and displaying each line in a message box.
\ Lines in file should not be longer then 255 characters.
VARIABLE list-file
CREATE list-contents 258 ALLOT
Action:
    S" test.txt" R/O OPEN-FILE-SHARED THROW list-file !
    \ writing the string into the second postion of array list-content
    BEGIN list-contents 1+ 255 list-file @ READ-LINE THROW WHILE
    \ Number of read characters remains on the stack..
    \ We will save it in the first position of array
    \ in order to get a string with a character count
    list-contents C!
    MSG: "%list-contents COUNT%"
    REPEAT
    DROP
    list-file @ CLOSE-FILE DROP
)#

#( test_read_by_line1
NoActive
\ Reading  file test.txt line by line (in a loop)
\ into variable list-contents
\ and displaying each line in a message box.
USER-VALUE list-file
USER-VALUE list-contents
\ maximum length of line  (number of characters)
10240 CONSTANT max-line-size
Action:
    \ Allocating sufficient space in memory
    \ and recording its address into list-contents
    max-line-size ALLOCATE THROW TO list-contents
    S" test.txt" R/O OPEN-FILE-SHARED THROW TO list-file
    BEGIN list-contents max-line-size 2- list-file READ-LINE THROW WHILE
    \ The number or read characters remains on the stack.
    \ Adding it to address of allocated memory
    \ and adding 0 to get a zero-terminated string
    list-contents + 0 SWAP C!
    MSG: "%list-contents ASCIIZ>%"
    REPEAT
    DROP
    list-file CLOSE-FILE DROP
    list-file FREE DROP
)#

How can I handle lists?

A list is a special type of data structure where each element (node) contains a reference to the next element in the list which unites the data and simplifies navigation of the list. Such a list is often called "linked list". The last element of a list does not contain a reference and returns a zero if you attempt to get the address of the next element. This permits us to easily learn if the list is empty or not. To declare and name a list use word VARIABLE.

Here are the words for working with lists:

  • DoList ( xt list -- ) execute xt for each of the list elements (nodes). xt is the address of the word which should be executed
  • NodeValue ( node -- value ) get the value of a node
  • FreeList ( list -- ) purge the list
  • AddNode ( value list -- ) add a node (with the specified value) in the beginning of the list
  • AppendNode ( value list -- ) add a node (with the specified value) in the end of the list
  • DelNode ( value list --) remove the node containing the specified value
  • InList? ( value list -- node/0) check if a list contains the specified value. This word returns address of the element containing the specified value or returns 0 if this value has not been found.

To illustrate this, let's create an elementary list, add some nodes to it, print their values to console, purge the list and make sure that it is really empty:

#( test_list
NoActive
\ creating a list
VARIABLE MY_LIST
\ defining a word that will print
\ contents of a node to console
: show_values NodeValue . CR ;
Action:
    \ adding nodes and their values to the list
    1 MY_LIST AppendNode
    2 MY_LIST AppendNode
    3 MY_LIST AppendNode
    \ printing to console addresses or the first,
    \ second and third nodes
    MY_LIST @ . CR
    MY_LIST @ @ . CR
    MY_LIST @ @ @ . CR
    \ now printing to console
    \ the values stored in the list nodes
    ['] show_values MY_LIST DoList
    \ printing the same values "manually"
    MY_LIST @ NodeValue . CR
    MY_LIST @ @ NodeValue . CR
    MY_LIST @ @ @ NodeValue . CR
    \ purging the list
    MY_LIST FreeList
    \ making sure that the list is empty:
    MY_LIST @
    IF S" List is not empty" TYPE CR
    ELSE S" List is empty" TYPE CR
    THEN
)#

Word ['] compiles the address of the next word in the definition as a literal, i.e. instead of the actual word we substitute the address where its definition is stored.

Another "real-life" example:

#( task1
NoActive
VARIABLE f-list
: f-action NodeValue ASCIIZ> MsgBox ;
: f-free NodeValue FREE DROP ;
Action:
    ['] faction f-list DoList
    ['] f-free f-list DoList
    f-list FreeList
)#

#( task2
NoActive
Action:
    f-list OFF
    FOR-FILES: x:\xxx\*.*
        IS-DIR? 0=
        IF FOUND-FULLPATH S>ZALLOC f-list AddNode THEN
    ;FOR-FILES
    f-list @ IF task1 RUN THEN
)#


Troubleshooting

  1. WatchConnect doesn't work!
  2. Help! nnCron won't let me to edit my task via GUI!
  3. WatchWin* doesn't work properly with Command Prompt window...
  4. nnCron can't "catch" the application window I need. What's the deal?
  5. Tasks using word IDLE: start at wrong times!
  6. nnCron started to tall back when I try to use words VARIABLE, CREATE... Why?
  7. WatchDir: and WatchFile: don't work in Novell network and return "error №2". What can I do??
  8. Why can't I start an application from a network drive? Why applications which were started from nnCron cannot see network drives?
  9. I have set WatchHotKey: to start a task. After that, this hotkey combination lost the functions it used to perform in other appliations: each time I press this hotkey, the nnCron task is started, no matter what application I'm working in. What's wrong?
  10. nnCron icon is not showing up in system tray if nnCron is used under Terminal Server (Remote Desktop). What is wrong there?
  11. I'm receiving 'Error opening file for writing: nnhook.dll' message when I'm trying to install new nnCron build over the previous one. Help, please!

WatchConnect doesn't work!

Words WatchConnect and WatchDisconnect work only in Windows NT/2000/XP.

Help! nnCron won't let me to edit my task via GUI!

Yes, that is true. Only relatively simple, "easy-to-formalize" tasks can be edited with the help of GUI. Complex task, including a lot of Forth code, regexps, Windows scripting etc., in most cases can only be edited manually, by modifying their source code.

WatchWin* doesn't work properly with Command Prompt window...

nnCron ignores console windows (this is a limitation of Windows OS).

Please keep in mind that word WIN-EXIST: can correctly handle console windows too. So you can try solve the task of "catching" console windows by periodically starting WIN-EXIST:.

nnCron can't "catch" the application window I need. What's the deal?

Most probably, this window has a parent window (probably, unseen) and WatchWin* words are working only with top-level windows (those which don't have a parent). You still can try to catch this child window using FOR-CHILD-WINDOWS: loop.

Tasks using word IDLE: start at wrong times!

It looks like you have run into another limitation of the OS: when some console window (Command Prompt, FAR etc.) is active, Windows ignores user's actions, and idle time counter goes on being incremented, regardless of user's activity.

To be more specific, in Widows 9* only keyboard input is ignored in such a situation, and mouse activity is processed correctly. In Windows 2000, both are ignored.

nnCron started to talk back when I try to use words VARIABLE, CREATE... Why?

nnCron has an option to limit the variety of syntactic constructs which can be used in the beginning of the task definition. File nncron.ini contains a special variable SyntaxRestriction which is used for that purpose. Most likely, it is set to ON in your configuration.

WatchDir: and WatchFile: don't work in Novell network and return "error №2". What can I do?

"Error №2" is ERROR_FILE_NOT_FOUND: The system cannot find the file specified. Another possible error is error №50: The network request is not supported. ERROR_NOT_SUPPORTED.

According to Nicholas, WatchDir: and WatchFile: don't work under Novell yet and hardly will work in near future. Since we have no definite hopes in this respect, I recommend to periodically check for the required file/directory by using FILE-EXIST:; this is just as good as Watch*, as far as functionality is concerned, although, of course, a bit more complex. :)

Why can't I start an application from a network drive? Why applications which were started from nnCron cannot see network drives?

It is because under Windows NT/2000/ХР, nnCron is started as a system service run by SYSTEM (this is a built-in user account). And user SYSTEM doesn't have enough rights to access network drives.

There are several ways to solve this problem:

  • to authorize the task
  • to use task option AsLoggedUser to run applications as the logged-on user
  • to run nnCron service as a particular user who has access to network drives
  • to start nnCron not as a system service but as a regular application (see the description of command line key -ns)

I have set WatchHotKey: to start a task. After that, this hotkey combination lost the functions it used to perform in other appliations: each time I press this hotkey, the nnCron task is started, no matter what application I'm working in. What's wrong?

Since version 1.89b8, nnCron can pass hotkeys to other apps when the task can not be started by WatchHotKey: because of Rule: or Time:. Thus, if you want some apps to receive the same key combination, which is used by nnCron, you can mention these apps in Rule:

#( test_watchhotkey
WatchHotKey: "^s"
\ pass this hotkey to other apps when  'notepad.exe' and
\ 'bred2.exe' are loaded
Rule: PROC-EXIST: "notepad.exe" 0= PROC-EXIST: "bred2.exe" 0= AND
Action:
    MSG: "beep"
)#

You can manipulate with Time: as well:

#( test_watchhotkey1
WatchHotKey: "^@s"
\ pass this hotkey to other apps when current time is not
\ falling to the time slice 14:00-18:00
Time: * 14-18
Action:
    MSG: "beep"
)#

nnCron icon is not showing up in system tray if nnCron is used under Terminal Server (Remote Desktop). What is wrong there?

Just start nnCron not as system service, but as a regular application (using command line switch -ns). This eliminates most of the problems, which arise when nnCron is used under Terminal Server/Remote Desktop.

I'm receiving 'Error opening file for writing: nnhook.dll' message when I'm trying to install new nnCron build over the previous one. Help, please!

Yes, sometimes nnhook.dll becomes locked by one of the processes, making impossible to delete or overwrite this file. Fortunately, there is an easy workaround for this problem: just rename the locked file nnhook.dll manually and start nnCron installation once again. You can safely delete the renamed nnhook.dll after the the next computer boot.


About this Help File

Last modification date: May 18, 2004

Author: Valery Kondakoff
e-mail: support@nncron.ru
FIDONET: 2:5020/163

Help file and nnCron interface was translated into English by Valeri Sivokon
e-mail: translations@nm.ru
Web site: http://translations.nm.ru (translations from English to Russian and Russian to English)

The latest version of nnCron help file can be downloaded here:
http://www.nncron.ru/download/help.zip

Click here to view nnCron help online:
http://www.nncron.ru/help/help.htm

Please let us know if you notice any errors or obsolete information.