指向 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.telekom8.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);