Java调用C++库dll文件接口(JNI)回传int参数(引用)

2023-05-16

vc写了一个标准的动态库,有如下接口:

const WCHAR* execCommand(const char* param, int& errCode);

java中的接口声明:

// VideoUnit.java

public class VideoUnit
{
  private VideoUnit() {}
  static
  {
    System.load("videounit.dll");
  }

  public static native String execCommand(String strParam, int[] errCode);
}

此文件通过javac命令进行编译:

javac VideoUnit.java

生成 VideoUnit.class 文件,然后再通过javah命令生成.h文件供c++库使用:

javah VideoUnit

生成VideoUnit.h文件。

java中,对execCommand()的接口调用形式如下:

	public static void main(String[] args) {
		int[] execArr = new int[1];
		System.out.println("execCommand: " + execCommand("", execArr));
		System.out.println("errCode is " + execArr[0]);
	}

注意,此函数可以直接写在VideoUnit类中,这样可以javac编译后,直接用java命令运行它。当然如此调试时,System.loada()的dll路径,必需是正确的。

在c++库中,为了java的调用,需要对接口execCommand()进行jni封装:

把 VideoUnit.h 文件加入进来,然后实现其接口 Java_execCommand(),如下的样子:

JNIEXPORT jstring JNICALSS Java_execCommand(JNIEnv* env, jclass obj, jstring strParam, jintArray errCode)
{
  const char* params1 = env->GetStringUTFChars(strParam, JNI_FALSE);
  jint* errCode1 = env->GetIntArrayElements(errCode, JNI_FALSE);
  int errCode2 = 0;
  const TCHAR* retv = execCommand(params1, errCode2);
  *errCode1 = errCode2;
  env->ReleaseIntArrayElements(errCode, errCode1, 0);
  jstring retv1 = env->NewString((const jchar*)retv, _tcslen(retv));
  return retv1;
}

这个函数的实现有一点绕,其总体思路就是:

把java的相关变量转换成本地可以使用的,然后调用c++对应的接口,结束后再把需要传出和返回的内容转换回java的类型。

其中的errCode参数,在C++接口中是引用,上述代码是调试时的过程,开始的时候在这个函数中添加打印回传的errCode是正确的,但在java代码中拿到的却是0,正常的应该不需要errCode2变量,execCommand()的第二个参数可以直接写成 (int&)errCode1[0]。为了调试,才添加了errCode2变量。

在调用完execCommand()之后,
env->ReleaseIntArrayElements(errCode, errCode1, 0);
一行非常重要,开始的时候就是缺少这一行导致errCode没有传回java代码。
此文的目的就是这一行。从此行大致可以看出,对于需要传出的参数,需要进行返回向转换操作,就像 ReleaseIntArrayElements()是反向转换int,其它还有很多,比如字符串。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java调用C++库dll文件接口(JNI)回传int参数(引用) 的相关文章

随机推荐