4

I have an own build Eclipse plugin where I need to call a C++ dll.

I tried to do this in two steps : 1. outside my Eclipse-plugin via a Java mainprogram calling the C++ dll 2. try to get it into my plugin (this is where the problem lies)

  1. outside Eclipse plugin.

Main Java-code HelloWorld.java.

class HelloWorld {
    //public native void print();  //native method
    public native String print(String msg);  //native method

    static   //static initializer code
    {
        System.loadLibrary("CLibHelloWorld");
    } 

    public static void main(String[] args)
    {
    //HelloWorld hw = new HelloWorld();
        //hw.print();

    String result = new HelloWorld().print("Hello from Java");

    System.out.println("In Java, the returned string is: " + result);
    }
}

Compiled via command : "C:\Program Files\Java\jdk1.6.0_34\bin\javac" HelloWorld.java

Then I made a h-file HelloWorld.h for the C++ dll via :

"C:\Program Files\Java\jdk1.6.0_34\bin\javah" HelloWorld

The h-file looks like this :

#include <jni.h>
/* Header for class HelloWorld */

#ifndef _Included_HelloWorld
#define _Included_HelloWorld
#ifdef __cplusplus
extern "C" {
#endif
/*
 * Class:     HelloWorld
 * Method:    print
 * Signature: (Ljava/lang/String;)Ljava/lang/String;
 */
JNIEXPORT jstring JNICALL Java_HelloWorld_print
  (JNIEnv *, jobject, jstring);

#ifdef __cplusplus
}
#endif
#endif

Now the C++ dll CLibHelloWorld.cpp :

#include "HelloWorld.h"
#include "jni.h"
#include "stdafx.h"
#include "tchar.h"

#import "..\ManagedVBDLL\bin\Debug\ManagedVBDLL.tlb" raw_interfaces_only
using namespace ManagedVBDLL;

JNIEXPORT jstring JNICALL Java_HelloWorld_print(JNIEnv *env, jobject thisObj, jstring inJNIStr) {
   jboolean blnIsCopy;
   const char *inCStr;
   char outCStr [128] = "string from C++";

   inCStr = env->GetStringUTFChars(inJNIStr, &blnIsCopy);
   if (NULL == inCStr) return NULL;

   printf("In C, the received string is: %s\n", inCStr);
   env->ReleaseStringUTFChars(inJNIStr, inCStr);  

   return env->NewStringUTF(outCStr);
}

Build the dll

When I run the java mainprogram ... it all works fine !

  1. try to get it into my Eclipse plugin (this is where the problem lies)

I made a class which should call the C++ dll :

package org.eclipse.ui.examples.recipeeditor.support;
import org.eclipse.jface.dialogs.MessageDialog;

public class HelloWorld {
    public native String print(String msg);  //native method

    static   //static initializer code
    {
        try {
            System.loadLibrary("CLibHelloWorld"); //$NON-NLS-1$
        } catch (Exception e) {
            e.printStackTrace();
            MessageDialog.openInformation(null, "HelloWorld", "HelloWorld Catch: " + e.getMessage());
        }
    } 
}

and call it like this :

HelloWorld hw = new HelloWorld();
result = hw.print("Hi from Eclipse");

Then I get this error on hw.print (the load of the dll is done) :

java.lang.UnsatisfiedLinkError: org.eclipse.ui.examples.recipeeditor.support.HelloWorld.print(Ljava/lang/String;)Ljava/lang/String;

A long story, but how can I solve it ?

Thanks.

maba
  • 47,113
  • 10
  • 108
  • 118
kahoona
  • 175
  • 2
  • 14
  • 3
    You have to put the DLL into the 'right' place and to inform Eclipse where is it. http://stackoverflow.com/questions/661320/how-to-add-native-library-to-java-library-path-with-eclipse-launch-instead-of – Aubin Nov 10 '12 at 13:04
  • Yes. At first the loadlibrary statement failed, but I fixed that by adding a library path to Eclipse. After that the loadlibrary statement went oke. – kahoona Nov 11 '12 at 21:59

2 Answers2

0

System.loadLibrary only loads the library if it is available in LD_LIBRARY_PATH (Linux) or in PATH (Windows). You need also to respect the correct name. Not sure in windows, but in linux if you are loading CLibHelloWorld like you did, your DLL should be called libCLibHelloWorld.so . I guess there is a System.getNativeMethodName or something like it so you can find it out.

Anyway, this is not my preffered way of loading DLLs, as you depend on a lot of environment settings. Instead, you could use System.load (dll_full_path) to load your DLL. It has the same effect, but you have more control.

If you sucessfully load your DLL by using this method, however, and keeps getting the error above when you try to call your native method, take a look at the DLL dependencies. You should load the dependencies first, then the lib you want to call.

Example, if you want to load dll1, that depends on dll2, which depends on dll3, you should do:

System.load(dll3_path);
System.load(dll2_path);
System.load(dll1_path);
mvallebr
  • 2,388
  • 21
  • 36
0

The method name in the native code must correspond to the class and package name of the java-class. Since your HelloWorld-class changed from the default-package to org.eclipse.ui.examples.recipeeditor.support you'll have to change the method name.

Just rerun javah with your new class to get the correct header-file.

Btw, there should be no need to set a separate library-path if you correctly define the dll in your OSGI-bundle using something like

Bundle-NativeCode: mydll.dll ; osname=win32 ; processor=x86

and include the dll in your plugin's root directory.

piet.t
  • 11,718
  • 21
  • 43
  • 52