The Basics of ActiveX

by Al Saganich

Java is a delight to program. Applications are quick to develop, robust, and expandable. But often, developers wish to use a host of controls and other gadgets that already exist. Perhaps you're a converted Visual Basic or Delphi programmer and want to use an old, familiar control in your hot new development environment. But Java is platform-independent, right? Well, yes, in its purest form—but you can use ActiveX controls in your Java application! And if you ever wanted to, here's your chance to learn how.

The hype about ActiveX and the Internet has been unrelenting—how ActiveX controls build excitement into your Web pages by providing fancy graphics or access to legacy code or some other wizzy feature. But what does ActiveX really give you, and how do you use it? Are there limitations as to which controls you can use in Java applications? And how does ActiveX impact Java from the points of security, interoperability, and portability?

In this article, we'll explore the basics of ActiveX, examining how to use ActiveX controls in Java applications. We'll investigate the nuts and bolts of ActiveX controls; we'll discuss which controls you can and can't use, and why; we'll detail how to call ActiveX methods and capture ActiveX events; and we'll touch on how Active X affects Java application security.

Next month, we'll continue our ActiveX journey by demonstrating how to load ActiveX controls directly into a Web page, then pass these controls into a Java applet. We'll also show you how to package and ship controls, how to write your own ActiveX controls, and how to expose your Java applications as ActiveX controls.

Why ActiveX?

Why use ActiveX in the first place? For many reasons. If you're like me, you're always looking for a simpler way to do something. I migrated from C to C++ because I liked classes and other aspects of C++, then on to Java because of its simple elegance. But along the way, I had to abandon a large body of code I'd written in C++. ActiveX lets me regain some of that investment.

Another compelling reason to use ActiveX is the wealth of ActiveX controls that already exist. Visual Basic programmers have been evangelizing about the wonders of OLE controls for ages. Now, you can use many of those controls from Java, as well. In addition, ActiveX lets you easily access database information. Not to mention the fact that you can control other Microsoft applications via ActiveX scripting—you can embed your favorite spreadsheet directly into your Web page!

The downside

ActiveX is a great technology, but it has its warts. First and foremost, Java is supposed to be portable—we've all heard about write once, run anywhere. Well, with ActiveX, that idea is gone. Currently, ActiveX controls bind you not only to a single platform—Windows—but also to a single browser—Internet Explorer. Your programs are no longer completely portable.

Actually, ActiveX isn't as proprietary as it seems. A plug-in for Netscape exists, so you can run ActiveX-based pages in Netscape, but you're still limited to Win32 platforms. However, even that situation is changing. In October 1996, Microsoft placed ActiveX into the public domain by giving over the base code and control to the Cambridge, Massachusetts-based Open Group (www.activex.org). In fact, several companies are actively involved in bringing ActiveX to other platforms: Macromedia and Metrowerks to the Mac, and Bristol Technologies to UNIX. While it remains to be seen whether ActiveX will make it to other platforms, it's certainly here to stay on Windows.

Tools of the trade

Three tools assist the Visual J++ developer in working with ActiveX controls: Regsvr32.exe, which registers a given control; JavaTLB, which generates .CLASS files and summary.txt from registered controls; and JActiveX.exe, which generates .CLASS files and java source code for a control. We'll discuss each of these tools as we encounter them in building an ActiveX-enabled Java application.

Preparing an ActiveX control

A Java application accesses an ActiveX control via a set of .CLASS files that normally reside in the ${windows}\java\trustlib directory tree. Preparing a control for use with Visual J++ is a two-step process. First, you register the control using Regsvr32.exe, which ships with Visual J++. Regsvr32 takes one argument—the DLL or control to register—and any of several command-line switches, the most notable of which is /u to uninstall a control. By default—that is, when run with only a dll or ocx—Regsvr32.exe registers the control.

Note: Download our code!

For the remainder of this article, we'll assume that the ActiveX control binary (OCX, EXE, or DLL) has “magically” arrived on your computer. Next month, we'll look more closely at packaging controls for distribution directly from a Web page. You can download this article's sample files, including the ActiveX control, from www.cobb.com/vjp.

If you've downloaded the source code for this month's example, open a DOS box and change to the directory containing prodcons.ocx. Then, type regsvr32 prodcons.ocx. Figure A shows the result of running Regsvr32.exe on the prodcons ocx.

Figure A

Regsvr32 displays output like this.

Once you've registered a control, it will appear in the JavaTLB (Java Type Library Wizard) tool. To run the JavaTLB, choose Tools | Java Type Library Wizard from Visual J++'s main menu; there's no keyboard shortcut. For example, in Figure B, JavaTLB displays all the currently registered controls.

Figure B

The JavaTLB displays the currently registered tools.

You can now manually generate the registered tool's required classes and package its files for use with Visual J++. For this example, select the ProdCons ActiveX Control Module control, as shown in Figure B, then click the OK button. Figure C shows the Java Type Library tab of the output window after we ran JavaTLB on the ProdCons control.

Figure C

JavaTLB produced this output for ProdCons.ocx.

Tip: Double-click the summary.txt line.

After running the JavaTLB tool, you can double-click on the summary.txt line for any of the processed controls to immediately open the summary.txt file. This file contains a definition of the objects and interfaces in the ActiveX control from a Java perspective.

Our first control

It's surprising how similar ActiveX controls are to everyday Java classes. From a programming perspective, they're just another class that Java can instantiate and use. Our ProdCon example is a simple ActiveX messaging control that works as a go-between for a producer and a consumer of strings. When an application sends a message, a NewMessage event is generated, signaling that a message can be retrieved. The control also supports getting the current count of available messages. Figure D shows the ProdCon example running. Let's look more closely at how other ActiveX controls work.

Figure D

Our ProdCon example looks like this while it's running.

An ActiveX control is really just reusable code in a binary form. Each control contains one or more interfaces that you can use to access it. For instance, our producer/consumer control could have had one interface for producers and another for consumers.

When you create an ActiveX control, you create an instance of the control, but cast it as an instance of the interface in which you're interested. Listing A shows the summary.txt file for the ProdCons ActiveX control. We've highlighted the interfaces in color.

Listing A: ProdCons ActiveX object description

public class prodcons/ProdCons extends 
  java.lang.Object
{
}
public interface prodcons/IProdConsEvents 
  extends com.ms.com.IUnknown
{
    public abstract void NewMessage();
}
public interface prodcons/IProdCons extends 
  com.ms.com.IUnknown
{
    public abstract int GetMsgCount();
    public abstract int SendMsg(java.lang.String);
    public abstract java.lang.String GetMsg();

       . . .

}

We could have chosen the IProdCons interface or the IprodConsEvents interface as the interface to access our instance of an IProdCons object. As you'll see, the IProdConsEvents interface captures events. So, we created our object, as shown in Listing B, using IProdCons on the ProdCons object. Looking closely at the code, you'll see that while we created an instance of a ProdCons object, it was assigned to an instance of the interface we wanted to use to access—in this case IProdCons.

Note: Understand the interface.

In order to use an ActiveX control, you must understand the interfaces to that control. Carefully consult the documentation that came with the control you're using, then choose the interface that best suits your needs.

Listing B: Creating the ActiveX control in Java

// ProdCon.java
// 19-September-1997
// Al Saganich for 
// Visual J++ Developer's Journal
//
// Copyright 1997, Al Saganich, 
// Visual J++ Developers Journal.
//
// This code is provided without warrantee 
// of any kind and may or may not be fit 
// for any purpose other than illustration.
// This code may be used, changed or 
// distributed in any form, 
// electronic or otherwise, as long as this 
// notice is not removed.
//
import java.awt.*;
import java.awt.event.*;
import com.ms.com.*;
import prodcons.*;

//
// ActiveX sample
// Al Saganich for 
// Visual J++ Developer's Journal
//
// This class uses the prodcons classes to send 
// and receive messages from an ActiveX control
// 
class ProdCon implements 
              IProdConsEvents,  
              // Event fired by the control.
              ActionListener
{
    IprodCons    iActiveX;
    ConnectionPointCookie     
                eventConnector;
. . .
    public ProdCon()
    {
        try
    {
        iActiveX = (IProdCons) new ProdCons();
    }
    catch (com.ms.com.ComFailException e)
    {
        System.out.println(e);
        return;
    }
 . . .
}

Methods

ActiveX controls can have methods, just like Java classes. While the arguments are limited to ActiveX-supported types, most Java types are supported. Table A shows most of the ActiveX types and their Java equivalents. Of course, the same types apply to both method arguments and return values.

Table A: ActiveX types and Java equivalents

ActiveX Java
short short
long int
float float
double double
CURRENCY long
DATE double
LPCSTR String
BOOL boolean
short * short[]
long * long[]

Calling ActiveX methods and functions from Java is straightforward. Listing C shows two of the methods that act on an ActiveX object. The two lines shown in color access data from and send data to the ActiveX object, respectively.

Listing C: Calling ActiveX methods

public void NewMessage()
{
    System.out.println(
      " New Message event fired\n");
    try
    {
        String msg = iActiveX.GetMsg();
        String old = receiveBuffer.getText();
        old += "\n" + msg;
        receiveBuffer.setText(old);
    }
    catch (com.ms.com.ComFailException e)
    {
        System.out.println(e);
    }
}

public void send(String msg)
{
    try
    {
        iActiveX.SendMsg(msg);
        int count = iActiveX.getMsgCount();
    }
    catch (com.ms.com.ComFailException e)
    {
        System.out.println(e);
    }
}

Errors and exceptions

To this point, we haven't discussed errors and exceptions. From Java's perspective, ActiveX objects and Java objects are one and the same: Both can return values and throw exceptions. However, unlike most Java classes, ActiveX objects throw a small number of exceptions and count on one of the exception's member variables to determine exactly what happened!

For the most part, ActiveX objects will throw com.ms.com.ComException—or exceptions derived from ComException, such as com.ms.com.ComFailException—when something goes wrong. To get more specific information, you need to use the getHResult() method to determine the type of exception.

Table B shows common exception values and their meanings. Listing D shows how a simple method captures and processes exceptions. Note that ActiveX objects may return values other than the ones listed in the table; see your control's documentation for the error values it may return.

Table B: Common exception values

Description Symbolic constant Value
Unexpected failure
E_UNEXPECTED
0x8000FFFF
Not implemented
E_NOTIMPL
0x80004001
Ran out of memory
E_OUTOFMEMORY
0x8007000E
One or more arguments invalid
E_INVALIDARG
0x80070057
No such interface supported
E_NOINTERFACE
0x80004002
Invalid pointer
E_POINTER
0x80004003
Invalid handle
E_HANDLE
0x80070006
Operation aborted
E_ABORT
0x80004004
Unspecified error
E_FAIL
0x80004005
General access denied error
E_ACCESSDENIED
0x80070005
Not implemented
E_NOTIMPL
0x80000001
Unknown interface
DISP_E_UNKNOWNINTERFACE
0x80020001
Member not found
DISP_E_MEMBERNOTFOUND
0x80020003
Parameter not found
DISP_E_PARAMNOTFOUND
0x80020004
Type mismatch
DISP_E_TYPEMISMATCH
0x80020005
Unknown name
DISP_E_UNKNOWNNAME
0x80020006
No named arguments
DISP_E_NONAMEDARGS
0x80020007
Bad variable type
DISP_E_BADVARTYPE
0x80020008
Exception occurred
DISP_E_EXCEPTION
0x80020009
Out of present range
DISP_E_OVERFLOW
0x8002000A
Invalid index
DISP_E_BADINDEX
0x8002000B
Memory is locked
DISP_E_UNKNOWNLCID
0x8002000C
Memory is locked
DISP_E_ARRAYISLOCKED
0x8002000D
Invalid number of parameters
DISP_E_BADPARAMCOUNT
0x8002000E
Parameter not optional
DISP_E_PARAMNOTOPTIONAL
0x8002000F
Invalid callee
DISP_E_BADCALLEE
0x80020010
Does not support a collection
DISP_E_NOTACOLLECTION
0x80020011

Listing D: Further refining errors

Try
{
  SomeActiveXObject.Method();
}
Catch (com.ms.com.ComFailException ce)
{
  switch (ce.getHResult()
     {
  case E_UNEXPECTED:
  System.out.println(“Unexpected exception!”);
  break;
  case E_ E_NOTIMPL:
  System.out.println(“Method not implemented exception!”);
  break;
         // Other cases as required
         . . .
     }
}

Events

We've talked about creating objects, calling methods, and handling errors. But Java normally provides another feature: events.

Note: Standard Visual J++ 1.1 doesn't support ActiveX events.

As of this writing, Visual J++ 1.1 didn't support capturing and processing events. In order to correctly handle events, you need to download the Java SDK 2.0 (now in final release) from Microsoft's Web site at www.microsoft.com/java. The remainder of this article section assumes that you've downloaded and installed the Java SDK 2.0 final release.

Earlier, we discussed which interface to use when accessing an ActiveX object. We also noted that another interface exists to support events. Listing E shows the portion of the ProdCon object description that deals with events. Let's see how to link a Java application to an ActiveX control for the purpose of capturing events.

Listing E: ProdCons events

public interface prodcons/IProdConsEvents extends com.ms.com.IUnknown
{
    public abstract void NewMessage();
}

As we previously mentioned, the IProdConsEvents interface defines the events that the ProdCons object produces—sharp eyes will have noticed that the one method this interface defines is abstract. Capturing events from an ActiveX object is a two-step process. First, the class that's going to intercept the events must implement the event interface, as defined in the summary.txt file. Second, the application must be connected to the object that generates the events. Listing F shows these steps in action.

Listing F: Steps to handing events

import java.awt.*;
import com.ms.com.*;
import prodcons.*;

class ProdCon implements 
        IProdConsEvents,  
        // Step 1
        ActionListener
{
    IProdCons               iActiveX;
      // Used for step 2
    ConnectionPointCookie   eventconnector;
    . . .
    public void NewMessage()
    {
        // Do something when event fires
        . . .
    }

    public ProdCon()
    {
        . . .

        // Step 2 attach the objects together.
        try 
        {
            eventconnector = 
              new ConnectionPointCookie(
                 iActiveX,this, 
                 Class.forName(
                 "prodcons.IProdConsEvents"));
        }
        catch (ClassNotFoundException e)
        {
            System.out.println(e);
            System.out.println(
              "Cannot catch prodcons events!");
            return;
        }

        . . .
    }
}

First we define the prodcon class as implementing the IProdConEvents interface. This interface requires that the NewMessage method be implemented. NewMessage events are fired whenever the SendMsg method is called.

Next, we hook the applet and the control together using a ConnectionPointCookie object. This object takes three arguments: the event source, the event sink, and the connection interface. The event source is the class responsible for generating events. The event sink is the class responsible for consuming generated events. The connection interface is the class responsible for connecting the source to the sink.

We create the first two arguments ourselves in the normal course of the application's development. However, we must force the third argument into existence. We can force a class to be loaded by using the forName static method of the java.lang.Class class. The forName static class method loads a class dynamically (and is often used to implement class loaders), then returns the loaded class or throws a ClassNotFoundException.

Properties

ActiveX controls also have properties, which basically are public values that a user can manipulate to read and write on an object. Visual J++ doesn't provide a way to access a control's properties directly, but rather wraps each property in a get and set method. The ProdCon object exposes a property that was intentionally omitted from the prior interface description. Interested readers might want to load the ProdCon ActiveX project and see if they can determine what that property is.

Control restrictions

It's important to understand the restrictions on using controls. Visual J++ has one major failing when it comes to using ActiveX controls: Any control created within a Java applet or application must be non-visual. In a future article, we'll discuss how to create simple non-visual controls with Visual C++. For now, suffice to say that you can't create visual controls within a Java application.

However, all is not lost! You still can use a visual control from Java—you simply can't create it from within a Java applet. Instead, you must create the control on your Web page, then pass it into your Java applet via one of the applet's exposed methods. The focus of this article is using controls, but next month we'll look at the mechanics of, among other things, creating controls on your Web page for use in Java applications.

Security (trusted vs. untrusted)

Finally, we must mention security. ActiveX uses the keys to the castle model of security, meaning that once you've installed a control on your machine, it can do what any application can do. Next month, we'll look more closely at security and how to create ActiveX controls, load them into cab files, then digitally sign the files for download.

Conclusion

ActiveX technology has its quirks. However, it expands Java's potential immensely, opening areas that were previously unavailable to developers. Among other things, you can now take advantage of a huge number of commercial controls, many of which you can embed and control from within your Java applets. As we'll discuss next month, creating your own ActiveX controls and packaging them for distribution, while not trivial, is easily accomplished. So dust off those controls you mothballed when you started developing in Java—they can ride again!

___________________________

Al Saganich is an independent software consultant, currently under contract to Digital Equipment Corporation. He's co-author of the best-selling Microsoft Visual J++ 1.1 SOURCEBOOK and is working on the next release of Java 1.2 for C/C++ Programmers, both published by J. Wiley and Sons. You can reach Al at asaganich@aol.com.

___________________________

This article is reproduced from the February 1998 issue of Visual J++ Developer's Journal. Visual J++ Developer's Journal is an independently produced publication of The Cobb Group. No part of this article may be used or reproduced in any fashion (except in brief quotations used in critical articles and reviews) without prior consent of The Cobb Group. To contact The Cobb Group, please call (800) 223-8720 or (502) 493-3200.

Copyright © 1998 The Cobb Group, a division of Ziff-Davis Inc. The Cobb Group and The Cobb Group logo are trademarks of Ziff-Davis Inc. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of Ziff-Davis is prohibited.