Please remember to add a category to the bottom of each page that you create.
See categories help for further details, but most will probably be [[Category:HTC ModelName]].

MortScript

From XDA-Developers
Jump to: navigation, search

Contents

Introduction

A Scripting/Batch Language for Windows Mobile, Windows CE and Windows PC OS developed by Mirko Schenk A.K.A. Mort.

It uses an executable file called MortScript.exe to run the line of commands in a text file saved as a .mscr or .mortrun file

The official site can be visited at: MortScript and Version 4.3 Beta 15 is here

MortScript examples accumulation forum thread.

WARNING

WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING

MortScript is like a knife, it can be a useful tool or it can kill you.
Running other user created or your own scripts can do serious damage to your device, only use installations from a trusted or confirmed source, but the responsibility and choice to use these, is always your own.

WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING WARNING

Useful Tools

Creating script files

A script file can be created with any text editor.
You can even use Pocket Word, but you have to use "Save as - Text" and rename the extension from .txt to .mscr or .mortrun afterwards.
If your editor supports multiple formats, please use “ANSI”.

Some editors set up for MortScript.
Syntax Highlighting for Morscript using Notepad++
MortScript IDE v0.1

Finding coordinates of points on your screen

You can use MyMobiler and take an image of your screen. Then open this with Microsoft Paint, this shows the x, y coordinates of your cursor on the bottom right....

With Version 4.3 Beta 15 you can now use MortScript to get the coordinates. Here is a little script I wrote to do this based on information from others on the discussion thread.

# PickPoint.mscr
Message( "After you close this message, you will have 10 seconds to get to your screen you want to select a point from." )
Sleep(10000)
SleepMessage( 2, "Select your point after this screen closes." )
Sleep(1000)
aMouse = ScreenshotClick()
sMSGOutput = "X = " & aMouse[1] &"^NL^Y = " & aMouse[2]
Message (sMSGOutput)

Based on MortScript V4.3 manual

Providing examples for each command

In the examples I am trying to write short scripts that will show the use of the commands. You should be able to copy the text into a text file and save it as a script file and then run it to see what it does and get a feel for how it works.

In order to get feedback most of these will use the command Message so you will see a result. If you copy this next line into a text editor and save it as a mortscript file (I suggest message.mscr) and then run it, you will get a message screen that has the text and has an ok button to close it.

Message( "Here is my message" )

Glossary

TERM: DEFINITION
Constant: A fixed value, i.e. numbers like "100" or strings like "Test"
Variable: A string that identifies an assigned value.
e.g. x = 5 (So the value "5" is assigned to variable "x")
so...
Message( x ) (The value assigned to variable "x" will be displayed, which is "5").
Expression: A combination of variables, constants, functions (see below) and operators, which results in a single value
e.g. 5*x
or
"Script type: " & ScriptType()
Assignment: Setting a value to a variable, usually done with variable_name=expression
e.g. x = 5 (So the value "5" is assigned to variable "x")
Parameter: Expression results which are passed to commands or functions
Command: An instruction without a return value
e.g. MouseClick or Message
Function: An instruction which returns a value
e.g. SubStr. It's used in expressions, so it can only be used in assignments or parameters.
Control structure: Instructions, which modify the course of the script, like If, Choice, Exit...

Syntax style in this manual

SYNTAX MEANING
bold Fixed value, e.g. the command or function name (this must be included in the command line)
italics Variable value, usually any expression
[...] Optional, can be omitted from the command line (usually, default values will be used in this case)
{...} Can be repeated or omitted
x|y|z Either x, y, or z must be used (usually fixed values).
(...) Grouping (usually to clarify "|" options).

If the characters are bold, they must be entered that way, e.g. parentheses (... ).
Generally, this syntax is used:

Command [ ( Expression {, Expression } ) ] or Variable = Function ( [ Expression {, Expression } ] )

When using one of the few commands which don't require any parameters the parentheses after it are optional i.e. it's up to your liking whether you write e.g. "RedrawToday" or "RedrawToday()".

Predefined variables

Some variables are predefined, to allow better readable instructions. Contrary to other languages, you are able to modify them, but you shouldn't do that:

VARIABLE Initialized value
TRUE, ON, YES 1
FALSE, OFF, NO 0
CANCEL 2
PI 3.1415926535897932384626433832795 (π)
SQRT2 1.4142135623730950488016887242097 (square root of 2)
PHI 1.6180339887498948482045868343656 (φ)
EULER 2.7182818284590452353602874713527 (e)

Variable or Array Element References

[variable_name]

References allow you to access a variable (or array element) by an expression.

They can be viewed like some kind of mixture between seeing the variables as an unnamed array and Eval() (see 9.2.2 Expressions in a string (Eval)).

To refer to a variable, just use an expression that evaluates to a valid variable name (optionally with array element) in brackets.

For example, [Array[1]] will refer to the first element of “Array”. Of course, this doesn't make much sense in that way, because Array[1] would be the same and faster to parse.
But make it [ArrayName & "[" & elem & "]" ], and you'll see the advantage. See Example 2 below.

Example 1: Creating a variable

Creating a variable with the name of the first item in an inifile and setting the value of that variable to the second item in the inifile.

Ini file. Save as produce.ini

[Settings]
fruit=apple
veg=carrot

Script

inifile=SystemPath("ScriptPath") & "\" &  "produce.ini"
foreach xkey, xvalue in inikeys ( inifile, "Settings" )
  [xkey]=xvalue
endforeach

# As a test to prove
Message( fruit & " is a fruit" )
Message( veg & " is a vegetable" )

[xkey] is where we are telling the script to create a variable with the name equal to the value of xkey

Example 2: Building an array

A more complex use is to build an array defining each element as a value from one array with values from another.
In this case the cvs files are similar to an ini file without needing the catagories e.g. [settings]

The first cvs file. Save as context.csv

travel
find

The second cvs file. Save as test.csv

Prague~100 tower city~n~travel
Rome~must see~n~travel
how to reduce weight~~s~find
Bratislava~small capitol~s~travel
how to get a new job~~s~find

The script

sp = SystemPath("ScriptPath")
SourceData = ReadFile( sp\"test.csv")
MainData = Split( SourceData, "^NL^")
ContextData  = ReadFile( sp\"context.csv")
ContextData = Split( ContextData, "^NL^")

For i=1 to (ElementCount(ContextData))
  MainDataIndex = 1
  n=0
  If( ContextData[i] NE "" )
    ForEach record in array(MainData)
    If (Part(record, "~", 4) eq ContextData[i]) 
      n = n + 1
      [ContextData[i] & "[" & n & "]" ] = MainDataIndex & "~" & Part(record, "~", 1)       
    EndIf
    MainDataIndex = MainDataIndex+1   
    EndForEach
  EndIf
Next

#Tests to confirm array is created
ForEach xrecord in array(travel)
  If( xrecord NE "")
    message( xrecord, "Travel")
  EndIf
EndForEach
ForEach xrecord in array(Find)
  If( xrecord NE "")
    message( xrecord, "Find")
  EndIf
EndForEach

[ContextData[i] & "[" & n & "]" ] is where we are telling the script to create an array variable with the name of the value of "ContextData[i]" where "[i]" is the counter to decide which element of the array "ContextData" we are getting the name from and we are then creating an array element numbered the value of "n".

For example the first element of ContextData is "travel" and the first element of MainData that is a travel item is "Prague" so this script's first action is to create an array element "travel[1]=Prague"

Operators

List of all possible operators

All possible operators by priority (highest first):
() are Parentheses - groups functions e.g. If((x EQ 1) OR (x EQ 4)) in the simplist form, but this could be done as If(x EQ 1 OR x EQ 4)
NOT is Negation
^ is Power (x^y is "x" to the "y" power)
* / MOD are Multiplication, division, modulo (remainder of divisions)
+ - are Addition, subtraction
& \ are Concatenation of strings
> >= < <= = <> are Numerical comparisons
GT GE LT LE EQ NE are Alphanumerical comparisons
condition ? true : false are Returns the “true” value if the condition is fulfilled, otherwise the “false” value
AND && are Binary / logical “and”
OR || are Binary / logical “or”

Example for condition

textstring = (textstring eq "")?"Default text":textstring # will set value of textstring to "Default text" if the value textstring has been set to empty "" otherwise value of textstring will be what has been set.

Logical and binary operators

For logical operations (true or false, i.e. &&, || and NOT) there's the following rule:

If the value represents a valid number except “0”, this means “condition fulfilled” resp. “on”, otherwise it's “not fulfilled” / “off”.
i.e. expressions like 5, "10", 1=1, etc. are “true/on”, while 0, "x", 2=1 are “false/off”.
"NOT 5" would return "0" (something not 0 = true will become false = 0),
"NOT (2-2)" will be "1" (2-2 = 0 = false becomes true = 1).

The difference between AND and && resp. OR and || is that for && and || every value which isn't 0 is handled like 1 (because 2 is as “true” as 1). If you use those operators only to combine the results of comparisons or check functions, there'll be no difference, because they'll only return 1 (true) and 0 (false) anyway.

The binary operators AND and OR additionally are useful for are bitwise checks, e.g. ”(x AND 4) = 4” will check whether the 3rd bit (4 = binary 100), is set in the value of variable “x”.

The logical operators && and || are primarily thought for “C hackers”, which are used that 1 AND 2 is not 0 (binary 01 AND 10 would result in 0) but 1 = “true”.

Comparisons

Numerical and alphanumerical comparisons have the same priority, they've been split in the operator list only for better overview.

Since MortScript doesn't support typing, the operator has to decide whether the values are compared as numbers or as strings. This means, "123" < "20" is “false” (because 20 is smaller than 123), but 123 lt 20 is “true” (because the character “1” is smaller than “2”, just like “a” is smaller than “b”).

If you can't memorize the alphanumerical operators: they're just the abbreviations of "greater than", "greater/equal", "less than", "(not) equals", etc.

Handling Conditions

If( expression )
{ instructions }
ElseIf( expression )
{ instructions }
Else
{ instructions }
EndIf

Here is an example of the If command to get the idea started.
Note: Screen( "Portrait" ) returns a true if the screen is in portrait mode otherwise it returns a false. In the script below you will get the second message no matter what the screen mode is as long as it is not "portrait" mode.

   If( Screen( "portrait" ))
      Message( "Screen is in Portrait Mode" )
   Else
      Message( "Screen is not in Portrait Mode" )
   EndIf

You do not need the Else portion like the script below, but if the screen is not in portrait mode there is no message for you to see.

   If( Screen( "portrait" ))
      Message( "Screen is in Portrait Mode" )
   EndIf

Here is an example of the ElseIf command. With this if the screen is neither portrait nor landscape you get no message for you to see.

   If( Screen( "portrait" ))
      Message( "Screen is in Portrait Mode" )
   ElseIf( Screen( "Landscape" ))
      Message( "Screen is in Landscape Mode" )
   EndIf

If you want a message for you to see, add an Else.

   If( Screen( "portrait" ))
      Message( "Screen is in Portrait Mode" )
   ElseIf( Screen( "Landscape" ))
      Message( "Screen is in Landscape Mode" )
   Else
      Message( "Screen is not in Portrait or Landscape Mode" )
   EndIf

The If statement is a way to get specific responses to specific conditions. As an example, in the script just above, each time the script runs only one of the messages will show up because as soon as one of the conditions checked is true, that instruction is run and the script goes to the next line of command after the if group.

Branching

By Values (Switch)

Switch( expression )
Case( value {, value } )
{ instructions }
{ Case( value {, value } )
{ instructions } }
{ Default
{ instructions } }
EndSwitch
 Switch (question ( "Do you wish to reset your device?", "Reset", "YesNoCancel" ))
 Case(YES)
    Message( “You answered yes to reset” )
    Exit
 Case(NO)
    Message( “You answered no to reset” )
    Exit
 Default
    Message( “You did not answer yes or no” )
    Exit
 EndSwitch

With Selection Dialog (Choice, ChoiceDefault)

Choice( title, hint, value, value {, value } )
 Choice( "Test”, “Select a character”, “One”, “Two”, “Three" )
 Case( 1 )
   Message( "One" )
 Case( 2, 3 )
   Message( "Two or three" )
 Case( 3 )
   Message( "Three" )
 Case( 0 )
   Message( "Cancel" )
   Exit
 EndChoice

A window with the title "Test" will open with the text "Select a number" and the choices listed below it. You highlight the choice and pick the okay button. If you pick the cancel button, the message "Cancel" shows and after you pick its ok button, the script exits. Notice that if you pick 3 and then ok you get the message "Two or Three". When you pick ok to close the message, the message "Three" shows up. This is because you did not exit the script as part of Case 2. So the thing to remember with choice is that if you do not exit, then each case will be checked sequentially.

You can also use an array to be your choices.

Choice( title, hint, array )
 ChoiceList=Array( “One”, “Two”, “Three” )
 Choice( "Test”, “Select a number", ChoiceList )
 Case( 1 )
   Message( "One" )
 Case( 2, 3 )
   Message( "Two or three" )
 Case( 3 )
   Message( "Three" )
 Case( 0 )
   Message( "Cancel" )
   Exit
 EndChoice

ChoiceDefault sets a time limit to choose and sets a default choice if you do not choose before the time runs out.

ChoiceDefault( title, hint, default, timeout, value, value {, value } ) or ChoiceDefault( title, hint, default, timeout, array )

This example chooses the third choice as default and gives you 5 seconds to choose.

 ChoiceDefault( "Test”, “Select a character",3,5,"Alpha”, “Bravo”, “Charlie" )
 Case( 1 )
   Message( "Alpha" )
 Case( 2 )
   Message( "Bravo or Charlie" )
 Case( 0 )
   Message( "Cancel" )
   Exit
 Default
   Message( "Charlie" )
 EndChoice

Repeating actions

There are several way to repeat actions. They can be done as long as a certain condition remains unchanged (While), for each value in a list (ForEach) or repeat a certain number of times (Repeat) and (For).

Conditional Loop (While)

While( condition )
{ instructions }
EndWhile

As long as the condition is true, the loop will repeat itself.

While( Question( “Do you want to repeat this script", "Repeater", "YESNO" )= "YES” )
  Message( "You chose to repeat" )
EndWhile
Message( “Goodbye” )

Looping Over Multiple Values (ForEach)

This allows you to sequentially perform an action over a list of items. The list can be an array, strings in an .ini file or other file, list of files in a folder, list of folders in a main folder, or a list of registry values in a key.

ForEach variable{, variable } in type ( parameter {, parameter } )
{ instructions }
EndForEach

Looping over list of expressions:

ForEach variable in values ( value {, value } )
 ForEach xnum in values( "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec” )
   Message( "Month is " & xnum )
 EndForEach

Looping over array contents:

ForEach variable in array ( array_variable_name )
xtrg="5 | 4 | 3 | 2 | 1"

# Create an array
xstring=Split( xtrg, "|", TRUE )
ForEach xnum in array( xstring )
 Message( xnum )
EndForEach

Looping over array contents including index:

ForEach key, value in array ( array_variable_name )
 months = Map( "1", "Jan", "2", "Feb", "3", "Mar", "4", "Apr", "5", "May", "6", "Jun", "7", "Jul", "8", "Aug", "9", "Sep", "10", "Oct", "11", "Nov", "12", "Dec" )
 ForEach xkey, xnum in array( months )
   Message( "Month " & xkey & " is " & xnum )
 EndForEach

Looping over splitted strings:

ForEach variable in split ( string, separator, trim? )
 xstring="5 | 4 | 3 | 2 | 1"
 ForEach xnum in Split( xstring, "|", TRUE )
   Message( xnum )
 EndForEach

Looping over characters of strings:

ForEach variable in charsOf ( string )
 ForEach xnum in charsOf ( "abcdefg" )
   Message( xnum )
 EndForEach

Looping over INI file values:

ForEach variable in iniSections ( file_name [, codepage ] )

Codepage has to do with what language the file is saved in like Greek and can include UNICODE or similar types.

Create an ini file and save as lang.ini

 [French]
 a=b
 c=d
 e=f
 [English]
 g=h
 i=j
 k=l

Create a mortscript

   ForEach xnum in iniSections( "lang.ini" )
       Message( xnum )
   EndForEach

This script will return two messages, one says English and the other says French.

Looping over INI file values including index:

ForEach key, value in iniKeys ( file_name, section [, codepage ] )

Same lang.ini file and this script.

   ForEach xnum, xvalue in iniKeys( "lang.ini", "French" )
       Message( xnum & " is " & xvalue )
   EndForEach

Returns a message for "a is b", "c is d" and "e is f", but none of the items under the section [English]

Looping over registry keys:

ForEach variable in regSubkeys ( root, key )

Example will list one at a time each registry key under HKey Local Machine\Software\Microsoft This loop will not return the key's default value (usually shown as “(Default)” or “@” in registry editors).

 ForEach xregkey in regSubkeys( "HKCU", "\Software\Microsoft" )
   Message( xregkey )
 EndForEach

Looping over registry entries:

ForEach value, data in regValues ( root, key )

Example will list one at a time each registry value under HKey Current User\Software\Microsoft\notepad

 ForEach xregkey, xregval in regValues( "HKCU", "\Software\Microsoft\File Explorer" )
   Message( xregkey & " is set to " & xregval )
 EndForEach

Looping over files:

ForEach variable in files ( search_expression )

Example will list one at a time each file under folder that contains MortScript.exe that has mort in its name.

 # The symbol at the beginning of this line tells MortScript this line is a comment and not to try to find commands in it.
 # SystemPath( “ScriptExe” ) finds the path to the folder that contains MortScrip.exe
 ForEach xfile in Files( SystemPath( “ScriptExe” ) \ "mort." )
   Message( xfile )
 EndForEach

Looping over directories:

ForEach variable in directories( search_expression )

Example will list one at a time each folder under the root folder.

 ForEach xdir in directories( "\." )
   Message( xdir )
 EndForEach

Repeat so many times

Fixed Number of Repeatings (Repeat):

Repeats the commands within {instructions} "count" times. Count must be at least 1.

Repeat( count )
{ instructions }
EndRepeat

The example will give message "1", then "2" and then "3" before stopping.

Repeat ( 3 )
  xnum = xnum + 1
  Message( xnum )
EndRepeat

Simple Iteration (For):

In the first iteration, the value of "variable" is set equal to the value of "start", then the value of "variable" is increased (or decreased, if step is negative) by the value of "step" in each further iteration, until the value of "end" is exceeded (variable's value becomes bigger than end if step is positive or smaller than end if step is negative).

For variable = start to end [ step step_amount ]
{ instructions }
Next

This example will only give message "1" and then message "3" since the step is 2.

 For xnum = 1 to 3 step 2
   Message( xnum )
 Next

Break and Continue

Structure type is for when you want to be sure the script knows where you intend the break or continue to apply. Allowed parameters are: BLOCK_FOR, BLOCK_FOREACH, BLOCK_REPEAT, and BLOCK_TRY. Only for Break additionally: BLOCK_SWITCH and BLOCK_CHOICE (for ChoiceDefault as well).

Break

Break out of the loop you are in and go to the next command line of the script.

Break[ ( structure type ) ]
   y=1
   While( y=1)
       If(Question( “Do you want to repeat this script", "Repeater", "YESNO" )="1” )
           Message( "You chose to repeat" )
       Else
           Break
           Message( "You chose to exit" )
           Exit
       EndIf
   EndWhile
   Message( “Goodbye” )

The message "You chose to exit" does not show up because the break jumps to the first line after the while group. So it shows "Goodbye"

Continue

Stop where you are in the loop and start from the first line of the loop.

Continue[ ( structure type ) ]
   y=5
   While( y>0)
       y=y-1
       If(Question( “Do you want to repeat this script", "Repeater", "YESNO" )="1” )
           Message( "You chose to repeat" )
       Else
           Continue
           Message( "You chose to exit" )
           Exit
       EndIf
   EndWhile
   Message( “Goodbye” )

When you pick "NO" instead of showing message and then exit, it goes back to the beginning of the when group. I set it to stop after 5 runs through the loop otherwise you would have to kill the script to get it to stop.

Blocks with Error Handling (Try, Continue/Break, Catch)

Try
instructions
{ Catch
instructions }
EndTry

Lets you define options that if your test is TRUE you can jump to after the Try group. In the example below, if file.ini and registry ( "HKCU", "Software\Test", "x" ) are empty, and you do not enter a value for ("Input text"), the Break jumps to the Catch that will give you the message "x was neither read nor entered". If you have the ini file the Continue jumps to after the EndTry and you will get the message ("x is: " & x).

file.ini (do not make this file for the first run)

 Test=x

Example

 Try
  x = IniRead( "file.ini", "Test", "x" )
  If ( x ne "" )
   Continue
  EndIf
  x = RegRead( "HKCU", "Software\Test", "x" )
  If ( x ne "" )
   Continue
  EndIf
  x = Input( "Input text" )
  If ( x eq "" )
   Break
  EndIf
 Catch
  Message( "x was neither read nor entered" )
 EndTry
 If(x NE "")
   Message( "x is: " & x )
 EndIf

Sub Routines (Sub, Call/CallFunction, @...)

Create a subroutine at the end of your script file.

Sub subroutine [ ( parameter {, parameter } ) ]
{ instructions }
EndSub

Calling the subroutine within the line of command in the main script:

Call( subroutine {, parameter } )
CallFunction( subroutine, variable {, parameter } )
@subroutine( [ parameter { , parameter } ] )
value = @subroutine( [ parameter { , parameter } ] )

With “Call”, “CallFunction” or an @subroutine() command/function, the script will continue at the line following the “Sub” with the given subroutine name.

When the end of the subroutine (EndSub or ExitSub) is reached, execution continues where it was invoked. In case of @subroutine() functions, this might be in the middle of a parameter expression.

 @MySub( "x" )
 y = @MySub( 1, 2, 3 )
 Call( "Other" & "Sub", @MySub(1,2) + 2 )
 CallFunction( "My" & "Sub", result, 1 )
 
 ######Sub Routines below here ######
 ###MySub####
 Sub MySub( p1, p2 )
   If ( IsEmpty( p1 ) OR IsEmpty( p2 ) )
     Message( "Not enough parameters passed" )
     ExitSub( 0 )
   EndIf
   If ( argc > 0 )
     Message( "More than two parameters passed" )
   EndIf
   Return( p1 + p2 )
 EndSub
 
 ###OtherSub####
 Sub OtherSub
   Message( argv[1] )
 EndSub

Include Sub Routines of Other Files (Include):

Include( file )

If you have a script file that contains subroutines you want to use in your new script you use the command line Include( "mysubs.mscr" ) to add those subroutines without having to type them in.

Other Script as Subroutine (CallScript/CallScriptFunction):

CallScript( MortScript file{, parameter } )
CallScriptFunction( MortScript file, variable{, parameter } )

Executes the given script as if it were a subroutine. See Sub routines (Sub, Call/CallFunction, @... above

Set Return Value (Return):

Return( value )

Returns the given value to an invoking CallFunction or CallScriptFunction call.

Leave Subroutine (ExitSub):

ExitSub[ ( value ) ]

Leaves the current sub routine. If a value is passed, it's returned like with Return(...). Otherwise, either a value set with Return or “nothing” (IsEmpty()) is returned.

Abort Script (Exit)

Exit

Stops executing the script.

 y=1
 While( y=1)
  If(Question( “Do you want to repeat this script", "Repeater", "YESNO" )="1” )
    Message( "You chose to repeat" )
  Else
    Message( "You chose to exit" )
    Exit
  EndIf
 EndWhile
 Message( “Goodbye” )

The message "Goodbye" does not show up because the Exit quits the whole script instead of the while section.

Error Handling (ErrorLevel)

ErrorLevel( error level )

Decides which error messages will be shown. The error level has to be a string (e.g. "syntax"), i.e. not ErrorLevel( syntax ) The default is „error“.

Possible error levels:
Off No error messages: The script might be terminated without any message
critical Critical messages: currently none, reserved for future use
syntax Syntax errors e.g. wrong parameter count or invalid command or function names
error Other errors: e.g. nonexistent windows, trouble writing or deleting registry entries or files, a new document or directory couldn't be created
warn Warnings: e.g. if a file/directory couldn't be removed, copy/move/rename didn't work (target already existing?)

The levels include all levels that are listed above, i.e. with “error” the messages of the levels “syntax” and “critical” are shown, too.

Running Programs Through the Notification Queue

The next three items relate to the notification queue feature of Mortscript.

Execute application at a given time (RunAt)

RunAt( Unix timestamp, application[, parameter] )
RunAt( year, month, day, hour, minute, application[, parameter ] )

The “Unix timestamp” is the time in seconds since 01/01/1970. This variant is interesting in combination with TimeStamp(), e.g. TimeStamp()+86400 for an execution in 24 hours (* 60 minutes * 60 seconds = 86400).

On many devices, MortScripts can't be executed directly. Instead, you have to invoke MortScript.exe with the script as parameter, e.g.

 RunAt( starttime, SystemPath( "ScriptExe" ) \ "MortScript.exe", \ """" & SystemPath( "ScriptPath" ) \ "notify.mscr" & """" )

Another problem: On many PPCs with WM5, the device wakes up and runs the program, but the display stays off, and the device goes back to standby shortly after the program was started. It often helps to invoke ToggleDisplay(ON) at the start of the scheduled script, if not, only a system update or registry hacks might help.

Write a script and save it as test.mscr or whatever

# Ensure the phone wakes up
ToggleDisplay(ON)

#Find path to mortscript.exe
mort = SystemPath("ScriptExe") & "\" & "MortScript.exe"

# This is how the script will know its own name to create the notification by and how the notification will know what script to run
script = """" & SystemPath("ScriptPath") & "\" &  SystemPath("ScriptName") & SystemPath("ScriptExt") & """"

#Removing previous versions by killing any lingering notification
RemoveNotifications(mort, script)

# Something to see that it ran
Message("I'll be back!")

# Set the next notification queue item to run
RunAt( Timestamp()+60, mort, script)

This will repeat the message every minute. Also, it will clean up (remove) the old notifications from the previous run of the script.

Execute application on each power on (RunOnPowerOn)

RunOnPowerOn( application [, parameter ] )

Executes a program every time the device is switched on.

Remove application from "Notification Queue"

RemoveNotifications( application [, parameter] )

Removes the program from the “Notification Queue”, i.e., it will no more be executed automatically at given times (RunAt) or events (like RunOnPowerOn). If there are multiple entries (e.g. multiple “RunAt”s), all of them will be removed.

If a parameter is given, it will be checked and only entries with the corresponding parameter will be removed. Otherwise, all entries with the program will be removed, no matter which parameter is entered in the notification. To remove only entries without a parameter, use an empty string ("") as parameter.

To stop the previous notification script and remove it from the queue, edit the script to only have this in it.

#Removing previous versions

#Find path to mortscript.exe
mort = SystemPath("ScriptExe") & "\" & "MortScript.exe"

# This is how the script will know its own name to create the notification by and how the notification will know what script to run
script = """" & SystemPath("ScriptPath") & "\" &  SystemPath("ScriptName") & SystemPath("ScriptExt") & """"

# kill any lingering notification
RemoveNotifications(mort, script)

Message("Script removed from queue")

You can also use something like dotFreds Task Manager to remove the notification.

You should always write your scripts to remove any possible previous notifications or you queue will get loaded with old ones.