JudoScript.COM Design principles of Judo the sport and the language
HomeJudo LanguageJuSP PlatformJamaica Language 
Judo ReferenceJuSP ReferenceWiki/WeblogTutorials/PresentationsDownloadsGoodiesFeedback  
Article: COM Scripting with JudoScript
 








This article is old and is being consolidated into the book.
Please refer to the corresponding chapter(s) therein.
If the chapters or sections are not completed yet, you can use this article.
Refer to the examples as they are tested against the latest code.

Table Of Content

  1. Introduction to COM and ActiveX
  2. ActiveX Scripting with JudoScript
    » Parameterized Property Getting
    » IEnumVARIANT Interface
  3. Setting Up and Java-COM-Bridge APIs
  4. Summary
  5. Code Listings

COM Scripting with JudoScript

By James Jianbo Huang    December 2002       printer-friendly version

Abstract  

Microsoft's COM and Java are the two most popular object models. JudoScript has native support for both. In JudoScript, ActiveX controls are obtained via the operator new com::. Once obtained, the object's methods can be called and properties accessed just like any other kinds of objects. One of the main reasons for ActiveX scripting is to use Microsoft Office products such as Word and Excel; sample code is presented to demonstrate their uses.

Currently ActiveX event handling is not supported due to the limitation of the underlying JCom package, and out-bound parameters are not supported in a more meaningful way. These situations may improve in the later versions.


 

1. Introduction to COM and ActiveX

Microsoft's Component Object Model (COM) and Java's object model are the two most important object models to date. JudoScript, as a language designed for Java scripting, has also native support for COM/ActiveX scripting. JudoScript seamlessly bridges these two powerful object models (without the Microsoft JVM).

In the early days of Windows, most programs are monolithic executables. DLLs provide limited flexibility and reusability. It was the "crazy" idea of embedding spreadsheets in word documents and vice versa that prompted the concept of OLE, which eventually led to the ubiquitous COM on Windows platforms. Today, most of the major Windows software are presented in the form of ActiveX (what a funky name!), making them readily scriptable with capable scripting languages like Visual Basic and JudoScript.

All COM objects are registered in the Windows registry when the software is installed. Windows have APIs to obtain such objects via GUIDs (Globally Unique IDentifiers). COM objects implements various interfaces; each interface is identified by a GUID and is also registered on the system. Every single COM object implements an interface called IUnknown, which is not useful in itself but allows clients to obtain other interfaces that it implements. Hence, in order to use a COM object, you will need to know its GUID and its interfaces. There are ways to describe and inspect those interfaces offline, but this is not generally available at runtime and type matching is challenging if possible at all. What this means is, general COM objects are not as easily scriptable with scripting languages.

In order to make COM objects scriptable, Microsoft has defined a special interface called IDispatch, which has such an invoke() method for any clients to call named methods supported by the object. In particular, there are two pre-defined method names, "GET" and "PUT", to access "properties" of the objects. Therefore, ActiveX objects are scriptable COM objects that implement IDispatch. How do you know what methods to call using the invoke() method? You as a programmer need to consult the manual for that particular object. (You may ask, why bother to have IDispatch interface anyhow, if you still need to know what the object supports? Keep in mind that IDispatch permits tools like Visual Basic and JudoScript to pass on your intention to call which method and get/set which property; without IDispatch, you may have to write C/C++ code to access these objects, albeit it is possible.)

 

»»» Top «««

 

2. ActiveX Scripting with JudoScript

To get hold of an ActiveX control in JudoScript, use the new with the com:: namespace; once obtained, call its methods and access its properties like any other types of objects in JudoScript.

Listing 1. vbscript.judo
1: sc = new com::ScriptControl;
2: sc.Language = 'VBScript';
3:
4: for i=0; i<10; ++i {
5:   println sc.Eval(i @ '+1001');
6: }

Microsoft Windows has aliases for ActiveX identifiers. In the above example, we instantiates a "ScriptControl", set its Language property to "VBScript", and (on line 5) invokes its Eval() method. To use GUID to find the object, you must use the format in the following example:

Listing 2. ietest.judo
 1: ie = new com::'{0002DF01-0000-0000-C000-000000000046}';
 2: //ie = new com::InternetExplorer.Application;
 3: ie.Visible = true;
 4: ie.AddressBar = true;
 5: ie.StatusText = 'My Status Text';
 6: println '----- Path: ', ie.Path;
 7:
 8: url = 'http://www.yahoo.com';
 9: println '----- Visiting ', url;
10: ie.Navigate(url);
11: sleep(5000);
12:
13: url = 'http://www.google.com';
14: println '----- Visiting ', url;
15: ie.Navigate(url);
16: sleep(5000);
17:
18: println '----- close the browser.';
19: ie.Quit();

This program brings up the Internet Explorer, prints out the path for the executable (line 6), visits Yahoo! and Google respectively for 5 seconds, then closes the brower.

Like calling methods in Java, you can cast values to Java primitive types. For ActiveX invocation, there is one more type, currency.

Parameterized Property Getting

One of the main reasons to script ActiveX controls is to script Microsoft Office products such as Word and Excel. The following is an example that uses Excel.

Listing 3. exceltest.judo
 1: xl = new com::Excel.Application;
 2: println 'Version: ', xl.Version;
 3: xl.Visible = true;
 4:
 5: workbooks = xl.Workbooks;
 6: workbook  = workbooks.Add;
 7: sheet = workbook.ActiveSheet;
 8: a1 = sheet['Range', 'A1'];
 9: a2 = sheet['Range', 'A2'];
10: a1.Value   = 123.456;
11: a2.Formula = '=A1*2';
12: println 'a1 from excel: ', a1.Value;
13: println 'a2 from excel: ', a2.Value;
14:
15: workbook.Close();
16: xl.Quit();

It launches Excel, creates a new workbook, sets a value at cell "A1" and sets a formula at cell "A2", then prints out the values at "A1" and "A2". On lines 8 and 9, it uses parameterized property get; its syntax is the same as the multi-dimensional array access operator. Similarly, a simple property access for ActiveX controls can be conceived as a single-dimensional array access. (It would be preferrable to use a syntax like sheet.Range['A1']; unfortunately JudoScript would be confused by this, since the dot operator and [] operator in this expression are two separate operations, whereas in this case it is really a single operation.) The following is another example for Excel; it lists all the files in the current directory and displays their attributes in Excel. It calculates the sum of file sizes.

Listing 4. testexcel.judo
 1: excel = new com::Excel.Application;
 2: excel.Visible = true;
 3: println "Version:  ", excel.Version;
 4: println "UserName: ", excel.UserName;
 5: println "Caption:  ", excel.Caption;
 6: println "Value:    ", excel.Value;
 7:
 8: xlBooks  = excel.Workbooks;
 9: xlBook   = xlBooks.Add;
10: xlSheets = xlBook.Worksheets;
11: xlSheet  = xlSheets['Item', 1];
12: xlRange  = xlSheet.Cells;
13:
14: xlRange['Item',1,1].Value = "Name";
15: xlRange['Item',1,2].Value = "Length";
16: xlRange['Item',1,3].Value = "Time";
17: xlRange['Item',1,4].Value = "Is-Dir";
18: xlRange['Item',1,5].Value = "Is-File";
19: xlRange['Item',1,6].Value = "Exists";
20: xlRange['Item',1,7].Value = "Writable";
21: xlRange['Item',1,8].Value = "Hidden";
22:
23: list './';
24: filenames = $$fs_result;
25: i = 2;
26: for file in filenames {
27:   xlRange['Item',i,1].Value = file;
28:   xlRange['Item',i,2].Value = file.fileLength();
29:   xlRange['Item',i,3].Value = file.fileTime();
30:   xlRange['Item',i,4].Value = file.isDirectory();
31:   xlRange['Item',i,5].Value = file.isFile();
32:   xlRange['Item',i,6].Value = file.fileExists();
33:   xlRange['Item',i,7].Value = file.fileWritable();
34:   xlRange['Item',i,8].Value = file.isFileHidden();
35:   ++i;
36: }
37: ++i;
38: xlRange['Item',i,1].Value = "Total Size:";
39: xlRange['Item',i,2].Formula = '=Sum(B2:B' @ (filenames.length+1) @ ')';
40: xlRange.Columns.AutoFit();
41:
42: sleep(10000);
43: xlBook.Close(false,null,false);
44: excel.Quit();

The following is an example that uses Microsoft Word. It opens a Word document and prints out its words and tables. Using this program as a template, you can do a lot more with Word; you will need to know the Word's DOM, which is not the topic of this article; this information is available in the help files of the Word product, or any books about VBA for Word.

Listing 5. testword.judo
 1: wdApp = new com::Word.Application;
 2: wdApp.Visible = true;
 3: 
 4: wdDocuments = wdApp.Documents;
 5: wdDocument  = wdDocuments.Open(#args[0].toAbsolutePath());
 6: println 'fullname=', wdDocument.FullName;
 7: 
 8: wdWords = wdDocument.Words;
 9: word_count = wdWords.Count;
10: for i from 1 to word_count {
11:   println wdWords.Item(i).Text;
12: }
13: 
14: wdTables = wdDocument.Tables;
15: println wdTables;
16: table_count = wdTables.Count;
17: println 'table count=', table_count;
18: for i from 0 to table_count-1 {
19:   println 'tables[', i, "]=", wdTables.Item(i+1);
20: }
21: 
22: sleep(3000);
23: wdApp.Quit();

IEnumVARIANT Interface

One of the COM interface, IEnumVARIANT, represents a collection of values. It can be returned by method calls. JudoScript directly converts an IEnumVARIANT into an array.

Listing 6. enumtest.judo
 1: excel = new com::Excel.Application;
 2: excel.Visible = true;
 3: 
 4: xlBooks = excel.Workbooks;
 5: xlBook = xlBooks.Add;
 6: xlSheets = xlBook.Worksheets;
 7: 
 8: ary = xlSheets._NewEnum.getIEnumVARIANT();
 9: for xlSheet in ary { println xlSheet.Name; }
10: 
11: sleep(5000);
12: xlBook.Close(false,null,false);
13: excel.Quit();

 

»»» Top «««

 

3. Setting Up and Java-COM-Bridge APIs

At this writing, JudoScript uses the JCom package for its ActiveX support. Java classes of JCom are already included in the JudoScript. JCom's JNI DLL, jcom.dll, must be put in the PATH environment variable.

JCom package is a straightforward Java-COM bridge. Its API is concise and elegant, and maps Java and COM data types well. However, JudoScript has a wish-list from a Java-COM bridge provider that would support by-reference parameters and event handling. So JudoScript has not ruled out the possibility of creating its own Java-COM implementation. For now, if scripting Microsoft Word and Excel is functioning well, it is deemed good enough, unless users strongly request the aforementioned features.

 

»»» Top «««

 

4. Summary

JudoScript bridges the two most powerful object models -- COM/ActiveX and Java. In JudoScript, scripting ActiveX controls is no different than scripting any other objects, including Java objects; the only difference is the way to obtain an object: ActiveX controls are obtained via the new com:: operator; once obtained, its methods can be invoked, and properties can be got and set. Parameterized property get is achieved with the syntax of multi-dimensional array access. A predefined COM interface, IEnumVARIANT, is interpreted by JudoScript as an array.

Currently, JudoScript does not handle ActiveX event handling, and by-reference parameters are not explicitly supported, that is, the out-bound parameters are not supported. This, however, may change in the future releases.

 

»»» Top «««

 

5. Code Listings

  1. vbscript.judo
  2. ietest.judo
  3. exceltest.judo
  4. testexcel.judo
  5. testword.judo
  6. enumtest.judo




Copyright © 2001-2005 JudoScript.COM. All Rights Reserved.