指向 JNA 结构的指针未正确解析
Pointer to JNA Structure not resolved correctly
我目前在 Linux 设备上使用 JNA,该设备用于 m2m 目的,并附带一个包含以下代码的 C 库:
typedef struct _INET_MODULE_CONFIG{
unsigned char wBearer;
void* wBearerParameters;
void (*inet_action)( INET_Events * );
}INET_MODULE_CONFIG;
typedef struct _GPRS_CONFIG{
unsigned char gprsUser[ 20];
unsigned char gprsPass[ 20];
unsigned char gprsDNS1[ 20];
unsigned char gprsDNS2[ 20];
unsigned char gprsAPN [ 20];
}GPRS_CONFIG;
typedef struct _GPRS_ENHANCED_CONFIG{
unsigned char gprsUser[ USER_SIZE];
unsigned char gprsPass[ PWD_SIZE];
unsigned char gprsDNS1[ IP_SIZE];
unsigned char gprsDNS2[ IP_SIZE];
unsigned char gprsAPN [ APN_SIZE];
}GPRS_ENHANCED_CONFIG;
wBearerParameter
指向其中一个 GPRS 结构,wBearer
通过使用常量决定指向哪个。
要将此映射到 Java 我使用此:
public class INET_MODULE_CONFIG extends Structure implements Structure.ByReference
{
public byte wBearer;
public Pointer wBearerParameters;
public inet_event_handler inet_action;
}
public class GPRS_CONFIG extends Structure implements Structure.ByReference
{
public byte[] gprsUser;
public byte[] gprsPass;
public byte[] gprsDNS1;
public byte[] gprsDNS2;
public byte[] gprsAPN;
}
public class GPRS_ENHANCED_CONFIG extends Structure implements Structure.ByReference
{
public byte[] gprsUser;
public byte[] gprsPass;
public byte[] gprsDNS1;
public byte[] gprsDNS2;
public byte[] gprsAPN;
}
然后使用它:
grsKonfig.gprsUser = new byte[20];
gprsKonfig.gprsPass = new byte[20];
gprsKonfig.gprsAPN = new byte[20];
gprsKonfig.gprsDNS1 = new byte[20];
gprsKonfig.gprsDNS2 = new byte[20];
gprsKonfig.gprsUser[0] = 't';
gprsKonfig.gprsUser[1] = '-';
gprsKonfig.gprsUser[2] = 'm';
gprsKonfig.gprsUser[3] = 'o';
gprsKonfig.gprsUser[4] = 'b';
gprsKonfig.gprsUser[5] = 'i';
gprsKonfig.gprsUser[6] = 'l';
gprsKonfig.gprsUser[7] = 'e';
for(int i = 8; i < 20; i++)
{
gprsKonfig.gprsUser [i]= 0;
}
gprsKonfig.gprsPass[0] = 't';
gprsKonfig.gprsPass[1] = 'm';
for(int i = 2; i < 20; i++)
{
prsKonfig.gprsPass [i]= 0;
}
gprsKonfig.gprsAPN[0] = 'i';
gprsKonfig.gprsAPN[1] = 'n';
gprsKonfig.gprsAPN[2] = 't';
gprsKonfig.gprsAPN[3] = 'e';
gprsKonfig.gprsAPN[4] = 'r';
gprsKonfig.gprsAPN[5] = 'n';
gprsKonfig.gprsAPN[6] = 'e';
gprsKonfig.gprsAPN[7] = 't';
gprsKonfig.gprsAPN[8] = '.';
gprsKonfig.gprsAPN[9] = 't';
gprsKonfig.gprsAPN[10] = 'e';
gprsKonfig.gprsAPN[11] = 'l';
gprsKonfig.gprsAPN[12] = 'e';
gprsKonfig.gprsAPN[13] = 'k';
gprsKonfig.gprsAPN[14] = 'o';
gprsKonfig.gprsAPN[15] = 'm';
for(int i = 16; i < 20; i++)
{
gprsKonfig.gprsAPN [i]= 0;
}
gprsKonfig.gprsDNS1[0] = '8';
gprsKonfig.gprsDNS1[1] = '.';
gprsKonfig.gprsDNS1[2] = '8';
gprsKonfig.gprsDNS1[3] = '.';
gprsKonfig.gprsDNS1[4] = '8';
gprsKonfig.gprsDNS1[5] = '.';
gprsKonfig.gprsDNS1[6] = '8';
for(int i = 7; i < gprsKonfig.gprsDNS1.length; i++)
{
gprsKonfig.gprsDNS1[i] = '0';
}
gprsKonfig.gprsDNS2[0] = '8';
gprsKonfig.gprsDNS2[1] = '.';
gprsKonfig.gprsDNS2[2] = '8';
gprsKonfig.gprsDNS2[3] = '.';
gprsKonfig.gprsDNS2[4] = '4';
gprsKonfig.gprsDNS2[5] = '.';
gprsKonfig.gprsDNS2[6] = '4';
for(int i = 8; i < gprsKonfig.gprsDNS2.length; i++)
{
gprsKonfig.gprsDNS2[i] = '0';
}
inetKonfig.wBearer = InternetBibliothek.NORMAL_BEARER_GPRS;
inetKonfig.wBearerParameters = gprsKonfig.getPointer();
inetKonfig.inet_action = callback;
编译没有错误。有时 C 库会告诉我我的 GPRS 参数有错误,但在大多数情况下不会。但是 DNS 服务器设置不正确。在 /etc/resolv.conf
中,我现在有 8.8.4.40000000000000internet.telekom
和 8.8.8.800000000000008.8.4.40000000000000internet.telekom
。
看起来它不知道数组在哪里结束。我还需要尾随 0 消失,因为我的互联网提供商告诉我将两个 DNS 服务器都留空(我上面使用的那些只是为了查看 /etc/resolv.conf
中的内容)。
初始化长度为20,尾部使用0不带''。
虽然您用 回答了您自己的问题,但我想添加更多细节以帮助您简化代码。
JNA 结构在为它们分配本机内存时必须知道它们的大小。因此,数组必须在结构实例化时以全尺寸初始化。在您的特定情况下,这意味着像这样初始化数组:
public class GPRS_CONFIG extends Structure {
public byte[] gprsUser = new byte[20];
public byte[] gprsPass = new byte[20];
public byte[] gprsDNS1 = new byte[20];
public byte[] gprsDNS2 = new byte[20];
public byte[] gprsAPN = new byte[20];
}
public class GPRS_ENHANCED_CONFIG extends Structure {
public byte[] gprsUser = new byte[USER_SIZE];
public byte[] gprsPass = new byte[PWD_SIZE];
public byte[] gprsDNS1 = new byte[IP_SIZE];
public byte[] gprsDNS2 = new byte[IP_SIZE];
public byte[] gprsAPN = new byte[APN_SIZE];
}
我还要指出,没有必要实现 ByReference
,除非该结构通过引用(作为指针)嵌套在另一个结构中。如果您实施它,则需要更多代码。
代码中的另一个错误是空终止字符串的实现。 Null 是一个实际的字节值 0。字符零 ('0'
) 不一样,它实际上是字节值 48。您可以使用字符 '\0'(字节值为 0)必要时完成此操作;但是通常不需要。
如果您使用 new byte[SIZE]
初始化原始字节数组,则 0 值已在数组中初始化,因此您无需执行任何特殊操作即可显式设置它们。
您可能还会发现使用 String
class getBytes()
设置字符值,然后使用 System.arraycopy()
复制数组中的值更容易。例如:
byte[] dnsBytes = "8.8.8.8".getBytes("ASCII");
System.arraycopy(dnsBytes, 0, gprsKonfig.gprsDNS1, 0, dnsBytes.length);
我目前在 Linux 设备上使用 JNA,该设备用于 m2m 目的,并附带一个包含以下代码的 C 库:
typedef struct _INET_MODULE_CONFIG{
unsigned char wBearer;
void* wBearerParameters;
void (*inet_action)( INET_Events * );
}INET_MODULE_CONFIG;
typedef struct _GPRS_CONFIG{
unsigned char gprsUser[ 20];
unsigned char gprsPass[ 20];
unsigned char gprsDNS1[ 20];
unsigned char gprsDNS2[ 20];
unsigned char gprsAPN [ 20];
}GPRS_CONFIG;
typedef struct _GPRS_ENHANCED_CONFIG{
unsigned char gprsUser[ USER_SIZE];
unsigned char gprsPass[ PWD_SIZE];
unsigned char gprsDNS1[ IP_SIZE];
unsigned char gprsDNS2[ IP_SIZE];
unsigned char gprsAPN [ APN_SIZE];
}GPRS_ENHANCED_CONFIG;
wBearerParameter
指向其中一个 GPRS 结构,wBearer
通过使用常量决定指向哪个。
要将此映射到 Java 我使用此:
public class INET_MODULE_CONFIG extends Structure implements Structure.ByReference
{
public byte wBearer;
public Pointer wBearerParameters;
public inet_event_handler inet_action;
}
public class GPRS_CONFIG extends Structure implements Structure.ByReference
{
public byte[] gprsUser;
public byte[] gprsPass;
public byte[] gprsDNS1;
public byte[] gprsDNS2;
public byte[] gprsAPN;
}
public class GPRS_ENHANCED_CONFIG extends Structure implements Structure.ByReference
{
public byte[] gprsUser;
public byte[] gprsPass;
public byte[] gprsDNS1;
public byte[] gprsDNS2;
public byte[] gprsAPN;
}
然后使用它:
grsKonfig.gprsUser = new byte[20];
gprsKonfig.gprsPass = new byte[20];
gprsKonfig.gprsAPN = new byte[20];
gprsKonfig.gprsDNS1 = new byte[20];
gprsKonfig.gprsDNS2 = new byte[20];
gprsKonfig.gprsUser[0] = 't';
gprsKonfig.gprsUser[1] = '-';
gprsKonfig.gprsUser[2] = 'm';
gprsKonfig.gprsUser[3] = 'o';
gprsKonfig.gprsUser[4] = 'b';
gprsKonfig.gprsUser[5] = 'i';
gprsKonfig.gprsUser[6] = 'l';
gprsKonfig.gprsUser[7] = 'e';
for(int i = 8; i < 20; i++)
{
gprsKonfig.gprsUser [i]= 0;
}
gprsKonfig.gprsPass[0] = 't';
gprsKonfig.gprsPass[1] = 'm';
for(int i = 2; i < 20; i++)
{
prsKonfig.gprsPass [i]= 0;
}
gprsKonfig.gprsAPN[0] = 'i';
gprsKonfig.gprsAPN[1] = 'n';
gprsKonfig.gprsAPN[2] = 't';
gprsKonfig.gprsAPN[3] = 'e';
gprsKonfig.gprsAPN[4] = 'r';
gprsKonfig.gprsAPN[5] = 'n';
gprsKonfig.gprsAPN[6] = 'e';
gprsKonfig.gprsAPN[7] = 't';
gprsKonfig.gprsAPN[8] = '.';
gprsKonfig.gprsAPN[9] = 't';
gprsKonfig.gprsAPN[10] = 'e';
gprsKonfig.gprsAPN[11] = 'l';
gprsKonfig.gprsAPN[12] = 'e';
gprsKonfig.gprsAPN[13] = 'k';
gprsKonfig.gprsAPN[14] = 'o';
gprsKonfig.gprsAPN[15] = 'm';
for(int i = 16; i < 20; i++)
{
gprsKonfig.gprsAPN [i]= 0;
}
gprsKonfig.gprsDNS1[0] = '8';
gprsKonfig.gprsDNS1[1] = '.';
gprsKonfig.gprsDNS1[2] = '8';
gprsKonfig.gprsDNS1[3] = '.';
gprsKonfig.gprsDNS1[4] = '8';
gprsKonfig.gprsDNS1[5] = '.';
gprsKonfig.gprsDNS1[6] = '8';
for(int i = 7; i < gprsKonfig.gprsDNS1.length; i++)
{
gprsKonfig.gprsDNS1[i] = '0';
}
gprsKonfig.gprsDNS2[0] = '8';
gprsKonfig.gprsDNS2[1] = '.';
gprsKonfig.gprsDNS2[2] = '8';
gprsKonfig.gprsDNS2[3] = '.';
gprsKonfig.gprsDNS2[4] = '4';
gprsKonfig.gprsDNS2[5] = '.';
gprsKonfig.gprsDNS2[6] = '4';
for(int i = 8; i < gprsKonfig.gprsDNS2.length; i++)
{
gprsKonfig.gprsDNS2[i] = '0';
}
inetKonfig.wBearer = InternetBibliothek.NORMAL_BEARER_GPRS;
inetKonfig.wBearerParameters = gprsKonfig.getPointer();
inetKonfig.inet_action = callback;
编译没有错误。有时 C 库会告诉我我的 GPRS 参数有错误,但在大多数情况下不会。但是 DNS 服务器设置不正确。在 /etc/resolv.conf
中,我现在有 8.8.4.40000000000000internet.telekom
和 8.8.8.800000000000008.8.4.40000000000000internet.telekom
。
看起来它不知道数组在哪里结束。我还需要尾随 0 消失,因为我的互联网提供商告诉我将两个 DNS 服务器都留空(我上面使用的那些只是为了查看 /etc/resolv.conf
中的内容)。
初始化长度为20,尾部使用0不带''。
虽然您用
JNA 结构在为它们分配本机内存时必须知道它们的大小。因此,数组必须在结构实例化时以全尺寸初始化。在您的特定情况下,这意味着像这样初始化数组:
public class GPRS_CONFIG extends Structure {
public byte[] gprsUser = new byte[20];
public byte[] gprsPass = new byte[20];
public byte[] gprsDNS1 = new byte[20];
public byte[] gprsDNS2 = new byte[20];
public byte[] gprsAPN = new byte[20];
}
public class GPRS_ENHANCED_CONFIG extends Structure {
public byte[] gprsUser = new byte[USER_SIZE];
public byte[] gprsPass = new byte[PWD_SIZE];
public byte[] gprsDNS1 = new byte[IP_SIZE];
public byte[] gprsDNS2 = new byte[IP_SIZE];
public byte[] gprsAPN = new byte[APN_SIZE];
}
我还要指出,没有必要实现 ByReference
,除非该结构通过引用(作为指针)嵌套在另一个结构中。如果您实施它,则需要更多代码。
代码中的另一个错误是空终止字符串的实现。 Null 是一个实际的字节值 0。字符零 ('0'
) 不一样,它实际上是字节值 48。您可以使用字符 '\0'(字节值为 0)必要时完成此操作;但是通常不需要。
如果您使用 new byte[SIZE]
初始化原始字节数组,则 0 值已在数组中初始化,因此您无需执行任何特殊操作即可显式设置它们。
您可能还会发现使用 String
class getBytes()
设置字符值,然后使用 System.arraycopy()
复制数组中的值更容易。例如:
byte[] dnsBytes = "8.8.8.8".getBytes("ASCII");
System.arraycopy(dnsBytes, 0, gprsKonfig.gprsDNS1, 0, dnsBytes.length);