The com2java tool generates Java "proxy" classes and interfaces that correspond to the coclasses and interfaces contained in a COM type library. It effectively generates a Java API which you can use to access a COM component from Java.
A type library is a binary file that describes a COM component's methods, properties, and data structures. Type libraries are compiled from Interface Definition Language (IDL) files using the Microsoft MIDL compiler. Files that end with the extension .tlb or .olb are type libraries. But type libraries can also be embedded inside other file types, such as .exe files. For example, the type library for Microsoft Excel 2003 is embedded in EXCEL.EXE.
The com2java tool comes in two forms:
When you start com2java.exe, the following dialog is displayed:
To view the com2java options, click Options. Once the Java proxy
classes are generated for a particular COM type library, its corresponding package,
output directory, and options are saved to com2java's configuration file.
The current set of
options and type libraries can also be saved to an XML file by selecting Save Settings from the File menu. These saved
options can then later be loaded by selecting Load Settings from the File menu, or specifying the desired XML
file as a program parameter when launching com2java.exe.
For most COM type libraries, the following default options will be sufficient to generate Java proxy classes which compile without error (all other options should be deselected):
Option | Definition | Command Line (com2javacmd) |
Generate Java AWT classes | This option appears on the main window of the com2java tool.
It tells com2java to generate the Java proxy classes as AWT classes. This option is required when
generating Java proxy classes for an ActiveX control that will be embedded in a Java frame. If
you will not be displaying the ActiveX control visually, do not use this option. * Before you can use this option, you must register your ActiveX control on the machine where you are running com2java (eg, regsvr32 myOcxFile.ocx). |
/AwtForOcxs |
Prompt for names for imported tlbs | Sometimes one TLB will import another TLB. If you are also generating Java proxy classes for the imported TLB, this option causes com2java to prompt you for their package name. See the Knowledge Base for more details. | /ExternalTypelib [typelib]=[packagename] |
Proxies retry on "0x80010001 - Call was rejected by callee" | If a COM server is busy, you may receive the above error. This option ensures the generated code keeps trying the method call when this error code is received. | /RetryOnReject |
Only generate Dispatch interfaces | Most COM interfaces are dual interfaces, which means they can be accessed via vtable pointers or IDispatch:Invoke(). However, a COM interface which is defined in its TLB as a dispinterface can only be accessed via IDispatch:Invoke(). By default, J-Integra® accesses COM interfaces via vtable pointers. This option tells J-Integra® to use IDispatch:Invoke() instead. | /IDispatchOnly |
Generate BeanInfo classes for ActiveX controls | This option allows you to generate BeanInfo classes for COM components marked as controls in the registry. This enables you to use COM ActiveX controls as Java Beans in Java IDEs such as JBuilder and Sun One Studio. If you wish to package these classes into a JAR file, then you will need to create an appropriate manifiest and corresponding GIF files (see the generated beaninfo proxy classes for the names/locations of the GIF files). Please consult your Java IDE's documentation for specific information on deploying beans within its environment. In order to use this option, you must also have the Generate Java AWT classes option selected. | /GenBeanInfo |
Option | Definition | Command Line (com2javacmd) |
Generate Java-style (lowercase) method names | The Java convention is that all method names start with a lowercase letter. Select this option to follow the Java convention. | /UpperCaseMemberNames allows uppercase method names (default: lowercase) |
Don't treat [in]* params as arrays | If the input parameter is called by reference - [in]* - com2java converts it to an array of the given type. For example, if the input parameter is int*, com2java generates int[] as the Java type. This option tells com2java not to treat [in]* parameters as arrays. This means the input parameter cannot be modified by the COM component. | /TreatInStarAsIn |
Generate Arrays as Objects | This option affects method parameters which are SAFEARRAYs. Rather than having the generated method parameter specify the specific array type, this option tells com2java to specify java.lang.Object instead. This is useful in situations where you want to pass a multi-dimensional array. The number of dimensions is not specified in the COM IDL for SAFEARRAYs, and if you don't use this option J-Integra® will assume you are passing a one-dimensional array and generate a corresponding prototype. For example, by setting this option and having com2java generate java.lang.Object instead of java.lang.String[], you are free to pass a 2D String array. Please note that this does not change what is actually passed over the wire (it is still an array). | /ArraysAsObjects |
Omit [restricted] methods | Prevents generation of methods marked [restricted] in the typelib. | /OmitRestrictedMethods |
Option | Definition | Command Line (com2javacmd) |
Clash Prefix | If a method defined in a TLB clashes with a standard Java method (e.g. "getClass"), com2java will prefix the generated method name with a string. "zz_" is the default. | /ClashPrefix [string] (default: "zz_") |
Option | Definition | Command Line (com2javacmd) |
Implement interfaces that may conflict | If a COM coclass implements multiple interfaces which contain methods with the same name, then deselect this option so that the generated Java proxy classes do not implement the conflicting interfaces. You can still access the conflicting interfaces using the generated getAsXXX() methods (see the generated comments for details). | /ImplementConflictingInterfaces |
Don't rename methods with same names | By default, if com2java detects a naming conflict in a COM coclass, it will automatically rename one of the methods by prepending the Clash Prefix. This option overrides the automatic renaming. | /DontRenameSameMethods |
Rename conflicting methods that differ by return value | This option tells com2java to rename interface methods when a COM coclass implements two (or more) interfaces where each interface has identical methods which differ only by return value (something which is allowed in COM but not in Java). The methods are renamed by prepending the interface name. | /RenameConflictingInterfaceMethods |
Reuse methods that have the same name | This option tells com2java to reuse interface methods when a COM coclass implements two (or more) interfaces where each interface has identical methods. The generated Java proxy class implements just one of the identical methods. | /ReuseMethods |
Option | Definition | Command Line (com2javacmd) |
N/A in com2java GUI version | This option forces an error if proxy generation will overwrite files. | /DontOverwrite |
N/A in com2java GUI version | The specified file contains the names of multiple TLBs, package names,
and output directories for generating Java proxy classes for multiple TLBs at the same time.
For example, a text file called msproxies.txt containing the following lines:
C:\Program Files\Microsoft Office\Office10\EXCEL.EXE,excel,C:\java2msexcel\excel Could be used to generate the Java proxy classes for both MSExcel and MSWord at the same time, by running com2javacmd as follows: com2javacmd [options...] /MoreTlbs msproxies.txt |
/MoreTlbs [fileName] |
The com2java tool processes the following data types in COM type libraries:
If a TLB contains an enumeration, com2java will generate a Java interface containing constant definitions for each element in the enumeration.
Example TLB:
typedef enum { MyEnum1 = 1, MyEnum2 = 2, MyEnum3 = 3, } MyEnum; |
Generated Java Interface (MyEnum.java):
public interface MyEnum ... { static final int MyEnum1 = 1; static final int MyEnum2 = 2; static final int MyEnum3 = 3; } |
A COM coclass implements one (or more) COM interfaces. In COM, it is the interface which defines methods and properties, not the coclass. However, you can only access a particular interface through the coclass which implements it. The com2java tool mimics this relationship between interfaces and classes when it generates Java proxy classes for a COM type library.
For each coclass defined in a TLB, com2java generates a Java class with the exact same name as the corresponding COM coclass. And for each interface that a coclass implements, com2java generates a Java interface with the exact same name as the corresponding COM interface. Com2java also generates a special "Proxy" class for each COM interface as well.
Example TLB:
[ uuid(00024500-0000-0000-C000-000000000046), helpcontext(0x00020001) ] coclass MyClass { [default] interface MyInterface; interface MyInterface2; }; |
Generated Java Classes:
Generated Java Class | Generated Java Interfaces | Generated Java "Proxy" Classes |
MyClass.java | MyInterface.java | MyInterfaceProxy.java |
MyInterface2.java | MyInterface2Proxy.java |
Internally, both IMyInterface.java and MyClass.java delegate the real work to IMyInterfaceProxy.java. This abstraction gives you a clean Java API with a one-to-one correlation between COM/Java interfaces and classes. This means the generated Java API is identical to the existing COM API for any given COM component. To demonstrate this, here is an example using Microsoft Excel...
Visual Basic code:
Dim excelApp As Excel.Application Set excelApp = New Excel.Application excelApp.Visible = True |
Corresponding Java code:
excel.Application excelApp; excelApp = new excel.Application(); excelApp.setVisible(true); |
Other than looking up interface and class names, you generally don't need to worry about the contents of these files in order to use J-Integra®. If you wish to learn more about some of the more advanced features of the generated classes, the Knowledge Base is a good source of information.
30425: How to Use Java Proxy Methods which Return java.lang.Object
One additional feature of the IMyInterfaceProxy class is the ability to access a particular COM interface using only the CLSID of the COM coclass which implements it. For example...
String clsid = "00024406-0001-0000-c000-000000000046"; IMyInterface myInterface = new IMyInterfaceProxy(clsid, "localhost", null); myInterface.doWork(); |
J-Integra® handles two kinds of COM interfaces:
By default, J-Integra® uses vtable pointers (i.e. early binding) to access COM interfaces. If the COM component you are accessing contains interfaces which are not dual interfaces, you will need to use the com2java Only generate IDispatch option when generating the Java proxy classes. This tells J-Integra® to use IDispatch:Invoke() (i.e. late binding) to access COM interfaces. See Early Binding (VTable) vs Late Binding (IDispatch) in the KB for more information.
COM events are generated by a special type of interface defined in a TLB as a [source] interface. COM coclasses that implement a [source] interface can subscribe to the events it defines. Since Java has a completely different event mechanism from COM, the com2java tool hides the COM mechanism from the Java programmer and presents the events using the standard Java protocol. To demonstrate how com2java does this, let's look at an example.
The Java to Excel Example, particularly the Bonus Step (subscribe to Excel events) is a good example to run if you wish to see J-Integra®'s event handling in action. If you are interested in knowing exactly what com2java generates in the Java proxy classes to facilitate the handling of COM events in Java, please read through the following example.
This is the IDL definition for the Excel Application class. Note how it specifies the AppEvents interface as a source interface:
[ uuid(00024500-0000-0000-C000-000000000046), helpcontext(0x00020001) ] coclass Application { [default] interface _Application; [default, source] dispinterface AppEvents; }; |
The AppEvents interface defines the events that can be generated as methods implemented by the interface:
[ uuid(00024413-0000-0000-C000-000000000046), helpcontext(0x000200a9), hidden ] dispinterface AppEvents { properties: [id(0x0000061d), helpcontext(0x0001061d)] void NewWorkbook([in] Workbook* Wb); [id(0x00000618), helpcontext(0x00010618)] void SheetBeforeRightClick( [in] IDispatch* Sh, [in] Range* Target, [in] VARIANT_BOOL* Cancel); etc... }; |
Application.java contains the standard Java methods for adding or removing an EventListener:
public void addAppEventsListener(excel.AppEvents theListener) ... {...} public void removeAppEventsListener(excel.AppEvents theListener) ... {...} |
Since AppEvents is a [source] interface, AppEvents.java extends java.util.EventListener:
public interface AppEvents extends java.util.EventListener ... { public void newWorkbook (excel.AppEventsNewWorkbookEvent theEvent) ... ; public void sheetBeforeRightClick (excel.AppEventsSheetBeforeRightClickEvent theEvent) ... ; etc... } |
Another Java event convention is that each of the methods in the interface should have a single parameter, which is an instance of a class derived from java.util.EventObject Java class. If you look at the SheetBeforeRightClick method in the COM IDL above, you will see that it takes three parameters. In order to comply with the Java convention, com2java generates an additional class for each method in an event interface, each holding the parameters to the method. For example, here is an clip from AppEventsSheetBeforeRightClickEvent.java:
public class AppEventsSheetBeforeRightClickEvent extends java.util.EventObject { public AppEventsSheetBeforeRightClickEvent(Object source) { super(source); } public void init(Object sh, excel.Range target, boolean[] cancel) { this.sh = sh; this.target = target; this.cancel = cancel; } etc... } |
One final Java event related convention is the use of an Adapter class which implements the event interface and provides empty default implementations for the methods in the interface. This allows developers to create a class which will subscribe to the event but not implement all of the methods in the interface. In the case of the AppEvents interface, com2java generates AppEventsAdapter.java:
public class AppEventsAdapter implements excel.AppEvents { public void newWorkbook (excel.AppEventsNewWorkbookEvent theEvent) throws java.io.IOException, com.linar.jintegra.AutomationException {...} public void sheetBeforeRightClickEvent (excel.AppEventsWorkbookPivotTableOpenConnectionEvent theEvent) throws java.io.IOException, com.linar.jintegra.AutomationException {...} etc... } |