Most of the things needed by a Java application can be found within the Java class library, yet there may be occasions when you need interaction with code residing outside the Java Virtual Machine. The mechanism to do this is called Java Native Interface. In this walkthough I shall describe the use of this interface to call code in a Visual Basic DLL from Java.
To create the DLL open the Visual Basic IDE and start a new project. Select ACtiveX DLL as the project type. The IDE creates an empty project with a default class named Class1. Rename the class to CTest and save the project as VBTestDLL. Now open project properties and change the project name to VBTestLib. Add the following code to the class body and compile VBTestDLL.
Private Sub Class_Initialize()
' ********
End Sub
Public Function vbConcat(ByVal a As String, ByVal b As String) As String
vbConcat = a & b
End Function
After compilig the class the IDE automatically registers the DLL in it's current location. If you move the dll elsewhere you need to re-register it using the command "regsvr32 VBTestDLL.dll".
To call code outside the JVM using JNI we need to create a wrapper DLL in C++ which will act as an intermediate layer between Java and the ActiveX dll. But, before we create the C++ dll we need to define the native method in a Java class. Now create the Java source file :
public class Test {
public static native String VBConcat(String s1, String s2);
static
{
System.loadLibrary("VBToJava");
}
public static void main(String [] args)
{
String a = "hello";
String b = " world";
System.out.println(VBConcat(a,b));
}
}
The argument to the call System.loadLibrary should be the name of the C++ wrapper dll that you are
going create. A Windows JVM automatically appends the ".dll" extension so it should not be added
to the dll name. The native method name can be any arbitrary name chosen by the programmer.
/* DO NOT EDIT THIS FILE - it is machine generated */
// #include <jni.h>
/* Header for class Test */
#ifndef _Included_Test
#define _Included_Test
#ifdef __cplusplus
extern "C" {
#endif
/*
* Class: Test
* Method: VBConcat
* Signature: (Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_Test_VBConcat
(JNIEnv *, jclass, jstring, jstring);
#ifdef __cplusplus
}
#endif
#endif
You need to comment out #include <jni.h>. It's beacuse we are going to add #include <jni.h> to StdAfx.h , so leaving this in will cause jni.h to be included twice.
The next step is creating a wrapper dll in C++ which can be called by the java class. The compiler we use is Microsoft's visual C++ 6. Create a new project in VCPP. Choose MFC DLL as the project type. Enable Automation in the project options dialog.
Name the project as "VBToJava". Copy the header files jni.h ,
jni_md.h and Test.h files to the same folder as your VCPP project.
You should have the following .cpp and .h files in your project folder
VBToJava.h
VBToJava.cpp
StdAfx.h
StdAfx.cpp
Resource.h
StdAfx.h
VBToJava.h
Now add the following include and import statements to StdAfx.h
#include "jni.h"
#include "Test.h"
#import "F:\VBProj\ActiveXDLL\VBTestDLL.dll"
using namespace VBTestLib;
In the import statement you have to specify the full path to the dll or if you want to avoid that
you must either move the dll to the Windows\System32 folder or add the VB project folder to your
path variable. Now write the implementation of the method declared in Test.h
JNIEXPORT jstring JNICALL Java_Test_VBConcat
(JNIEnv* env, jclass jc, jstring a, jstring b) {
HRESULT hresult;
CLSID clsid;
_CTest *t; // a pointer to the CTest object
jboolean blnIsCopy;
jstring jstrOut;
_bstr_t bstrA;
_bstr_t bstrB;
_bstr_t bstrR;
char* strR;
const char* strA = (env)->GetStringUTFChars(a , &blnIsCopy);
const char* strB = (env)->GetStringUTFChars(b , &blnIsCopy);
// convert jstring to a C++ constant string
bstrA = (_bstr_t) strA;
bstrB = (_bstr_t) strB; // convert the C++ string to BSTR
::CoInitialize(NULL);
hresult=CLSIDFromProgID(OLESTR("VBTestLib.CTest"), &clsid);
hresult= CoCreateInstance(clsid,NULL,CLSCTX_INPROC_SERVER,
__uuidof(_CTest),(LPVOID*) &t);
if(hresult == S_OK)
{
bstrR = t->vbConcat(bstrA , bstrB);
strR = (char*)bstrR;
jstrOut = (env)->NewStringUTF(strR); // create a new jstring
}
else
{
jstrOut = (env)->NewStringUTF("error");
}
(env)->ReleaseStringUTFChars(a, strA); // release jstring
(env)->ReleaseStringUTFChars(b, strB); // release jstring
return jstrOut;
}
Note : The strings passed from Java are jstring objects these strings have to be converted to native C++ strings and then to BSTR to be passed to the VB DLL. The returned string is then converted from BSTR to C++ string and then to jstring and passed back to Java.
Build the project, copy VBToJava.dll to Windows\System32 folder and register it. Now the native method VBConcat can be called from Java.