SWIG和Java:如何将指向对象输出参数的指针的c ++指针映射到Java

时间:2016-04-26 08:27:51

标签: java c++ swig

首先,我找到了几个匹配的问题,但没有找到令人满意的答案。他们中的大多数都涵盖了指向指针的c参数(而不是c ++)。还有一些是Python而不是Java。

我有一个c ++方法,它有一个输出参数,它是指向一个对象的指针。我想从Java中调用这个方法。

在使用SWIG with Java的文档中,我找到了this Butler example。这几乎是我需要的,除了它涵盖了结构而不是对象。它也是为C而不是C ++编写的。我从这个例子开始,认为我需要的东西可能看起来很像这个例子(也许我需要一个完全不同的方法,但我还是试了一下)。

原始C实现如下所示:

int HireButler(Butler **ppButler) {
  Butler *pButler = (Butler *)malloc(sizeof(Butler));
  pButler->hoursAvailable = 24;
  pButler->greeting = (char *)malloc(32);
  strcpy(pButler->greeting, "At your service Sir");
  *ppButler = pButler;
  return 1;
}

在我的C ++版本中,它看起来像这样(我制作了Butler类的HireButler和FireButler静态方法):

class Butler {
    // ... necessary class members, getters and setters go here ...

    static int HireButler(Butler **ppButler) {
      Butler *pButler = new Butler();
      pButler->setHoursAvailable(24);
      pButler->setGreeting("At your service Sir");
      *ppButler = pButler;
      return 1;
    }

    static void FireButler(Butler *pButler) {
      delete pButler;
    }
};

对于SWIG interfance文件,我几乎完全复制了示例中的代码。除了我必须将c风格的JNI调用更改为c ++风格的JNI调用(因此jenv->而不是(* jenv) - >并删除第一个参数):

// Do not generate the default proxy constructor or destructor
%nodefaultctor Butler;
%nodefaultdtor Butler;

// Add in pure Java code proxy constructor
%typemap(javacode) Butler %{
  /** This constructor creates the proxy which initially does not create nor own any C memory */
  public Butler() {
    this(0, false);
  }
%}

// Type typemaps for marshalling Butler **
%typemap(jni) Butler ** "jobject"
%typemap(jtype) Butler ** "Butler"
%typemap(jstype) Butler ** "Butler"

// Typemaps for Butler ** as a parameter output type
%typemap(in) Butler ** (Butler *ppButler = 0) %{
  $1 = &ppButler;
%}
%typemap(argout) Butler ** {
  // Give Java proxy the C++ pointer (of newly created object)
  jclass clazz = jenv->FindClass("Butler");
  jfieldID fid = jenv->GetFieldID(clazz, "swigCPtr", "J");
  jlong cPtr = 0;
  *(Butler **)&cPtr = *$1;
  jenv->SetLongField($input, fid, cPtr);
}
%typemap(javain) Butler ** "$javainput"

在使用SWIG生成必要的Java和C ++包装器代码之后,所有内容都会编译,Java代码看起来很好。但是,当我尝试运行以下Java代码时,我得到一个例外:

    Butler jeeves = new Butler();
    Butler.HireButler(jeeves);
    System.out.println("Greeting:     " + jeeves.getGreeting());
    System.out.println("Availability: " + jeeves.getHoursAvailable() + " hours per day");

从错误报告文件中,使用JNI检索swigCPtr字段时似乎发生异常:

Stack: [0x0000000002590000,0x0000000002690000],  sp=0x000000000268f630,  free space=1021k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
V  [jvm.dll+0x136519]
C  [TestDll.dll+0x411f]  JNIEnv_::GetFieldID+0x4f
C  [TestDll.dll+0x4e05]  Java_com_test_exampleJNI_Butler_1HireButler+0x95
C  0x000000000297dcec

不幸的是,我对JNI没有任何经验,所以我现在很困难。

1 个答案:

答案 0 :(得分:0)

这是典型的,在我问我的问题之后,我得到了我的aha-moment并找到了问题所在。

我需要在JNI调用中使用完全限定的类名:

jclass clazz = jenv->FindClass("com/test/Butler");

而不是

jclass clazz = jenv->FindClass("Butler");