In this chapter, we'll be examining Windows Script Components. We will examine their structure and also how to create and register them. Later in the chapter, we'll look at how we can use classes in our components.
If you are used to using XML then the structure of the script here will be familiar to you and that will be a huge advantage, if not, work carefully through the examples and all will become clear!
Windows Script Components are interpreted COM components (they have to be interpreted because VBScript and all other scripting languages are interpreted). Structurally, they are XML-based files that contain script code. Within the files themselves you can use VBScript, JScript, Python, PScript, PERLScript, or any other scripting language. As always, we will focus on using VBScript in this chapter (for obvious reasons), but it is possible to use the script language of your choice.
The script components are interpreted by the Script Component Runtime which exposes the internal properties and methods , fires the events, and makes the component look like a compiled COM component to the calling application. We will look at the Script Component Runtime in more detail in the next section.
Script components are full COM components, and have the ability to call other COM components. Script components have some built-in interfaces into the Active Server Pages library and Internet Explorer DHTML behaviors that make it very easy to build these components for the Web.
One important point to note is that script components are not designed for use as early bound access objects. If you reference a script component as an early bound component then your application will generate a runtime error. This is a common issue when using script components, which crops up all the time. Keep them late bound and you will have fewer problems implementing them.
Late bound access means that there is no information available at compile time about the object being accessed, and everything is evaluated dynamically at runtime. Early bound access provides you with information about the object you are accessing while you are building your program. It is normally faster when running your program to use early bound access, but in this case it cannot be used.
You might be wondering, why you would want to use these when you could use Visual Basic to build a standard COM component instead. The main reason is that Windows Script Components don't require a compiler. The minimum that you will need to build script components is the good old Windows Notepad or another simple text editor. Script components are also a quick and easy way to encapsulate functions and routines that you write in VBScript. By doing this you can create a library of your source code. Finally, if you still need convincing, the ASP interfaces allow you to directly access the Active Server Pages library for quick and easy integration with your Internet or intranet sites.
Tip |
If you're not familiar with ASP, don't worry-Chapter 18 is an introduction to that subject. |
Before we move on, let's get your toolkit in order. You can create Windows Script Components with nothing more than Notepad and your imagination , but if you plan on doing a lot of scripting, you may find it a little tedious to do it all by hand. Microsoft provides the Script Component Wizard (which you can find at www.microsoft.com/scripting/ -the precise URL for this varies but if you access the download section of the scripting area you will find it there. You are looking for a file called wz10en.exe ) to help speed up the creation of the script component framework. You need to have the VBScript 5.0 libraries (preferably the latest 5.6 libraries) on your machine to run script components properly. Script components use the Windows Script Host when they run, so you'll also need that. Luckily, all this will be installed with the scripting libraries.
Here's a list of items that you must have to create script components.
Tip |
All these downloads are available free of charge from the Microsoft Web site. |
Since Script Components are interpreted during runtime (as they are run) there is need for an interpreter to be installed on the client system. The Script Component Runtime ( scrobj.dll ) is the interpreter used to control calls between clients and script components. The runtime implements the basic COM interfaces for the component ( IUnknown ) and handles some of the basic COM methods ( QueryInterface , AddRef ) in the same way that the Visual Basic runtime handles the low-level COM routines of Visual Basic components.
Since we are running though an interpreter, our script components will look different from other COM components in the registry. Let's examine this in a little more detail. We will assume that our object is called ' Math.WSC ' and that we are calling this object through script.
Set objMath = CreateObject("Math.WSC")
The first thing that happens is that the registry will be searched for the Math.WSC entry under HKEY_CLASSES_ROOT . The registry entry of this is shown in Figure 13-1.
Figure 13-1
If we look up the GUID ( Globally Unique IDentifier ) under HKEY_CLASSES_ROOTCLSID then it brings us to our information for our COM component.
Notice that in Figure 13-2 the InprocServer32 key is actually scrobj.dll , not the script component file itself. We are actually creating the scrobj.dll component when we call our CreateObject statement.
Figure 13-2
The scrobj.dll file knows to look at the ScriptletURL key for the location of our component. It now knows that we need to look at that path for the actual object for the method calls. The registry entry that corresponds to this is shown in Figure 13-3.
Figure 13-3
Notice that the key is named ScriptletURL . This implies that these can be called over the Internet. Don't worry about this just yet, because we won't cover this until later in the chapter. There is a bit more to know about script components first.
Now let's look at how to create the actual script component. As we've already said, you can build script files by hand, however, Microsoft makes a free wizard available for building a script component file, automating a lot of the laborious tasks when creating script components . The wizard simply builds the XML framework that defines your component. There's nothing at all to stop you creating this yourself if you know how it's done, however, XML is very strict and mistakes are easily made. Of course, the best way to find out how it's done is to use the wizard first, so let's do that.
We invoke the wizard under XP from the Start ( All Programs ( Microsoft Windows Script (Windows Script Component Wizard shortcut (for other operating systems go Start ( Programs ( Microsoft Windows Script ( Windows Script Component Wizard shortcut). First, we will tell the wizard the name of the component, along with its ProgID . One point to note is that script components use a special ProgID that defines the component. By default, the ProgID of the component will be componentname.WSC . Don't worry though, this can be changed in this step or after the component file has been created.
Script components can also maintain version information just like any other COM component, as you can see in the Version field. This is very useful for keeping track of updates.
Note that the Location in this dialog is simply the location of the source files that the wizard produces. The location of the source files will not be important to the actual Windows operating system until you register the component.
Step 1 of the Script Component Wizard is shown in Figure 13-4.
Figure 13-4
Once you are satisfied with the settings that you have chosen for the various options (some you have huge scope over, such as version, others less so), select the Next button to go to the second step of the wizard.
Windows Script Components can use VBScript or JScript natively, but other scripting platforms such as Python and PERL can be used as well if the proper interpreter is installed on the computer. There are two options under the implements section that need a little extra background information. These are DHTML behaviors and Active Server Pages.
DHTML behaviors are simple, lightweight components that interface with some of the DHTML objects and events of Internet Explorer. DHTML components are beyond the scope of this chapter, but for more information you can refer to the Microsoft Scripting site and the MSDN Web Workshop ( http://msdn.microsoft.com/library ).
Active Server Pages support will be covered in more detail in this chapter, and ASP itself will be covered later on in the book. Basically, ASP support allows a script component to gain direct access to the ASP object model. The ASP object model exposes the vast ASP Request , Response , Application , Session , and Server objects.
Finally, error checking and debugging can be selected as options. If you select debugging, you'll be allowed to use the script debugger. The script debugger can be found at http://msdn.microsoft . com/scripting/ , and using it is the only way to debug a script component. It gives you the ability to check variables and view data, and works in a way very similar to the Visual Basic debugging tools.
Step 2 of the Script Component Wizard is shown in Figure 13-5.
Figure 13-5
When you have selected the options that you want, select the Next button to move to step 3 of the wizard.
This screen allows you to define the properties of your object. You are able to define the name, type, and default values for the component. The Type setting is not the data type, but the property type, which can be one of the following:
The Default entry allows you to specify a default value for the property. The following code listing shows a read/write property with a default value of 5 .
Dim ReadWriteProperty ReadWriteProperty = 5
Note that this is how the wizard declares a variable that will be accessed by a property. This should be changed to read.
Private ReadWriteProperty ReadWriteProperty = 5
This will make sure that the variable is private to the script component. If this isn't done the variable would be public, as would the property accessing it, which could in turn lead to problems and conflicts.
Step 3 of the Script Component Wizard is shown in Figure 13-6.
Figure 3-6
Press the Next button to proceed to step 4 in the wizard.
The fourth step of the wizard brings us to the methods of our component. You can specify the name of the method as well as the parameter list. When adding parameters, be sure to separate them with a comma, so that the parameter list looks like the following:
param1, param2, param3,
Again, remember that VBScript uses only variants, so you don't need to specify a type. If you go as far as trying to specify a type you will get an error. For similar reasons, you also can't specify a return type. The use of variant data types does reduce overall performance somewhat because variants are the largest data type that can be used, and are designed to represent any other data type, so each time a variant is called the application must decide what format the variable should be in. But since there is nothing we can do about that, there's no point worrying about it.
We will add a few methods here for our Math component. The Script Component Wizard will generate all methods as functions. If you want you can manually change these to subprocedures later if you don't need return values. It is an inconvenience that this can't be set in the wizard but again since there is nothing we can do about that, there's no point worrying about it here.
Step 4 of the Script Component Wizard is shown in Figure 13-7.
Figure 13-7
The fifth step of the wizard allows us to specify the events for our component. This is one of the most exciting areas of script components. We will see a little more on events in script components later in this section. Our Math component won't actually use events as such. If you do want to have events in your objects, enter one event name per line.
Tip |
A previous version of the Script Component Wizard had a bug that ignored any entries in this section. If you discover that you are affected by this, will need to add events manually once the component has been created. We will go into more detail later in this chapter. If you are affected by this we suggest that you upgrade to the latest release of the Script Component Wizard. |
Step 5 of the Script Component Wizard is shown in Figure 13-8.
Figure 13-8
Once you are satisfied with the layout of the events, press the Next button to move to the final step of the wizard.
The final step of the wizard gives us some information about our component and some of the settings that we have selected. If you find any errors or omissions at this point then you can press the Back button to return to the previous steps and make the necessary changes.
Step 6 of the Script Component Wizard is shown in Figure 13-9.
Figure 13-9
Once we click Finish , the wizard will create a skeleton component like that in the following code sample:
description="Math" progid="Math.WSC" version="1.00" classid="{585c5e81-addf-4006-993a-9701d7c4a41b}" >
If your code looks like the earlier listing, you have now created a Windows Script COM Component. Now let's take a look at it in a little more detail.
The next thing to do is to actually define the properties, methods, and events that your component needs to contain.
Properties within script components can be read/write, read-only, or write-only. They are implemented within the script file using < property >< /property > tags. Within these tags you set the get and put options for the property. Gets are used for reading the values and puts are for writing to the properties. The following code sample lists the structure that's created to first 'declare' the three types of properties.
The properties are then actually defined within script code later in the script file.
You can script any additional logic within the get and put functions of the properties. For this example we haven't included any real properties. Later on, when we look at classes, we'll actually see an example that does use properties.
Remember that script components can implement other COM objects, so you can create an ADO component, access LDAP and Exchange, or even call Microsoft Word and Excel. The sky is the limit with script components!
Methods in script components are defined in < method >< /method > tags in the object definition section of the script file. Parameters for a method use a < parameter > definition for the values, as you can see in the following code sample.
The < parameter > tag simply defines the name of the input parameters. Remember that everything that comes from the Script Component Wizard is, by default, a function within the script components and no return type is specified since all variables are of the variant data type. We are, however, free to use subprocedures as our methods in place of functions.
The actual method code is within the script tags of the script component.
Note that all methods that are created though the Windows Script Component Wizard return the value ' Temporary Value '. You will probably need to change this (unless you really need a function that returns ' Temporary Value '!). You will also need to declare any temporary variables before the function definitions.
Let's add our real methods to our Math component.
Something that is not documented in the WSC documentation (because it's specific to the scripting language you use) is that you can use the byval (by value) and byref (by reference) keywords within the parameter declaration of the method. By default in VBScript all values are passed byref , so any changes to the variables in the method will change the underlying value in the calling function.
Tip |
JScript variables are all passed byval since JScript cannot pass a variable byref . |
Events are defined within < event >< /event > tags within the object definition of the script file.
There was a bug in an older release (we can't call it a version because the Windows Script Component Wizard is still in version 1.0) of Windows Script Component Wizard, which meant that it did not create the events you specified. All event declarations had to be created manually within a script file. The latest release of the Windows Script Component Wizard behaves correctly.
The event is actually fired through the FireEvent() method. FireEvent() is called within the script of the script component. The event itself should also be described here, using the form ComponentName_EventName .
Script components can also handle events using an < implements > tag within the script definition. The syntax for capturing events in a script component is defined as
handler-specific information here
The COMHandlerName is the name of the handler (ASP or behavior) or the COM object that is being handled. InternalName is an optional parameter that allows you to define a variable name for the COM handler. The fAssumed property is a Boolean flag (the default value is True ) that indicates InternalName is assumed in scripts. If you set this to False you would hide some members in the < implements > tag.
There are two built-in COM handlers, ASP and Behaviors. We will look at the ASP COM handler later in the next section.
To be able to register a Windows Script Component you will need to have the Script Component Runtime ( scrobj.dll ) on your machine and have it properly registered. This file is automatically registered when you install the VBScript or JScript script engines. Once you have the scripting runtime and a valid script component ( .wsc ) file then you can register the component. There are three methods available for properly registering a WSC file.
The easiest way to register and unregister a script component is to right-click the component file in Windows Explorer and select Register or Unregister from the popup menu. This is shown in Figure 13-10 and is both easy and convenient to use.
Figure 3-10
In the event that you need to manually register and unregister a component you can still use regsvr32.exe . If you are using an old version of regsvr32 that comes with Windows or Visual Studio then you can use the following command.
regsvr32 scrobj.dll /n /i:Path/component_name.wsc
New versions of regsvr32 that ship with the script component packages can directly register the script component file.
regsvr32 path/component_name.wsc
You can also add a registration entry into the script component that defines the registration behavior. You can add the < registration > tag to the component as defined in the following code.
version="version" [remotable=remoteFlag]>
Within the < script > tags you can add a Register() and Unregister() event that will be fired whenever the component is registered or unregistered on the system. The progID attribute is optional, but you must have data for either the classid or progID in order for the component to register.
If you leave either classid or progID out then it will be automatically generated when the component is registered.
All of these methods will properly register a script component file on your system. This is nice, but what about remote components? Well, the short and simple (and sweet!) answer is that Windows Script Components can be registered remotely.
In order to make the components DCOM-ready, you need to follow these four simple steps:
Another way to simplify this process would be to register the component on the server and export the registry key information using regedit . You can then copy the exported .reg file from regedit to each machine that needs the component. Once the file has been copied to the local machine, double-click the .reg file to merge the data into the registry. You now have a DCOM-ready script component that can be used throughout the enterprise.
Let's quickly test the component with a short test script. Save the following code as a file called testmathcomp.vbs and then run it after you've registered your Math component:
dim obj set obj = wscript.createobject("math.wsc") msgbox obj.add(15, 9) msgbox obj.subtract(15, 9) msgbox obj.multiply(15, 9) msgbox obj.divide(28, 4) set obj = nothing
Script components are no different to any other COM component and can have type libraries generated. Type libraries are used in some environments (such as Visual Basic) for enabling events or for enabling the use of IntelliSense by programs such as Visual InterDev. Type libraries contain descriptions of the COM components and also help with early binding of objects or using tools such as OLE2VIEW to view the declarations and constants in a component.
To generate a type library for a script component, simply right-click on the script component file and select the Generate Type Library option from the popup context-sensitive menu, as shown in Figure 13-11.
Figure 10-11
Though there is another way to generate a type library within a script component. Script components can automatically generate a type library for themselves when the Register method is called. When this method is called, the component uses the information that exists within the < registration > tags. The syntax of the < registration > tag is as follows .
version="version" [remotable=remoteFlag]>
Remember that both the progID and classid items are optional, but one of the two must be specified for the tags to be valid. The progID is the component name while the classid entry is for the GUID of the component. If the classid entry is left blank, then a GUID will be assigned to the component at registration time by the system.
Both description and version are optional as well. If we used a registration entry with our previous Math component, then we would add the following < registration > tags.
description="My Simple Math Component" progid="Math.WSC" version="1.0" classid="{585C5E81-ADDF-4006-993A-9701D7C4A41B}">
Remember, if you plan to use this component through DCOM then you would also need to add this line.
remotable=true
This line of code tells the component that it needs to set itself up in the registry for DCOM.
A script component file can contain multiple components within itself. You can easily create a library of components just as you would in Visual Basic, however, you cannot use the Windows Script Component Wizard to do this and you would need to do this manually. The script components use a series of < package >< /package > tags to create script libraries. For example, you would define a series of components within a file as follows.
Within each script you would add the appropriate properties, methods , and events for each component. You would also need to add the necessary registration information as well.
You can reference another component within the package by using the CreateComponent function. If we want to reference COMObj2 in the preceding code, we would set a reference to an object using CreateComponent .
Set oComponent = CreateComponent("COMObj2")
This will give us a runtime reference of COMObj2 . How does this help? It allows you to add components that implement ASP interfaces and DHTML behaviors, while at the same time exposing properties and methods to other client applications. Your ASP and DHTML components can access all of the properties and methods of the COM component and will reduce the amount of redundant code.
While the Windows Script Component Wizard can't help you with all of it, it can build the individual objects for you. Once all of the objects have been created, you can then build a package and cut and paste the contents of the individual files into the one package.
ASP script components include the functionality of the Active Server Pages library to allow for Web enabled script components. These script components are called from within ASP pages and can contribute greatly to code reuse of ASP components and business logic and also save time by separating functional code from the Web page that displays it.
In order to ASP-enable a script component, you will need to add an < implements > tag with a reference to the ASP COM handler.
Once the < implements > tag has been set up, the script component will have a reference to ASP and can make use of the Response , Request , Session , Application , and Server ASP objects. For example, we can have a component that outputs the current date and time to an ASP page. The script component would look like the following.
The code for out ASP page would create this object and call the OutputDateTime method.
ASP Script Objects
An ASP script component can also contain complex database functions, which can be reused for generic database output. Since script objects can call other COM components, we have access to all ADO functions, Office COM libraries, and third party objects. That is a lot of power!
So, how do ASP script components operate ? When the script object is called from an ASP page, the script object is run in the same namespace (or process space) as the calling page. This gives the script component direct access to the page, so it can use all of the intrinsic ASP objects, and all output back to ASP is directed back to the page. The script component and the ASP page both see the exact same objects. This is similar to creating a Visual Basic COM component that implements the OnStartPage method. When a Visual Basic COM component has this method, ASP will call it automatically and send a reference to the ASP library, thus giving Visual Basic full control over ASP.
If you're familiar with using ASP, you might be wondering why is this better than using #include directives? Whenever you include a library into ASP files, the entire contents of the file is merged with the source file. As an example, say that you have a library that contains 50 relatively complicated functions. A library like this can easily run into several hundred, if not thousands, of lines of source code. If you only wanted to use one function out of the 50, you are still forced into a position where you have to add all of the remaining lines of redundant code, code that will need processing. What if you don't happen to use any of the functions due to the way the page is processed ? Too bad, because ASP must still merge all of the included files in order to process the page. This isn't an effective use of system resources that might be better needed elsewhere.
An ASP script component, on the other hand, can contain all of the library functions that you use, but it is only loaded when it is needed. If the page logic does not require a function then the object is never loaded and the page contains less code and needs less processing which makes it smaller and faster. ASP script components are by far a better design choice for ASP pages because you can organize individual components with related functions, you're not required to add #include directives for every page that might need a function. You can also remotely execute complex scripts on middle tier servers. Included files, on the other hand, run directly on the Web server and cannot take advantage of n- tier architectures in intranet and Internet applications.
When you register your script component something else happens at the same time. The script syntax is also validated. You will receive error messages if there are scripting errors or if the XML cannot be validated . The error messages are not very verbose and give you little more than a position in the file and possibly a snippet of the affected code.
As an example, I've added a semicolon to my script (let's pretend we were converting the source from JScript).
function Add(X,Y) Add = X + Y; end function
What we get when we register the component are the dialog boxes shown in Figures 13-12 and 13-13, which show that there has been an error and that registration wasn't successful.
Figure 13-12
Figure 13-13
The text shown in the error message gives the approximate location ( expressed as line number followed by column number) of the error in the component. Unfortunately this is not usually completely accurate, but it's close. Also, it's not easy to count lines, let alone columns , in Notepad and this is where a text editor that give line and column numbers comes in handy.
For example, the location quoted earlier is actually pointing to the plus sign in our code, rather than the semicolon at the end of our line.
Compile-time error checking is far from perfect, but it will point you in the general direction of any errors that exist in your code.
As you have seen previously, VBScript includes the ability to declare classes and class constructs. You can integrate a standard VBScript class into a Windows Script Component within the < script >< /script > tags in the data portion of the XML file. You still use the standard construct for classes.
class end class
There is one key limitation of using VBScript classes in Windows Script Components that you should be aware of: class information is not exposed automatically. In essence, script components know nothing about the structure of an internal class. In order to expose the class to the outside world you must wrap the class information around methods and properties declared in the script component file.
So, why use a class in a script component? Well, classes will not provide a lot of functionality for a small component, but a complex component can benefit from a class by helping a developer to organize the object structure in a more meaningful way. Large script components can get very complex due to the reliance on XML parsing, so your component may become harder to maintain over time. A well-defined class will always provide a more familiar structure to developers.
As we will see later , you can include external source files. If you have defined many classes you can simply include the source file and provide a COM wrapper for the class definition. Remember that VBScript classes cannot be exposed automatically to COM, so you must provide a mechanism for other objects to access your class.
Internal classes in script components need a class construct and a series of methods and properties that wrap the internal class. We can take the Math component that we built earlier in the chapter and use it as a class wrapper. Initially our script component had the following form.
Within our < script > tags we can build a class that handles the methods of the script component.
You can see that we have built a VBScript class and we have wrapped the functionality into the script component. This can provide a new level of flexibility to a script component, as you will see in the next section.
We are not required to have our class declarations (or our source for that matter) in the file itself. There is a declaration within the < script > tag that allows us to include an external source file. The src=declaration acts as an include for another file. This gives us the ability to move our class declarations to a .vbs (or a .txt file for that matter) file for later use. We can then leverage our external source files across both the Windows Script Host as well as within Active Server Pages and script components.
We can move the class declaration from our math sample to math.vbs . The text of math.vbs is simply the entire class declaration.
Class clsMath Public Function Add(X, Y) Add = X + Y End Function Public Function Subtract(X, Y) Subtract = X - Y End Function Public Function Multiply(X, Y) Multiply = X * Y End Function Public Function Divide(X, Y) Divide = X / Y End Function End Class
We then change the text of the Math component to include the new source file.
Introduction