[Previous] [Contents] [Next]

Scripting

Over the last 20 years, interpreted programming languages have gradually been replaced by compilers. Compilers are now available for all major programming languages. The rise of the Internet and the interpreted HTML document format has been accompanied by a renewed interest in interpreted languages for scripting. You can use scripting languages to automate user-driven administrative tasks or to create server-side Web applications. You can even write COM+ objects entirely in script. (We'll cover this topic shortly.)

In the past, when macro programming languages were embedded in major applications such as WordPerfect or CorelDraw, the user had to learn a new macro programming language for each application. This problem has been partially addressed through the adoption of Visual Basic for Applications by many major applications. Scripting presents similar difficulties in that each environment that uses script might adopt a proprietary scripting language. There is nothing wrong with having multiple scripting languages (Perl is obviously designed for different tasks than JScript), but the problem is that every environment generally locks you into one scripting language. Ideally, you should be able to choose the scripting language that is best suited for the job and simply plug that language into the environment at run time.

To address this issue, Microsoft created the ActiveX Scripting specification, which defines two types of components: scripting engines and scripting hosts. Scripting engines are COM+ components that implement the IActiveScript and IActiveScriptParse interfaces to provide support for a specific scripting language. Scripting hosts are applications that make use of scripting engines, including Internet Explorer, IIS, and the Windows Scripting Host.

The great thing about the scripting facility is that a scripting environment such as Internet Explorer can execute scripts written in any programming language for which a scripting engine is available. Today, Microsoft ships two scripting engines with Windows: VBScript and JScript. VBScript is a lightweight version of Visual Basic; JScript12 is a more object-oriented scripting language that is distantly related to Java. Third-party scripting engines are available for many popular scripting languages, including PerlScript, PScript, and Python.

Building Automation Clients in Script

You can automate components that support the IDispatch interface using script code written in any compatible scripting language, such as VBScript or JScript. Internet Explorer, IIS, and the Windows Scripting Host support these scripting languages. Listing 5-1 shows an HTML document that you can view with Internet Explorer to test the component.

client.html

<HTML>
<HEAD><TITLE>HELLO THERE</TITLE></HEAD>
<BODY>
This is a VBScript sample that uses the Component.InsideCOM 
object.<BR> VBScript will talk only to a component using 
IDispatch.<BR>
Here we go: 4 + 5 =
<OBJECT ID="MyComponent" 
    CLASSID="CLSID:10000002-0000-0000-0000-000000000001">
</OBJECT>
<SCRIPT LANGUAGE="VBScript">
    Document.Write MyComponent.Sum(4, 5)
</SCRIPT>
</BODY>
</HTML>

Listing 5-1. An HTML document containing VBScript code that uses the InsideCOM component.

When Internet Explorer opens this HTML file, it might ask the user if the object is safe for scripting, depending on the current security settings. Internet Explorer is quite wary when executing scripts against components because of the potential for malicious script to turn even a usually benign component into a terror. To placate Internet Explorer, you should mark components in the registry as being safe for use by scripting languages, indicating that the component cannot do any damage to the user's data even if operated by a malevolent script. Because the ISum interface of our InsideCOM component cannot do any harm, it is safe to add this setting in the registry.

To mark an object as safe for scripting, you create an Implemented Categories subkey under the object's CLSID entry, as shown in Figure 5-9. This subkey should contain additional subkeys of the category identifiers (CATIDs) of any categories supported by this component. The available categories are listed in the registry under HKEY_CLASSES_ROOT\Component Categories. The CATID {7DD95801-9882-1CF-9FA9-00AA006C42C4} indicates that a component is safe for scripting. (For more on component categories, see Chapter 7.) Once these registry entries are added, Internet Explorer can work with our Automation component without prior warning to the user.

Click to view at full size.

Figure 5-9. An Implemented Categories subkey indicating that a component is safe for scripting.

The Windows Scripting Host

The Windows Scripting Host is a language-independent scripting host supplied with Windows. It was designed to replace MS-DOS batch files. Using a scripting language, you can write real programs to automate administrative and end user tasks. The neat thing about the Windows Scripting Host is that it is extensible through COM+. Client applications running in the Windows Scripting Host can access any Automation-compatible COM+ components via the CreateObject function; components installed on remote machines are also accessible via the second parameter of the CreateObject function, which specifies the target machine.

To test the Automation component from the Windows Scripting Host, open the file shown in Listing 5-2 from the Windows shell or run the script file from the command prompt using the cscript.exe or wscript.exe utility.

client.vbs

Dim myRef
Set MyRef = CreateObject("Component.InsideCOM")

MsgBox "Sum(5, 3) = " & myRef.Sum(5, 3)

Listing 5-2. A Windows Scripting Host file containing VBScript code that uses the InsideCOM component.

Scriptlets

Continuing in the grand tradition of making COM+ objects accessible to any language, Microsoft enables scripts that are embedded in an HTML document or in a Windows Scripting Host file to access COM+ objects. What's even more amazing, however, is that you can actually create COM+ objects in script code stored in an Extensible Markup Language (XML) file. COM+ objects defined in this way are called scriptlets. Another type of scriptlet, called a Dynamic HTML scriptlet, is written using Dynamic HTML with user interface elements; these components are exposed as ActiveX controls. Thus, you have three ways to package a COM+ object:

Scriptlets are a powerful packaging technique because they let you create COM+ objects using XML and an interpreted scripting language. For example, the scriptlet shown in Listing 5-3 qualifies as a COM+ object. This scriptlet is written in VBScript, but you could use any scripting language for which a scripting engine is available.

Component.sct

<?XML version="1.0"?>
<scriptlet>

<registration
    description="Component"
    progid="Component.InsideCOM"
    version="1.00"
    classid="{10001111-0000-0000-0000-000000000001}"
>
</registration>

<public>
    <method name="Sum">
        <PARAMETER name="X"/>
        <PARAMETER name="Y"/>
    </method>
</public>
<script language="VBScript">
<![CDATA[

function Sum(X, Y)
    Sum = X + Y
end function

]]>
</script>

</scriptlet>

Listing 5-3. A scriptlet written in VBScript.

At run time, scriptlets are executed by the scriptlet run-time component (scrobj.dll), which is a sort of virtual machine for scriptlet components. When a scriptlet is registered, its InprocServer32 subkey refers to the scrobj.dll file. The <registration> tag defines the information that must be added to the registry when the scriptlet is registered. This tag includes the attributes for the description, ProgID, CLSID, and version number for a scriptlet. You can register scriptlets by running RegSvr32, or more easily by right-clicking on the scriptlet file and choosing Register from the context menu. The <registration> tag shown in Listing 5-3 creates the following registry entries in the HKEY_ CLASSES_ROOT\CLSID section of the registry.13

[HKCR\CLSID\{10001111-0000-0000-0000-000000000001}]
@="Component"

[HKCR\CLSID\{10001111-0000-0000-0000-000000000001}\VersionIndependentProgID]
@="Component.InsideCOM"

[HKCR\CLSID\{10001111-0000-0000-0000-000000000001}\ProgID]
@="Component.InsideCOM.1.00"

[HKCR\CLSID\{10001111-0000-0000-0000-000000000001}\ScriptletURL]
@="file://C:\\WINDOWS\\Desktop\\Component.sct"

[HKCR\CLSID\{10001111-0000-0000-0000-000000000001}\InprocServer32]
@="C:\\WINDOWS\\SYSTEM\\SCROBJ.DLL"
"ThreadingModel"="Apartment"

The <?XML version="1.0"?> declaration at the top of the scriptlet file indicates that this file conforms to the XML protocol.14 The <scriptlet> tag encloses an entire scriptlet definition. Each <scriptlet> tag in a .sct file defines one coclass. If multiple <scriptlet> tags are to be defined in a single .sct file, you use the <package> tag to contain all of the scriptlets in the component. The example shown in Listing 5-3 defines only a single scriptlet, so the <package> tag is not required. The <public> tag defines the properties, methods, and events of the dispinterface exposed by each scriptlet. Finally, the <script> tag is where the actual scripting code is implemented. You must define this in a <![CDATA[]]> tag for XML compatibility. Also, you can use a <comment> tag to provide comments in the scriptlets source code. The various XML elements that can go into a scriptlet are described in the table below:

Tag Description
<comment> Contains text that is ignored when the scriptlet is parsed and executed.
<implements> Specifies the COM+ interface implemented by the scriptlet. Interfaces are implemented using an interface handler. (Scriptlets currently support three interface handlers: Automation (IDispatchEx), Active Server Pages (ASP), and DHTML behaviors. In the future, it might be possible to build custom interface handlers that plug into the scriptlet at run time.)
<object> Contains information about an object that you use in your script, such as another COM+ component.
<package> Multiple <scriptlet> elements can appear in the same .sct file and are contained within a master <package> element.
<public> Encloses definitions for properties, methods, and events that your scriptlet exposes via the Automation interface handler. These definitions point to variables or functions defined in a separate <script> block.
<reference> References a type library containing constants you want to use in script.
<registration> Includes information used to register your scriptlet.
<resource> Contains values that should not be hard-coded into scriptlet code. Resource elements can include infor- mation that might change between versions, strings that might be translated, and other values.
<script> Contains the script used to implement the logic of your scriptlet.
<scriptlet> Encloses one entire scriptlet definition.

You can build client applications that use scriptlet components in any development environment that supports COM+. For example, a scriptlet can be called from an HTML page displayed by Internet Explorer or from a Java applet executed by the Microsoft Java VM. For demonstration purposes, let's build a client program in Visual Basic that calls the scriptlet shown in Listing 5-3. Here are the steps to follow:

  1. In Visual Basic, open a Standard EXE project.
  2. Place a command button on the form.
  3. In the Code window, enter the following code:
  4. Private Sub Command1_Click()
        Dim ref As Object
        Set ref = CreateObject("Component.InsideCOM")
        MsgBox ref.Sum(4, 6)
    End Sub
    

  5. Run the program and test it by clicking the button.