|
|
|||||||||||
Mixing Java and Native CodeJava is a powerful and sophisticated language that is taking its place alongside other widely used software development languages. Because few developers have the time to rewrite much of the useful code available in libraries written in other languages, it makes sense to understand how Java can access this code. Like any other programming language, Java embodies a set of tradeoffs, making it a good solution for some problems and a poor solution for others. The ability to mix and match code written in different languages lets developers achieve the maximum benefit from the tools at their disposal. There are many scenarios that require Java code to call code that is written in some other language. For example, a Java developer may want to do any of the following:
Almost all class libraries, including the ones from JavaSoft's JDK, call code written in other languages to exploit some of these scenarios. In the context of Java, any code that is not written in Java is called native code. This document does not dwell on the pros and cons of using native code versus Java code. Rather, it attempts to give the spectrum of options available to a Java programmer who wants to call native code from Java for any number of reasons. The Microsoft Win32 VM for Java (Microsoft VM) provides many ways for Java code to call native code, as shown in the following list:
The remainder of this document discusses these interfaces between Java and native code in more detail. J/DirectMicrosoft® J/Direct is a powerful mechanism that enables Java code to call application programming interfaces (APIs) in DLLs in the most straightforward manner possible. The code in DLLs called through J/Direct has no additional interfacing responsibility imposed on it, which makes J/Direct an excellent vehicle for calling previously developed native code. (The RNI or JNI programmer typically must write wrapper DLLs around existing native code to interface between the Java environment and the native code.) The most obvious use of J/Direct is to call Win32 APIs or APIs in third-party Dynamic-link libraries. The Microsoft VM automatically translates common Java data types to those expected by C functions. Compared to RNI, J/Direct dramatically reduces the amount of extra code and the number of wrapper Dynamic-link libraries that would need to be written. J/Direct is best illustrated with an example, as follows: class ShowMsgBox { public static void main(String args[]) { MessageBox(0, "Hello World!", "Message box using Win32 API from Java", 0); } /** @dll.import("USER32") */ private static native int MessageBox(int hwnd, String text, String title, int fuStyle); } If you know both Java and Microsoft® Windows® programming, the only line that might be new is: /** @dll.import("USER32") */ In the example, this line is a directive to the compiler to link MessageBox to the Win32 API in USER32.DLL using the J/Direct protocol. The Microsoft VM provides the necessary support to make this happen. For example, the String Java class is marshaled into a null-terminated string, expected by the C language calling convention for a string. The support provided by the Microsoft VM makes it possible to call more than 95 percent of the Win32 API functions in a simple manner, similar to the previous example. Helper classes, source code, and samples provided as part of the Microsoft SDK for Java will help Java programmers who want to exploit the richness of the Win32 platform from their Java applications. For a detailed description of how to use J/Direct, see About J/Direct. Also, see the J/Direct samples that are available in the SDK for Java. ActiveX/Beans IntegrationJavaBeans provides the component model for Java. JavaBeans, while still in its infancy, is gaining popularity with Java developers. It is likely there will be a variety of JavaBeans components in the marketplace in the near future. ActiveX is a language-neutral component model that uses COM as its base. In terms of the marketplace, ActiveX is a much more mature component model, supported by a whole set of power tools, such as Microsoft® Visual Basic®, Microsoft® Visual C++®, Borland Delphi, and Powersoft PowerBuilder, as well as thousands of commercially available ActiveX components. The integration of ActiveX and Beans provided by the Microsoft VM enables a Java programmer to take advantage of the vast array of rich ActiveX controls available. Similarly, ActiveX control programmers can make use of compelling JavaBeans components as they begin to appear in the marketplace. The integration provided by the Microsoft VM is such that an ActiveX control appears as just another Bean to the Java programmer. Likewise, the JavaBeans component appears as just another ActiveX control to the ActiveX control programmer or control container. This enables programmers to work in the environment they are most familiar with, while exploiting the richness of the available components and controls on the platform, no matter what language was used to develop the control or component. Thus, the two main features of the integration provided by the Microsoft VM enable a programmer to:
The following sections describe how a developer can utilize the Microsoft VM and SDK tools to accomplish these objectives. Hosting a Bean in an ActiveX ContainerIn JavaBeans architecture, a Bean is a reusable Java component, which is usually meant to be used in the context of other Beans or components in some container. The Microsoft VM provides the bridge necessary to host a Bean in an ActiveX container. The ActiveX container cannot differentiate the Bean from an ActiveX control; it treats it like any other ActiveX control. So, for example, Microsoft® Visual Basic® 5.0 can use the Bean exactly as it would use a control. Hosting a Bean in an ActiveX container is essentially a two-step process: write the Bean and run a tool called javareg. The following example shows a typical javareg command line registering a Bean called JChart: javareg /register /control /class:JChart /codebase:. /clsid:{177cf4a0-e7e0-11d0-b8e7-0000f81ecce7} /typelib:JChart.tlb The javareg tool introspects the JavaBeans component to gather information about its properties, events, and methods, and then outputs this information in the form of a type library. A type library is the file that an ActiveX container uses to find information about an ActiveX control. The tool also registers the Bean, which allows an ActiveX container to find the Bean, like it would any other ActiveX control. For more information about the javareg tool, see Using Javareg. The Microsoft SDK for Java also provides samples of this technique that a developer will find useful. After running javareg, the Bean can be hosted in any ActiveX container, appearing there as an ActiveX control. When the JavaBeans component is invoked as an ActiveX control, the Microsoft VM is loaded and makes the appropriate mapping between the methods, properties, and events of the JavaBeans and the interfaces, methods, properties, and events of the ActiveX control. Examples of some popular ActiveX containers include Visual Basic, Microsoft® Office, Borland Delphi, and Corel WordPerfect, among others. It should be noted at this point that Microsoft® Internet Explorer is itself an ActiveX container, and when a JavaBeans component is wrapped as an ActiveX control by the VM in Internet Explorer, the component exposes the same COM interfaces as any ActiveX control in the browser. To enable this mode of use, however, you must use the OBJECT tag to load your Java applet. When you use the OBJECT tag, you do not need to run javareg. See Using the HTML 4.0 OBJECT Tag below for more information on using this tag. Java MonikersActiveX containers, such as Visual Basic 5.0, are able to find a Bean through a "Java Moniker," which uses a URL syntax similar to the one used in the HTML OBJECT tag. So for example, in Visual Basic 5.0, you can use the command GetObject("java:java.util.Date") to create an instance of the Date object, and then invoke methods on it. This is possible because DCOM introduced an extensible moniker namespace, so if you pass a string like "java:some.class" to MkParseDisplayName, OLE32 will load the Microsoft VM and let it provide the class moniker to bind to the object (it looks up "java" as a progid in the registry and gets the CLSID of a handler implemented by the VM). Furthermore, ActiveX containers that host a Bean can find information about the Bean through a COM interface called ITypeInfo. This allows access to interfaces such as IDispatch and permits all the usual operations represented through ActiveX interfaces, such as calling QueryInterface, and so on. To help illustrate how moniker binding works, here is an example C++ program that uses monikers to bind to a simple Java object called TestObject, whose source code follows this example: TEST.CPP #include <windows.h> #include <olectl.h> #include <stdio.h> HRESULT BindToObject(LPOLESTR pwszDisplayName, REFIID riid, LPVOID *ppunk) { HRESULT hr; IBindCtx *pbc; ULONG chEaten; IMoniker *pmk; *ppunk = NULL; hr = CreateBindCtx(0, &pbc); if (hr == S_OK) { hr = MkParseDisplayName(pbc, pwszDisplayName, &chEaten, &pmk); if (hr == S_OK) { hr = pmk->BindToObject(pbc, NULL, riid, ppunk); pmk->Release(); } pbc->Release(); } return hr; } void main(int argc, char *argv[]) { HRESULT hr; IUnknown *punk; hr = CoInitialize(NULL); if (hr == S_OK) { hr = BindToObject(L"java:TestObject", IID_IUnknown, (LPVOID *) &punk); if (hr == S_OK) { punk->Release(); } else { printf("failed to bind to java object (hr=%08x)\n", hr); } CoUninitialize(); } } TestObject.java import java.io.*; import java.net.*; import com.ms.com.*; public class TestObject { public TestObject() { System.out.println("created java object!"); } } Using the HTML 4.0 OBJECT TagIf you want to treat the Bean as an ActiveX control in Internet Explorer 4.0, to gain access to COM interfaces on that object for example, you can skip the javareg process and just use the HTML 4.0 OBJECT tag (Internet Explorer 4.0 queries the object directly for its Typeinfo data rather than having to rely on the Typelib information generated by javareg). The HTML 4.0 OBJECT tag specification is supported by the Microsoft VM in Internet Explorer 4.0 so that you can use the OBJECT tag instead of the APPLET tag to run Java applets from a local or remote codebase. For example, the following code fragment could be used to load the Java class myprogram.one from http://www.one.come/two/three/. <OBJECT classid="java:myprogram.one"> codebase="http://www.one.come/two/three/"> </OBJECT> Note that the Microsoft VM only provides access to COM interfaces for Java classes loaded using the OBJECT tag. The APPLET tag is handled in a different manner internally. For more information on HTML 4.0 and the OBJECT tag, see http://www.w3.org/TR/WD-object. Exposing JavaBeans Methods through IDispatchBy default, the Microsoft VM for Java uses JavaBeans introspection to enumerate the methods and properties that are exposed through IDispatch. Unless a Bean provides its own BeanInfo, all public methods are exposed, as well as properties discovered using standard design patterns (such as setText and getText). Mapping JavaBeans Events to ActiveXIn addition to exposing event interfaces, ActiveX controls have the concept of a default, outgoing set of events. A control developer defines this default event set, which is often the only event source connected to by ActiveX containers. To provide the greatest flexibility to Java developers, the ActiveX control framework allows use of design patterns to define this default event interface. Since the JavaBeans eventing model is sufficient for many eventing needs and maps well to the ActiveX IConnectionPointContainer model, Microsoft recommends that events be exposed using the JavaBeans eventing specification. When an ActiveX component attempts to connect to the default event interface of an ActiveX control for Java, the Microsoft VM introspects that control and looks for event listener interfaces. Unless a Bean provides its own BeanInfo, all outgoing events are in the default event set. For example, a developer could define the following interfaces in Java to define its outgoing default event set. interface mouseListener { public void mouseEvent( int ButtonState, int x, int y ); } interface buttonListener { public void clickEvent( Object ButtonSource ); } interface keyListener { public void keyEvent( int shiftState, int key ); } These interfaces define events that could be sourced from three different JavaBeans event connections in a Java control. The Microsoft VM will combine them into one interface that is exposed through ActiveX. Be aware that the methods in the interface freely define parameters that are not event objects. The JavaBeans specification states that this free-form method specification is fully supported, but not necessary. Microsoft encourages its use because it can improve performance in passing events in and out of Java. To attach an event sink to the Java control, the Microsoft VM calls the addListener methods of the outgoing event sources and passes the instance of an object, which implements the appropriate interface. Mapping JavaBeans Properties to ActiveXProperties allow control developers to expose state variables that can be queried, set, and monitored by other controls or control containers. Again, the JavaBeans model provides a one-for-one mapping with ActiveX property concepts and change notifications. The Microsoft VM exposes ActiveX properties based on design patterns and BeanInfo information as detailed in the JavaBeans specification. To source property change events (equivalent to ActiveX OnChanged events) a developer can simply support the JavaBeans addPropertyChangeListener and removePropertyChangeListener methods, which accept the propertyChangeListener interface as a parameter. Likewise, to source vetoable property change events (equivalent to OnRequestEdit events), a developer just supports addVetoableChangeListener and removeVetoableChangeListener methods, which accept the vetoableChangeListener interface as parameters. The Microsoft VM will automatically connect to these property change event sources and handle them appropriately. To ActiveX clients of the object, these events will map to IPropertySinkNotify and IPropertySinkNotify::OnRequestEdit. Hosting an ActiveX Control in JavaActiveX controls are Automation-enabled controls that support the IDispatch COM interface, which enables the control to be scripted. These controls can also be dropped into containers, such as Visual Basic. Hosting an ActiveX control in Java is a four-step process:
Notice that the control is manipulated like any other Bean. The constructor code creates the Bean, registers a listener (in this case, one defined by the ActiveXControlListener interface), and then adds itself to the layout. The single method of the ActiveXControlListener interface is controlCreated. When the control is created, the Microsoft VM fires an event defined by the ActiveXControlListener interface and, if the ActiveX control supports events as this example does, the corresponding listener method on the Bean is called. The code necessary to sink the event to the corresponding listener is provided automatically by the Microsoft VM. The result is that when the Calendar control is created, and the controlCreated method is called, which displays the month corresponding to the current date. Raw Native InterfaceThe Raw Native Interface (RNI) is a high-performance interface supported by the Microsoft VM for Java. This interface is meant for "pedal-to-the-metal" kind of performance programming. It provides an efficient way of both traversing between Java and native code, and manipulating objects while in native code. The native code must be an active participant when running in or interfacing with a Java environment; it has certain responsibilities, which include following naming conventions, adapting to Java data representations, and dealing with the garbage collection process of the Java environment. For example, if the native code is going to be in a long loop, the garbage collector should be called periodically. Similarly, if the code is going to block on user input or call a thread that will block, it should call the garbage collector around the code that can block. Furthermore, objects need to be protected by garbage collection frames when calling back into Java. The required knowledge of garbage collection and other issues increases the complexity of programming using RNI for the benefit of increasing performance. For this reason, this interface should be used only in cases where high performance is needed and therefore justifies the extra effort. For more information about using the raw native interface, see Introduction to Using the Raw Native Interface and see the samples in the Microsoft SDK for Java. Low-Level Java/COM IntegrationActiveX objects can be implemented as dual-interface objects, meaning that they support both the IDispatch interface for automation and also vtable access to COM interface methods. Like C and C++, Java can access the vtable methods directly. When accessed this way, these objects do not have many of the restrictions as to the type of data they can pass and the type of interfaces they must support as do ActiveX controls that use automation. Also, some COM objects do not support IDispatch and can only be accessed through vtable methods. The tool that enables this access is jactivex, the same tool used for hosting ActiveX controls as JavaBeans components, but using the -javatlb switch. Because this is a much lower-level approach than the ActiveX/Beans integration, and data types are less restricted, there may be additional steps involved. This is especially true if there are complex data types passed through the interfaces exposed by the COM object. In particular, custom marshaling techniques might have to be used to manipulate these data types. It should also be noted that this approach does not create a JavaBeans object from the COM object. Instead, it creates a class that exposes the methods in the COM interfaces as its own class methods and calls the COM object for implementation. See the Using Jactivex to Create a User-Defined Type for Java/COM Marshaling article for more information on Custom Marshaling, the Low-Level Java/COM Integration article for an overview of Java/COM integration, and the Jactivex Reference for detailed information about the JactiveX tool. Also, see the samples in the SDK for Java. Samples pertaining to low-level COM integration can be found in subdirectories under the /MsVmJava/Samples/ directory in the SDK. SummaryThe Microsoft VM provides various ways to call non-Java code from Java. The programmer can choose the best way depending on the issue at hand. The approach taken can be one of the following:
Most programmers will use the first two approaches listed above: J/Direct and ActiveX/JavaBeans integration. The support provided by the Microsoft VM is both broad and complete: broad, in that it covers most scenarios for accessing native code, and complete in that it provides full access to the immense feature set of native code on the Win32 platform.
|
© 1998 Microsoft Corporation. All rights reserved. Terms of use. |