使用JNA的时候除了Native.loadlibrary用了JNA的东西,还有什么地方用啊?
传递到dll函数的参数也要都用JNA提供的数据类型吗?请问dll函数需要pChar类型的变量,我怎么定义啊?和pointer\memory有关系吗?
请大家帮帮忙,非常感谢◎!

解决方案 »

  1.   

    答:1)传递到dll函数的参数也要都用JNA提供的数据类型吗? 当然要用到啊。
    2)dll函数需要pChar类型的变量,我怎么定义啊?
    DELPHI DLL 是需要一个PChar的数组作为参数的,问:JAVA中如何向它传递参数? 
    用JNA时不要用JAVA中的byte[],楼主要使用JNA中的ByteByReference[]即ByteByReference数组来传递。
      

  2.   

    动态链接库源码用C++写的,函数描述:
    int DUABind(struct UserInfo *puserinfo,
    char *dsaip_address,
    int port_no,
    SOCKET *psock,
    int bindseconds)delphi调用该dll时的接口描述:
    function   DUABind(puserinfo     : PUserInfo;
                       dsaip_address : pchar;
                       port_no       : integer;
                       var psock     : TSocket;
                       bindseconds   : integer
                       ):integer;cdecl;external CLIENT_DLLNAME name 'DUABind';
    使用JNA时如何写接口?
    我这样写的:
        int DUABind(TUserInfo.ByReference  puserinfo,
                    byte[]                 dsaip_address ,
                    int                    port_no,
                    Socket                 psock,
                    int                    bindseconds);其中TUserInfo定义如下
    public class TUserInfo extends Structure implements Invariable{
        public static class ByReference extends TUserInfo implements Structure.ByReference{}
        public static class ByValue extends TUserInfo implements Structure.ByValue{}    public byte[] Name = new byte[20];      //登录名
        public byte[] Password = new byte[20];  //登录密码
    }函数返回参数0-8,0表示连接成功,但返回3(网络连接失败),源码中是在initsock函数时没有成功,所以返回3 ,但是没有报错
    应该是第二个参数传递错误(pchar),请问楼上,其他的参数有没有问题?非常感谢
      

  3.   

    第二个参数传递错误(pchar)?
    答:一个PChar,用ByteByReference。
      

  4.   

    答:ByteByReference传入参数值,楼主会使用否?
    用法是:
    ByteByReference mybbr = new ByteByReference();
    Memory mymem = new Memory(20);//20个c字符
    mymem.setString(0, "myip");
    mybbr.setPointer(mymem.getPointer(0));
      

  5.   


    我昨天试过你的方法了 ,应该是对的,但是返回结果还是不对,返回的结果是对socket的绑定错误(第四个参数)
    这个结果只与char *dsaip_address,和int port_no,有关,很郁闷啊,不知道还可能是什么原因呢?P.S.:第四个参数我是这样定义的 Socket sock = null;
    这个函数正确后,对sock进行初始化。
      

  6.   

    对socket的绑定错误(第四个参数) ?
    答:根据你目前所提供的信息,我猜测是在执行“源码中在initsock函数时”,它当中的代码在执行bind()函数时时发生的错误。能否给出bind的错误信息,这样我就知道是错误在何处.bind发生的错误有:EADDRINUSE(给定的地址已在使用当中),EBADF(bind()函数第一个参数sockfd非法-如sockfd为空),EINVAL(bind()函数第一个参数sockfd已经bind给其它地址了),ENOTSOCK(bind()函数第一个参数sockfd不是一个正确的sockfd).只有第一个错误EADDRINUSE与第三个错误EINVAL与char *dsaip_addresss相关,而这个错误明确表示:char *dsaip_addresss已正确地传入进去了。因此:这个错误信息表明是一个网络程序的逻辑错误
    因此:请你根据你程序中的bind的错误信息与上述我给出的四种错误信息对比,就能知道问题在何处了。
      

  7.   

    真的非常非常感谢你,的确是在initsock出问题的时候才返回3,DLL源码如下:

    if(PackDAPRequestOrResult(&duainfo,package,&package_len,0))
    {
    return 2;//打包失败
    }
    printf("after packdaprequestorresult package len:%d\n",package_len);//yfzy
    if(InitSocket(dsaip_address,port_no,psock))
    {
    return 3;//网络连接失败
    }

    InitID(id_name,id_add,Port_dapConnection,1);
    //打公共上三层数据包
    printf("after id_add:%d\n",id_add);//yfzy
    if(Common_pack(package,&package_len,(unsigned char **)id_add,3,MAX_BINDINFO_LENGTH))
    {
    ExitSocket(*psock);
    return 4;//打上三层数据包错误
    }但是我实在是不知道你说的bind的错误怎么查看,很菜啊,不好意思,能告诉我怎么知道bind的错误吗?DLL中还有个DUAUnBind(SOCKET× psock),我在JAVA中只测这个函数
    如果Socket psock = null;则返回没有这个socket
    如果Socket psock = new Socket("192.168.0.87",2509);,则返回Unsupported argument type java.net.socket.net.Socket at parameter 0 of function DUAUnBind.
    是不是JNA里也有相应的对应类型,不是java的Socket呢?这位大哥实在是太感谢你了!!
      

  8.   

    答:1)if(InitSocket(dsaip_address,port_no,psock)) 

    return 3;//网络连接失败 

    这一部分代码,当出错时只返回3,确实将详细的错误信息全丢失了。这样就不知道真正的错误信息及原因了。
    2)我认为,问题真正的原因十分可能是在这儿:DELPHI中和TSOCKET本质是一个Integer,又是通过
    var psock    : TSocket; 因而psock本质上是一个Integer的指针。而这个类型正好对应原C++中的SOCKET *psock;因为在C++中,SOCKET就是一个int。现在我们将它对应JAVA中的java.net.Socket类,我十分怀疑,这就是问题的根源。
    3)若真是这样,问题比较棘手。因为:无论C++的SOCKET,还是DELPHI中的TSOCKET,本质是int,其真正的含义是网络通信的socket的fd来处理的(fd是int),而这个返回出来的socket fd,如何转换成java.net.Socket类的对象,这才是真正困难的地方。(JNA对这一个没有提供转换)。通过JNA,如IntByReference,是可以将这个fd(网络连接成功的socket的fd)的值带出来,但带出来后在JAVA中怎么使用它呢?即:如何将这个已连接成功的socket的fd,转换成java.net.Socket对象在JAVA中使用呢?这才是真正困难的地方。
    目前还没有想到一个好的办法。还想思考中
      

  9.   

    Socket                psock, 
    这个psock参数,你JAVA程序中要使用吗?若不要使用,则直接用JNA中的IntByReference来表达SOCKET* psock。若要使用,则比较麻烦,;因为JNA中对这一个(socket fd 转换成java.net.Socket类的对象)没有提供转换。
      

  10.   

    云上飞翔:
    非常高兴的告诉你,结果已经不是3了
    很郁闷的再告诉你现在结果是7...
    相应的源码是这样的:
    if(status !=1) 
    {
    ExitSocket(*psock);
    return 6;//注册信息接收失败或超时;
    }
    printf("before common_unpack\n");//yfzy
    if(status=Common_unpack(recv_buf,&package_len,id_val))
    {
    ExitSocket(*psock);
    printf("after common_unpack\n");//yfzy
    return 7;//解上三层数据包错误
    }我再看看Common_unpack(recv_buf,&package_len,id_val)很开心!!非常感谢你!对了,我把pchar用byte[],socket*用IntByReference,3那一段代码就过去了,用ByteByReference还是出3,不知道为什么
      

  11.   

    我在想是不是结构体的原因
    public class TUserInfo extends Structure implements Invariable{ 
        public static class ByReference extends TUserInfo implements Structure.ByReference{} 
        public static class ByValue extends TUserInfo implements Structure.ByValue{}     public byte[] Name = new byte[20];      //登录名 
        public byte[] Password = new byte[20];  //登录密码 
    } 原来的:
    name: array[0..19] of char;
    password :array[0..19] of char;不知道这样对不对。返回值为‘7’,表示服务器端解包错误,所以我觉得应该是传过去的参数不太对既然socket能建立那么就剩结构体这一个参数了。。
      

  12.   

    int DUABind(TUserInfo.ByReference  puserinfo, 
                    byte[]                dsaip_address , 
                    int                    port_no, 
                    Socket                psock, 
                    int                    bindseconds); 其中TUserInfo定义如下 
    public class TUserInfo extends Structure implements Invariable{ 
        public static class ByReference extends TUserInfo implements Structure.ByReference{} 
        public static class ByValue extends TUserInfo implements Structure.ByValue{}     public byte[] Name = new byte[20];      //登录名 
        public byte[] Password = new byte[20];  //登录密码 

    既然socket能建立那么就剩结构体这一个参数了。。
    答:这样定义试试
    int DUABind(TUserInfo puserinfo,...
    public class TUserInfo extends Structure implements Invariable{   
        public byte[] Name = new byte[20];      //登录名 
        public byte[] Password = new byte[20];  //登录密码 
    }  
      

  13.   

    答:不过你用public static class ByReference extends TUserInfo implements Structure.ByReference{} 
    也是正确的。
    但其它看起来,都是正确的啊
      

  14.   

    云上飞翔:
    您说的第一种方法我试过,直接就有异常了,第二种应该是对的。我觉得好像和结构体的初始化有关系。
    我把byte[]的初始化过程用byte[] UserInfo.Name = Native.getBytes(String s)(我原来用的就是String s;UserInfo.Name =s.getbytes),结果变成1了
    源码中1的判断在7的后面,说是‘注册失败,非法用户’好像又进了一步(不知道能不能这么想啊!)。Native.getBytes(String s)是以/0结尾的,
    不知道是不是和没有这个结尾有关系,还没有找到不以/0结尾的方法。我在想是不是所有函数参数都要用JNA自己定义的变量呢?包括初始化似乎也要用JNA的方法。
    又不知道该怎么办了呵呵
      

  15.   

    答:对于你的定义:
    public class TUserInfo extends Structure implements Invariable{ 
        public static class ByReference extends TUserInfo implements Structure.ByReference{} 
        public static class ByValue extends TUserInfo implements Structure.ByValue{}     public byte[] Name = new byte[20];      //登录名 
        public byte[] Password = new byte[20];  //登录密码 
    } 原来的: 
    name: array[0..19] of char; 
    password :array[0..19] of char; 如何初始化赋值?
    我感觉应该是这样:(因为:Name 与 Password[color=#FF0000]必须是20个字节的数组[/color)byte[] tmp=Native.getBytes(s);或者是:byte[] tmp=s.getBytes();
    然后利用:System.arraycopy(...)将这个tmp数组内容(可有少于20个字节)拷贝到20个字节的Name 与 Password中。
      

  16.   

    云上飞翔:
    啊,您真的是经验老到阿,确实是你说的那样子,开始用System.arraycopy(...)之后还是有问题,后来又发现我师兄把密码给错了,害我折腾了老半天,已经能正常输出0了
    呵呵,非常感谢。关于那个socket的问题,确实需要解决的,还有好多函数的参数直接就用的DUABind之后产生的socket值,我直接将sock输入DUAUnBind好像有问题。socket的问题确实很麻烦阿总之,非常感谢你