Access COM Via Java -- A Tutorial

The fact is that Java has been accepted more quickly than any other programming language for Internet applications running on multiple platforms. But many a COM object has been developed by using C++ technology, which are still very useful and very fast as compared with Java.

Hence, I'm inspired to use these COM objects that already exist using Sun's Java. The COM object can be called by a client with Microsoft's JVM or J++, but not with Sun's Java directly. I'll try to show you the way to do this using Java.

In this tutorial, I intend to build an application that can access a COM object created using VC++ 6.0 ATL and then call this COM-server object via a pure Java client.

I believe you should first know how to employ simple COM using ATL with VC++.

Part I

Step 1: Building ATL COM

Choose the "ATL COM AppWizard". Give the project the name "Java_COM_ATL".
Set the location where you want this project to
be saved in Select "Server Type" as "Dynamic Link Library".
Press the finish button to have the Wizard generate the
appropriate files for you. A "New Project Information" window will
appear to tell you what files are going to be created. Press the OK
button to accept this.

Step 2: Creating a New ATL

Make sure you can see the "Workspace View" inside the VC++ IDE.
Choose New ATL Object from the Inset Menu. You will see a window like the
following:

The default choice, Simple Object, is what we want. Click the Next
Button, and you will be in the "ATL Object Wizard Properties"
window. In the "Short Name" textbox, enter "Jcom". Notice
how the Wizard automatically fills in the rest of the textboxes for
you. Click on the "Attributes" tab at the top. Here, you have
several choices to make. For the first choice, Threading Model, we
will stick with the default Apartment Model. For the "Interface",
click on "Custom", instead of "Dual". Finally, as we are not going
to be concerned with "Aggregation", click on the "No" radio button.
We don't need to worry about any of the three checkboxes at the
bottom. Click on the OK Button and let the Wizard create our new
ATL Jcom Object.

Step 3: Adding a Method

If you click on the "ClassView" tab now in your workspace, you will
notice that the Wizard added a bunch of things. The first thing we
want to do is add a method. We can do this easily by right
clicking on "IJcom" and choosing "Add Method".

Once you have clicked on "Add Method", you will see the "Add Method
to Interface" window. Under the Return Type, you can see that by
default the method will return "HRESULT". The next textbox allows
us to type in the MethodName. Let's type in "AddNumbers". The last
textbox asks us the Parameters we wish to use. As we want to add
two numbers together and get a result back, we will use three
parameters. The last parameter will be a pointer for a return
textbox:

[in] long num1, [in] long num2, [out] long *ReturnVal

We are declaring two parameters as long, the values
are going in [in], and a final value to return [out] the answer.
Click on the OK Button. Click on the "ClassView" tab and expand all the "+"
symbols so the tree is fully open to view. Under the top
interface ("IJcom"), you will see our "AddNumbers" method and
the parameters we gave it. Double-click on this, and it will place
you into the code. Add the following code: This is a must
for any job.

On compiling, the Com Server will be built. As usual, the compiler will register
your new DLL in the registry so that other programs can make use of it.
Let's try it with Java. Up to this point, it's all very normal; but to write Java code to access
this COM server, we need the help of Java Native API. Before that, though, we have to create
the Java client. Stop or minimize VC++ now for the moment; you will need it again in Part III.

Part II

Step 1: Java Code

To write Java code, you may choose any IDE you wish, but I have done it with
Notepad to make things simpler at the latter stage. Prepare the file name
as HelloCom.java as follows and compile to generate the HelloCom.class file as directed below.

Here, you can see that to call the native method, the system has to load a DLL file which
we will create in Part III, but we will now call "ComClient" (remember the
name with case). There should not be any problem in the compilation of the file, but it will throw an UnSatisfiedLinkError exception if you try to run it without ComClient.dll created or not in the classpath. Before going further, we need to do some more work.

Go to the command prompt and compile the file with following command:

javac HelloCom.java

And then give the following command:

javah HelloCom

This will generate the HelloCom.class and HelloCom.h files.
You will need these two files in the next part.

Part III

Here is the unusual part of the tutorial. Normally, to access a COM object created as
in Part I, you would use C++ code. Subsequently, it would generate an .exe
file for running the COM object. In our case, however, we will not generate an .exe file, but we will
generate another .dll file to access the COM object. In the end, this DLL (ComClient.dll) will be a pure client for the COM object to serve, with Java code, our Java client (HelloCOM.class). This can be done as follows.

Step 1: Creating ComClient.dll

Start up VC++ again and Select New|Project|Win32 Dynamic Link Library
and use the name ComClient. (Be careful, here you must give the
same name that was given for loading the lib. in Part II, and it is case-sensitive, too.)

Step 2: Include Header File

Now copy the HelloCom.h file of Part II to the working dir of the
project (in my case, it is "C:\Program Files\Microsoft Visual Studio\MyProjects\ComClient"), and include it
as the header file.

Step 3:Write C++ File in the Project

Again, create one C++ file (named MyComClient.cpp) using the editor, and save and include it in the same dir. The source code of the C++ file is given below, with comments whenever it's required.

//Include JNI.H file which is available with JDK1.3 to tell complier
//Open Tools|Option|directories and include the proper dir. so that
//complier can open it for reading otherwise fatal error will be
//reported.
#include
//Allready in the working dir.
#include "HelloCom.h"
#include
//Normal for the Com Client
#include "..\Java_COM_ATL\Java_COM_ATL.h"
#include
//Refere JNI API or get the following native method signature from
//HelloCo.H file This is the method called by JavaClient.
JNIEXPORT void JNICALL Java_HelloCom_HelloCom_1function
(JNIEnv *, jobject)
{
// Copy the following from the Java_COM_ATL_i.c file
// from the Java_COM_ATL project directory
//This number may be diff. as it generated by VC++ using uuidgen.exe.
const IID IID_IJcom = {0x665A282D,0x3ECD,0x11D5,{0xAC,0x5C,0xDF,0xF9,0xE8,0x6D,0xD6,0x2D}};
const CLSID CLSID_Jcom = {0x665A282E,0x3ECD,0x11D5,{0xAC,0x5C,0xDF,0xF9,0xE8,0x6D,0xD6,0x2D}};
// Declare and HRESULT and a pointer to the Java_COM_ATL interface
HRESULT hr;
// Interface creadted in Part I
IJcom *IJComAtl;
// Now we will intilize COM
hr = CoInitialize(0);
if(SUCCEEDED(hr))
{
hr = CoCreateInstance( CLSID_Jcom, NULL, CLSCTX_INPROC_SERVER,
IID_IJcom, (void**) &IJComAtl);
// If we succeeded then call the AddNumbers method, if it failed
// then display an appropriate message to the user.
if(SUCCEEDED(hr))
{
long ReturnValue;
hr = IJComAtl->AddNumbers(5, 7, &ReturnValue);
cout << "The answer for 5 + 7 is: " << ReturnValue << endl;
hr = IJComAtl->Release();
}
else
{
printf("CoCreateInstance Failed.");
}
}
// Uninitialize COM
CoUninitialize();
printf("Hello Com is ok and over!\n");
return;
}

Step 4: Compile

Compile the code to create "ComClient.dll" and put this file in the working dir. Stop VC++, we do not need it now. It's all over.

Step 5: Follow This Step to Run the Java Client.

Step A. Copy your java class file (HelloCom.class) created in Part II to this
working dir.

Step B.Go to the DOS prompt and change the dir to that of working
Dir.

Step C.Execute the Java class as follows.

java HelloCom

You must see the output as:

The answer for 5 + 7 is: 12
Hello Com is ok and over!

Note: Here, only the simple function HelloCom_function is used, without any
return type, and any argument is passed; but in the real world, this can be modified
very easily. The ComClient is pure C++ and can even access both the Java object and COM
objects.