Java调用第三方dll

刚接触Java几天,项目需要,使用Java调用can卡的dll,发现网上的帖子有很多不明确的地方,特此写之。

       首先安装开发环境,考虑到兼容性,安装的JDK和eclipse都是32位的,正常安装结束后,需要添加一些环境变量(网上有说正常安装后,环境变量就不用配置了,我安装了两台电脑,都不行的,需要手动添加环境变量)。找到高级系统设置-->高级-->环境变量,在系统变量一栏添加如下信息:

变量名:JAVA_HOME,值:D:\A_Z_R_J\Java\jdk1.8.0_131,就是JDK的安装路径。

变量名:CLASSPATH,值:.;%JAVA_HOME%\lib\dt.jar;%JAVA_HOME%\lib\tools.jar;

在Path一栏,继续添加值:%JAVA_HOME%\bin;

 

总共需要添加三处,即JAVA_HOME、CLASSPATH和Path。

       然后,使用Java调用第三方的DLL,一般来说,DLL都是使用C/C++语言编写的,Java不同于其他语言(如C++,C#等),使用C++可以直接调用DLL,而使用Java必须封装一层,才可以调用。或者这样讲:比如需要用Java调用A.dll,那么首先需要用Java编写一个代码B.Java,这个代码可以理解为C++里与dll配套使用的h文件,用来对dll里的函数进行声明(但又不同于h文件),然后使用Java命令,将这个B.Java代码编译成一个B.h文件,再拿这个B.h文件到C++里,制作对应的接口函数内容(因为这个B.h文件只有函数的声明,没有具体实现,需要新建B.cpp来写入其实现),制作完成后生成B.dll,这时拿这个B.dll回到B.Java的工程中,放置于其根目录下,或lib里,保证工程能搜索到就可以。这时可以新建一个main.Java代码,写一个主函数,来调用A.dll里的内容。写了这么多,可能很多人都觉得比较费劲,确实有点啰嗦,怪不得很多CAN卡都没有Java的代码。下面写一下具体操作步骤:

       新建Java Project,新建一个Java工程,如ControlCANAPI.Java,一般一个Java的Public类只能对应一个Java文件。需要注意的事,下面代码里loadLibrary里的dll需要与这个公共类的名字一致。

package com.sdk.api;

public class ControlCANAPI {
    static
    {

        System.loadLibrary("ControlCANAPI");
    }

    public native static void HelloWord();
    public native static String cToJava();
    public native  long VCI_OpenDevice(long DeviceType,long DeviceInd,long Reserved);
    public native  long VCI_InitCAN(long DeviceType, long DeviceInd, long CANInd, long[] Init);
    public native  long VCI_StartCAN(long DeviceType,long DeviceInd,long CANInd);
}

建立好类之后,打开系统cmd对话框,将路径切换到当前目录。如果你的工程在d盘,需要从c盘切换到d盘,方法是键入d:,就可以切换到d盘。想具体到某一个文件夹,输入cd d:/test…

这里假设工程结构如下:

D:\WorkSpace_eclipse\ControlCANTest\src\com\sdk\api,在api文件夹下为ControlCANAPI.Java。

那么首先需要使用cmd命令,切换到api目录下,即cd D:\WorkSpace_eclipse\ControlCANTest\src\com\sdk\api。然后使用javac ControlCANAPI.java命令,生成class文件,这时再切换到工程主路径下即src文件夹下(Java里分为主路径和包路径,这里的包路径就是com文件夹后的内容),使用cd D:\WorkSpace_eclipse\ControlCANTest\src,最后使用javah com. sdk.api.ControlCANAPI生成对应的h文件,生成的h文件在src目录下,文件名一般比较长,可以不管。

    使用VS建立dll工程,工程名同类名,即新建win32项目,勾选dll和导出符号。

打开JDK的安装目录,找到include文件夹,复制该文件夹下的jni.h,include/win32文件夹下的jawt_md.h、jni_md.h到VS的安装目录下,复制到VC/include文件夹里。

之后将前面使用javah命令生成的h文件的内容,复制到这个c++工程里的h文件中(不用改动,全部复制),然后在cpp里编写其函数实现。

typedef DWORD (_stdcall *VCI_OpenDevicec)(DWORD,DWORD,DWORD);//参数需要何商家提供的DLL文件中方法的参数一致
typedef DWORD (_stdcall *VCI_StartCANc)(DWORD,DWORD,DWORD);
typedef DWORD (_stdcall *VCI_InitCANc)(DWORD,DWORD,DWORD,PVCI_INIT_CONFIG);

HINSTANCE dllHandle;
int result;

JNIEXPORT jlong JNICALL Java_com_sdk_api_ControlCANAPI_VCI_1OpenDevice
  (JNIEnv *env, jobject jo, jlong DeviceType, jlong DeviceInd, jlong Reserved) 

{
    VCI_OpenDevicec pIniCom;
    dllHandle = LoadLibrary("ControlCAN.dll");//商家提供的库文件
    pIniCom = (VCI_OpenDevicec __stdcall)GetProcAddress(dllHandle,"VCI_OpenDevice");//寻找商家提供库中对应的方法名
    result = pIniCom(DeviceType,DeviceInd,Reserved);
    //FreeLibrary(dllHandle);
    return result;
}

。。。。

 

这里遇到一个问题,正常情况下,都是LoadLibrary后再进行FreeLibrary,我这边测试的结果是,如果在这里FreeLibrary了,后面的函数就无法正常LoadLibrary,索性暂时就只LoadLibrary一次,后面函数不再继续LoadLibrary了。

编写好程序后,生成Release版的dll,记住,是Release版的!然后把生成的dll放置于刚才的java工程目录下,新建一个Maintest文件,在里面写main函数。

package com.sdk.api;
import com.sdk.api.ControlCANAPI;

public class Maintest {
    public static void main(String[] args)
    {
        ControlCANAPI CCANAPI = new ControlCANAPI();
        CCANAPI.VCI_OpenDevice(4, 0, 0);
        long Init[]= {0,0xF,0,0,0,0,0};
        CCANAPI.VCI_InitCAN(4, 0, 0,Init);
        CCANAPI.VCI_StartCAN(4, 0, 0);
    }
}

终于,结束了一天的折腾,总得来说,Java不需要h文件,写起来也不错,一个文件名就是一个类名,比较容易管理。

已标记关键词 清除标记
©️2020 CSDN 皮肤主题: 编程工作室 设计师:CSDN官方博客 返回首页