Interpretation of and Deviation from the WSH Specification

This section deals with a number of issues to do with interpreting the WSH specification and with deviations from it.

Windows Scripting Host (WSH) Advanced Overview

Accommodating to WSH has necessitated some deviations from the Object Rexx standard. To best understand what these deviations are, you need to be aware of the components of WSH. In addition to the products that are hosts, there are special COM objects and different mechanisms for initiating the engine.

Hosts Provided by Microsoft

Microsoft provides three fully-implemented scripting hosts. They are Microsoft Internet Explorer, CScript, and WScript. As an expansion on the concept of using a scripting language to drive external products, CScript and WScript were developed to control the Windows operating system. The two modules are so similar that they are sometimes referred to as C/WScript. CScript is intended to be used from the command line, and WScript is best used in the Windows environment. Both provide their services to the script through the WScript object. Using the default method for output WScript~Echo(), CScript sends the output to a console screen in the same manner as the Object Rexx command Say, whereas WScript~Echo() in a script controlled by WScript will create a pop-up box in which the user must click the OK button to make it disappear.

These are not the only Microsoft products that have WSH capabilities. The core of C/Wscript is scrobj.dll. Several Microsoft products implement various parts of the scripting host architecture by using scrobj.dll.

Additional COM Objects

Since JScript and VBScript were developed primarily to manipulate the Web browser DOM (Domain Object Model), they lack many of the features associated with a language that drives an operating system. They have no native facilities for I/O (Input and Output), or for controlling the file system. These powers are granted through several additional COM objects.

Most of the literature on WSH describes these objects. Most of the features in these additional COM objects are native to Object Rexx; for further information, see The OLEObject Class. Further documentation on the additional COM objects is readily available from other sources.

Object Rexx, since it is OLE-enabled, has access to all of these objects. OLE (Object Linking and Embedding) is an advanced protocol based on COM. Be aware that the automatic object WScript is only available when Object Rexx is activated by C/Wscript. Access cannot be obtained if Object Rexx is initiated by Internet Explorer, or when it is initiated in the classical method "Rexx someFile.rex", either from the command line or from a command issued by the file explorer as an association with a file type. This is not a limitation of Object Rexx. It is a consequence of the manner in which this object is loaded.

The WScript object is not registered in the Windows Registry. It exists only when C/WScript dynamically creates it and then passes the pointer to Object Rexx. All scripting languages, including JScript and VBScript, have this limitation.

Where to Find Additional Documentation

The best source of up-to-date information on WSH is the World Wide Web. The keyword to use when searching the help facilities provided by Microsoft is "scripting". If you are using a search engine (available when you click "Search" on your browser's menu bar), insert "activescript" as the keyword.

In addition, there are several books on the subject. When browsing online bookstores, use the keyword, "activescript". The MSDN (Microsoft Developers Network) is a good reference source for the syntax of the XML used to define the WSH files.

Note that the correct file type to use for the XML file that C/WScript processes is .wsf. Existing documentation often states misleadingly that the file type to use is .ws. C/WScript requires the full file name, including file type, and it processes the file correctly only when the file type is .wsf. This seems to be hard coded into C/WScript, and no workaround is available.

Object Rexx in the WSH Environment

Object Rexx is fully compatible with the WSH environment. Interaction with JScript and VBScript is transparent. Legacy applications developed with these languages will not have to be discarded.

Object Rexx Features Available

All of the features normally associated with Object Rexx are available when Object Rexx is loaded by WSH. In addition, OLE support is loaded automatically. Scripts do not need to include '::requires "ORexxOLE.CLS"'. However, when Object Rexx is invoked by Internet Explorer, it honors the "sandbox" settings that the user has set in the browser's security panel. Access to I/O, the file system, external commands, and COM objects may not be granted.

Changes in Object Rexx due to WSH

To comply with the WSH definition, some of the scoping rules and default behavior of Object Rexx have been modified. The default behavior has been altered to allow some objects to be implicitly defined. The normal scoping rules now allow "global" objects to appear at any procedure depth, without requiring the use of EXPOSE, or the passing of the object as a parameter. Second-level objects can now be accessed without specifying the first level. These changes only apply to objects that WSH provides to Object Rexx. All other objects and variables behave in the standard ways.

Normally, access to objects requires explicit declaration through one of the OLE methods, as in:

"Window = .OLEObject~new("window")"

Some, like WScript, can only be passed in; others - window, for example - have a history of being implicitly available. Full documentation is not yet available as to what objects have these features, and therefore only a few will be mentioned.

As previously mentioned, the WScript object is implicitly available when Object Rexx is started by C/WScript. The "window" object is implicitly available when Object Rexx is initiated by Internet Explorer. For events associated with an HTML tag - ONMOUSEOVER, for example - the scriptlet in the HTML tag has THIS implicitly defined. Unlike "WINDOW", THIS is not global. Typically, this scriptlet calls a procedure, and THIS must be passed to the procedure if the procedure needs to reference THIS.

Normally, you reference an object by naming the top level object, followed by the objects at second and subsequent levels, separated by the tilde symbol (~). However, in order to emulate the current behavior of Internet Explorer, the engine must resolve object names starting at the second level to the appropriate top level that owns them. The shorthand "Document~WriteLn()" or "Alert()" is just as acceptable as "Window~Document~WriteLn()" or "Window~Alert()". It is preferable, as good coding practice, to explicitly state this relationship. Stating "Doc = Window~Document" removes all doubt as to which global object WriteLn() is associated with when the statement "Doc~WriteLn()" is encountered.

Note: This applies only to global objects supplied by WSH. Objects created in or supplied by Object Rexx must be named in the normal fashion.

Parameters

A called routine may receive more parameters than expected. This is not necessarily an error on the caller's part; WSH adds extra parameters on occasion. When WSH does this, Object Rexx adds the parameters at the end. There is an exception to this. The documentation is ambiguous in certain sections about defining properties for scripts that are used as COM objects. If the XML that defines the script states that a name should be a property, but Object Rexx finds it defined as a function, then Object Rexx will prepend the parameter list with GET or PUT, depending on the direction of the property access. For more information, see the sample file Call_ExtraParms.wsf in the Samples\WSH subdirectory of your Object Rexx for Windows installation directory.

Properties

WSH defines properties as variable values that a COM script exposes to outside routines, or strings and numbers extracted from a Typelib. Properties are to be treated as global variables within the accessing script. Properties can be implemented as variables or as functions.

Object Rexx supports declaring and defining properties in the intent of the specification (see the section on .wsc files). That means that the variables at the highest scope, the closest to what could be considered as global, may have their values exposed as properties for other programs to use.

For another program to reference these properties, it must instantiate the COM object, and the object name must precede the property name. For example:

Object = .OLEObject~New("SimpleObjectRexx.Com")
/*  The next line is a property GET */
Say "The value for ExternalPropertyName is:" Object~ExternalPropertyName
Object~ExternalPropertyName = "New Value"  -- This is a PUT

If you experiment, you will find that there is also a shorthand method, as follows:

Object = .OLEObject~New("SimpleObjectRexx.Com")
/*  The next line is a property GET */
Say "The ExternalPropertyName value is:" Object~ExternalPropertyName()
Say Object~ExternalPropertyName("New Value")

In the case of the second reference, the method is both a PROPERTYGET and a PROPERTYPUT. It gets the old value, replacing the current one with the parameter inside the parenthesis. If more than one parameter is passed, the additional parameters are ignored.

Note: This does not always work, and is supported only by Object Rexx. The cases in which it does not work are where the properties are defined as functions and not as simple variables. These calls are, in fact, methods and not property references. When Object Rexx receives method calls for properties, it converts them to the appropriate action. In the case of properties defined as functions, WSH translates the property action into a function action. However, when the action is initiated as a function and not as a property, WSH does not always make the appropriate or correct translation.

Object Rexx does not support the concept of global variables. For a COM script to reference its own properties, and to react to outside scripts changing them, then the properties have to be global. To meet the requirement that properties are global in scope within the defining script, the Built-In Function (BIF) Value() has been expanded to accept "WSHPROPERTY" as a selector when referencing properties. As with variables accessed with the "ENVIRONMENT" selector, these variables persist only during the life of the COM object that supplies the properties. The next time that the COM is run, the values will be at initial coded state.

The WSH supports various syntax combinations in the case of implementing a property as a function. In all combinations, the function is named in the <property> section or tag. It assumes that, when no function is named, the property is a variable; however, it does not enforce this assumption. It is possible to name a property and define it as a function. Object Rexx defines this to mean that the function must be invoked whenever a property access is attempted. Object Rexx notifies the function of the intended access direction by inserting GET or PUT as the first argument, and shifting all original arguments accordingly; that is, the original first argument is the second, the second is the third, and so on. For a demonstration of this behavior, see the Call_PropertyORexx.wsf sample in the Samples\WSH subdirectory of your Object Rexx for Windows installation directory.

The WSH also establishes that Type Library variables may be made accessible to the script. This violates the default value and scope mechanisms of Object Rexx. To meet the requirement that properties are global in scope within the defining script, the Built-In Function (BIF) Value() has been expanded to accept "WSHTYPELIB" as a selector when referencing elements in a Type Library. As with variables accessed with the "ENVIRONMENT" selector, these variables (because they are external to Object Rexx) are global and persist only during the life of the COM object that supplies the properties. In addition, they are read only. They are immutable; they cannot be changed.

The Object Rexx "Sandbox"

Object Rexx contains a feature known as the Security Manager. When this is enabled it can restrict and audit the other native abilities of Object Rexx. When used with WSH, Object Rexx honors the IObjectSafety interface and its methods GetInterfaceSafetyOptions() and SetInterfaceSafetyOptions() by translating their calls into Security Manager settings. This means that when Object Rexx is in the Internet Explorer's sandbox, it will restrict itself to the user's settings. The most secure situation is one where Object Rexx does not interact with the user's desktop (no reads or writes to the hard disk, no external commands, and so on).

Implications of Browser Applications That Run Outside the "Sandbox"

The most useful aspect of this feature is that the user may select the most secure settings for the Internet, but allow desktop interaction for pages delivered by the local intranet server. In keeping with the current trend in IT, Object Rexx allows users to leverage their investment in desktop software. This facility is intended for clients who use the intranet to lighten the client, or put a Web interface on legacy applications. A lighter client desktop means less software on the user desktop to maintain.

Features Duplicated in Object Rexx and WSH

Several features are available from both WSH and Object Rexx. However, the overlap is not exact, and knowing the differences can aid the user in deciding which is more appropriate to use.

Declaring Objects with Object Rexx or WScript

When instantiating COM or OLE objects as Rexx objects, either the native Rexx .OLEObject~new() method, or the WScript~CreateObject() method can be used. The WSH method has the advantage of allowing the script to support the events that the object might fire. This is part of its definition, and no scripting language will have access to this ability in its native object enabler. The disadvantage is that it is a COM object performing a function that can be done internally.

Another disadvantage of using the WSH method becomes evident if the script is executed outside of the context of WSH. The WScript object will not exist. Therefore, unless the ability to sink events is necessary, it is suggested that the native Object Rexx method be used.

Subcom versus the Host Interface

With the advent of WSH, there are two ways to use Object Rexx to drive a product. The first is through the Object Rexx Subcom interface. The second is for the product to become a Windows Scripting Host. The advantage of the WSH interface to the product is that it is a COM interface. This positions the product to take advantage of DCOM. This interface also allows the package developed by the user to pass objects to Object Rexx.

The disadvantage is the loss of richness contained in the Subcom interface, and the loss of the close integration that a .dll connection has over a COM connection. The Subcom interface allows the package to tailor Object Rexx in ways that are not possible through the COM interface, especially when the Object Rexx Exit Handlers are implemented.

When writing a product that will be a WSH to Object Rexx, refer to the sections "Concurrency" and "COM Interfaces" in "Windows Scripting Host Interface", in the Object Rexx for Windows: Programming Guide.

.dll vs COM

There are several issues that should be considered when a choice needs to be made between a COM or a .dll interface. These issues stem from the intended purposes of each interface.

The .dll interface was developed to extend code reuse by allowing global scope subroutines and functions to be externalized into a module that is separate from the executable. When more than one executable wanted these functions, they all shared the same code that was loaded into memory. The code that was in the .dll executed in the frame of the .exe module. It had the same address space and other environmental parameters. Multiple copies of a *.dll code exist on a machine at one time. The first one that was found in the search path was loaded.

COM was developed to embody a flat model world; only one copy per machine. It was developed to solve two problems with the *.dll interface. The first was entry point resolution, and the other was using the wrong *.dll because the search path was not correct. COM does this by using RPC, a mechanism that was designed to communicate between different machines. For conceptual purposes, COM modules then function in a different address space from that of the invoking *.exe. Therefore, there is overhead in making any data that is to be passed back and forth opaque on the sender's side, and converting it into usable data on the receiver's side.