简体   繁体   中英

Pointer to JNA Structure not resolved correctly

I am currently using JNA on a Linux device that is used for m2m purposes and comes with a C Library that includes the following code:

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;

The wBearerParameter points to one of the GPRS Structs, and wBearer decides to which, by using a constant.

To map this to Java I use this:

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

And then this to use it:

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;

It compiles without an error. Sometimes the C Library tells me I have an error in my GPRS params, but in most cases not. However the DNS servers are not set correctly. In /etc/resolv.conf I now have 8.8.4.40000000000000internet.telekom and 8.8.8.800000000000008.8.4.40000000000000internet.telekom . It looks like it does not know where the arrays end. Also I need the trailing 0 to go away, since my internet provider tells me to leave both DNS server empty (The ones I used above are just to see what stands in /etc/resolv.conf ).

While you answered your own question with a correct answer , I want to add a bit more detail to it that may help you streamline your code.

JNA Structures must know their size when allocating native memory for them. Therefore, arrays must be initialized with full size at the time of structure instantiation. In your specific case, this means initializing the arrays like this:

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

I'll also note that there's no need to implement ByReference unless the struture is nested by reference (as a pointer) inside another structure. If you do implement it, there's more code you'd need.

Another error in your code is implementation of null terminated strings. Null is an actual byte value of 0. The character zero ( '0' ) is not the same, it is actually the byte value of 48. You could use the character '\\0' (which has the byte value 0) to accomplish this if necessary; however it's not usually needed.

If you are initializing a primitive byte arrays with new byte[SIZE] , the 0 values are already initialized in the array, so you don't need to do anything special to explicitly set them.

You might also find it eaiser to set the character values by using the String class getBytes() and then copying the values in the array over using System.arraycopy() . For example:

byte[] dnsBytes = "8.8.8.8".getBytes("ASCII");
System.arraycopy(dnsBytes, 0, gprsKonfig.gprsDNS1, 0, dnsBytes.length);

用 20 的长度初始化它,并使用 0 不带 '',作为尾随。

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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