java调用c++的第三方dll动态库详解

由于在项目中用到了java调用c++的SDK动态库的例子,博主之前没有接触过,所以一直在网上百度,千篇一律,经过几天的努力终于成功了。所以博主想把它记录下来,方便其他人参考。

以下是要调用的接口方法:
/************************************************
方法一:(上传图片)1、fileName:输入参数。
×************************************************ */

M2CCGKEYER_API BOOL CALL_TYPE  M2CLogoCgKeyerUpLoadFile(const char *fileName);

/************************************************
方法二:(图片上线叠加)1、fileName:输入参数。
×************************************************ */

M2CCGKEYER_API BOOL CALL_TYPE M2CLogoCgKeyerSetupLogo(const char *fileName, int x, int y, BOOL bEnabled);


其中M2CLogoCgKeyerUpLoadFile和M2CLogoCgKeyerSetupLogo是方法名称,此方法在第三方提供的.h文件里面,我采用的是jni,之前也查过很多资料,考虑到效率问题我还是选择了我有难度的jni,至少效率比不用写c++的jna要高很多。因为这个函数是需要将图片叠加在视频上,必须要做到毫秒级别的。

第一步:(非必须的,根据项目实际需要)

          下载 dom4j-1.6.1.jar和log4j-1.2.17.jar的jar包,右键选中项目创建文件夹lib,将jar包copy进去,最后build path.(在此说明jni是java自带的所以不需要jar包的,前面两个jar包,是因为我要解析XML文件,并做一个日志输出,我会在后面的文章中逐一讲解的)

第二步:
         还是直接上代码吧,其中MyDLL7是用vs2015生成的dll文件,会在下面详细说明的,而M2CCGKeyer是第三方提供的dll动态库,注意这里加载顺序不能错,必须先加载MyDLL7,其实在这里有个误解,第三方的M2CCGKeyer.dll文件可以不用System.loadLibrary("M2CCGKeyer"),直接右键选中项目把这个文件copy在项目路径下就可以了,到时候会自己找到加载的。但是如果你写了System.loadLibrary("M2CCGKeyer"),那也必须将M2CCGKeyer.dll放在项目路径下。

  

public class Task1 {
package cn.com.plustv;

public class SmartCard {
	static {
		System.loadLibrary("MyDLL7");//用c++自己编写的dll库文件
		System.loadLibrary("M2CCGKeyer");//第三方提供的库文件

	}

	/*方法一:
	 * ***********************************************
	 * 上载logo到设备,支持文件格式有:BMP和TGA。 
	 * 支持BMP和TGA 24bit或32bit像素深度; 支持TGA RLE压缩格式
	 * 1、fileName:输入参数。 表示本地存储的Logo文件名,例如C://test.tga
	 * ×************************************************
	 */
	private native boolean M2CLogoCgKeyerUpLoadFile(String  fileName);
         //使用jni必须要用native修饰,不是我说的哦,因为就这么规定的,好了,接下来该头疼的参数问题了,对于一个没接触过c++的人,可能比较吃力,比如小编我就是,其实java中的String对应c++中的char  但是在编写c++的过程中需要转换,还有释放内存,我会在后面讲解的。而fileName就是输入参数。
        private native boolean M2CLogoCgKeyerSetupLogo(String fileName, int x, int y, boolean bEnabled);//M2CLogoCgKeyerSetupLogo这种方法名称必须和第三方提供的接口方法名称保持一致,参数也要保持一一对应。
        // 外部类能调用的方法一
	public boolean tjSDK(String fileName) {

		return this.M2CLogoCgKeyerUpLoadFile(fileName);
	}
    //方法三:
    public boolean tjSDK03(String fileName, int x, int y, boolean bEnabled) {
        
        return this.M2CLogoCgKeyerSetupLogo(fileName, x , y , bEnabled);
    }
 }
第三步:

           需要编写一个测试方法,等到dll文件生成后,测试。

public class Task1 {
package cn.com.plustv;

import org.junit.Test;

public class TestSdk {
	SmartCard sc = new SmartCard();
	@Test
	public void test01() {

		//测试方法一:通过
		boolean tjSDK = sc.tjSDK("D:/200311000100101.tga");
		System.out.println(tjSDK);
	}
    @Test
    public void test03() {
        // 测试方法三:通过
        boolean tjSDK03 = sc.tjSDK03("/logo/200311000100103.tga", 0, 0, true);
        System.out.println(tjSDK03);
    } }
第四步:


然后使用javac  cn/com/plustv/SmartCard.java回车,再使用javah  cn.com.plustv.SmartCard  回车,你会发现在src下会生成一个.h的文件,如下图所示:


第五步:(编写dll文件)

          1、 打开visual Studio2015,新建一个项目,选择Win32—>win32项目,项目名称为:MyDLL5。如下图所示:


           2、 点击确定,然后点击下一步,进入应用程序设置的页面,如下图所示:在应用程序类型下选择”DLL”,在附加选项中选中”导出符号”,点击完成。如下图所示:


生成的项目的目录结构如下图所示:


          3、 在VS工程中,添加c/c++工程中外部头文件及库的基本步骤:(重要)
a、添加工程的头文件目录:工程---属性---配置属性---c/c++---常规---附加包含目录:加上头文件存放目录。(此处需加上自己用javah生成的.h文件目录和第三方提供的.h文件目录)
b、添加文件引用的lib静态库路径:工程---属性---配置属性---链接器---常规---附加库目录:加上lib文件存放目录。(此处加上第三方提供的lib文件目录)然后添加工程引用的lib文件名:工程---属性---配置属性---链接器---输入---附加依赖项:加上lib文件名。(此处加上第三方提供的lib文件名)

          4、在MyDLL7.cpp中加入以下代码:

// dllmain.cpp : 定义 DLL 应用程序的入口点。
// MyDll.cpp : 定义 DLL 应用程序的导出函数。
//
#include "jni.h"
#include "stdafx.h"
#include "cn_com_plustv_SmartCard.h"
#include "M2CCGKeyerDll.h"
#include "stdafx.h"
#include <tchar.h>
#include <iostream>
using namespace std;

#ifdef __cplusplus
extern "C" {
#endif


    //方法一:
    JNIEXPORT jboolean JNICALL Java_cn_com_plustv_SmartCard_M2CLogoCgKeyerUpLoadFile
    (JNIEnv * env, jobject obj, jstring fileName)
    {
        //char strText[256] = { 0 };
        //char buf[128];
        //测试
        //    MessageBox(0, (LPCWSTR)"OK", 0, 0);
        BOOL result = 0;
        jboolean jb = JNI_TRUE;
        const char* strDeviceInfo = (*env).GetStringUTFChars(fileName, &jb);
        //printf("String1 = [%s]\n", strDeviceInfo);
        //执行商家提供的方法
        //sprintf_s(strText, 128, "fileName: %s", strDeviceInfo);
        //MessageBox(NULL, strText, "UpLoadFile", 0);
        if (strDeviceInfo == NULL) {
            return NULL;
        }
        result = M2CLogoCgKeyerUpLoadFile(strDeviceInfo);


        //释放资源
        //在使用完你所转换之后的对象之后,需要显示调用ReleaseStringUTFChars方法,
        //让JVM释放转换成UTF-8的string的对象的空间,如果不显示的调用的话,JVM中会一直保存该对象,不会被垃圾回收器回收,因此就会导致内存溢出
        env->ReleaseStringUTFChars(fileName, strDeviceInfo);
        return (jboolean)result;
    }


    //JNIEXPORT jboolean JNICALL Java_cn_com_plustv_SmartCard_M2CLogoCgKeyerSetupLogo
    //(JNIEnv *, jobject, jstring, jint, jint, jboolean);
    //M2CCGKEYER_API BOOL CALL_TYPE M2CLogoCgKeyerSetupLogo(const char *fileName, int x, int y, BOOL bEnabled);
    //方法三:jint 和 c或c++的 signed int 是等同的
    JNIEXPORT jboolean JNICALL Java_cn_com_plustv_SmartCard_M2CLogoCgKeyerSetupLogo
    (JNIEnv * env, jobject obj, jstring fileName, jint x, jint y, jboolean bEnabled)
    {
        //    MessageBox(0, (LPCWSTR)"OK", 0, 0);
        BOOL result = 0;
        jboolean jb = JNI_TRUE;
        const char* strDeviceInfo = (*env).GetStringUTFChars(fileName, &jb);    
        //执行商家提供的方法
        result = M2CLogoCgKeyerSetupLogo(strDeviceInfo, x, y, bEnabled);
        //释放资源
        //在使用完你所转换之后的对象之后,需要显示调用ReleaseStringUTFChars方法,
        //让JVM释放转换成UTF-8的string的对象的空间,如果不显示的调用的话,
        //JVM中会一直保存该对象,不会被垃圾回收器回收,因此就会导致内存溢出
        (*env).ReleaseStringUTFChars(fileName, strDeviceInfo);
        return (jboolean)result;
    }

#ifdef __cplusplus
}
#endif


说明:代码具体的实现涉及到jni中的类型和vc++中类型的对应转换的操作,第三方提供的dll中的函数参数是c/c++中的类型,而通过java方法传进来的参数通过jni的处理转变为java和c/c++之间的一种过渡类型,比如jstring等,此时,就需要我们调用jni中的对应方法来转换该类型,具体需参照jni文档。

第六步:(生成dll文件)

如下图所示,在解决方案配置中选择”Dubug”,点击”启动调试”按钮,在这里我选择32位,最好跟第三方用的操作系统保持一致。


这时,就会在工程下的Dubug文件夹下生成MyDLL5.dll。我的是在:C:\Users\java\Documents\Visual Studio2015\Projects\MyDLL5\Debug路径下。注:在解决方案配置中如果选择Release,则会在工程下的Release文件夹下生成MyDLL5.dll

第七步:(测试)

将dll文件放到java项目中将生成的MyDLL5.dll和商家提供的M2CCGKeyer.dll文件拷贝到项目的目录下,如下图:


说明:在我的项目中是通过网络连接第三方那个设备,所以我需要将netconfig.ini(里面是一个ip地址)文件放在自己的jre的bin目录下。

           最后运行测试方法会在控制台打印一个true.


我不能保证写的每个地方都是对的,但是至少是我仔细思考过的,希望大家多多指教,面对压力,我可以挑灯夜战、不眠不休;面对困难,我愿意迎难而上、永不退缩

     

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小盒子_spring

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值