简体   繁体   English

带有指向结构参数的指针的 JNA 回调函数

[英]JNA callback function with pointer to structure argument

I am busy with a project in which I have to do native calls to a proprietary C library.我正忙于一个项目,在该项目中我必须对专有 C 库进行本机调用。 I came across JNA, which seems to be tried and tested with a number of successful projects.我遇到了 JNA,它似乎在许多成功的项目中进行了尝试和测试。

I am having trouble passing a structure (or pointer to) through to a callback function.我无法将结构(或指向)传递给回调函数。 I have tried many different scenarios before, and basically, any structure member that requires memory allocation, like a String (char *), for instance, is null when I retrieve it.我之前尝试过许多不同的场景,基本上,任何需要内存分配的结构成员,例如 String (char *),在我检索它时都是空的。

I have tried to illustrate the problem with the following example:我试图用下面的例子来说明这个问题:

C code:代码:

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-code: 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);
}

The main Java class:主要的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 then null:字符串值为空:

The string value is null

I am a complete noob when it comes to JNA, so I have lots to learn.说到 JNA,我完全是个菜鸟,所以我有很多东西要学。 I'm not sure if the mapping of the structure is correct, which might be the cause of the null value.我不确定结构的映射是否正确,这可能是空值的原因。

Any help will be greatly appreciated!任何帮助将不胜感激!


EDIT: I made the question a bit more interesting:编辑:我让这个问题更有趣一点:

So the argument to a callback function is a union, instead of a struct.所以回调函数的参数是联合体,而不是结构体。 The struct is now part of the union.该结构现在是联合的一部分。 When I do it this way, the value of the struct string variable seems to be null as well.当我这样做时,结构字符串变量的值似乎也为空。

I just found the answer to the updated question myself.我自己刚刚找到了更新问题的答案。 This example ultimatley shows how to do it.这个例子 ultimatley 展示了如何做到这一点。 As a union only takes up the memory of its largest member, its type has to be set to that member.由于联合只占用其最大成员的内存,因此必须将其类型设置为该成员。 The Union.read() function must then be called to read the "selected" variable.然后必须调用 Union.read() 函数来读取“selected”变量。 This is done as follows:这是按如下方式完成的:

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

The testStruct variable can then be accessed.然后可以访问 testStruct 变量。 The correct callback function is then:那么正确的回调函数是:

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);
  }

It might be useful when you implement the Union 's Pointer -based constructor to invoke read after calling super , and override read() so that it always does the right thing, eg当您实现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 will generally try to auto-populate as much data as it can if the union's type has not been set, avoiding any pointer fields (like strings) which might result in memory faults if they contain invalid data.如果联合的类型尚未设置,JNA 通常会尝试自动填充尽可能多的数据,避免任何指针字段(如字符串),如果它们包含无效数据,则可能导致内存错误。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM