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

时间:2015-10-29 12:55:02

标签: java pointers struct callback jna

我正忙于一个项目,我必须在其中对专有的C库进行本机调用。我遇到了JNA,这似乎是通过一些成功的项目进行试验和测试的。

我无法将结构(或指针)传递给回调函数。我以前尝试了很多不同的场景,基本上,任何需要内存分配的结构成员,比如String(char *),当我检索它时都是null。

我试图通过以下示例说明问题:

C代码:

<?php
$video = time().$_FILES["file"]["name"];
print_r($_FILES);
print_r($_REQUEST);
move_uploaded_file($_FILES["file"]["tmp_name"], "../uploads/videos/".$video);

//$fileName = $_REQUEST["fileName"];

//save data to database...

$inputbox = $_REQUEST["inputbox"];

  if(isset($video)) {
    // insert user(create Post)
      $insertSQL = sprintf("INSERT INTO feeds (feeds_poster_id, feeds_video, feeds_content, feeds_date) VALUES (%s, %s, %s, %s)",
                           GetSQLValueString($_SESSION["id"], "int"),
                           GetSQLValueString($video, "text"),
                           GetSQLValueString($inputbox, "text"),
                           GetSQLValueString(date("Y-m-d h:i:s"), "date"));
      //Set post
      mysql_select_db($database_dbcon, $dbcon);
      $Result1 = mysql_query($insertSQL, $dbcon) or die(mysql_error()); 

      //Mentioned user...
  }

Java的代码:

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

字符串值为null:

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

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

任何帮助将不胜感激!

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

因此回调函数的参数是union,而不是struct。该结构现在是联盟的一部分。当我这样做时,struct string变量的值似乎也是null。

2 个答案:

答案 0 :(得分:1)

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

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

答案 1 :(得分:1)

在实施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();
    }
}

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