我有个问题 请问下各位 
我现在有个vb的 .dll文件 ,里面函数为
closecomm(comm_value& )
参数为 comm_value 的结构为Public Type Comm_value 
com_port As String * 3    //传入参数
dis_value As String * 40  //传出参数 
data_len As String * 2    //传出参数
End Type现在我使用jni的方法 重新用c++写个dll让java 调用代码如下
main.hclass comm_value{
 public:
   char com_port[10];
   char dis_value[40];
   char data_len[2];};typedef int __stdcall (*SendCard_c_mcom_set)(comm_value& value);
typedef int __stdcall (*SendCard_closecomm)(comm_value& value);
main.cppJNIEXPORT jint JNICALL Java_SendCardJava_c_1mcom_1set
  (JNIEnv * env, jobject, jobject comm)
{
   jclass commValueCls = env->FindClass("Comm_Value");
   jfieldID fid_CommValue_comport = env->GetFieldID(commValueCls,"com_port","Ljava/lang/String;");
   jobject proCommport = env->GetObjectField(comm,fid_CommValue_comport);
   jstring ppCommPort = (jstring)env->GetObjectField(proCommport,fid_CommValue_comport);      HINSTANCE  DLLHandle;
      SendCard_c_mcom_set sc_c_mcom_set;
      int open_result = 0;      DLLHandle = LoadLibrary("D:\\DGD4V3.0\\sendcard.dll");  //      if (DLLHandle) //call crmp timeout hook
      {
          try
         {
           sc_c_mcom_set = (SendCard_c_mcom_set)GetProcAddress(DLLHandle,"c_mcom_set");
           if (sc_c_mcom_set)
           {
              -----------------------------------------
              问题: 下面的我调用vb 的dll 中的函数 c_mcom_set (Comm_value  & parameter ) parameter 参数应该如何转换成Comm_value 类
                并使引用中的传出的2个参数怎样传出 希望大家能帮帮忙 谢谢~
              open_result = sc_c_mcom_set(commValueCls);
              
           }
           }catch(...)
           {
         }
      }
}

解决方案 »

  1.   

    对不起,因为我不会用c/C++, 所以没做过JNI的调用,不过你可以去google搜索一下哦!这个应该不是很麻烦的!native class 之类的
    native myMethod() 之类的总之,书写一个类或者一个方法为native ,
      

  2.   

    偶只试验过一个很简单的打印的JNI实现,呵呵,不会c++。推荐: healer_kx (甘草),这位c++ 貌似非常强劲!
    帮up
      

  3.   

    谢谢,现在是这样的我有个问题 请问下各位  
    我现在有个vb的 .dll文件 ,里面函数为 
    closecomm(comm_value& ) 
    参数为 comm_value 的结构为 Public Type Comm_value  
    com_port As String * 3    //传入参数 
    dis_value As String * 40  //传出参数  
    data_len As String * 2    //传出参数 
    End Type 现在我使用jni的方法 重新用c++写个dll让java 调用 代码如下 
    main.h class comm_value{ 
     public: 
       char com_port[10]; 
       char dis_value[40]; 
       char data_len[2]; }; typedef int __stdcall (*SendCard_c_mcom_set)(comm_value& value); 
    typedef int __stdcall (*SendCard_closecomm)(comm_value& value); 
    main.cpp 
    JNIEXPORT jint JNICALL Java_SendCardJava_closecomm 
      (JNIEnv *env, jobject, jobject comm) 
      { 
          jclass commValueCls = env-> FindClass("Comm_Value");       jfieldID fid_CommValue_comport = env-> GetFieldID(commValueCls,"com_port","Ljava/lang/String;"); 
          jobject proCommport = env-> GetObjectField(comm,fid_CommValue_comport); 
          jstring ppCommPort = (jstring)env-> GetObjectField(proCommport,fid_CommValue_comport); 
          char * comportStr =(char*)env-> GetStringUTFChars(ppCommPort,NULL);       jfieldID fid_CommValue_disvalue = env-> GetFieldID(commValueCls,"dis_value","Ljava/lang/String;"); 
          jobject proDisvalue = env-> GetObjectField(comm,fid_CommValue_disvalue); 
          jfieldID fid_CommValue_DataLen = env-> GetFieldID(commValueCls,"data_len","Ljava/lang/String;"); 
          jobject proDataLen = env-> GetObjectField(comm,fid_CommValue_DataLen);       HINSTANCE  DLLHandle; 
          SendCard_closecomm sc_closecomm; 
          int close_result = 0;       DLLHandle = LoadLibrary("D:\\DGD4V3.0\\sendcard.dll");  //       if (DLLHandle) //call crmp timeout hook 
          { 
              try 
             { 
               comm_value value  ; 
               strcpy(value.com_port,comportStr) ;            sc_closecomm = (SendCard_c_mcom_set)GetProcAddress(DLLHandle,"closecomm"); 
               if (sc_closecomm) 
               { 
                 close_result = sc_closecomm(value);             // env-> SetObjectField(proDisvalue,fid_CommValue_disvalue,env-> NewStringUTF(value.dis_value)) ; 
                // env-> SetObjectField(proDataLen,fid_CommValue_DataLen,env-> NewStringUTF(value.data_len )) ; 
               } 
               }catch(...) 
               { 
               } 
          } 
          return close_result; 
      } 
    java 代码 
    public class SendCardJava { 
         public native int closecomm(Comm_value Comm_value); static 

    System.loadLibrary("JavaSendCard"); 

    } 调用 public class SendCardJavaDLLApp { /** 
     * @param args 
     */ 
    public static void main(String[] args) { 
    // TODO Auto-generated method stub 
    SendCardJava sendCardJava = new SendCardJava(); Comm_value comm = new Comm_value(); 
    comm.com_port = "COM1"; System.out .println("Close Result : " + sendCardJava.closecomm(comm)); 
    System.out.println("Data Len: " + comm.data_len ); 
    System.out .println("Dis Value: " + comm.dis_value ); } 
    现在报错误 

    # An unexpected error has been detected by Java Runtime Environment: 

    #  EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x6d890e20, pid=4312, tid=6096 

    # Java VM: Java HotSpot(TM) Client VM (1.6.0-b105 mixed mode, sharing) 
    # Problematic frame: 
    # V  [jvm.dll+0xd0e20] 希望各位能帮忙解决下  谢谢
      

  4.   

    楼主是想用COM端口操作吗?
    如果是的话,可以用JAVA的标准API,comm.jar,它提供了跨平台的对COM端口的读写以及打开关闭等操作
      

  5.   

    谢谢各位了,是这样的, 我有个D4 读卡器  需要发指令才能读 写数据的,所以 我想利用已经有的dll 再封装个dll 再用java调用 .现在在 执行jclass commValueCls = env->  FindClass("Comm_value");  时就报错了,但我java里面已经定义了Comm_value这个类的
    public class Comm_value {
    public String com_port; public String dis_value; public String data_len;
    }请高手们多给点意见
      

  6.   

    不妨把一个参数comm_value拆成三个string作为三个参数,再试试。
    在java代码中增加print语句,进行诊断。
    这个调用应该不麻烦。
      

  7.   

     请问下代码中,
    JNIEXPORT jint JNICALL Java_SendCardJava_closecomm  
      (JNIEnv *env, jobject, jobject comm) 
           
          // get class Comm_value refrence 
          jclass commValueCls = env->GetObjectClass(comm);       //get Comm_value jfiledID comport
          jfieldID fid_CommValue_comport = env->GetFieldID(commValueCls,"com_port","Ljava/lang/String;");       //get string comm_port  
          jstring ppCommPort = (jstring)env->GetObjectField(commValueCls,fid_CommValue_comport);      //transfer string to char*
          const char* comportStr =(char*) env->GetStringChars(ppCommPort,0);  请问下下是不是这样转换的,我为什么这样调用后,程序就报错误呢
      

  8.   

          const char* comportStr =(char*) env->GetStringChars(ppCommPort,0);      ........
        
          DLLHandle = LoadLibrary("D:\\DGD4V3.0\\sendcard.dll");  //        if (DLLHandle) //call crmp timeout hook  
          {  
              try  
             {  
               comm_value value  ; 
               如果是strcpy(value.com_port,"COM1") ; 就调用正确 
               如果是strcpy(value.com_port,comportStr) ; 调用的时候就报错,我不知道comportStr 有没问题             sc_closecomm = (SendCard_c_mcom_set)GetProcAddress(DLLHandle,"closecomm");  
               if (sc_closecomm)  
               {  
                 close_result = sc_closecomm(value);              // env->  SetObjectField(proDisvalue,fid_CommValue_disvalue,env->  NewStringUTF(value.dis_value)) ;  
                // env->  SetObjectField(proDataLen,fid_CommValue_DataLen,env->  NewStringUTF(value.data_len )) ;  
               }  
               }catch(...)  
               {  
               }  
          }  
      

  9.   

    试问一下,你在前边comportStr,有内容吗?
    const char* comportStr =(char*) env-> GetStringChars(ppCommPort,0);       ........ print出来试试。
      

  10.   

     const char* comportStr =(char*) env->GetStringChars(ppCommPort,0);
     printf("%s\n",comportStr);
     是个空的,请问我的代码 哪写的不对?
      

  11.   

    comportStr为空,是导致后边出错的根本原因。
    你看看const jchar * GetStringChars(JNIEnv *env, jstring string,
    jboolean *isCopy); 返回的是jchar*, 它是unicode char*啊。相当于是short*
    你得把它们转换成gbk串才行。
      

  12.   

    这样吧,不要使用GetStringChars,改调用:
    int len = env->GetStringUTFLength(ppCommPort); char* comportStr = env->GetStringUTFChars(name, iscopy)
    看它里边有没有内容,这个是utf-8编码的,如果是ansi char,不会有什么问题。如果是中文,则要转到gbk,才能显示。
      

  13.   

    是不是当时的classpath里面找不到这个类的定义呢
    还好,你的类最好是用包组织一下.试试看
      

  14.   

    我按照你的方法试了
    LEN
    96comportStr 
    浼�悼毽�秵甓版秵缃�稁绱愭秵砘版秵殳版秵顐愭秵顐�秵绉愭秵旌�秵霋版秵鞝版秵顐犳秵顑�秵飹�秵伀浿?涆?涆罀涎紐涆?涆?涆涆涆秐涆?涆?涆?涆涆涆?涆得到这些乱码
    奇怪了我在java调用的时候
    Comm_value comm = new Comm_value();
    comm.com_port = "COM1";
    System.out .println("Close Result : " + sendCardJava.closecomm(comm));都是ansi char 为什么会这样呢
      

  15.   

    使用JNI可以,但已经有几个封装好JNI调用的工具可以用,例如JNative。因为现在在上班偷偷泡BBS,不能说详细,你可以参考下
    http://blog.sina.com.cn/s/blog_4ec996be01008lz9.html总共2个方法,一个通过JNI,一个通过JNative,因为是笔记,没写得明白,只有代码,希望对你有所启发,建议善用GOOGLE。
      

  16.   

    1. VB无法直接生成native dll, Vb6以及以前的版本生成的DLL是COM DLL,里面都是自动化对象,无法直接使用GetProcAddress来获取地址。虽然有办法生成真正的native dll,但都属于偏门。应该在C++里面调用创建自动化对象后访问VB的DLL。2. 你的c++和vb的结构定义不同。3. VB6以及之前的VB,并没有对Unicode提供直接支持
      

  17.   

    现在的问题是
      //get string comm_port   
      jstring ppCommPort = (jstring)env-> GetObjectField(commValueCls,fid_CommValue_comport);   //transfer string to char* 
      const char* comportStr =(char*) env-> GetStringChars(ppCommPort,0);   printf("%s\n",comportStr);  我在java调用传入的是"1" 打印出来的是乱码
      

  18.   

    哈哈哈,小子你碰上我,算你命好,给你看段代码.
    jstring 装的是UNICODE的字符,你要把它转成ASCIIJNIEXPORT jint JNICALL Java_DllConvert_TScan_selectSource
      (JNIEnv *env, jobject, jstring sSrcName)
    {
    int nLen = env->GetStringLength(sSrcName) * 2 + 1;
    char *pcName = new char[nLen];
    memset( pcName, 0, nLen ); const wchar_t* w_buffer = env->GetStringChars( sSrcName, 0 );
    nLen = WideCharToMultiByte(CP_ACP, 0, 
    w_buffer, wcslen(w_buffer) + 1, pcName, nLen, NULL, NULL);        //上面几行就是把jstring 类型转为char* int nRes = TSCAN_SelectSource(pcName);   //这是我的函数. env->ReleaseStringChars(sSrcName, w_buffer); //用完了要释放,但不释放好象也行,似乎没有内存泄露,呵呵不清楚.
    delete pcName;
    return nRes;
    }
      

  19.   

    怎么我用const wchar_t* w_buffer = env-> GetStringChars( sSrcName, 0 ); 
    nLen = WideCharToMultiByte(CP_ACP, 0,  
    w_buffer, wcslen(w_buffer) + 1, pcName, nLen, NULL, NULL); 
    转换程序报错呢?
      

  20.   

    加头文件
    #include <string.h>
    #include <stdio.h>
    #include <windows.h>
      

  21.   

    const wchar_t* w_buffer = env->  GetStringChars( sSrcName, 0 );  
    这个函数得到是unsigned short*  请问怎么转换成wchar_t*的? 
      

  22.   

    unsigned short*  和wchar_t*不是一回事吗?
    typedef unsigned short wchar_t;   //这事它的宏定义.
      

  23.   

    现在调用的问题基本解决,现在还存在2个问题,希望大家帮下忙.
    第一个:
    我用vb 调用dll的方法 传进去的这样的类型进去的
    Public Type comm_value
        com_port As String * 1
        dis_value As String * MAXCARDALL
        data_len As String * 2
    End TypeDim MyCOM As comm_value
    c_mread_card(MyCOM, MyKeySet, MyZone)传出来的MyCOM.dis_value 是正确的,  F1FBC8FFC8FF000000000000000000005510但在c++里面我定义的 
    class comm_value{
     public:
       char com_port[10];
       char dis_value[100];
       char data_len[2];};comm_value MyCOM ;
    Result = sc_c_mread_card(MyCOM, MyKeySet, MyZone);
    但是传出来的MyCom.disvalue 只有 8FF000000000000000000005510第二个问题:
    是怎么把java 传进来的String 类型转换成char*,再 怎么把c++的char* 转换成String 多谢各位的帮忙!
      

  24.   

    JNIEXPORT jstring JNICALL Java_SendCardJava_getCardNo
      (JNIEnv *env, jobject, jobject comm, jobject keyset, jobject zone)
      {
         jclass commValueCls = env->FindClass("module/Comm_value");
         jfieldID fid_CommValue_comport = env->GetFieldID      (commValueCls,"com_port","Ljava/lang/String;");
         jstring ppCommPort = (jstring)env->GetObjectField(commValueCls,fid_CommValue_comport);我只是想得到comm 对象的com_port 我在java 赋的是"1"  这样取出来的 是些乱码 ,请帮忙看看.
      

  25.   

    现在还有个小问题 问下大家,
    jni 在javac javah  时应该在什么目录下? 再就是dll应该放什么路径下?
    我在javah 包含包名后,dll也改了名字 调用时还报 java.lang.UnsatisfiedLinkError: getCardNo(方法名错误)
      

  26.   

    为什么我试了下面2个函数都 jstring 转换成char* 都是乱码 ,请高手帮看看
    char* jstringTostring(JNIEnv* env, jstring jstr)

          char* rtn = NULL; 
          jclass clsstring = env->FindClass("java/lang/String"); 
          jstring strencode = env->NewStringUTF("utf-8"); 
          jmethodID mid = env->GetMethodID(clsstring, "getBytes", "(Ljava/lang/String;)[B"); 
          jbyteArray barr= (jbyteArray)env->CallObjectMethod(jstr, mid, strencode); 
          jsize alen = env->GetArrayLength(barr); 
          jbyte* ba = env->GetByteArrayElements(barr, JNI_FALSE); 
          if (alen > 0) 
          { 
                    rtn = (char*)malloc(alen + 1); 
                    memcpy(rtn, ba, alen); 
                    rtn[alen] = 0; 
          } 
          env->ReleaseByteArrayElements(barr, ba, 0); 
          return rtn; 
    } int JStringToChar(JNIEnv * env, jstring str)
    {
        int nLen = env-> GetStringLength(str) * 2 + 1;
        char *pcName = new char[nLen];
        memset(pcName, 0, nLen);    const wchar_t * w_buffer = (wchar_t*) env->GetStringChars(str, 0);
        nLen = WideCharToMultiByte(CP_ACP, 0, w_buffer, wcslen(w_buffer) + 1, pcName, nLen, NULL, NULL);
        printf("%s\n",pcName);
        env->ReleaseStringChars(str, (unsigned short*)w_buffer);    return strlen(pcName);
    }
      

  27.   

    首先我是
    JNIEXPORT jstring JNICALL Java_com_autotoll_hk_cms_integrated_reader_SendCardJava_getCardNo
      (JNIEnv *env, jobject, jobject comm, jobject keyset, jobject zone)
      {
         jclass commValueCls = env->FindClass("com/autotoll/hk/cms/integrated/module/Comm_value");
         //或着
         //jclass commValueCls = env->GetObjectClass("comm");
         jfieldID fid_CommValue_comport = env->GetFieldID(commValueCls,"com_port","Ljava/lang/String;");
         jstring ppCommPort = (jstring)env->GetObjectField(commValueCls,fid_CommValue_comport);
         这样得到jstring 之后用上面的转换的, 显示的总是乱码 请各位帮忙
      

  28.   

    最后结贴,比较遗憾的是 我一直没搞清楚 为什么我传对象进来string属性取出来 的是乱码 ,直接传string没有问题.
      

  29.   

    小兄弟,建议你一步步简化问题,
    比如,我给你出一道题,你什么时候会做了,上述乱码问题就都解决了。class TestJava
    {
    private native printHello(String hello);
    public static String getStrCallback(String str);
    };要求,在实现printHello方法的C代码里头,要进行TestJava class的getStrCallback方法回调,并且,打印的是中文串。
    比如“中文测试”。这里边就包含了unicode16BE到gbk编码相互之间的转换。
      

  30.   

    给LZ推荐一个JNI的使用,有源码和大量注释,LZ一定要试下:
    http://download.csdn.net/detail/txzsp/2285294