其实本来就是闲的蛋疼,有个开发板,以前用VC,VB些过测试程序,,一时心血来潮,想弄个JAVA来控制下开发板玩玩
没想到遇到了个问题卡壳了,,, 做过技术的人应该都能理解我的心情吧 呵呵前前后后,已经送了1000分了对于这个问题, 但是还是没有解决掉,,前面的帖子都结了也这次送1000分,问题解决后,另开贴9个帖子送分。
外加3合1的ARM开发板一块,配件齐全,但邮费需要自付。我的问题如下,先列下我参考的代码,如下:假设我们现在有这样一个C语言结构体
struct UserStruct{
  long id;
  wchar_t* name;
  int age;
};使用上述结构体的函数
#define MYLIBAPI extern "C" __declspec( dllexport )   
MYLIBAPI void sayUser(UserStruct* pUserStruct);
对应的Java程序中,在例1的 接口中添加下列代码:
  public static class UserStruct extends Structure{
  public NativeLong id;
  public WString name;
  public int age;
public static class ByReference extends UserStruct implements Structure.ByReference { }
public static class ByValue extends UserStruct implements Structure.ByValue
 { }
  }
  public void sayUser(UserStruct.ByReference struct);Java中的调用代码:
UserStruct userStruct=new UserStruct ();
  userStruct.id=new NativeLong(100);
  userStruct.age=30;
  userStruct.name=new WString("奥巴马"); TestDll1.INSTANCE.sayUser(userStruct); 我觉得这段代码和我的应该比较类似的, 我做了如下的声明,请高手帮看看哪里有问题谢谢
 首先模仿结构的声明:
public static class UserStruct extends Structure{
public static class ByReference extends UserStruct implements Structure.ByReference { }
public static class ByValue extends UserStruct implements Structure.ByValue { }
public int Address;
public int Length;
public byte num[][]=new byte[8][30];
}
接口函数里做如下模仿
public static interface RFSAPIV2 extends Library {
  RFSAPIV2 INSTANCE = (RFSAPIV2)
  Native.loadLibrary("RFSAPIV2",
  RFSAPIV2.class);
  int ReadLabelID(long hh,int nMax, UserStruct.ByReference idBuffer,int[] nCounter);
} 在按钮过程中做如下
private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {   
  // TODO add your handling code here:
  UserStruct idBuffer = new UserStruct();
  idBuffer.Address=0;
  idBuffer.Length=0;
  idBuffer.num[0][0]=(byte)0x00; // 这地方没有把数组全面初始化不知道影响否???  int nCounter[]={0};
  int nMax=10;  apiReturn=RFSAPIV2.INSTANCE.ReadID(hScanner[0], nMax, idBuffer, nCounter);
}  做语法检查时,,提示上面的函数调用部分的红色字体,即第三个参数 错误。
  “
  无法将 接口 desktopapplication2.DesktopApplication2View.RFSAPIV2 中的 方法 ReadID 应用于 long,int,desktopapplication2.DesktopApplication2View.UserStruct.ByReference,int[](long,int,desktopapplication2.DesktopApplication2View.UserStruct,int[])
--
(按 Alt-Enter 组合键可显示提示)

请指导一下 ,谢谢。
指导解决问题后,送1000分,外加3合1 ARM开发板一块(邮资自付)
本人结贴即使,可参加近几天的结贴情况,已经前后送出了1000分了,就这个问题

解决方案 »

  1.   

    /**
    *  此处可供大家参考,有什么不对的地方请大家指点。
    */public class FNHFD1008 { /**
     * 打开指定串口、地址的读写器,并加载动态链接库。 在对读写器进行操作前必须调用此方法。在应用程序退出前需调用StopComm方法。
     * @param Port 串口号
     *  USB串口号为1000, 0 表示com1, 1表示串口2, 依次类推,最大可到9表示com10
     * @return
     *  0:成功
     *  -1 加载动态库失败,
     *  其他值表示失败
     */
    public native int OpenComm(int Port);

    /**
     * 关闭串口,释放动态库资源
     * @return
     *  1:成功
     *  其他值表示失败
     */
    public native int StopComm();

    /**
     * 读卡片的序列号
     * @return Tag UID
     */
    public native String ReadUID(); /**
     * 读取卡片上指定Block的数据
     * @param keyA 密钥
     * @param blockNum 块号
     * @return 块数据 
     * 如果密钥错,返回"ERROR:readBlockFun failed!ret:4"
     */
    public native String ReadBlock(String keyA, int blockNum); /**
     * 写卡片上指定Block的数据
     * @param keyA 密钥
     * @param blockNum 块号
     * @param data 块数据 必须是16字节的16进制数据,eg:2009050720093C0A000000000000FF20
     * @return 
     * 如果密钥错,返回"ERROR:readBlockFun failed!ret:4"
     */
    public native String WriteBlock(String keyA, int blockNum,String data);


    /**
     * 加载JNI动态链接库
     */
    static {
    String libName = "FNHFD1008Dll"; //加载FNHFD1008Dll.dll
    try {
    System.loadLibrary(libName);
    System.out.println("Load Dll Success! Dll:" + libName);
    } catch (UnsatisfiedLinkError err) {
    System.out.println("Load Dll Error!dllName:" + libName);
    }
    } public static void main(String[] args) {
    int ret=0;

    FNHFD1008 fn = new FNHFD1008();
    ret = fn.OpenComm(1000);
    System.out.println("HFD1008:OpenComm ret:" + ret );

    String uid = fn.ReadUID();
    System.out.println("HFD1008:ReadUID ret:" + uid );

    String block = fn.ReadBlock("ffffffffffff", 4);
    System.out.println("HFD1008:ReadBlock ret:[" + block + "]");
    //
    String retStatus = fn.WriteBlock("ffffffffffff", 5, "00000000000000000000000031322E44");
    System.out.println("HFD1008:WriteBlock ret:[" + retStatus + "]");

     block = fn.ReadBlock("ffffffffffff", 5);//123456789abc
    System.out.println("HFD1008:ReadBlock ret:[" + block + "]");
    ret = fn.StopComm();
    System.out.println("HFD1008:StopComm ret:" + ret );

    }}
      

  2.   

    接口函数里做如下模仿
    public static interface RFSAPIV2 extends Library {
      RFSAPIV2 INSTANCE = (RFSAPIV2)
      Native.loadLibrary("RFSAPIV2",
      RFSAPIV2.class);
      int ReadLabelID(long hh,int nMax, UserStruct.ByReference idBuffer,int[] nCounter);
    } 在按钮过程中做如下
    private void jButton3ActionPerformed(java.awt.event.ActionEvent evt) {   
      // TODO add your handling code here:
      UserStruct idBuffer = new UserStruct();
      idBuffer.Address=0;
      idBuffer.Length=0;
      idBuffer.num[0][0]=(byte)0x00; // 这地方没有把数组全面初始化不知道影响否???  int nCounter[]={0};
      int nMax=10;  apiReturn=RFSAPIV2.INSTANCE.ReadID(hScanner[0], nMax, idBuffer, nCounter);
    }
      

  3.   

    另外UserStruct.ByReference idBuffer和下面的UserStruct idBuffer类型也不一样
      

  4.   

    natalya13回 
      你列的两个函数,即声明时,和调用时,我自己贴代码时疏忽了,但这个没有影响
    因为我工程代码里是一致的。 所以不存在这个不匹配的问题,要不语法检查就过不了。 
     我去玩了几天,刚回来来,高手们还是要指点指点啊,,, 10.1 前都有效 
      

  5.   


    其实是一样的,因为对于结构体,在JNA中一般传参的时候都默认是引用,除非要传值的话就要实现这个借口:
    public static class ByValue extends UserStruct implements Structure.ByValue { },其实楼主在声明函数时可以直接这样写:
     int ReadLabelID(NativeLong hh,int nMax, UserStruct idBuffer,int[] nCounter); 
    你函数的第一个参数在c中声明是long型,但是在JNA中一定要用NativeLong这个长整型来代替个人一点观点,最近也在研究这个,不知道可不可行,楼主试试吧~~呵呵,有问题继续提
      

  6.   

     谢谢  renic1987  晚上我再试试,,,有问题再请教你
      

  7.   

    说一点自己可能愚昧的的看法好象是说
    如果你的Struct实现Structure.ByReference接口,那么JNA认为你的Struct是一个指针。指向C语言的结构体。
    如果你的Struct实现Structure.ByValue接口,那么JNA认为你的Struct是值类型,就是C语言的结构体。
    如果你不实现这2个接口,那么就相当于你实现了Structure.ByReference接口。
    既然实现了两个接口,那么JNA是不是已经认定你的Struct是值类型,是不是这和ReadLabelID中的定义冲突?
    楼主有没有试过,去掉这两个接口的实现,或者保持这样,而结构体用值传递
      

  8.   

    我觉得楼主想要的是要的实现的是传指针,那么还是实现Structure.ByReference好拉,不然同时实现2个接口是也可能出现接口冲突的,毕竟在java里指针就是引用吗!
      

  9.   

    JNative deviceInitialize = new JNative("TenxHID.dll","HID_DeviceInitialize");
    // 设置返回值类型:
    deviceInitialize.setRetVal(Type.INT);
    // 设置参数
    deviceInitialize.setParameter(1, 3132);
    // 执行
    deviceInitialize.invoke();
    // 获取返回值
    int dd = deviceInitialize.getRetValAsInt();
      

  10.   

    我做了个java调用dll的,java的String参数传过去,jvm就报错了,我想应该是String类型转换有问题,但是不知道怎么下手,传int参数又没问题,哎,蛋疼