Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1723516
  • 博文数量: 171
  • 博客积分: 11553
  • 博客等级: 上将
  • 技术积分: 3986
  • 用 户 组: 普通用户
  • 注册时间: 2006-05-25 20:28
文章分类

全部博文(171)

文章存档

2012年(2)

2011年(70)

2010年(9)

2009年(14)

2008年(76)

分类: C/C++

2010-12-30 01:00:30

    项目中很多代码采用C++编写,配置界面则采用BS结构,使用Java语言进行设置。因此需要实现Java调用C++编写的函数库(dll文件或so文件),采用的技术为JNI(Java Native Interface),对于常用的调用方式在《The Java Native Interface Programmer's Guide and Specification》一书中有详细的描述,不在进行描述。本文中主要介绍在动态链接库中如果含有回调函数作为函数参数的C++函数如何使用JNI实现调用。在C++中函数定义格式为:

    typedef int (*UserProcess)(int nEncrptType);

    CALLBACK_API int Process(UserProcess cb,int nCompanID);

即如何采用Java语言实现Process函数?下面将分别针对C++和Java语言使用回调函数进行说明。

1.回调函数库

本文中定义了一个简单的回调函数接口,目的是根据公司ID进行加密,加密函数为回调函数。头文件定义如下



#ifdef CALLBACK_EXPORTS
#define CALLBACK_API __declspec(dllexport)
#else
#define CALLBACK_API __declspec(dllimport)
#endif

#ifdef __cplusplus
extern "C"
{
#endif
    typedef int (*UserProcess)(int nEncrptType);
    CALLBACK_API int Process(UserProcess cb,int nCompanID);
#ifdef __cplusplus
}
#endif

其实现文件为

#include "stdafx.h"
#include "CallBack.h"


CALLBACK_API int Process(UserProcess cb,int nCompanID)
{
    if(cb == NULL)
    {
        return -1;
    }

    cb(nCompanID);
    return 0;
}

2.C++语言使用回调函数库
用法比较简单,直接实现一个满足UserProcess定义的函数,然后将其传递给Process函数即可,见下文代码内容。

#include "stdafx.h"
#include "../CallBack/CallBack.h"

int WanporProcess(int i)
{
    printf("Process = %d\n",i);
    return i;
}
int _tmain(int argc, _TCHAR* argv[])
{

    Process(WanporProcess,100);
    return 0;
}

加密函数将公司ID直接输出,未进行其他处理。
3.Java语言使用回调函数
这个过程相对于C++显得比较繁琐,主要包含以下一个过程:
3.1编写回调函数的抽象接口,并实现一个回调类;
3.2在JNI中安装回调接口类
3.3实现C++的回调函数,在此回调函数中获取抽象接口类对象、回调函数的接口名称、调用回调函数
3.4调用process进行回调函数执行
2.5卸载回调类
下面依次实现上述中的内容
3.1回调函数接口定义

package cn.com.wanpor;
//编写回调函数接口

public interface CBInterface{
    public abstract int UserProcess(int encryptType);
}

3.2实现回调类

//实现回调类

class WanporCB implements CBInterface {
    public int UserProcess(int encryptType){
        System.out.println("Java = " + 3*encryptType);
        return 0;
    }
}

3.3C++ JNI代码中安装回调类

#include "stdafx.h"
#include "../CallBack/CallBack.h"
#include "cn_com_wanpor_CallBackJNI.h"

typedef struct CBData{
    UserProcess m_pfnUserProcess;
    jobject m_objInterface;
    JNIEnv* m_pEnv;
    jobject m_objCallBack;
}CBData;

CBData g_cbData;
JNIEXPORT jint JNICALL Java_cn_com_wanpor_CallBackJNI_setUserCallBack
(JNIEnv * env, jobject obj, jobject cb)
{
    
    g_cbData.m_pEnv = env;
    g_cbData.m_objCallBack = env->NewGlobalRef(obj);
    g_cbData.m_objInterface = env->NewGlobalRef(cb);

    return 0;
}

3.4实现C++回调函数

int ProcessJNICB(int nEncrpytType)
{
    JavaVM* pVm;
    g_cbData.m_pEnv->GetJavaVM(&pVm);
    pVm->AttachCurrentThread((void**)&g_cbData.m_pEnv,NULL);

    jclass jclsProcess = g_cbData.m_pEnv->GetObjectClass(g_cbData.m_objInterface);
    if (jclsProcess == NULL)
    {
        printf("jclsProcess = NULL\n");
        return -1;
    }
    jmethodID jmidProcess = g_cbData.m_pEnv->GetMethodID(jclsProcess,"UserProcess","(I)I");
    if (jmidProcess == NULL)
    {
        printf("jmidProcess = NULL\n");
        return -2;
    }

    g_cbData.m_pEnv->CallIntMethod(g_cbData.m_objInterface,jmidProcess,nEncrpytType);
    
    pVm->DetachCurrentThread();
    
    return 0;
}

3.5执行回调函数

JNIEXPORT jint JNICALL Java_cn_com_wanpor_CallBackJNI_process
(JNIEnv * env, jobject obj, jint nCompanyID)
{
    Process(ProcessJNICB,nCompanyID);
    return 0;
}

3.6卸载回调类

JNIEXPORT jint JNICALL Java_cn_com_wanpor_CallBackJNI_resetUserCallBack
(JNIEnv * env, jobject objCallBack, jobject objInterface)
{
    g_cbData.m_pEnv->DeleteGlobalRef(objInterface);
    g_cbData.m_pEnv->DeleteGlobalRef(objCallBack);
    return 0;
}

4.Java测试程序
下面的代码是对JNI接口的测试程序,WanporCB实现了回调接口,回调函数返回值为0,但打印出3*nCompany的值,程序执行函数的顺序是:
创建回调函数接口实例
创建测试对象
安装回调类
执行加密
卸载回调类
代码如下:

package cn.com.wanpor;

//实现回调类

class WanporCB implements CBInterface {
    public int UserProcess(int encryptType){
        System.out.println("Java = " + 3*encryptType);
        return 0;
    }
}
public class CallBackJNI{
    static{
        System.load("E:\\Program Files\\Java\\jdk1.5.0_15\\bin\\CallBackJNI.dll");
    }
    
    //设置回调函数

    public native int setUserCallBack(CBInterface cb);
    //清除回调函数

    public native int resetUserCallBack(CBInterface cb);
    //执行用户自定义加密

    public native int process(int companyID);
    
    //测试程序

    public static void main(String[] argv){
        CallBackJNI cbj = new CallBackJNI();
        WanporCB wcb = new WanporCB();
        cbj.setUserCallBack(wcb);
        cbj.process(300);
        cbj.resetUserCallBack(wcb);
    }
    
}


阅读(11232) | 评论(2) | 转发(0) |
给主人留下些什么吧!~~

swt1234572014-11-25 00:07:47

前辈,java调用第三方dll(C++),然后让第三方dll回调java方法怎么弄,中间dll回调java方法没有问题,但是第三方dll(多线程)回调有没有什么要注意的问题

chinaunix网友2011-01-04 09:06:52

很好的, 收藏了 推荐一个博客,提供很多免费软件编程电子书下载: http://free-ebooks.appspot.com