C++回调函数调用Java接口抽象函数

原文:http://www.diybl.com/course/3_program/c++/cppjs/20110103/552247.html

项目中很多代码采用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进行加密,加密函数为回调函数。头文件定义如下

  1. #ifdef CALLBACK_EXPORTS
  2. #define CALLBACK_API __declspec(dllexport)
  3. #else
  4. #define CALLBACK_API __declspec(dllimport)
  5. #endif

  6. #ifdef __cplusplus
  7. extern "C"
  8. {
  9. #endif
  10.     typedef int (*UserProcess)(int nEncrptType);
  11.     CALLBACK_API int Process(UserProcess cb,int nCompanID);
  12. #ifdef __cplusplus
  13. }
  14. #endif



其实现文件为

  1. #include "stdafx.h"
  2. #include "CallBack.h"


  3. CALLBACK_API int Process(UserProcess cb,int nCompanID)
  4. {
  5.     if(cb == NULL)
  6.     {
  7.         return -1;
  8.     }

  9.     cb(nCompanID);
  10.     return 0;
  11. }


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

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

  3. int WanporProcess(int i)
  4. {
  5.     printf("Process = %d\n",i);
  6.     return i;
  7. }
  8. int _tmain(int argc, _TCHAR* argv[])
  9. {

  10.     Process(WanporProcess,100);
  11.     return 0;
  12. }

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


  3. public interface CBInterface{
  4.     public abstract int UserProcess(int encryptType);
  5. }


3.2实现回调类

  1. //实现回调类


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


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

  1. #include "stdafx.h"
  2. #include "../CallBack/CallBack.h"
  3. #include "cn_com_wanpor_CallBackJNI.h"

  4. typedef struct CBData{
  5.     UserProcess m_pfnUserProcess;
  6.     jobject m_objInterface;
  7.     JNIEnv* m_pEnv;
  8.     jobject m_objCallBack;
  9. }CBData;

  10. CBData g_cbData;
  11. JNIEXPORT jint JNICALL Java_cn_com_wanpor_CallBackJNI_setUserCallBack
  12. (JNIEnv * env, jobject obj, jobject cb)
  13. {
  14.     
  15.     g_cbData.m_pEnv = env;
  16.     g_cbData.m_objCallBack = env->NewGlobalRef(obj);
  17.     g_cbData.m_objInterface = env->NewGlobalRef(cb);

  18.     return 0;
  19. }


3.4实现C++回调函数

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

  6.     jclass jclsProcess = g_cbData.m_pEnv->GetObjectClass(g_cbData.m_objInterface);
  7.     if (jclsProcess == NULL)
  8.     {
  9.         printf("jclsProcess = NULL\n");
  10.         return -1;
  11.     }
  12.     jmethodID jmidProcess = g_cbData.m_pEnv->GetMethodID(jclsProcess,"UserProcess","(I)I");
  13.     if (jmidProcess == NULL)
  14.     {
  15.         printf("jmidProcess = NULL\n");
  16.         return -2;
  17.     }

  18.     g_cbData.m_pEnv->CallIntMethod(g_cbData.m_objInterface,jmidProcess,nEncrpytType);
  19.     
  20.     pVm->DetachCurrentThread();
  21.     
  22.     return 0;
  23. }


3.5执行回调函数

  1. JNIEXPORT jint JNICALL Java_cn_com_wanpor_CallBackJNI_process
  2. (JNIEnv * env, jobject obj, jint nCompanyID)
  3. {
  4.     Process(ProcessJNICB,nCompanyID);
  5.     return 0;
  6. }

 
3.6卸载回调类
  1. JNIEXPORT jint JNICALL Java_cn_com_wanpor_CallBackJNI_resetUserCallBack
  2. (JNIEnv * env, jobject objCallBack, jobject objInterface)
  3. {
  4.     g_cbData.m_pEnv->DeleteGlobalRef(objInterface);
  5.     g_cbData.m_pEnv->DeleteGlobalRef(objCallBack);
  6.     return 0;
  7. }


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

  1. package cn.com.wanpor;

  2. //实现回调类


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


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


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


  19.     public native int process(int companyID);
  20.     
  21.     //测试程序


  22.     public static void main(String[] argv){
  23.         CallBackJNI cbj = new CallBackJNI();
  24.         WanporCB wcb = new WanporCB();
  25.         cbj.setUserCallBack(wcb);
  26.         cbj.process(300);
  27.         cbj.resetUserCallBack(wcb);
  28.     }
  29.     
  30. }
阅读(1374) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~
评论热议
posted on 2016-01-25 16:35  玄冬  阅读(799)  评论(0编辑  收藏  举报