If you’ve been scripting for more than a few minutes, you’ve undoubtedly used some form of COM object in your scripts. These are objects provided by the operating system and other applications that allow you to perform tasks that aren’t provided by the scripting environment. Most of these objects are compile code that resides in a DLL or OCX file somewhere. Most people believe that you have to have some level of advanced programming ability to create these objects for yourself. That’s not the case. Today I’m going to show you how to create custom COM objects using nothing more than the scripting knowledge you already possess.
The technology we’ll be using is called Windows Script Components—a technology designed specifically to allow programmers to create objects with nothing more than a knowledge of scripting. The Windows Script Component Technology works with the scripting environment to expose simple scripts as COM-enabled objects.
The WSC technology was originally known as Scriplets, a means of creating small COM-enabled applications and objects for use in web development. However, since this technology relies on COM, this isn’t just limited to browser-based development. It can be utilized by any technology that is capable of working with a COM interface. As COM gained more and more popularity (and Windows Scripting became more widely used), the Scriptlet technology was expanded into Windows Script Components.
Creating a Windows Script Component is as easy as creating a text file. At its most basic level, a WSC is little more than a Windows script wrapped inside of an XML file. This XML file is used to provide the information necessary for the component to be recognized as a COM object, while the contained script performs the programming magic.
A WSC is powered by the Windows Script Host environment. The WSC is (generally) registered on the system as a COM object. When that object is instantiated, the system points to the WSC file, which is then executed by the Windows Script Host and exposed to the calling application through a generated COM interface. This is all done seamlessly behind the scenes so that the result is no different from what would have happened if the programmer had used some compiled object.
Windows Script Components have several distinct advantages. The primary advantage is the ability to create COM-enabled objects (even on-the-fly) without the need for advanced programming skills or compiled code. This makes COM creation available to those who only have simple scripting knowledge. Since they are simple text files, this prevents the need for any development environment as well.
As with all COM objects, WSC provides a means of making your code available to any script or application running on a system. It also provides a nice means of distributing your code by providing a package with universal portability across Windows platforms. Your WSC object can be used on any system that employs COM and by any COM-enabled application—even compiled ones!
Windows Script Components can be registered from any valid local or network path. This makes WSC a great way to distribute your code across an entire network while maintaining a single point of origin.
Using customized COM objects can also provide a layer of security. The scripts contained in your WSC files can be encoded to protect your source code from prying eyes. This provides a means of distributing ready-to-use code while protecting your intellectual property.
Finally, using COM-enabled code objects in your scripts and applications provides an easy, centralized location for updating or upgrading your code without having to change every script or application in which the code is used. Any changes made to a component become immediately available to any calling application.
COM objects created with Windows Script Components can execute any code that you require. They behave similarly to a local scripting class. They can expose properties and methods to your code and even execute code when they are created. Components and classes are so closely similar that it’s sometimes easier to think of a component as a class that is available to scripts and applications system-wide.
Unlike classes, however, components are executed independently of the running application or scripting host. This provides some flexibility that isn’t necessarily available in a standard class. Because WSCs are executed by the scripting engine at runtime, threading is handled slightly differently than with compiled COM objects. When developing full-scale applications, this should be taken into consideration, but it has little or no effect when used in scripting.
Outside of exposing properties and methods, Windows Script Components can take class-style execution to the next level. Components are able to hook system events, events in the host and calling applications. In some cases, components can even be given limited access to the system API. Components also provide a much-missed feature in classes, the ability to fire custom events.
There are many more features of Windows Script Components as well. Some of these are geared toward COM objects developed for use in applications, others are geared toward use inside the browser. The scope of the Windows Script Component technology could easily be the topic of an entire book, so I’ll limit my description of features to those that would be most commonly used by Windows scripters.
One more key feature that is useful for scripters is the ability for components to wrap enumerations. Since enumerations are not exposed to scripts, you can create a component to wrap an enumeration and effectively imitate a type library to expose those constants to your script.
As I’ve mentioned previously, a Windows Script Component is little more than a text file written in XML format. The syntax is used to provide key information about the object that is used when the object is registered and deployed by the system. They describe things like the component name, version number, ProgID, and ClassID. You can see the layout of a simple COM object below. It accepts a user string through the Message property and displays it in a message box when the user calls the Show() method.
<?xml version="1.0"?>
<component>
<?component error="false" debug="false"?>
<public>
<property name="Message">
<get/>
<put/>
</property>
<method name="Show">
</method>
</public>
<implements type="Behavior" id="Behavior"/>
<implements type="ASP" id="ASP"/>
<script language="VBScript">
<![CDATA[
Dim strMessage
Function get_Message()
get_Message = strMessage
End Function
Function put_Message(strValue)
strMessage = strValue
End Function
Function Show()
' Check to see if the behavior handler is loaded
If IsObject(Behavior) Then
element.innerHTML = strMessage
' Check to see if the ASP handler is loaded
ElseIf IsObject(ASP) Then
Response.Write strMessage
Else
' Default to something that will work in any application
MsgBox strMessage
End If
End Function
]]>
</script>
</component>
As you can see, the XML structure for a Windows Script Component is actually pretty simple. The <component> element houses all of the pieces for the component, as I explain in the following paragraphs.
The <public> element contains the instructions that will be used to create the COM interface for this component. This is where you should declare all of your public properties and methods, along with their permissions and attributes.
The <implements> elements are optional and are used to add functionality to your components. The first one allows this component access to the Behavior handler, which attaches to the Internet Explorer DOM. The ASP handler gives this component access to the ASP environment when used inside of an ASP page. This allows the component to use ASP’s objects, such as Response.Write() and Server.MapPath().
Next, we come to the meat and potatoes of the component. The <script> element houses all of the code. Since this is an XML document, the contents will need to be enclosed in a CDATA comment so that they are hidden from the XML parser. The script will execute in the global namespace of the component. While you should probably be dropping functions here, you can have code execute when the object is instantiated.
If you’re writing in good form, you should be specifying the language in which your code is written by using the script element’s language attribute. If you do not, the scripting engine is pretty good at determining what language you used. You may use any supported scripting language. Ordinarily this is VBScript and Jscript, but if you’ve installed third-party languages like Perl or Ruby, those are perfectly acceptable.
You can even mix and match multiple languages by providing multiple <script> elements. This means that you can write part of your component in one language and finish it in another. You’ll be able to call functions back and forth between the languages without any problem. The scripting host will sort it out!
The above example represents a fully functioning Windows Script Component. However, if you plan on registering your component with COM (which you should), you will need to add one more portion to this file to provide the registration information.
<registration
description="My Message Component"
progid="Message.WSC"
version="1.00"
classid=""
remotable="True">
</registration>
The registration provides a few attributes that determine the COM properties of your new component. You can provide a name with the description attribute as well as file version. The two attributes that are required for registration are the ProgID and the ClassID. The ProgID will be used to reference your component from your scripts and the ClassID will be used to identify your component. This is a globally unique identifier and must be generated using a GUID generator. I’ll explain more about that in my next article.
There you have it, the basics for creating your own scriptable COM object. Stick around for my next article when I’ll show you step-by-step how to create an actual, useful object. You’ll learn about a tool that will have you up and running in just a few minutes. Don’t miss it! Until next time, keep coding!