By Trevor Harmon
In July of 1996, I was hired to write a book about Microsoft Visual J++. I studied up on the product and was amazed at its potential. It could provide what no other software could: a bridge between the distant worlds of ActiveX and Java. With Visual J++, I could now integrate legacy Windows code with the elegant new features of Java. My mouth watered at the thought of designing Java applets that could talk to the powerful ActiveX controls I had written.
When Microsoft sent me a beta version of Visual J++, I popped open the hood and poked around, checking out the user interface and discovering (in utter disbelief) that the compiler could churn through a million lines in less than a minute. I also took a look at the ActiveX integration features in Visual J++, but I was disappointed to learn that most of those features were not working in my beta version.
Puzzled, I contacted one of the program managers for Visual J++ and asked him why the product’s ActiveX support — a feature that had been so heavily hyped on Microsoft’s Web site — was seemingly non-existent. “Well,” he said, “that’s just marketing slime, I’m afraid.” He went on to explain how Microsoft’s marketing department had redefined the meaning of the term ActiveX control. Previously, an ActiveX control was a heavyweight software component that supported a variety of interfaces and required a container application in which to operate. Now, however, it was nothing more than a simple OLE object.
I suddenly realized what had happened. Facing increasing competition from Borland, Symantec, and other vendors of Java development tools, Microsoft was under pressure to release the final version of Visual J++ as quickly as possible. They had already implemented support for basic OLE objects, but integration of true ActiveX controls was still several months away. So, rather than ship Visual J++ without its most significant feature, Microsoft’s “marketeers” decided to save face by quietly changing the definition of ActiveX controls. The result was a product whose feature set matched the wording of its press releases perfectly, but only because the meaning of those words had completely changed.
Over the next several months, I waited patiently as Microsoft upgraded Visual J++ and released two versions of their Java SDK. None of the products offered the ActiveX integration that was originally announced. Today, more than a year and a half later, Microsoft has finally delivered: Java SDK 2.0 can handle two-way integration of ActiveX and Java. Available for free download at http://www.microsoft.com/java, it can put ActiveX components inside Java programs, and it can put Java components inside ActiveX programs. Thanks to these features, developers must no longer choose between the two architectures — they can simply choose whatever tool is right for the job.
In this article, we’ll learn how to harness the power of Microsoft’s Java SDK to combine an ActiveX control with a JavaBean, the standard form for Java components. All the code we’ll be looking at centers around two components: an ActiveX control that plays video files, and a JavaBean that displays a few 3D-style buttons for controlling multimedia streams.
The ActiveX control is called “Video Playback”; I created it using Microsoft Visual C++ 5.0. It exposes methods for opening, playing, and pausing video files. It also offers properties for obtaining the total number of frames, changing the current frame, and stretching the video to a window. Because of the unnecessary complexity of the Windows Multimedia API and the C++ language itself, the source code for the Video Playback control is far too long to present here. However, you can download the code from the Informant Web site; see end of article for details. Figure 1 shows the control in action.
Figure 1: The Video Playback ActiveX control exposes methods and properties for playing videos.
The JavaBean is called “Video Buttons”; I created it using Microsoft Visual J++ 1.1 and the Microsoft Java SDK 2.0. It displays four buttons: reverse, play, stop, and forward (see Figure 2). It is much simpler than the Video Playback control — partly because the bean’s purpose is less demanding, but mostly because the Java language makes just about everything easier. This component doesn’t expose any methods or properties, although it does implement an event that gets fired whenever the user clicks one of the four buttons. Listing One on page XX shows the complete source code for the buttons.
Figure 2: The Video Buttons JavaBean fires an event whenever the user clicks one of its buttons.
The virtual machine (VM) included with Microsoft’s Java SDK can recognize ActiveX controls and treat them as though they were 100 percent pure Java components. However, it can’t do its job alone. It needs the help of a utility program called “JActiveX”. Located in the Java SDK’s bin directory, JActiveX reads the type library in an ActiveX control and generates a Java source-code wrapper from the information it finds. It stores this wrapper in a directory descending from the trusted libraries directory that was created by the installation of Microsoft’s VM. For instance, to generate a Java wrapper for the Video Playback control, I issued the following command in a DOS box:
jactivex VideoPlayback.ocx
Moments later, JActiveX placed a Java source-code wrapper for my control in a directory called C:\Windows\Java\TrustLib\videoplayback. By browsing the source code in this directory, I was able to determine how to call the Video Playback control’s methods, as well as how to access its properties from Java.
You can use this same technique for integrating ActiveX controls in your Java applications. Simply run the JActiveX tool on your control as I did, then check your C:\Windows\Java\TrustLib directory. (Note that this directory may differ depending on where you installed Windows.) Look for a Java source-code file whose name is identical to the name of your control, but with an ‘I’ prepended to it. This file should contain the Java interface that gives you access to the control’s methods and properties. The Video Playback control, for example, has a wrapper file named IVideoPlayback (see Listing Two on page XX). Note: Listing Two is a simplified version of the output from JActiveX; the code is the same, but Listing Two doesn’t show the comments that the Microsoft Java compiler requires.
Notice how JActiveX automatically translated the ActiveX property types and method parameter types into their Java equivalents when it generated the interface file (i.e. BOOL became boolean and LPSTR* became String).
Note: To compile the interface IVideoPlayback from the Java SDK, users must employ the Microsoft Java compiler. The source code is standard Java, but Microsoft’s compiler interprets the comments in IVideoPlayback to generate the ActiveX-Java bridge.
Once you’ve studied a control’s Java interface wrapper, you can easily write an application that integrates with the control via that interface. Simply create a new instance of the control, then call the interface methods. For example, here’s how to open a video file in Java using the Video Playback control:
VideoPlayback vp = new VideoPlayback();
vp.Open("test.avi");
Note that we can’t simply create an instance of an interface; we can only create an instance of a class. This is why the previous code uses the VideoPlayback class instead of the IVideoPlayback interface. The VideoPlayback class provides an implementation of IVideoPlayback, and it was generated by JActiveX along with the other source-code wrapper files. See Listing Three, beginning on page XX, for a complete example program that uses this class. Figure 3 shows the results of running the Java program.
Figure 3: The results of running the Java program shown in Listing Three.
That’s about it. After you’ve learned to use JActiveX and the interfaces it generates, you can integrate just about any ActiveX control into your Java programs. There are, of course, some other issues you might run into, such as how to catch events fired by ActiveX controls and how to generate source-code wrappers for non-standard ActiveX data types. These topics are beyond the scope of this article, but you can find plenty of details on them in the Java SDK documentation.
Despite these extra complications, the Microsoft Java SDK 2.0 does a remarkably good job of shielding Java developers from the complexities of the ActiveX architecture. It finally provides them with the full power of ActiveX — including real ActiveX controls — while still allowing the elegance and ease of the Java language to shine through. In fact, as this article has shown, the Java SDK can help achieve what many thought was impossible: full-motion video playback in Java.
So far, we’ve looked at how the Java SDK allows ActiveX controls to masquerade as JavaBeans. In this section, we’ll see how the SDK can make JavaBeans look like standard ActiveX controls. This feature lets any development tool that supports ActiveX, such as Visual Basic, Delphi, and PowerBuilder, import Java components into its native environment. The result is a two-fold advantage whenever developers build software in pure Java: Their components are usable not only on any platform, but also from any language. (Microsoft’s Java SDK 2.0 wasn’t the first product to offer this benefit. See the sidebar “Sun’s ActiveX Bridge” on page XX for details.)
The key to gaining this dual advantage is a utility program called JavaReg. JavaReg, which can be found in the Java SDK’s bin directory, saves information about a JavaBean in the Windows registry. The information is stored in the same format for standard ActiveX components. Consequently, all ActiveX-compatible development tools think that the JavaBean is just another ActiveX control. When they attempt to load the disguised control, they are not loading the JavaBean, but rather Microsoft’s VM. The VM acts as a proxy for the bean, translating ActiveX method calls into Java method calls and Java events into ActiveX events.
To learn how to use JavaReg, let’s run it on my Video Buttons JavaBean. First, we must supply JavaReg with a so-called Globally Unique Identifier, or GUID. A GUID is a 128-bit value that is always unique, no matter when or where it is generated. Every ActiveX control requires its own GUID to prevent naming and versioning conflicts. To generate a GUID for JavaReg, simply run the Create GUID program that ships with the Java SDK (see Figure 4).
Figure 4: The Create GUID program generates the 128-bit values required by JavaReg.
The other parameters needed by JavaReg are:
/register: Registers a JavaBean. (Use /unregister to unregister a bean.)
/class:javabean: Specifies the name of the bean to register.
/codebase:directory: Specifies the directory in which the bean is stored.
/typelib:filename: Specifies the name of the file in which to store the bean’s type library.
/control: Specifies that the bean should be treated as a true ActiveX control, not just an OLE object.
When we put these parameters together, here’s how the command line would look:
javareg /register /control /class:VideoButtons /codebase:. /clsid:{CD71F6B1-5280-11d1-A816-0020AFC746E8} /typelib:VideoButtons.tlb
Running this command line should produce the message “Successfully registered Java class.” Development tools will then display the registered JavaBean as if it were a standard ActiveX control (see Figure 5).
Figure 5: The JavaReg utility lets ActiveX development tools — such as Microsoft Visual C++ 5.0 shown here — use JavaBeans as if they were ActiveX controls.
To illustrate the benefits of JavaReg, I’ve put together a C++ application that integrates the Video Playback control with the Video Buttons JavaBean. Like any C++ application that uses ActiveX, its source code is ridiculously complex and is thus too long to include in this article (however, it is available for download; see end of article for details). Without the Microsoft Java SDK, however, the code would have been far more complex, because it would be forced to handle all the Java-to-ActiveX mappings itself. The fact that only a simple utility program was necessary for the mappings is a testament to the hidden power of Microsoft’s SDK.
Naturally, Microsoft is tight-lipped about their long-term plans for Visual J++, but you can be sure that a future version will include all the features found currently in the Java SDK. Newer versions will most likely provide enhancements to the SDK’s features, such as the ability to drag-and-drop ActiveX controls onto a Java dialog box. You will no longer have to shell to DOS and run an external utility every time you want to use an ActiveX component in a Java application.
Still, the present form of the Java SDK packs both power and simplicity. It provides a nearly transparent two-way bridge between the ActiveX architecture and the Java language. With the SDK, you finally have the freedom to choose whatever tool works best for you.
Begin Listing One — The Video Buttons JavaBean
import java.awt.*;
import java.awt.event.*;
import java.awt.image.*;
import java.util.*;
public class VideoButtons extends Panel
implements java.io.Serializable {
public static final int BACK = 1;
public static final int PLAY = 2;
public static final int STOP = 3;
public static final int FORWARD = 4;
Image imageButtons;
Vector listeners = new Vector();
public VideoButtons() {
imageButtons = loadImage("buttons.gif");
enableEvents(AWTEvent.MOUSE_EVENT_MASK);
}
public void paint(Graphics g) {
g.drawImage(imageButtons, 0, 0, this);
}
protected void processMouseEvent(MouseEvent e) {
if ( e.getID() == MouseEvent.MOUSE_PRESSED ) {
if (e.getX() < 1 * 34) {
fireButtonEvent(BACK);
}
else if (e.getX() < 2 * 34) {
fireButtonEvent(PLAY);
}
else if (e.getX() < 3 * 34) {
fireButtonEvent(STOP);
}
else {
fireButtonEvent(FORWARD);
}
}
super.processMouseEvent(e);
}
private void fireButtonEvent(int button) {
Vector l;
synchronized (this) {
l = (Vector)listeners.clone();
}
for (int i = 0; i < l.size(); i++) {
VideoButtonsListener listener =
(VideoButtonsListener) l.elementAt(i);
listener.buttonClicked(button);
}
}
private java.awt.Image loadImage(String name) {
try {
java.net.URL url = getClass().getResource(name);
return createImage((ImageProducer)url.getContent());
}
catch (Exception ex) {
System.err.println("ERROR: Could not load " + name);
return null;
}
}
public void addVideoButtonsListener(
VideoButtonsListener listener) {
listeners.addElement(listener);
}
public void removeVideoButtonsListener(
VideoButtonsListener listener) {
listeners.removeElement(listener);
}
}
interface VideoButtonsListener
extends java.util.EventListener {
public void buttonClicked(int button);
}
End Listing One
Begin Listing Two — The IVideoPlayback interface generated by the JActiveX tool
package videoplayback;
import com.ms.com.*;
import com.ms.com.IUnknown;
import com.ms.com.Variant;
public interface IVideoPlayback extends IUnknown {
public int getTotalFrames();
public void setTotalFrames(int newValue);
public boolean getFitToWindow();
public void setFitToWindow(boolean newValue);
public int getCurrentFrame();
public void setCurrentFrame(int newValue);
public void Close();
public boolean Open(String strFilename);
public void Pause();
public void Play(boolean bLoop);
public void Stop();
}
End Listing Two
Begin Listing Three — VideoPlayer provides easy access to Video Playback
import java.awt.*;
import java.awt.event.*;
import videoplayback.*;
public class VideoPlayer extends Frame
implements ActionListener, VideoButtonsListener {
public static void main(String args[]) {
VideoPlayer player = new VideoPlayer();
}
private VideoPlayback videoPlaybackControl;
private VideoButtons videoButtonsBean;
private Button loadVideoButton;
VideoPlayer() {
addWindowListener(new VideoPlayerWindowListener());
setTitle("Video Player");
setBackground(Color.lightGray);
setVisible(true);
}
private class VideoPlayerWindowListener
extends WindowAdapter {
public void windowClosing(WindowEvent e) {
System.exit(0);
}
public void windowOpened(WindowEvent e) {
videoPlaybackControl = new VideoPlayback();
videoButtonsBean = new VideoButtons();
loadVideoButton = new Button("Load video...");
videoButtonsBean.addVideoButtonsListener(
VideoPlayer.this);
loadVideoButton.addActionListener(
VideoPlayer.this);
setLayout(null);
add(videoPlaybackControl);
add(videoButtonsBean);
add(loadVideoButton);
Insets i = getInsets();
setSize(i.left + 340 + i.right,
i.top + 344 + i.bottom);
videoPlaybackControl.setBounds(i.left + 10,
i.top + 10, 320, 240);
videoButtonsBean.setBounds(i.left + 102,
i.top + 260, 136, 34);
loadVideoButton.setBounds(i.left + 130,
i.top + 304, 80, 30);
}
}
public void actionPerformed(ActionEvent e) {
FileDialog dlg = new FileDialog(this, "Open Video",
FileDialog.LOAD);
dlg.show();
if ( dlg.getFile() != null ) {
videoPlaybackControl.Open(dlg.getFile());
}
}
public void buttonClicked(int button) {
switch (button) {
case VideoButtons.BACK:
videoPlaybackControl.setCurrentFrame(
videoPlaybackControl.getCurrentFrame() - 1);
break;
case VideoButtons.PLAY:
videoPlaybackControl.Play(false);
break;
case VideoButtons.STOP:
videoPlaybackControl.Stop();
break;
case VideoButtons.FORWARD:
videoPlaybackControl.setCurrentFrame(
videoPlaybackControl.getCurrentFrame() + 1);
break;
}
}
}
End Listing Three
The files referenced in this article are available for download from the Informant Web site at http://www.informant.com/ji/jinewupl.htm. File name: JI9802TH.ZIP.
Microsoft’s Java SDK 2.0 isn’t the only game in town. Sun Microsystems, the company that created Java, offers a similar product called the ActiveX Bridge, available for free download from http://java.sun.com/beans. It can’t put ActiveX controls into Java programs, but it can bring JavaBeans into the ActiveX world. By running a bean through the ActiveX Packager (a utility program included with ActiveX Bridge), developers can perform the same tricks that they can perform with the Microsoft Java SDK. In other words, the ActiveX Packager stores information about a JavaBean in the Windows registry, allowing the ActiveX Bridge to serve as a proxy for the bean. As a result, Sun’s ActiveX Bridge can disguise a JavaBean as an ActiveX control just as well as Microsoft’s Java SDK can.
So which product do you choose? They’re both free, so the money issue is moot. To make the decision, you must ask yourself two questions. First, do you need independence from Microsoft’s VM? Sun’s offering can work with any virtual machine, so if you don’t like Microsoft’s VM for some reason, the ActiveX Bridge would be the better choice. Second, do you need a Java-to-ActiveX link for your Internet applications? If so, then the ActiveX Bridge should be your pick. Under the hood, it’s simply a standard ActiveX control, allowing for easy, automatic installation through any ActiveX-compatible Web browser. The Java SDK, on the other hand, requires a separate end-user installation of Microsoft’s VM, and works best only on Microsoft’s Web browser.
— Trevor Harmon
Trevor Harmon is president of Vocaro Technologies (http://vocaro.com), a development and consulting firm specializing in JavaBeans components. He is also the author of Web Developer’s Guide To Visual J++ And ActiveX, published by Coriolis Group Books (ISBN: 1-57610-062-6). Trevor will soon graduate from Washington University in St. Louis with a degree in Computer Engineering.