使用JNI调用dll(C++)

使用JNI调用dll(C++)

  简单说下业务背景,有一个用C++写的加密算法(据说速度快),需要用JAVA来调用,并将值展示在页面。这块内容网上一搜一大堆,给个别人写的教程,非常详细,照着做,可以实现一个DEMO,传送门
  但是,这仅仅只是一个DEMO,在实际应用中,应该怎么做。

dll文件的位置

  网上说法是将调用的dll放在tomcat的bin目录下,但是在实际生产中,我们希望能将调用的dll文件放在工程里,这样,就不会对环境产生依赖。
  废话不多说,直接上代码。

public class CallThirdDll {

    public native String callThirdDll(String str, int mode);
    //这是大多数的作法,但是dll必须放在java.library.path目录
    /*static {
        //这里只需要写上你生成的那个中介dll名称即可
        System.loadLibrary("CallThirdDll");
    }*/


    public CallThirdDll()
    {
        //我这里将dll放在包下面
        String packagePath = "/com/test/common/jni/";
        //这里注意,先写第三方的dll名称,再写自己JNI产生的dll,否则,系统会提示找不到CallThirdDll.dll
        String[] filenames = new String[]{"ThirdDll.dll", "CallThirdDll.dll"};
        // 取得src下的物理路径,
        String path = CallThirdDll.class.getResource("/").getPath();
        // 将路径里的%20替换成空格
        path = path.replaceAll("%20", " ");
        System.out.println(path);

        for (String filename : filenames)
        {
            //这里的Load里在的地址是绝对地址
            System.load(path + packagePath + filename);
        }
    }
}

  这样的好处,显而易见。

  但是我却没有使用这种方式,应为生产环境是WAS,使用这种方式,找不到dll所在目录。

  于是采用下面的方式来取得dll的绝对路径,虽然可以正常打印出dll的目录,但是却报java.lang.UnsatisfiedLinkError。我郁闷了,打印出来的目录明明可以找到dll的,为什么会报这个错,如果有知情的,求告知。最终,我还是把所用的dll放在JDK的Bin目录下面,代码采用System.loadLibrary("MediumDll");的方式来调用dll的。

CallThirdDll.class.getClassLoader().getResource("/com/test/common/jni/JACVinToPin.dll").toURI().getPath();

关于32位 OR 64位的dll

  如果你的JDK是32位的,那么请使用对应的32位的dl,不要问为什么,因为不那样做,会报错。具体的异常代码,我就不贴了。
另外,在用javah来编译你的头文件时,请采用实际环境中的JDK下的javah.exe来编译。
  既然说到javah编译头文件,再多说一句,请切到你的编译出来的class的包所在的上级目录来执行javah com.test.jni.CallThirdDll。
即classes这个目录下执行javah命令。

内存泄漏

  如果说使用JNI最令人头疼的事情是什么,就是出了问题,不知道怎么排查。我调用dll可以正常返回值,但是却会导致JVM异常退出,我一开始觉得是内存溢出,我在这件事情上搞了一整天,最终发现完全不是的。

  是因为我在C++中(我不了解C++)里面进行char声明的时候,内存大小申请小了,就是下面这句话。

char* m_char = (char*)malloc(sizeof(char)*10);

好吧,至于其他要Release的地方,请自行释放。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
Java使用JNIJava Native Interface)调用DLL(Dynamic-Link Library)中间件需要以下步骤: 1. 创建Java类和本地方法声明:首先,在Java类中声明本地方法。本地方法声明使用`native`关键字,并且没有方法体。例如: ```java public class MyDLL { public native void myFunction(); } ``` 2. 生成JNI头文件:运行`javac`命令编译Java类,然后使用`javah`命令生成JNI头文件。在命令行中切换到包含Java类的目录,并执行以下命令: ```shell javac MyDLL.java javah MyDLL ``` 这将生成名为`MyDLL.h`的头文件。 3. 编写C/C++实现:使用生成的JNI头文件作为C/C++代码的基础,实现本地方法。在C/C++文件中,包含生成的头文件并实现本地方法。例如: ```c #include "MyDLL.h" JNIEXPORT void JNICALL Java_MyDLL_myFunction(JNIEnv *env, jobject obj) { // 实现DLL中间件的功能 } ``` 4. 编译C/C++代码为DLL使用适当的编译器将C/C++代码编译为DLL。具体步骤取决于所使用的编译器和操作系统。 5. 加载和调用DLL:在Java代码中加载并调用DLL。在Java代码中,使用`System.loadLibrary()`方法加载DLL,并调用本地方法。例如: ```java public class Main { static { System.loadLibrary("mydll"); } public static void main(String[] args) { MyDLL mydll = new MyDLL(); mydll.myFunction(); } } ``` 在上述示例中,`System.loadLibrary("mydll")`加载名为`mydll`的DLL,然后通过创建`MyDLL`对象并调用`myFunction()`方法来调用DLL中的函数。 请注意,执行此操作需要确保DLL文件与Java代码在相同的操作系统平台和架构上兼容,并且DLL文件路径正确。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值