Windows Script Components: They Get Around

 

Andrew Clinick
Microsoft Corporation

September 13, 1999

Contents

Just How Many Names Can a Technology Have?
Writing a Component that Runs on the Server or Client
Using the Component
Login Screen Component
Summary

I wrote an article way back when I started this column (when I was promised it would be an occasional series that wouldn't take much of my time—yeah, right!) about scriptlets and how they provided a component technology that "real" people could use. This month, I'll follow up on that article and how you can use the newer 1.1 version of Windows Script Components to write components that can be used on the client or server, hopefully by writing only one component.

Just How Many Names Can a Technology Have?

Those of you who have been following the Windows Script technologies for a while will be aware that Windows Script Components have had more than their fair share of names. Perhaps they should be called the technology formerly known as Scriptlets? The first iteration of components written in script were released with Internet Explorer 4.0 with the catchy title of scriptlets. They provided a way to componentize your DHTML code for Internet Explorer but were constrained by working only on the client. This proved to be quite a shortfall, considering the amount of script being written on the server. So, the script team started work on "server scriptlets," which would provide a lightweight runtime for script running in Active Server Pages (ASP) technology and Microsoft Transaction Server (MTS) transactions. The more we developed server scriptlets, the more we realized that they would be useful on the client as well as the server. This realization resulted in a quandary. We were developing a script component runtime, and scriptlets was just too cute a name to pass up, so we decided to simply rename the existing scriptlets, "DHTML scriptlets." Then we could call the new technology scriptlets. Users would understand that the names had changed and that the technologies had little in common, other than that they both used scripts!

One soggy January morning, reality hit the scripting team: Rewriting history to use a catchy product name doesn't delight customers! We went back to the drawing board, and decided that since we were creating script technologies for Windows, why not call them Windows Script? We could then have Windows Script Engines, Windows Script Host, Windows Script Interfaces, Windows Script Debugger, and, finally, Windows Script Components. Thus, Windows Script was born.

Writing a Component that Runs on the Server or Client

One of the advantages of Windows Script Components is that the runtime library works well on either the client (Internet Explorer 5, Windows Script Host, or any COM application) or the server (Internet Information Server [IIS], MTS, etc.). In version 1.0, we didn't make it easy for you to write a component that could take advantage of this—if you included both the DHTML behavior and the ASP handler, you'd get an error. We discovered this oversight too late in the product cycle for version 1.0, but we've made amends in version 1.1 (which is beta at the moment). You can get the Windows Script Component 1.1 Beta download now through Windows Script Host Beta 2 Version 1.1 for Windows® 95, Windows 98, and Windows NT® version 4 will ship with Windows Script 5.1 when Windows 2000 ships.

In Windows Script Component version 1.1, you can include the <implements> element for both behaviors and ASP functionality in the same WSC. The runtime will determine which can be run, and load only the handler that makes sense. This new capability means that you have to write only one component—and that component will adapt to the environment, client or server, in which it's being run. To illustrate this, I've created a simple WSC that has one property, message, and one method, display. The WSC has both the behavior and ASP handlers implemented to take advantage of both Internet Explorer and ASP technology:

<?xml version="1.0"?>
<component>

<?component error="true" debug="true"?>
<public>
   <property name="message">
      <get/>
      <put/>
   </property>
   <method name="display">
   </method>
</public>

<implements type="Behavior" id="Behavior"/>
<implements type="ASP" id="ASP"/>

<script language="VBScript">
<![CDATA[
dim message

function get_message()
   get_message = message
end function

function put_message(newValue)
   message = newValue
end function

function display()
   ' Check to see if the behavior handler is loaded
   if isobject(Behavior) then
      element.innerHTML=message
   ' Check to see if the ASP handler is loaded
   elseif isobject(ASP) then
      response.write message
   else
   ' ASP and Behavior not loaded so default to something that
' will work in any application aka msgbox
      msgbox message
   end if
end function

]]>
</script>

</component>

The key to the above component is within the display method. When the method is called, it checks to see where the component is being created. If the behavior handler is loaded, it will return true when queried by isobject. So, when the component is being loaded by Internet Explorer, set the value of the innerHTML property to the value of the message property. If the ASP handler is loaded, the component is running in ASP, so use response.write. If none of the above, then the component is running in an unknown client, so default to something useful.

Using the Component

Using simple.wsc is relatively simple—just create an instance of the component, set the message property, and then call the display method. The trick is how you instantiate the component. For this article, I'll cover Internet Explorer, ASP, and Windows Script Host, (This is the generic mechanism for instantiating a WSC. You can apply it to any COM application, such as Visual Basic®, Office, and so forth).

Internet Explorer

In Internet Explorer 5, WSCs are used via the new DHTML behavior feature. DHTML behaviors are simple, lightweight components that encapsulate specific functionality or behavior on a page. When applied to a standard HTML element on a page, a behavior enhances that element's default behavior. The simplest way to get a script component working is to create a new class in the style sheet for the page, set the behavior attribute to the URL of the WSC, set the class of an HTML element to be the new class, and set properties and methods on the WSC associated with the HTML element.

Here's simple.htm that I created for this article. The page references the simple.wsc described earlier and associates it with the simple class on the style sheet for the page. The <DIV> then uses the simple class as its style, creating an instance of the WSC. Once the WSC has been loaded, the <DIV> "inherits" the methods and properties of the WSC. When the page loads, it sets the message property on the <DIV>, and then calls the display property.

<HTML>
 <HEAD>
  <TITLE>Simple WSC example</TITLE>
   <STYLE>
   .simple
     {
       behavior: url(simple.wsc) ;
     }
    </STYLE>
   </HEAD>
 <BODY onload="startup()">
  <h1>Simple Demo</h1>
  <div class="simple" id="simple"></div>

  <script language="JScript">
  function startup()
  {
   simple.message =  "Hello World"
   simple.display()
  }
  </script>

 </BODY>
</HTML>

Active Server Pages Implementation

Using simple.wsc in an ASP environment is a little different, because the component needs to be instantiated on the server rather than the client. To create the component without registering it on the server, the Visual Basic Scripting Edition (VBScript) code uses the script: moniker provided by the Windows Script Component Runtime. Once an instance has been created the message property is set and the display method called, as in the HTML example.

<HTML>
 <HEAD>
  <TITLE>Simple WSC ASP example</TITLE>
   </HEAD>
 <BODY>
  <h1>Simple Demo</h1>
  <%
      dim simple
      ' Create an instance of simple.wsc from the file system
      ' You could register the component rather than doing this
      set simple=getobject("script:c:\demo\simple.wsc")
      ' set the message property
      simple.message =  "Hello World"
      ' Call the display method
      simple.display
%>

 </BODY>
</HTML>

Windows Script Host

The use in Windows Script Host (WSH) is even simpler than in the ASP environment, yet uses exactly the same code. The only difference is in the run-time behavior of the component. When the display method is called, the component will create a message box with the value of message.

dim simple
' Create an instance of simple.wsc from the file system
' You could register the component rather than doing this
set simple=getobject("script:c:\demo\simple.wsc")
' set the message property
simple.message =  "Hello World"
' Call the display method
simple.display

Login Screen Component

To illustrate the use of Windows Script Components with a more realistic scenario, I've built a login screen component. The component is pretty simple. It has a display method that will cause the HTML-based login screen to be displayed. The key to using HTML for the user interface to this component is the <resource> element provided by the WSC runtime. Using <resource> allows you to insert a block of text into your component, give it an ID, and then refer to it in your script. In the login screen component, I have one resource that contains the HTML for the login form:

<resource id="login">
<![CDATA[
<form method="POST" action="login.asp">
  <div>
   <center>
    <table border="0">
      <tr>
        <td width="50%" align="right">User Name:</td>
        <td width="50%"><input type="text" name="T1" size="20"></td>
      </tr>
      <tr>
        <td width="50%" align="right">Password:</td>
        <td width="50%"><input type="password"
name="T2" size="20"></td>
      </tr>
    </table>
    <p><input type="button" value="OK" id="btnSubmit"
name="Submit"><input type="reset"

value="Cancel" name="btnCancel"></p>
   </center>
  </div>
</form>
]]>
</resource>

Getting to the resource is simple—call the getResource function, provided by the WSC runtime library, with the ID of the resource:

<script language="VBScript">
<![CDATA[

function display()
   form = getResource("login")
   ' Check to see if the behavior handler is loaded
   if isobject(Behavior) then
      ' set the innerHTML to be the value of the resource
      element.innerHTML=form
   ' Check to see if the ASP handler is loaded
   elseif isobject(ASP) then
      'write in the html from the resource
      response.write form
   else
   ' ASP and Behavior not loaded so display the HTML in a new
   ' instance of IE
      set ie=createobject("InternetExplorer.Application")
      ie.height = 175
      ie.width = 300
      ie.menubar = false
      ie.toolbar = false
      ie.statusbar = false
      ie.resizable = false
      ie.navigate "about:blank"
      'Loop until IE is finished displaying the HTML
      Do while ie.busy: x=x+1: loop
      ie.document.body.innerHTML = cstr(form)
      ie.visible = true
   end if
end function

]]>
</script>

The addition of the resource and some simple script has allowed the creation of a component that will change its behavior (pardon the pun) dependent on the client from which it's being called. This can really help if you're trying to develop code for different environments yet want to maintain some form of uniform user interface.

To maximize the use of the login WSC in a Web page, I've written a simple ASP script that detects whether the request is coming from Internet Explorer 5. If it is, the script will redirect to a client-side HTML page (login.htm), which references the WSC as a behavior. If not, the script will use the WSC to output the HTML into the response stream from the ASP file.

<HTML>
 <HEAD>
  <TITLE>Simple WSC ASP example</TITLE>
   </HEAD>
 <BODY>

  <h1>Simple ASP Demo</h1>
  <%
  Set bc = Server.CreateObject("MSWC.BrowserType")
  if bc.browser = "IE" and bc.version >= 5 then
   response.redirect "login.htm"
  else
   dim simple
   ' Create an instance of simple.wsc from the file system
   ' You could register the component rather than doing this
   set simple=getobject("script:c:\demo\login.wsc")
   ' Call the display method
   simple.display
  end if
  %>

 </BODY>
</HTML>

To use the same WSC from Windows Script Host, I created login.vbs, which creates an instance of the component and calls the display method. When the WSC gets a call from a client that isn't Internet Explorer or an ASP environment, it creates an instance of Internet Explorer, changes the size, turns off the toolbars, etc. -- and uses the document object model to insert the contents of the resource. It then shows Internet Explorer. This is somewhat of a poor man's dialog box, but it gets the user input required and passes it back to the server.

   set ie=createobject("InternetExplorer.Application")
   ie.height = 175
   ie.width = 300
   ie.menubar = false
   ie.toolbar = false
   ie.statusbar = false
   ie.resizable = false
   ie.navigate "about:blank"
   'Loop until IE is finished displaying the HTML
   Do while ie.busy: x=x+1: loop
   ie.document.body.innerHTML = cstr(form)
   ie.visible = true

Summary

Windows Script Components provide a lightweight, component-creation mechanism that can be combined with other key technologies in the Windows platform to create components that adjust to fit the applications from which they are being called. The examples in this article are pretty simple, but I hope they have given you some insight into what is possible for Windows Script Components and some ideas about how you might use them in your next Web application. As always, I encourage you to get your feedback to the Windows Script group at msscript@microsoft.com or via our newsgroups at news:msnews.Microsoft.com.microsoft.public.scripting.scriptlets.

 

Scripting Clinic

Andrew Clinick is a Program Manager in the Microsoft Script Technology group, so chances are, if there's script involved, he's probably had something to do with it. He spends most of his spare time trying to get decent rugby coverage on U.S. television and explaining cricket to his new American colleagues.