Scripting in the Windows Style

Each flavor of WSH has an associated file type. This section gives a brief example of scripting for each file type, and suggestions that are appropriate in each case. If you need to, see the appropriate documentation for the exact syntax of WSH's XML format, and the syntax of an HTML file.

Invocation by the Browser

Invocation by the Web browser is probably the easiest scripting technique to illustrate, and the most familiar use of WSH. The following is a small HTML file that shows Object Rexx as the scripting language. There are three paragraphs that have the animating power of Object Rexx behind them. Each uses an Internet Explorer pop-up window to denote a particular mouse action. The appropriate activity takes place when the mouse is rolled over the first paragraph, when it leaves the second, and when it is used to click the third.

<HTML>
<!--
/******************************************************************/
/* DISCLAIMER OF WARRANTIES. The following [enclosed]             */
/* code is sample code created by Rexx Language Association. This */
/* sample code is not part of any standard or RexxLA              */
/* product and is provided to you solely for the                  */
/* purpose of assisting you in the development of your            */
/* applications.  The code is provided "AS IS", without           */
/* warranty of any kind.  RexxLA shall not be liable for          */
/* any damages arising out of your use of the sample              */
/* code, even if they have been advised of the                    */
/* possibility of such damages.                                   */
/******************************************************************/
 !-->

<HEAD>
  <TITLE>A simple event</TITLE>
  <script language="Object Rexx" >
::Routine Display Public
   Window~Alert(Arg(1))
   Return   "something to keep the mouseover function call happy"
   </script>
</HEAD>

<BODY BGCOLOR="#ffffff">
  <FONT FACE="Arial, Helvetica" COLOR="#f00000">
  <H1>How to use events</H1>

  <FONT COLOR="#000000">
  <P>Moving the cursor over the following paragraphs will cause two
  events, respectively: one when you move onto the text, and one when
  you leave it. At both times a pop-up message will inform you about this.</P>

  <!-- in both cases the "alert" function of the object "window" is called !-->
  <FONT COLOR="#0000ff">
  <P onmouseout="alert("Cursor left paragraph")" LANGUAGE="Object Rexx">
  Event takes place when cursor leaves this paragraph.</P>

  <P onmouseover="a = Display('Cursor is over paragraph')"
LANGUAGE="Object Rexx">
Event takes place when cursor moves over this paragraph.</P>

  <FONT COLOR="#000000">
  <P>The following paragraph reacts when you click it:</P>

  <FONT COLOR="#0000ff">
  <P onclick="call Display "Thank you! The current time is" time()"," date()"
  LANGUAGE="Object Rexx">Click me!</P>
  </FONT>

</BODY>

</HTML>

The important things to note in this example are:

Additional examples can be found in the Samples\WSH subdirectory of your Object Rexx for Windows installation directory.

WSH File Types and Formats

Two main file types are used by WSH. Both follow an XML format that wraps the script code. The XML tags are interpreted by C/WScript, and direct it to the correct scripting engine to process the code inside. The file type .wsf is used to define scripts that are executed as commands. This is similar to the conventional way of invoking Object Rexx in the Windows environment. The file type .wsc is used to define scripts that are treated as COM objects. The XML tags here denote the properties, methods, and events of the COM object, as well as the correct engine to invoke for scripts.

Note that these XML files are well formed, but not valid. There is no associated Document Type Definition (DTD).

.wsf

The .wsf file type is as easy to invoke as HTML, and is very similar in appearance, with only minor differences. The .wsf file is used to drive the operating system in the same way that an HTML file is used to drive the browser. The file is an Object Rexx script file with an XML wrapper.

The following sample prints the version of the JScript engine and the version of the scripting host. If this file had the name "SimpleORexx.wsf", the command to invoke it would be "CScript //nologo SimpleORexx.wsf", or "WScript //nologo SimpleORexx.wsf".

<?xml version="1.0"?>
<?job error="true" debug="true" ?>

<package id="wstest">

<!--
/******************************************************************/
/* DISCLAIMER OF WARRANTIES. The following [enclosed]             */
/* code is sample code created by Rexx Language Association. This */
/* sample code is not part of any standard or RexxLA              */
/* product and is provided to you solely for the                  */
/* purpose of assisting you in the development of your            */
/* applications.  The code is provided "AS IS", without           */
/* warranty of any kind.  RexxLA shall not be liable for          */
/* any damages arising out of your use of the sample              */
/* code, even if they have been advised of the                    */
/* possibility of such damages.                                   */
/******************************************************************/
 !-->

<!--  Just a small file to demonstrate the *.wsf file format, and
    ---  what Windows provides by default.
    -->
<job idid="RunByDefault">

<!---
  ---   These functions are provided by WSH.
  -->
 <script language="JScript"><![CDATA[


function GetScriptEngineInfo(){
   var s;
   s = ""; // Build string with necessary info.
   s += ScriptEngine() + " Version ";  //  Except this function.  It can
                                       // only be accessed from JScript
                                       // or VBScript.
   s += ScriptEngineMajorVersion() + ".";
   s += ScriptEngineMinorVersion() + ".";
   s += ScriptEngineBuildVersion();
   return(s);
   }


]]></script>
<!---
  ---  Not all of the script needs to be within one tag, or use the
  ---  same language.
  -->
 <script language="Object Rexx"><![CDATA[

Say "This is "GetScriptEngineInfo()
Ver = "Accessing the version info from Object Rexx yields"
Ver = Ver ScriptEngineMajorVersion()"."
Ver = Ver||ScriptEngineMinorVersion()"."ScriptEngineBuildVersion()
Say Ver

WScript~Echo("Done!")

]]></script>
</job>

</package>

The important things to note in this example are:

  • Accept the two XML tags (<? ... ?>) at the beginning as boilerplate, although the debug="true" can also be debug="false" without any detrimental effect.

  • All XML tag names and attributes are in lower case.

  • All XML tags have a beginning and an end tag. The beginning tag looks like <tag>, and the end tag </tag>. Where the tag contains only attributes, and there is no content between the beginning and the end tag, it is acceptable to abbreviate <tag attribute=""></tag> to <tag attribute=""/>.

  • Comments are the same as in HTML.

  • Following the <script> tag is the tag <![CDATA[, and preceding the <script/> tag is ]]>. This tells the XML parser to ignore this text. If this is not done, many of the operators and special characters in the script will confuse the XML parser, and it will abort the script.

  • There are several <script> tags; here Object Rexx is invoking a JScript function.

  • The functions that begin with ScriptEngine... and the WScript object are not declared, yet Object Rexx finds them. They are implicit, and their scope is global.

Additional examples can be found in the Samples\WSH subdirectory of your Object Rexx for Windows installation directory.

.wsc

The .wsc file type is much more elaborate than the .wsf type. Since a .wsc file is used as a COM object, the XML must describe the object in a way that is independent of the script language. Consider the following example.

<?xml version="1.0"?>
<?component error="true" debug="true" ?>

<package id="SimpleObjectRexxCOMScriptTest">

<!--
/******************************************************************/
/* DISCLAIMER OF WARRANTIES. The following [enclosed]             */
/* code is sample code created by Rexx Language Association. This */
/* sample code is not part of any standard or RexxLA              */
/* product and is provided to you solely for the                  */
/* purpose of assisting you in the development of your            */
/* applications.  The code is provided "AS IS", without           */
/* warranty of any kind.  RexxLA shall not be liable for          */
/* any damages arising out of your use of the sample              */
/* code, even if they have been advised of the                    */
/* possibility of such damages.                                   */
/******************************************************************/
!-->


<!---
  ---  An example script to demonstrate the features provided by the
  ---  COM structure.  Register our own typelib, create methods,
  ---  and create a property.
  !-->


<!---

  ---    This section registers the script as a COM
  ---  object when Register is chosen from the list of commands
  ---  that appear when this file is right-clicked.
  ---
  ---    The value of progid= is how the world will find us.
  ---  Two GUID's are needed, one for the COM object, and one
  ---  for the Typelib that will be generated. The routine's
  ---  Register and Unregister mimic those required in a COM
  ---  *.dll.  Even within these routines, there is full
  ---  Object Rexx capability.
  !-->
<component id="SimpleORexxCOM">
  <registration
     progid="SimpleObjectRexx.Com"
     description="Test of the COM scriptlet interface as seen by Object
     Rexx."
     version="1.0"
     clsid="{6550bac9-b31d-11d4-9306-b9d506515f14}">
   <script language="Object Rexx"><![CDATA[
::Routine Register Public
  Shell = .OLEObject~New("WScript.Shell")
  Typelib = .OLEObject~New("Scriptlet.TypeLib")
  Shell~Popup("We are registering, n o w . . . .")
     /*
      *  Please note that the name that follows must match
      * our file name exactly, or this fails when registering
      * with an "OLE exception", Code 800C0005 or Code 800C0009.
      */
     Typelib~AddURL("SimpleORexxCOM.wsc")
     Typelib~Path= "SimpleORexxCOM.tlb"
     Typelib~Doc = "Test component typelib for Simple Object Rexx.Com"
     Typelib~Name = "Test component typelib for Simple Object Rexx.Com"
     Typelib~MajorVersion = 1
     Typelib~MinorVersion = 0
     Typelib~GUID = "{6550bac5-b31d-11d4-9306-b9d506515f14}"
     Typelib~Write()
     Typelib~Reset()
     Shell~Popup("We've really done it n o w . . . .")

   ::Routine Unregister Public
     Shell = .OLEObject~New("WScript.Shell")
     Shell~Popup("We are outa here!")

     ]]></script>
    </registration>

<!---
  ---    This section is what describes this COM object to the outside
  ---  world. There is one property, and there are two methods named.
  ---  One of the methods is the default, since its dispid is 0.
  ---  Object Rexx does not support calling the default in a shorthand
  ---  manner. All calls are as follows:
  ---
  ---  Obj = .OLEObject~New("SimpleObjectRexx.Com")
  ---  Obj~DefaultMethod("Some Parm")
  ---
!-->
<public>
  <property name="ExternalPropertyName"
internalName="InternalPropertyName" dispid="3">
     </property>
  <method name="NamedRoutine">
     <parameter name="NamedParameter"/>
     </method>
  <method name="DefaultMethod" dispid="0">
     <parameter name="ReallyForTheOutsideWorld" />
     </method>
  </public>


<!---
  ---    This is the actual script code. Note that the property
  ---  is declared at the highest scope. If this is not done,
  ---  then the property will not be found, and the script
  ---  will not abend when the property is referenced.
!-->
  <script language="Object Rexx" ><![CDATA[
InternalPropertyName = "Sample Property"

::Routine NamedRoutine Public
say "There are "Arg()" args."
a = RxMessageBox("Is executing, now.","NamedRoutine","OK",)
  Return

::Routine DefaultMethod Public
say "There are "Arg()" args."
a = RxMessageBox("Is executing, now.","DefaultMethod","OK",)
WShell = .OLEObject~New("WScript.Shell")
a = WShell~Popup("A message via an implicit COM object.");
  Return  "a value"

  ]]></script>

</component>

</package>

The important things to note are:

  • There are three distinct sections in this file, and two of them contain Object Rexx code.

    • The first section identifies this as a COM object. The progid=, version=, and clsid= attributes of the <registration> tag are given so that this file can be entered into the Windows Registry as a COM object. This is one of the sections that has code. The code here generates the Typelib when the script is registered as a COM object.

    • The second section lists all of the entry points to this object, their parameters, and any data that is being externalized. When the Typelib is generated, this information is used to create its contents. This is more of a designer's wish list than something that is enforced. The designer states what he or she believes to be the minimal number of parameters. The designer must then enforce this within the subroutine. However, be aware that other routines calling these listed here may pass more, or fewer, parameters than this section suggests. This is especially true for procedures named with <method> tags. WSH passes the named parameter THIS, which Object Rexx passes on to the routine.

    • The third section is the actual code.

  • Read the comments before each section; they contain important information about that particular section.

  • Any code that is put in the same scope as the property being assigned its value is called immediate code. Immediate code is executed when the COM object is loaded, before any of its pieces (methods, properties, or events) are accessed. It executes even if none of the external pieces are accessed.

Additional examples can be found in the Samples\WSH subdirectory of your Object Rexx for Windows installation directory.

Invocation from a Command Prompt

Invocation from a command prompt covers many possible means:

A conventional Object Rexx file is one in which every line is valid Object Rexx syntax, and makes no assumptions about global objects. It contains no XML wrapper as described in the section on .wsf files.

Consider what happens when a file named WSH.rex contains the single line: 'WScript~Echo("WSH is available.")'; another file named WSH.wsf contains the same line of code in the .wsf wrapper described above; and another file, Safe.rex, contains the line "Say 'Conventional Rexx file' Arg(1)".

As a Conventional Object Rexx File

From a command prompt, "Rexx WSH.rex", will stop with an error 97: Object "WScript" does not understand message "Echo".

From a command prompt, "Rexx WSH.wsf", will stop with an error 35: Invalid expression detected at "<".

From a command prompt, "Rexx Safe.rex GREAT!", produces one line of output, "Conventional Rexx File GREAT!".

As a Windows Scripting Host File

Both CScript and WScript will invoke a file from the command line. All of their parameters begin with a double slash. Two useful parameters are: //nologo and //e:. The //nologo parameter prevents the banner from being displayed, and //e: tells WSH not to interpret this file, and to pass the complete contents to the named engine. Enter CScript or WScript with no parameters or file names to see a complete list of parameters.

WScript converts all WScript~Echo() output into pop-up text boxes, whereas with CScript they are displayed as output lines in a DOS window. If CScript is executed from outside a DOS window (either from Start->Run, or from the use of Windows Explorer), a DOS window will be created for the output. Note, however, that it is removed when the script is complete. Usually, this means that the lifetime of the DOS window is long enough for a person to detect it, but not to actually read it.

From a command prompt, "cscript //e:"Object Rexx" WSH.rex" produces one line of output, "WSH is available." From a command prompt, "wscript //e:"Object Rexx" WSH.rex", produces a pop-up box that contains the title "Windows Script Host", an OK button, and the text "WSH is available."

From a command prompt, "cscript //e:"Object Rexx" WSH.wsf" will stop with an error 35: Invalid expression detected at "<". From a command prompt, "wscript //e:"Object Rexx" WSH.wsf", will seem as if it produced no output at all. Though Object Rexx is still generating the error message, WScript does not detect the output to STDOUT, and no DOS window is created.

From a command prompt, "cscript //e:"Object Rexx" Safe.rex GREAT!" produces one line of output, "Conventional Rexx File". Note the lack of the word GREAT!. WSH does not pass the command line args to Object Rexx. The WScript~Arguments method/object must be used, as in the following code:

/*    Note that the WScript object is not declared. It just appears
 * courtesy of CScript and WScript
 */
Say  "The arguments as WSH sees them."
If WScript~Arguments~length > 0 Then Do I = 0 To (WScript~Arguments~length - 1)
  Say i WScript~Arguments(i)
  End
Else Say "No arguments were sent."

From a command prompt, "wscript //e:"Object Rexx" Safe.rex GREAT!", will seem as if it produced no output at all. As when WSH.wsf is run by WScript with a known engine (see the relevant paragraph earlier), Object Rexx is still executing the SAY instruction, WScript does not detect the output to STDOUT, and no DOS window is created.

Invocation as a COM Object

This is the most intricate of the script files to execute. Multiple steps are involved, and there is no command that directly invokes the script. C/WScript cannot be used to directly invoke a .wsc file. It must be processed by other means first. Once created, the file must be registered.

Once registered, this can be invoked by any program that can call COM objects. It does not have to be another script; that program could be Visual Basic or C++. If the COM object is to be invoked by Visual Basic, it is a good idea to generate a Typelib. This helps Visual Basic to form its parameter list.

Registering the COM Object

Use either of two methods to register a .wsc file. The first is to right-click it in Windows Explorer, and choose Register from the list of commands that appears. The second is from the command line. For example, to register WSH.wsc, at a command prompt, enter the command, "regsvr32 /c WSH.wsf".

The GUID in the clsid= attribute must be unique for the machine the COM object is being registered on. In other words, no other COM object may use the GUID. Once it is registered, the script cannot be moved. The path to a COM object is stored in the Registry as a complete path. If the script is moved, then Windows will not know how to find it.

Generating a Typelib

Use either of two methods to generate the Typelib. One is using code in the Register method of the <registration> section. See the sample .wsc code above for an example of this. The other is to choose Generate Type Library from the list of commands that appear when the file name is right-clicked in Windows Explorer.

Invoking

The easiest method of invoking the script, once it is a COM object, is to use an OLE-enabled application, such as Object Rexx. The following Object Rexx code shows how to define the object in Object Rexx, and invoke its methods.

<?xml version="1.0"?>
<?job error="true" debug="true" ?>

<package id="wstest">

<!--
/******************************************************************/
/* DISCLAIMER OF WARRANTIES.  The following [enclosed]            */
/* code is sample code created by Rexx Language Association. This */
/* sample code is not part of any standard or RexxLA              */
/* product and is provided to you solely for the                  */
/* purpose of assisting you in the development of your            */
/* applications.  The code is provided "AS IS", without           */
/* warranty of any kind.  RexxLA shall not be liable for          */
/* any damages arising out of your use of the sample              */
/* code, even if they have been advised of the                    */
/* possibility of such damages.                                   */
/******************************************************************/
 !-->

<!---
  ---     This example shows how easy it is to
  ---  invoke a COM object that is a script by means of
  ---  Object Rexx.
  -->
<job id="RunByDefault">
  <script language="Object Rexx"><![CDATA[

Say "Creating the ObjectRexx.Com object. "
Sample = .OLEObject~new("SimpleObjectRexx.Com")
Say "Just before the default method "
ReturnValue = Sample~DefaultMethod("A parm");
ReturnValue = Sample~NamedRoutine("A parm");
  ]]></script>
  </job>
</package>

Object Rexx is not the only way to invoke the script. Any application that can call COM objects can invoke it. For further information, see the relevant documentation.

Events

When scripts are turned into COM objects they can initiate events. Several types of events are supported: the default COM events, HTML or Behavior events, and ASP events. The type of event that the COM object supports is denoted by the type= attribute of the <implements> tag. An in-depth discussion of events and how to create, code, and handle them is beyond the scope of this documentation. However, there are a few concepts that should be mentioned.

COM Events

In the <public> section, where the external attributes of the COM object are disclosed, <event> tags can be added. They name the events that the script could possibly activate. When the script that calls the COM object instantiates it by using the method provided by WScript, rather than the Object Rexx method, it can inform the COM object that it will handle the events that the COM object fires. Note that when a script agrees to handle the events of an object, it must handle all of the events of that object.

For example, suppose the public section looked as follows:

<public>
  <event name="Event1" />
  <event name="Event2" />
</public>

and the script that instantiated the COM objects code looked as follows:

RexxObject = WScript~CreateObject("ObjectRexx.Com","Event_");

In that case, the instantiating script would be required to define the two routines below.

::Routine Event_Event1 Public
::Routine Event_Event2 Public

It is not acceptable if only one of the events is supported. Also, note the naming convention. The second parameter of CreateObject() names the prefix of the routine name that will support the event. The remainder of the routine name is composed of the event name from the <event> tag of the <public> section. Neither the prefix nor the empty string can be elided. In other words, neither CreateObject("object",) nor CreateObject("object","") is allowed. The script host will generate an error.

Internet Explorer Events

When coding Internet Explorer events, the user should be aware of the following. The section of code between the quotes on an HTML tag has to be complete, with correct syntax. The THIS object is implicity defined for the scope of the section. If the section calls a function, and the function needs access to THIS, then the section must pass THIS as a variable to the function. THIS is the browser's object that represents the tag that the event was fired from. For all of the exact properties and methods associated with THIS, see the documentation for the corresponding tag.

To illustrate, consider the following code extract:

<p onmouseover="Call RxMouseOver This" id="SomeTag">
"HOT" text, get your "HOT" text right here
</p>

<script language="Object Rexx">
::Routine RxMouseOver Public
Use Arg This
Text = "This is a <"This~tagName"> tag named '"THIS~id"'"
a = RxMessageBox(Text,"RxMouseOver","OK",)
Return "OK"
</script>

The code for the onmouseover= "Call RxMouseOver This" is complete and correct. If a function call had been used instead, the code would be something similar to "a = RxMouseOver(This)". Do not forget to assign the results of a function call to something. If THIS is not passed as an argument to RxMouseOver, it will have the default value of a string whose content is THIS.

To cancel Internet Explorer events, the Object Rexx Boolean value .false must be returned. The integer values 0 and 1 are not appropriate alternatives. For example:

<a onmouseover="call SomeFunction; return .false" href="someURL">

WSH Samples

There are more features to WSH than are listed here. The Samples\WSH subdirectory of your Object Rexx for Windows installation directory contains some appropriate samples and an explanation of the relevant features. Before running any samples, make sure that the latest version of Windows Scripting Host is installed on the machine.

Several sample files are stand-alone; these are all of the file types .htm, .wsf or .rex. However, all of the samples covering the aspects of using Object Rexx scripts as COM objects are in pairs or, in one case, a group of three. One file is the COM object, and the other is the script that instantiates it. All of the COM objects are of the file type .wsc. The files that instantiate them are either .wsf or .rex. The sample that uses three files illustrates the include= attribute of the <script> tag. All of the .wsc files must be registered before they can be used (see Registering the COM Object).

To view the .htm samples, use Windows Explorer to view the sample directory. Right-click the desired sample file, and choose Open With->Internet Explorer from the menu that appears.

To view the .wsf or .rex samples, use either a DOS window or Windows Explorer. From Windows Explorer, double-click the desired file. It will execute automatically. From the DOS window, make the sample directory the current directory, and use either CScript or WScript to execute the sample. The file Print.rex is an include file. It is not intended for direct execution.

Samples whose names begin with "w" use only Window pop-up boxes for output. Samples without the leading "w" are best viewed from the DOS window. They produce output that will not display in a Windows-only environment. Samples whose name begins with "call" are used to instantiate the COM objects once they are installed. If they are not installed, the error message "Error 98.909: Class "......" not found" will be issued.