4

我有一个自己的构建 Eclipse 插件,我需要在其中调用 C++ dll。

我尝试分两步执行此操作: 1. 在我的 Eclipse 插件之外通过调用 C++ dll 的 Java 主程序 2. 尝试将其放入我的插件中(这就是问题所在)

  1. Eclipse 插件之外。

主要 Java 代码 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);
    }
}

通过命令编译:“C:\Program Files\Java\jdk1.6.0_34\bin\javac”HelloWorld.java

然后我通过以下方式为 C++ dll 制作了一个 h 文件 HelloWorld.h:

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

h 文件如下所示:

#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

现在是 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);
}

构建 dll

当我运行 java 主程序时……一切正常!

  1. 尝试将它放入我的 Eclipse 插件中(这就是问题所在)

我做了一个应该调用 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());
        }
    } 
}

并这样称呼它:

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

然后我在 hw.print 上得到这个错误(dll 的加载完成):

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

一个很长的故事,但我该如何解决呢?

谢谢。

4

2 回答 2

0

System.loadLibrary 仅在 LD_LIBRARY_PATH (Linux) 或 PATH (Windows) 中可用时才加载库。您还需要尊重正确的名称。不确定在 Windows 中,但在 linux 中,如果您CLibHelloWorld像以前一样加载,您的 DLL 应该被调用libCLibHelloWorld.so。我想有一个 System.getNativeMethodName 或类似的东西,所以你可以找到它。

无论如何,这不是我加载 DLL 的首选方式,因为您依赖于很多环境设置。相反,您可以使用它System.load (dll_full_path)来加载您的 DLL。它具有相同的效果,但你有更多的控制权。

但是,如果您使用此方法成功加载了 DLL,并且在尝试调用本机方法时不断收到上述错误,请查看 DLL 依赖项。您应该先加载依赖项,然后再加载要调用的库。

例如,如果你想加载依赖于 dll2 的 dll1,而后者又依赖于 dll3,你应该这样做:

System.load(dll3_path);
System.load(dll2_path);
System.load(dll1_path);
于 2012-11-29T04:50:15.290 回答
0

本机代码中的方法名必须与java-class的类名和包名相对应。由于您的 HelloWorld-class 从 default-package 更改为 org.eclipse.ui.examples.recipeeditor.support,您必须更改方法名称。

只需使用新类重新运行 javah 即可获得正确的头文件。

顺便说一句,如果您使用类似的东西在 OSGI 捆绑包中正确定义 dll,则不需要设置单独的库路径

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

并将 dll 包含在插件的根目录中。

于 2013-08-22T06:57:01.273 回答