|
|
|||
|
|
||
EarthWeb sites:
|
|
Chapter 21Building COM Objects with Javaby Bryan Morgan
Chapter 20, "Calling COM Objects from Java," gives examples showing COM objects being used in code written in the Java programming language. Because of the similarities between COM and Java, the two technologies can work together in a seamless fashion. When Java classes have been built to "wrap" the COM object, these classes can be treated like any other Java class in a Java program. Chapter 20 gives examples showing Java code calling a COM dynamic link library as well as an ActiveX control in a Web page. This chapter addresses the opposite situation: Just as Java code can be written to call COM objects, it can also be written to implement COM objects. Because COM is a language-independent object model, when a COM object has been implemented in Java and registered on the system, this Java COM object can be used by programmers writing in Visual Basic, C++, Delphi, or other popular Windows programming languages. This chapter examines the process of designing and constructing COM objects as well as the issues involved with their use. The examples demonstrate building a COM object that is used in a Java applet, a Java application, and a Visual Basic application to demonstrate the power of combining Java and COM. A Brief Review of COMSeveral topics discussed in Chapter 16, "Java and the Component Object Model," help lay the groundwork for the material covered here. COM provides the "plumbing" that is used by objects implemented in various programming languages. Using the rules laid down by COM, these objects can coexist and interact in a predictable fashion-even if the objects were developed by different vendors in different years! However, much of the material introduced in Chapter 16 remains unseen by the COM developer programming in Java. For instance, recall the rule that each COM object must implement, at a minimum, the IUnknown interface. This remains true for COM objects implemented in Java; however, thanks to the methods by which COM and Java were integrated using the Microsoft Virtual Machine, the developer is shielded from the details of implementing this interface (and many other details). Whereas programmers in other languages are forced to use the API functions in COM to initialize COM and retrieve interface pointers, Java programmers can create a COM object by simply using the new() operator. This is identical to the way that standard Java classes are instantiated in Java. Reference counting is normally accomplished through calls to the AddRef() and Release() methods of the IUnknown interface. However, thanks to Java's garbage-collected memory-management model, the Java runtime environment handles the freeing of any memory associated with an allocated COM object. Finally, containment and aggregation using COM objects is presented in Chapter 16 as a way to support code reuse. The Java programmer can extend an existing COM class through aggregation by using the extends keyword when defining the new class. To sum up programming COM objects in Java, it is fair to say that the integration between COM and Java is so seamless that another Java programmer could read your completed source code and not even know that COM was being used. In fact, the differences would only show up if someone wanted to use your Java COM object on a platform other than Windows. Developing COM Objects for Programmers Using Other LanguagesChapter 20 mentions that calling COM/ActiveX objects from Java has its disadvantages. For instance, the charting example given in Chapter 20 will only run within the Microsoft Internet Explorer browser and (currently) on the Windows platform. This can be viewed as a disadvantage in the Internet environment, where many users using many platforms will routinely access your Web-based information or application. However, developing COM objects in Java in no way puts you at such a disadvantage because COM objects are typically developed to accomplish tasks other than providing active content within a Web browser. If you write a powerful, well-designed COM object in Java, your end result will be a standalone object that can be used by programmers coding in Visual Basic, C++, and Delphi. Using distributed COM (DCOM), this object can even be on a remote machine across a network. Therefore, instead of limiting the Java programmer, it opens up the Java language to a whole new world of users. Although Java is still in its infancy, one of its chief criticisms is that is does not "play well" with other languages. Building a Java class as a COM object opens its use up to programmers in many other languages (including Java). Designing a Simple COM ObjectBefore worrying about the implementation details involved with constructing a COM or Java object, take a moment to think about the design issues. As mentioned before, the following Java constructs remain the same when constructing COM objects:
Knowing these things, you can set out to design a COM class just
as you would design a Java class. The only possible difference
is that all methods used to put or get object
information must be defined in an interface in the COM class.
In the examples used throughout this chapter, a COM class is created to perform string manipulation functions equivalent to the functionality found in the java.lang.String class. (Keep in mind that although Java programmers may take this class for granted, programmers in other languages do not have these built-in capabilities!) When completed, the example demonstrates a generic COM object that programmers can use in any language to perform common string operations.
Examining the java.lang.String class reveals a wide variety
of useful functionality that will be implemented in our string
object (we'll call it CString). Table 21.1 is a list
of the CString class's methods.
These methods will be implemented in Java and packaged as a COM object. Listing 21.1 shows the Java method definitions for each of the methods contained in Table 21.1. Listing 21.1. Java definitions for the methods in Table 21.1.
Creating the Type LibraryAs mentioned in this chapter and originally discussed in Chapter 16, COM classes are defined within a type library. This type library is created from an object description language (ODL) object specification file containing the definition of a COM class and its interfaces. This section demonstrates how to create the ODL definition for the CString object using the MKTYPLIB tool included with Visual J++ to build the type library. To review, the following steps must be completed to build a COM object for use by other applications:
After completing these steps, the COM object is ready to be used by any application capable of calling COM objects. We are now ready to begin the actual construction of the object. Generating GUIDs for the COM ObjectBefore generating GUIDs for the COM object, you must first decide how many interfaces and classes will be contained in the defined ODL library. You will be defining one class, CString, that could contain one or more interfaces. For simplicity's sake, group all the methods listed in Table 21.1 into one interface named IString. Although it would be possible to group all the different types of methods into smaller, separate interfaces, nothing would be gained from that exercise from a learning standpoint. (The same effort and knowledge required to create one COM interface is basically duplicated when creating two or more.) Therefore, the COM object to be built in this chapter consists of a class named CString containing an interface named IString. The contents of the IString interface are the methods listed in Table 21.1. Three GUIDs must be generated to define the elements within the type library: The first will be used to define the library itself; the second will be used to identify the COM class Cstring; and the third will be used to identify the IString interface. Chapter 16 introduces the GUIDGEN tool, which is capable of generating GUIDs. This tool is included with Visual J++ and can be run from the Tools | Create GUID main menu option. Running this tool three times on my machine produced the following three GUIDs for the type library:
If you run this tool on your machine, you will retrieve a different set of IDs. Therefore, unless you are planning to re-create the entire example, simply use these GUIDs in any code you create throughout the remainder of the chapter. Building the Shell of a Type LibraryNow that the GUIDs have been generated for the CString class, the shell of the COM object can be created. This empty shell is listed in Listing 21.2 and contains no method definitions as of yet. Listing 21.2. The initial attempt at the CString type library.
What is accomplished in Listing 21.2? Basically, the entire ODL definition for the CString class is created except for the method declarations. The class definition, in fact, is complete. It simply defines dispinterface IString as a member of the CString class. Two things should be noted about the definition in Listing 21.2. First, note the use of the GUIDs throughout the class definition. As stated earlier, one GUID was generated to be used by the library, the interface, and the class. The second item to note is the dispinterface keyword used to define the IString interface. Declaring an interface in ODL using the dispinterface keyword means that this interface will derive from the IDispatch interface rather than directly from the IUnknown interface. Deriving from the IDispatch interface enables the object to be accessed directly through OLE Automation. In the C programming language, the contents of the IDispatch interface appear as follows:
The Invoke() method is used by OLE Automation controllers (such as Visual Basic) to call a method or access a property within a dispatch interface. The GetIDsOfNames() method converts the physical names of properties or methods to logical dispatch IDs within the dispatch interface. The GetTypeInfoCount() method determines whether type library information is available for the interface. Finally, the GetTypeInfo() method returns type information for the dispatch interface. Fortunately for the Java programmer, the plumbing involved with implementing the IDispatch interface is handled by the Microsoft Virtual Machine. The Java developer must simply implement the additional functions defined in the interface that derives from IDispatch. Mapping Java Types to ODL TypesNow that you have laid down the outline of the CString class, it is time to start defining the methods in the IString interface. Each method declaration has the following general syntax:
Before randomly assigning ID numbers to identify a specific method within dispinterface, note that the id flag is a 32-bit integer number. The first 16 bits (0Ð15) are open for the developer to use. Bits 16Ð31 are reserved to pass additional information to the calling object. (Consult the COM documentation included with Visual J++ to learn more about the id flag.)
The ODL defines its own set of data types, all of which map, in
one way or another, to corresponding Java data types (see Table
21.2).
For instance, nearly all the methods to be declared in the IString interface use Java String objects in one way or another. To declare a java.lang.String parameter in ODL, the parameter would be declared as type BSTR. Now that you know the syntax for each method's definition and have an understanding of the available ODL data types, it is time to actually build the ODL definitions for the IString methods. Because these methods were originally defined in Java (refer to Listing 21.1), it is a relatively easy step to convert them to their ODL equivalents. The Example21 library is fully defined in Listing 21.3. Listing 21.3. The complete definition of the IString interface.
The ODL file containing the contents of Listing 21.3 is named Example21.ODL. It can be found in the \TypeLib directory for this chapter on the CD-ROM included with this book. Using MKTYPLIB to Build the Type LibraryWhen the ODL source code has been created for the IString interface, the type library can be created using the MKTYPLIB tool included with Visual J++. For Java programmers, this tool can be utilized using the following syntax: mktyplib /nocpp filename.odl The /nocpp option must be specified on the command line, or else MKTYPLIB will try to use a C preprocessor. In addition to the /nocpp option, MKTYPLIB also accepts several other useful command-line options. For a complete list of these options, see the documentation on MKTYPLIB in Chapter 16. Before using MKTYPLIB, make sure its directory is in your system PATH. By default, this directory will be C:\MSDEV\BIN. To build the Example21.TLB type library file, simply execute the following command: mktypelib /nocpp Example21.odl Running this command creates the EXAMPLE21.TLB file. This file will be utilized by the JAVATLB file to create skeleton Java classes based on the contents of the type library. You may receive warnings about using the char data types in the ODL, because the char data type is not directly supported by the IDispatch::Invoke() method. Therefore, you cannot invoke any methods using this data type through an OLE Automation controller. Because neither the Java nor the Visual Basic examples use these methods, in this example these warnings will be ignored. However, if you were building an application to use these methods, it would be wiser to use the unsigned char data type instead. When this happens, the Java class files that are generated treat the unsigned char data type as a byte value. It would be the programmer's responsibility in the Java implementation to convert this byte value to a character value. For our purposes, however, the example continues as is. Generating the Java Interface to the COM Object Using JAVATLBIn Chapter 20, the Java Type Library Wizard is used from within the Visual J++ development environment to build Java class files for registered COM objects. The JAVATLB tool is the command-line version of the Java Type Library Wizard that performs a similar task. However, when JAVATLB is used from the command prompt, it can generate class files from a type library even if that type library has not yet been registered. In the previous section, "Using MKTYPLIB to Build the Type Library," you should have built a type library correctly for your CString class. Therefore, at this point you will generate trusted class files from this type library. After making sure that the directory containing JAVATLB.EXE is included in your system PATH statement, run the following command to generate the Java class files: javatlb Example21.tlb When this command has been completed successfully, examine the contents of your Java \Trustlib directory. By default, this directory should be c:\windows\java\Trustlib. To determine the exact location of the Trustlib directory on your machine, examine the following registry key: HKEY_LOCAL_MACHINE\Software\Microsoft\Java VM\TrustedLibsDirectory A new directory should have been created within your \Trustlib directory named Example21. This directory will contain two Java class files: CString.class and IString.class. To receive a SUMMARY.TXT file containing the interface method definitions in Java, run JAVATLB with the following syntax: javatlb /U:T Example21.tlb This produces the SUMMARY.TXT file shown in Listing 21.4. Listing 21.4. Example21.TLB summary information created by JAVATLB.
A quick comparison of the summary file contents with the Java methods defined in Listing 21.1 reveals an exact match! Therefore, the type library was created correctly and the JAVATLB tool was able to accurately build Java classes based on the contents of this type library. Now all that is left to do is to actually implement the IString interface in Java and then register the Java class as a COM object. When this is done, sample applications will be built in Java and Visual Basic that make use of this COM object. Implementing the COM Object in JavaThe "new" work is now behind you. You have made use of the JAVATLB and MKTYPLIB tools to build a COM type library and create Java classes based on the contents of that type library. Now you must climb back on familiar ground and implement the IString interface in Java. Because the methods in this interface very closely resemble the member methods of the java.lang.String class, nearly all of these methods will consist of a single line of code. Listing 21.5 contains the actual implementation of the CString class in Java. This Java class will be named COMString to avoid name conflicts with the CString.class file. Listing 21.5. Contents of the COMString Java class.
Each method in this class simply calls the corresponding method within the java.lang.String class. This class implements the IString interface and therefore implements all the IString methods. If any of these methods were left off, the compiler would generate an error. Registering the Java Classes Using JAVAREGOne last step remains before the COMString class can be used as a COM object by any other application: registering the new COM object in the Windows Registry. Visual J++ comes with a command-line tool named JAVAREG that will insert the proper entries into the Registry based on the options passed to it by the user. (See Chapter 16 for a complete listing of the JAVAREG options.) The two most important options for registering a Java class as a COM object are /class:class_name and /clsid:{xxxxx}. To register a new class, use the /register option. Likewise, to unregister a class, use the /unregister option. Using this set of commands, register the COMString class using the following syntax:
The CLSID used when registering the Java class should always be the CLSID of the coclass defined in the ODL file. To verify that the COMString class was correctly registered, search through the Registry for the string COMString. Notice that the value of the HKEY_CLASSES_ROOT\CLSID\0AD2C502-18A5-11d0-B4EE-444553540000\InprocServer32 Registry key is MSJAVA.DLL. This is the in-process server for the Microsoft Virtual Machine. This value will remain the same for all Java classes registered as COM objects. Calling the COM Object from a Java AppletNow that a COM object has been created in Java, you must test it out to ensure that things are working the way they are supposed to. The remainder of the chapter demonstrates thoroughly testing the COM object using a Java applet and a Visual Basic application. Each of these applications looks virtually identical; the only difference is that one of them is written in Java and runs in a Web browser, whereas the other one is written in Visual Basic and runs as a standalone Windows application. What these applications have in common is that they both will call the same COM object: CString. To demonstrate that the Java/COM object actually works as promised, five methods will be called and results will be displayed to the screen:
To call a COM object from Java, you will have to reuse the knowledge gained in Chapter 20. However, the only tricky material covered in that chapter involved registering the COM object and generating the Java class files from the COM object's type library. In the case of the COMString class, both operations have already been accomplished. Therefore, you are free to dive right in and begin building a Java applet to test the five candidate methods. This applet simply needs to import the CString classes using the following statement: import example21.*; The source code for the Java tester applet is shown in Listing 21.6. The interesting portion of this sample program occurs during the action() method, where the contents of the text components are retrieved based on button-push events. The text retrieved is passed to one of the COM object's member methods. The output from these methods is displayed in the text boxes on the right side. Listing 21.6. The Java/COM tester applet.
The following COMString methods are called in Listing 21.6:
Figure 21.1 illustrates what the applet looks like in the Internet Explorer 3.0 Web browser. Figure 21.1 : The tester applet in Internet Explorer 3.0.
This example demonstrates that it is possible to call a COM object from within a Java application. However, one of COM's best features is its language independence. The example in the following section builds a sample application that is very similar to the first except that it is created in Visual Basic. Calling the COM Object from Visual BasicFor a Visual Basic application to retrieve a Java/COM interface and call that interface's methods, two steps are required. First, the Visual Basic application must declare a variable whose data type is defined to be the interface name. For instance, in the previous sections you created a COM interface named IString. To use this interface in Visual Basic, you would declare a variable using the following syntax: Dim StringObj As IString Continuing with the objects created in the previous example, to initialize the StringObj variable, you would issue the following statement: Set StringObj = New CString
From that point on, the interface methods can be called using
the standard Visual Basic dot notation (.) syntax.
If you plan to build a Visual Basic application from scratch that calls an existing COM object, add a reference to that object's type library by selecting the Tools | References menu option and then selecting the COM object's type library in the ensuing dialog. When this is done, Visual Basic adds a CLSID and type library name internally in the project. When this is done, you can create and use an object of that type freely within the program. The StringObj parameter can be initialized by issuing the following command in the Form_Load() method: Set StringObj = New CString When this variable has been initialized, it is simply a matter of calling the COMString object's methods and returning their results to the screen. Listing 21.7 contains a partial code listing of the COMServer Visual Basic application. It shows the syntax used to call the various COM functions from Visual Basic. Listing 21.7. Visual Basic code used to call COM interface methods. Private Sub bEquals_Click() EqualsR.Text = StringObj.EqualsIgnoreCase(EqualsTL.Text, EqualsBL.Text) End Sub Private Sub bLength_Click() Dim length As Integer length = StringObj.length(LengthL.Text) LengthR.Text = length End Sub Private Sub bLower_Click() LowerR.Text = StringObj.ToLowerCase(LowerL.Text) End Sub Private Sub bStarts_Click() StartsR.Text = StringObj.StartsWith(StartsTL.Text, StartsBL.Text) End Sub Private Sub bTrim_Click() TrimR.Text = StringObj.Trim(TrimL.Text) End Sub Figure 21.2 shows the Visual Basic application running with outputs sent from the COMString Java/COM object. Figure 21.2 : The Visual Basic COMTester application.
Although the examples here use only Java and Visual Basic, similar functionality is possible using languages such as Delphi or C++. Keep in mind that to call Java COM objects from a Visual Basic (or other language) application, you must have the Microsoft Virtual Machine installed on the local system. It then follows that for the Virtual Machine to be installed, Microsoft's Internet Explorer browser must also be installed. The reality of the situation now is that few people will probably choose to implement a COM object using Java because Java is an interpreted language. To avoid this performance hit, COM objects will probably continue to be built using C or C++ until Java can be compiled to machine code in future versions of Visual J++. SummaryUsing tools such as JavaTLB and JAVAREG, the Visual J++ developer can develop COM objects that can then be used by programmers using other languages such as Visual Basic, Delphi, and C++. The ODL is used to build a COM class definition. After the definition has been completed, the ODL source file can be compiled to create a COM type library using the MKTYPLIB tool included with Visual J++. When the type library has been built, Java classes can be generated using the JavaTLB tool. The Java code for the COM object can be written to utilize COM without adding any new Microsoft-proprietary extensions to the Java language. A COM object can be created for use within an application simply by using the new keyword. Methods and properties within that object can then be utilized using standard Java syntax. After the class has been successfully built using Visual J++, it can be registered in the Windows Registry using JAVAREG. When the object has been registered, it can be used by any Windows application that can dynamically allocate and create a COM object. |
|
|
|
|
Use of this site is subject certain Terms & Conditions. Copyright (c) 1996-1998 EarthWeb, Inc.. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of EarthWeb is prohibited. |