有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java从JNA调用读取字符串[]失败

我正试图通过JNA调用以下函数:

struct group * getgrnam (const char *name)

如中所述: http://www.gnu.org/software/libc/manual/html_node/Lookup-Group.html#Lookup-Group

根据文件,结构如下:

char *gr_name

The name of the group.

gid_t gr_gid

The group ID of the group.

char **gr_mem

A vector of pointers to the names of users in the group. Each user name is a null-terminated string, and the vector itself is terminated by a null pointer.

我创建了以下简单的测试类

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;

public class Test {

    public interface CLibrary extends Library {
            CLibrary INSTANCE = (CLibrary)  Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"), CLibrary.class);

            void printf(String format, Object... args);

            public Group getgrnam(String groupName);
        }


        public static void main(String[] args) {
            CLibrary.INSTANCE.printf("Hello, World\n");

            Group group = CLibrary.INSTANCE.getgrnam(args[0]);

            System.out.println(group.gr_name);
            System.out.println(group.gr_mem);

        }
    }

以及表示结构的组类:

import java.util.ArrayList;
import java.util.List;

import com.sun.jna.Structure;

public class Group extends Structure {
    public String gr_name;
    public int gr_gid;
    public String[] gr_mem = new String[128];

    @Override
    protected List<String> getFieldOrder() {
        List<String> fields = new ArrayList<>();
        fields.add("gr_name");
        fields.add("gr_gid");
        fields.add("gr_mem");
        return fields;
    }
}

marshalling documentation of JNA表示字符**已转换为字符串[]

但是,当我运行此代码时,会出现以下错误:

/tmp # java -cp .:jna-4.5.1.jar Test root Hello, World Exception in thread "main" java.lang.IllegalArgumentException: Reading array of class java.lang.String from memory not supported at com.sun.jna.Pointer.readArray(Pointer.java:538) at com.sun.jna.Pointer.getValue(Pointer.java:459) at com.sun.jna.Structure.readField(Structure.java:720) at com.sun.jna.Structure.read(Structure.java:580) at com.sun.jna.Structure.autoRead(Structure.java:2074) at com.sun.jna.Structure.conditionalAutoRead(Structure.java:550) at com.sun.jna.Function.invoke(Function.java:446) at com.sun.jna.Function.invoke(Function.java:354) at com.sun.jna.Library$Handler.invoke(Library.java:244) at com.sun.proxy.$Proxy0.getgrnam(Unknown Source) at Test.main(Test.java:23)

如何正确转换char**的结构字段


共 (1) 个答案

  1. # 1 楼答案

    自我回答,因为我在挖掘后发现了它

    主要突破是这个工具:https://github.com/nativelibs4java/JNAerator

    它从C结构生成Java类,这非常有帮助

    最终,正确映射组结构的Java类如下所示:

    import com.sun.jna.Pointer;
    import com.sun.jna.Structure;
    import com.sun.jna.ptr.PointerByReference;
    import java.util.Arrays;
    import java.util.List;
    /**
     * <i>native declaration : line 2</i><br>
     * This file was autogenerated by <a href="http://jnaerator.googlecode.com/">JNAerator</a>,<br>
     * a tool written by <a href="http://ochafik.com/">Olivier Chafik</a> that <a href="http://code.google.com/p/jnaerator/wiki/CreditsAndLicense">uses a few opensource projects.</a>.<br>
     * For help, please visit <a href="http://nativelibs4java.googlecode.com/">NativeLibs4Java</a> , <a href="http://rococoa.dev.java.net/">Rococoa</a>, or <a href="http://jna.dev.java.net/">JNA</a>.
     */
    public class Group extends Structure {
      /**
       * Group name.<br>
       * C type : char*
       */
      public Pointer gr_name;
      /**
       * Password.<br>
       * C type : char*
       */
      public Pointer gr_passwd;
      /**
       * Group ID.<br>
       * C type : __gid_t
       */
      public int gr_gid;
      /**
       * Member list.<br>
       * C type : char**
       */
      public PointerByReference gr_mem;
      public Group() {
        super();
      }
      protected List<String> getFieldOrder() {
        return Arrays.asList("gr_name", "gr_passwd", "gr_gid", "gr_mem");
      }
      /**
       * @param gr_name Group name.<br>
       * C type : char*<br>
       * @param gr_passwd Password.<br>
       * C type : char*<br>
       * @param gr_gid Group ID.<br>
       * C type : __gid_t<br>
       * @param gr_mem Member list.<br>
       * C type : char**
       */
      public Group(Pointer gr_name, Pointer gr_passwd, int gr_gid, PointerByReference gr_mem) {
        super();
        this.gr_name = gr_name;
        this.gr_passwd = gr_passwd;
        this.gr_gid = gr_gid;
        this.gr_mem = gr_mem;
      }
      public Group(Pointer peer) {
        super(peer);
      }
      protected ByReference newByReference() { return new ByReference(); }
      protected ByValue newByValue() { return new ByValue(); }
      protected Group newInstance() { return new Group(); }
    //  public static Group[] newArray(int arrayLength) {
    //    return Structure.newArray(Group.class, arrayLength);
    //  }
      public static class ByReference extends Group implements Structure.ByReference {
    
      };
      public static class ByValue extends Group implements Structure.ByValue {
    
      };
    }
    

    gr_mem字段(C中的字符**类型)使用PointerByReference是一个突破

    之后可以这样读:

      public static void main(String[] args) {
    
        Group group = CLibrary.INSTANCE.getgrnam(args[0]);
        System.out.println(group.gr_name.getString(0));
    
        PointerByReference pbr = group.gr_mem;
        String[] groups = pbr.getPointer().getStringArray(0);
    
        for (String g : groups) {
          System.out.println(g);
        }