Clinick's Clinic on Scripting: Take Five What's New in the Version 5.0 Script Engines
November 4, 1998
The script team at Microsoft started a little over two years ago with Visual Basic® Scripting Edition (VBScript) 1.0 and JScript® 1.0—yet we are about to release Version 5.0 of the languages. Talk about Internet time! Hopefully, time scales will get a little more reasonable in the future, which should make your life and ours just a little easier (although it will make writing my articles more difficult without new stuff coming out every six months or so).
Version 5.0 of the script languages represents a major upgrade from the last version most of you are using, version 3.1. Where did version 4.0 go? It was a part of the latest Visual Studio release, and provided all the IntelliSense and debugging features in Visual InterDev™ 6.0. Version 4.0 had no new language features; unless you were running Visual Studio, you would probably not notice any difference. For version 5.0, we concentrated on three major areas:
- Language features
- Script encoding
In this article, I will provide a brief discussion of each of these areas. I will concentrate on the new language features, covering the other areas more deeply in later articles.
There have been many debates over which script language to use, VBScript or JScript. I even wrote an article about it. In that article, I proclaimed "Microsoft is fully committed to evolving implementations of both JScript and VBScript to a level where each language is functionally equivalent. So don't feel that you need to commit to one just to ensure that you are investing in a language that has a future." With version 5.0, we start to deliver on this promise.
VBScript Version 5.0
VBScript 5.0 has a host of new features included to bring it level with JScript, so that your choice of language is one of personal preference. Specifically, we have added regular expressions, classes, With statement, Eval/Execute, function-pointer support, and DCOM support. In addition to the language features, we have beefed up performance of VBScript within HTML pages in Internet Explorer 5.
Regular expressions provide a powerful tool for developing string manipulation code in script; just ask any Perl developer. VBScript 5.0 adds regular expressions—but in a way that is consistent with Basic. To do this, we have added a RegExp object, which is always available to VBScript regardless of security settings in Internet Explorer. The object model is similar in concept to the JScript RegExp object, but it is a little more similar to Basic in its design (collection-based, etc.), so VBScript users should feel at home. The regular expression syntax is identical to that of JScript (which is, in turn, based on Perl), making it easy to move between the two languages.
How do you use regular expressions? I'll give you a simple example of checking to see if somebody has entered a valid e-mail address on an HTML form. In this example, I create a new variable, myRegExp, and then set its value to be a new instance of the RegExp object using the new keyword. Once I have a RegExp object, I need to set the pattern property, which contains the regular expression; in this case, I've set it to be "\w+\@[.\w]+", which will check for a word followed by an @ symbol followed by a word. Once the pattern has been set, I call the test method with the value of the txtEmail text box. The test method returns true if it finds the pattern in the string. I check its return result, and if it's true, I submit the form.
Sub btnSubmit_onclick dim myRegExp set myRegExp = new RegExp ' Set the pattern to check for a word followed by ' an @ followed by a word myRegExp.pattern = "\w+\@[.\w]+" ' Use the test method to see if the email address entered ' is valid if myRegExp.Test(myForm.txtEmail.value) then ' It is so submit the form in this example I ' just alert the user. If you want to use this ' code just remove the comments on the next line ' myform.submit alert("The form would submit now") else ' It's not so inform the user ' and set the focus back to the email text box alert("Please enter a valid email address.") myform.txtEmail.focus() end if End Sub
For more information on regular expressions in VBScript, go to the VBScript site
Note: This is a very simple e-mail address checker, and certainly doesn't cover all the potential valid e-mail addresses. I kept it simple for demo purposes. If you want to know more about regular expression syntax, read Mastering Regular Expressions, by Jeffrey E.F. Friedl. It's based on Perl, but it gives a great backgrounder on regular expressions, and the author even provides a complete example of how to use regular expressions to match e-mail addresses.
Before we leave regular expressions, there's one more interesting feature of the VBScript regular expression object. To maximize the usefulness of regular expressions, the VBScript regular expression object is implemented as a COM object; any application that uses COM can make use of the object. All you need to do is install VBScript Version 5.0 and use the COM object with ProgID "VBScript.RegExp". Now, you Visual Basic developers can use regular expressions in your Visual Basic projects!
One feature supported by JScript and Visual Basic is the ability to create objects internally from either prototypes (JScript) or classes (Visual Basic). This really helps with larger-scale development projects, and allows you to start thinking about object-oriented design. We wanted to keep the VBScript class implementation as close as possible to that of Visual Basic, but Visual Basic relies on having separate .cls files to implement classes. Since VBScript is an embedded language, the run time can't rely on having separate files. VBScript 5.0 introduces the Class statement. This allows the definition of a class in VBScript code without resorting to any special file-naming conventions. Properties and methods for a class are defined in the same way as in Visual Basic, using the Public/Private keywords and the Property keyword. Here's an example of a class that defines a customer:
Class Customer Public FirstName, LastName Private nCreditLimit Private strEmailName Property Get EmailName EmailName = strEmailName End Property Property Let EmailName ( strName) StrEmailName = strName End Property Property Get FullName FullName= FirstName & " " & LastName End Property Property Let CreditLimit ( s ) if s >= 0 then nSalary = s End If End Property Property Get CreditLimit Salary = nSalary End Property Sub Add( First, Last ) FirstName = First LastName = Last End Sub Function RaiseCreditLimit( Amount ) nCreditLimit = nCreditLimit + Amount RaiseSalary = nSalary End Function End Class
The class has two public properties, FirstName and LastName, that are read/write and don't have any code associated with the read/write process. The class also has two read/write properties, CreditLimit and EmailName, and a read-only property, FullName. These properties have code associated with them when their values are changed or queried using the Property statement. FullName is read-only since it has only a Property Get statement. Finally, the class has a method, RaiseCreditLimit. All functions and subroutines in a class are Public unless they are declared Private by using the Private keyword.
Once a class has been defined, VBScript code can create an instance of the object using the new keyword. When an instance has been created, you can use the object just as you would any other object in VBScript. To finish off the example:
' Create a myCustomer variable Dim myCustomer ' Create a new instance of the Customer Class ' and set the value of myCustomer to be that instance set myCustomer = new Customer ' Add a new customer myCustomer.Add(myForm.txtFirstName.value,myForm.txtLastName.value) ' Set their Email address myCustomer.EmailName = myForm.txtEmailName.value ' Set their credit limit myCustomer.CreditLimit = myForm.txtCreditLimit.value ' Display the customers fullname msgbox (myCustomer.FullName)
This is a somewhat contrived example, because the class does not persist itself—but it could easily call Active Data Objects (ADO) or Remote Data Objects (RDO) to persist itself to a database. The key thing here is that classes provide a mechanism for encapsulation of business logic within VBScript, and really help in the development of large-scale projects.
Script is commonly used for "gluing" together objects either on the client or on the server. This typically means setting values on a lot properties and calling methods, which can be time consuming to write as a developer and also inefficient when running the script. To address this problem, VBScript borrows a feature from Visual Basic, the With statement. This statement allows you to qualify an object once and then use it for a series of calls (methods or properties). The VBScript engine can optimize calls to the object in use, and your code is so much more manageable.
For instance, in the customer example in this article, the With statement can help with calls to the customer object.
' Create a myCustomer variable Dim myCustomer ' Create a new instance of the Customer Class ' and set the value of myCustomer to be that instance set myCustomer = new Customer ' Use the myCustomer object With myCustomer ' Add a new customer .Add(myForm.txtFirstName.value,myForm.txtLastName.value) ' Set their credit limit .CreditLimit = myForm.txtCreditLimit.value ' Set their Email address .EmailName = myForm.txtEmailName.value ' Display the customers fullname msgbox (.FullName) End With
Using the With statement means you have to type less, and VBScript doesn't have to keep looking up the name of the object at every call, so your calls to objects will be quicker.
Eval and Execute
One JScript feature that has proved popular is the Eval method. Eval provides the ability to evaluate JScript code at run time. This allows you to write simple calculators by evaluating user input, e.g.1+2, through to adding functions and/or objects to the engine. JScript developers have taken advantage of this feature to build dynamically generated scripts. VBScript 5.0 adds this feature, but takes into account the different semantics of VBScript. The main difference between JScript and VBScript is in the = operator. In JScript, = is used only to assign values to a variables; you use the == or === operators to compare values. In VBScript, the = operator assigns and compares values. To deal with this ambiguity, VBScript has Eval, Execute and ExecuteGlobal.
Eval will evaluate an expression so that Eval("x=1") will return true if x is equal to 1. Eval can be used to evaluate a single expression, so if you want to write a simple VBScript calculator program, Eval is the statement for you. It also allows you to build expressions at run time and get the result. This is especially useful in Dynamic HTML, as objects can be added at run time, and the only way to build an expression including properties from these objects is to use the Eval function.
Execute and ExecuteGlobal
These two functions provide the ability execute a series of VBScript statements at run time. Execute works in the local namespace, so if you need to get access to local variables, Execute is the function to use. If you need to access or add functions to the global scope—useful if you want to add classes at run time --use ExecuteGlobal.
Dynamic HTML provides the ability to assign event handlers to objects at run time. This is especially useful if you are adding objects and code (using Eval) to your Web page at run time. In Internet Explorer 4.0, the only way to get VBScript to hook up code to events was to use the VBScript standard Sub objectname_eventname () naming convention or by setting the event in the HTML element (<body onload="foo()">) Both these mechanisms work well, but are statically defined. In JScript, you can use window.onclick = foo GetRefGetRefGetRefGetRef
set window.onclick = getref("Foo")
window.onclick = foo
Distributed COM (DCOM) provides a mechanism to call COM objects remotely. In Windows Script Host, you could create a logon script that called a COM object on a remote server and returned information from a database located on the server. This allows processing to be distributed to the server and also means deployment of the object is simplified, since the object exists only on the server. DCOM support has been added to both JScript and VBScript by extending the existing functions that allow the creation of COM objects. In VBScript, the CreateObject function now takes an additional optional argument, the server name. For example
Set myremoteobject = CreateObject("MyRemoteObject","\\myserver")
will create MyRemoteObject, which has been registered on \\myserver. After the object has been created, you can use it just as you would a local object.
JScript Version 5.0
The biggest request we've received for JScript since version 3.1 is the ability to catch exceptions, especially on the server. We have been working with the other members of the ECMAScript standards body to ensure that the implementations from different vendors work in the same way. Exception handling in JScript is implemented via the familiar (if you're a Java or C++ programmer) Try Catch notation.
You can get more information from MSDN's Jscript site.
JScript implements DCOM in the same way as in VBScript but with the ActiveXObject rather than CreateObject. For example
var myremoteobject = new ActiveXObject("MyRemoteObject","\\myserver")
will create MyRemoteObject, which has been registered on \\myserver. After the object has been created, you can use it just as you would a local object.
People are developing more and more complex applications with script, and are continually asking for enhanced performance of script in HTML and Active Server Pages (ASP) files. In version 5.0, two main areas of the script engines have been the focus of significant work: VBScript HTML performance and ASP script performance.
VBScript HTML performance has improved considerably. In Internet Explorer 4.0, all VBScript pages would query every element on the page and check to see what events could be fired by each element. Once the events had been queried, the VBScript engine would create dummy event handlers in the script engine—so that if code were added at run time, it could hook up to the events. This solution worked well, but it meant that pages with many elements could be very slow starting up, as VBScript queried the elements for their events at page load time. In VBScript 5.0 and Internet Explorer 5, the event hook up works quite differently. When a page loads in Internet Explorer 5, only objects with event handlers defined in script on the page at load time are hooked up. If you have a page with a table of 100 rows and 100 columns, and you want to respond only to the onclick event of the first cell, only the first cell will be linked to. Any other events will be added at run time if required. This makes VBScript pages much faster loading up in Internet Explorer 5.
ASP performance is not simply a case of speeding up script, but of how script integrates into the whole server environment. In the beta versions of Internet Information Server (IIS) 5 and Windows 2000, ASP performance has improved on average by three times. How did we do that? The main reason is the work done by the Windows 2000 team to ensure that IIS scales better, but we have also done work in the script engines to "early bind" to the response.write and response.writeblock methods. Early binding means that the script engine already has a connection to the object at run time, so there is no need to requery the object at every method call. We chose reponse.write and response.writeblock, because these methods are called in nearly every ASP file, so speeding up these calls will have an impact on a high proportion of ASP code. That's the good news; the bad news is that you'll have to wait until Windows NT 5.0 Beta 3 to see these performance gains in ASP files.
We've made script faster, and we've added a ton of features to VBScript, so you're going to develop your next application in script. Great—but there's always been one problem with script: Anyone can see it by doing a simple View Source. This is a helpful feature in some respects—and it's why there are so many scripters out there, because they can "borrow" other people's code or ideas. As solutions written in script become more complex, and people try to make a living out of those solutions, this availability becomes a major obstacle to script adoption. To help combat this, we have added an exciting new feature in Version 5.0: script encoding.
Script encoding allows you to encode the script in your HTML, ASP, Scriptlet or Windows Script Host file so that if a user looks at the source, he will see something that certainly isn't readable by most human beings. Taking the classes example from earlier, I've encoded the VBScript.
Hopefully you agree that the above code is pretty unintelligible to the average user. It's important to note that this is a relatively simple encoding scheme and is not designed to keep out a determined hacker. What it does provide is a further step required by people to find out how cool your code is. To further protect your code, include a copyright statement at the top of the script; then your lawyers can get involved if anybody uses your code without your permission.
One further benefit of script encoding is check sums. Whenever you encode script, the encoding mechanism creates a check sum based on the contents of the script block. If a user attempts to change any of the encoded text, the script will no longer match the check sum and will fail to run. This is a real boon for support. Imagine you shipped a product with thousands of lines of ASP code, and you got support calls saying the code just stopped working. Since your code is always perfect, you're sure that it can't be your code—but it's still failing for the customer. Without a check sum, you would have to investigate the customer's site extensively, only to find that he had "tweaked" the code you gave, resulting in the errors. If you encode the script, that same "tweak" will stop the script running completely.
To encode script, we provide a command line script encoder (screnc.exe) that will take an HTML, ASP, VBS, JS or SCT file and encode any script contained in the file. When the script is encoded, the encoder changes the script language name to be scriptlanguagename.encode, so VBScript becomes vbscript.encode. We took this approach so that if an HTML page with encoded script is loaded into an older browser, the script code will be ignored, since Internet Explorer 3. x or 4.0 and Netscape Navigator don't recognize the language. It also allows Internet Explore 3. x and 4.0 users to take advantage of encoding by upgrading the script engines to version 5.0. Script encoding deserves its own article, and I will cover it in more depth in the future. In the meantime, you can get more info and the script encoder from the Microsoft Scripting site.
Version 5.0 of scripting represents a major release of the script engines, and tries to address the feedback we've had from script developers. We hope that the additions to VBScript make it easier for you to deliver more sophisticated Web applications on the client and server, while encoding allows you to protect the fruits of your labor. I look forward to hearing your feedback on our progress to date, so please use our scripting newsgroups on msnews.microsoft.com. I monitor them daily, and most of our developers are on at least once a week, so you should get feedback quickly. To make it even faster and easier, I've set up an e-mail address at Microsoft: firstname.lastname@example.org. All e-mails to this alias will be automatically added to our wish database, so please write us.
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.