【问题标题】:JNA callback function with pointer to structure argument带有指向结构参数的指针的 JNA 回调函数
【发布时间】:2015-10-29 12:55:02
【问题描述】:

我正忙于一个项目,在该项目中我必须对专有 C 库进行本机调用。我遇到了 JNA,它似乎已经通过许多成功的项目进行了尝试和测试。

我在将结构(或指向的指针)传递给回调函数时遇到问题。我之前尝试过许多不同的场景,基本上,任何需要内存分配的结构成员,例如 String (char *),在我检索时都是 null。

我试图用下面的例子来说明问题:

C 代码:

typedef struct {
    int number;
    char *string;
} TEST_STRUCT;

typedef union {
    int number;
    TEST_STRUCT test_struct;
} TEST_UNION;

typedef void (*TEST_CB)(TEST_UNION*);

void test(TEST_CB test_cb)
{
    TEST_STRUCT *test_struct = malloc(sizeof *test_struct);
    test_struct->number = 5;
    test_struct->string = "Hello";

    TEST_UNION *test_union = malloc(sizeof *test_union);
    test_union->number = 10;
    test_union->test_struct = *test_struct;

    test_cb(test_union);

    free(test_struct);
    free(test_union);
}

Java 代码:

public interface TestLib extends Library
{
  class TestStruct extends Structure
  {
      public int number;
      public String string;

      public TestStruct() {
          super();
      }
      protected List<? > getFieldOrder() {
          return Arrays.asList("number", "string");
      }
      public TestStruct(int number, String string) {
          super();
          this.number = number;
          this.string = string;
      }
      public TestStruct(Pointer peer) {
          super(peer);
      }
      public static class ByReference extends MBTStatus implements Structure.ByReference {}
      public static class ByValue extends MBTStatus implements Structure.ByValue {}
   }


class TestUnion extends Union {
    public int number;
    public TestStruct testStruct;

    public TestUnion() {
        super();
    }
    public TestUnion(int number, TestStruct testStruct) {
        super();
        this.number = number;
        this.testStruct = testStruct;
    }
    public TestUnion(Pointer pointer) {
        super(pointer);
    }
    public static class ByReference extends TestUnion implements com.sun.jna.Structure.ByReference {}
    public static class ByValue extends TestUnion implements com.sun.jna.Structure.ByValue {}
}


   interface TestCallback extends Callback
   {
       public void callback(TestUnion testUnion);
   }

   void test(TestCallback testCallback);
}

主要的Java类:

public class TestMain
{
    static
    {
        System.loadLibrary("test");
    }

    public static void main (String [] args)
    {
        TestLib.INSTANCE.test(
                new TestLib.TestCallback()
                {
                      public void callback(TestLib.TestUnion testUnion)
                     {
                         System.out.println(testUnion.testStruct.string == null ? "The string value is null" : "The string value is: " + testUnion.testStruct.string);
                     }
                }
        );
    }
}

然后字符串值为空:

The string value is null

对于 JNA,我完全是个菜鸟,所以我有很多东西要学。我不确定结构的映射是否正确,这可能是空值的原因。

任何帮助将不胜感激!


编辑:我让这个问题变得更有趣了:

所以回调函数的参数是一个联合,而不是一个结构。该结构现在是联合的一部分。当我这样做时,结构字符串变量的值似乎也为空。

【问题讨论】:

  • 将您的 Pointer 更改为您的 Structure 类型,事情将自动处理。在这种情况下,JNA 在本机调用同步本机内存和 Java 字段之前和之后执行隐式 Structure.write()/Structure.read()
  • 感谢@technomage,成功了!我编辑了这个问题以反映一个稍微复杂的问题。回调的参数现在是一个联合,结构是联合的一部分。我会假设工会的处理方式不同?

标签: java pointers struct callback jna


【解决方案1】:

我自己刚刚找到了更新问题的答案。 This example ultimatley 展示了如何做到这一点。由于联合仅占用其最大成员的内存,因此必须将其类型设置为 那个 成员。然后必须调用 Union.read() 函数来读取“选定”变量。这样做如下:

testUnion.setType(TestLib.TestStruct.class);
testUnion.read();

然后可以访问 testStruct 变量。那么正确的回调函数是:

public void callback(TestLib.TestUnion testUnion)
  {
    testUnion.setType(TestLib.TestStruct.class);      
    testUnion.read();
    System.out.println(testUnion.testStruct.string == null ? "The string value is null" : "The string value is: " + testUnion.testStruct.string);
  }

【讨论】:

    【解决方案2】:

    当您实现 Union 的基于 Pointer 的构造函数以在调用 super 后调用 read 并覆盖 read() 以便它始终做正确的事情时,它可能很有用,例如

    class MyStructure1 {
        public int type;
        public int intField;
    }
    class MyStructure2 {
        public int type;
        public float floatField;
    }
    class MyUnion extends Union {
        public int type;
        public MyStructure1 s1;
        public MyStructure2 s2;
        public MyUnion(Pointer p) {
            super(p);
            read();
        }
        protected void read() {
            int type = getPointer().getInt(0);
            switch(type) {
                case 0: setType(MyStruct1); break;
                case 1: setType(MyStruct2); break;
            }
            super.read();
        }
    }
    

    如果未设置联合的类型,JNA 通常会尝试自动填充尽可能多的数据,避免任何指针字段(如字符串)包含无效数据时可能导致内存错误。

    【讨论】:

    • 感谢@techomage - 这是一个更好的方法,我会这样做。
    猜你喜欢
    • 1970-01-01
    • 2012-03-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多