带有指向结构参数指针的 JNA 回调函数
JNA callback function with pointer to structure argument
我正忙于一个项目,我必须在其中对专有 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);
}
主要Javaclass:
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,我完全是菜鸟,所以我有很多东西要学。不知道结构的映射是否正确,可能是空值的原因
任何帮助将不胜感激!
编辑:我让问题更有趣了一点:
所以回调函数的参数是联合体,而不是结构体。该结构现在是联合的一部分。当我这样做时,struct string 变量的值似乎也为 null。
我刚刚自己找到了更新问题的答案。 This 示例 ultimatley 展示了如何做到这一点。由于联合体只占用其最大成员的内存,因此其类型必须设置为 that 成员。然后必须调用 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);
}
当您实现 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 通常会尝试自动填充尽可能多的数据,避免任何指针字段(如字符串),如果它们包含无效数据,可能会导致内存错误。
我正忙于一个项目,我必须在其中对专有 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);
}
主要Javaclass:
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,我完全是菜鸟,所以我有很多东西要学。不知道结构的映射是否正确,可能是空值的原因
任何帮助将不胜感激!
编辑:我让问题更有趣了一点:
所以回调函数的参数是联合体,而不是结构体。该结构现在是联合的一部分。当我这样做时,struct string 变量的值似乎也为 null。
我刚刚自己找到了更新问题的答案。 This 示例 ultimatley 展示了如何做到这一点。由于联合体只占用其最大成员的内存,因此其类型必须设置为 that 成员。然后必须调用 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);
}
当您实现 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 通常会尝试自动填充尽可能多的数据,避免任何指针字段(如字符串),如果它们包含无效数据,可能会导致内存错误。