Java之JNI参数传递

Java之JNI参数传递


转载:http://blog.sina.com.cn/s/blog_75a8cfac010152t3.html

一 Java端
----------------------------------------------------------------------------------begin
import java.io.UnsupportedEncodingException;

public class DESInvokeLib {
         static { 
                     System.loadLibrary("encrypt"); 
          }

        public native static byte[] encrypt(int len, byte[]str); 
        public native static byte[] decrypt(byte[]str); 
 
        public static void main(String[] args) {
                   DESInvokeLib desInvokeLib = newDESInvokeLib(); 
  
                  String plainText = "Welcome to My Jni Test! -wangfei/n" +
                                                         "1Welcome to My Jni Test! -wangfei/n" +
                                                         "2Welcome to My Jni Test! -wangfei/n" +
                                                          "Emai: vinch.wang@gmail.com/n";
                   System.out.println("plain text is: " + plainText);
  
                   try {
                            //将String转换为字符数组
                            byte[] plainTextBytes = plainText.getBytes("ISO-8859-1");
                             intlen = plainTextBytes.length;
                            System.out.println("plainTextBytes length is: " + len);

                            //先加密,再解密
                            byte[] encryptedTextBytes = desInvokeLib.encrypt(len,plainTextBytes);
                            byte[] decryptedTextBytes =desInvokeLib.decrypt(encryptedTextBytes);
   
                            //将字符数组转换为String
                            System.out.println("decryptedTextBytes length is: " +   

                            decryptedTextBytes.length);
                            String decryptedText = new String(decryptedTextBytes,"ISO-8859-1");
                            System.out.println("decryptedText is: " + decryptedText);
                           
                            catch (UnsupportedEncodingException e) {
                                    e.printStackTrace();
                            
     
}

----------------------------------------------------------------------------------end 

 

保存为DESInvokeLib.java文件, 先编译生成class文件, 再用"javahDESInvokeLib"命令生成包含dll函数导出声明的头文件"DESInvokeLib.h". 具体内容如下:
----------------------------------------------------------------------------------begin

#include <jni.h>

#ifndef _Included_DESInvokeLib
#define _Included_DESInvokeLib
#ifdef __cplusplus
extern "C" {
#endif

JNIEXPORT jbyteArray JNICALL Java_DESInvokeLib_encrypt
  (JNIEnv *, jclass, jint, jbyteArray);


JNIEXPORT jbyteArray JNICALL Java_DESInvokeLib_decrypt
  (JNIEnv *, jclass, jbyteArray);

#ifdef __cplusplus
}
#endif
#endif
----------------------------------------------------------------------------------end

 

二 VC端

1.在VC6的"Tool->Options"下,添加java的库文件路径. 
    如C:/JDK1.5.0/INCLUDE  和 C:/JDK1.5.0/INCLUDE/WIN32.

2. 建立"Win32 Dynamic-Link Library"类型的空工程, 导入DES.cpp, DES.h. DESInvokeLib.h文件.
   工程名存为"encrypt".

3. 在encrypt.cpp文件内编写代码, 具体如下
----------------------------------------------------------------------------------begin
#include   "windows.h"
#include  "jni.h"                         
#include  "Des.h"                     //参照原DES加密程序
#include  "DESInvokeLib.h"    //参照原DES加密程序

BOOL APIENTRY DllMain( HANDLE hModule, 
                      DWORD  ul_reason_for_call, 
                      LPVOID lpReserved
     )
{
    returnTRUE;
}


JNIEXPORT jbyteArray JNICALL Java_DESInvokeLib_encrypt
  (JNIEnv *jniEnv, jclass,
jint length, jbyteArray jarrByte)
{
 //接收明文
 jbyte* pJbyte =jniEnv->GetByteArrayElements(jarrByte,0);
 char* szByte = (char*)pJbyte;

//显示调试信息
 printf("/ncome-in: /n%s, %d/n",szByte,strlen(szByte));

 //定义Key和Buffer
 char key[] ={0,2,0,0,9,3,5,1,9,8,0,0,9,1,7};
 char buf[255];
 
 //存明文到buffer并加密
 memset( buf, 0, sizeof(buf) );
 strcpy( buf, szByte );

 
 buf[length] = '/0'; 

//参照原DES加密程序 
Des_Go(buf, buf, strlen(buf), key, sizeof(key), ENCRYPT);

 //生成结果并返回
 jbyteArray jarrRet =jniEnv->NewByteArray( strlen(buf) );
 strcpy( szByte, buf );

 jniEnv->SetByteArrayRegion(jarrRet, 0, strlen(buf), (jbyte *)szByte );
 jniEnv->ReleaseByteArrayElements(jarrRet,pJbyte, 0);
 return jarrRet;
}

JNIEXPORT jbyteArray JNICALL Java_DESInvokeLib_decrypt
  (JNIEnv *jniEnv, jclass, jbyteArrayjarrByte)
{
 //接收
 jbyte* pJbyte =jniEnv->GetByteArrayElements(jarrByte, 0);
 char* szByte = (char *)pJbyte;

 //定义Key和Buffer
 char key[] ={0,2,0,0,9,3,5,1,9,8,0,0,9,1,7};
 char buf[256];
 
 //存明文到buffer并加密
 memset( buf, 0, sizeof(buf) );
 strcpy( buf, szByte );

 // 参照原DES加密程序 
Des_Go(buf, buf, strlen(buf), key, sizeof(key), DECRYPT);

 //生成结果并返回
 jbyteArray jarrRet =jniEnv->NewByteArray( strlen(buf) );
 strcpy( szByte, buf );

 //显示调试信息
 printf("/nout: /n%s, %d /n/n",szByte,strlen(szByte));

 jniEnv->SetByteArrayRegion(jarrRet, 0, strlen(buf), (jbyte *)szByte );
 jniEnv->ReleaseByteArrayElements(jarrRet,pJbyte, 0);
 return jarrRet;
}

----------------------------------------------------------------------------------end

4.为方便起见,在VC6的"Project->Settings->Link->General"中,设置dll导出路径为java文件所在路径.
5. 按F7编译生成dll, 并在控制台中运行java程序, 命令如 "java DESInvokeLib", 可见结果.

 

三 小结

1.  java与vc之间传递参数, 如果是整数类型(int), 一般不会有问题,但如果是传递字符串,则要考虑的问题较多.
 java程序编译时使用的是unicode编码, 传输时使用的是utf-8格式,而vc6默认使用的是ansi编码.

2.  传递字符串, 在java端可以选择参数类型为 String 或者byte[], 如果选择String,则与vc6配合做参数传递时,问题多多,还会生成不少乱码.  如果选择使用byte[], 则处理起来容易一些,问题也要少一些.

3. 为了解决参数传递中产生的乱码问题, 所以特别在参数中加入字符串长度 len, 并在vc6收到字符串后,
用  " buf[length] = '/0'  命令做处理. 实践表明, 效果还比较理想.

ps: 未解决的问题
1.  在vc6中接收java传递过来的字符串参数,会在正常字符串内容的末尾产生多余的乱码.
2.  DES程序能处理的明文长度只到255. 即buf变量定义长度.

 

参考:
1.  http://www.vckbase.com/code/viewcode.asp?id=1897
2.  http://www.iplab.cs.tsukuba.ac.jp/~liuxj/jdk1.2/zh/docs/guide/jni/spec/jniTOC.doc.html
3.  http://www.sagewire.org/java-programmer/JNI-DLL-VC-173069.aspx

 



1、java向c传递基本数据类型


对于基本数据类型,java和c是相互对应的,所以可以直接使用。它们的对应关系为;


------------------------------------------------------------------------


Java类型     本地类型  字节(bit)


-------------------------------------------------------------------------

  

  boolean   jboolean   8,unsigned

  byte    jbyte     8

  char    jchar    16,unsigned

  short    jshort    16

  int    jint     32

  long    jlong    64

  float    jfloat    32

  double   jdouble   64

  void    void     n/a


------------------------------------------------------------------------


2.java向c传递对象类型


对于java传递进来的java对象模型,c要加载java类的原型,根据创建相应的c对象,获取java对象的方法的id,然后调用java对象的方法。举例说明:比如有个java类customer对象作为jni参数传递到c程序,customer有方法StringgetName()。


JNIEXPORTjobject JNICALLJava_com_oracle_estt_sc_db_impl_SCQueryODBC__1getCustomer

(JNIEnv*env, jobject,  jobjectcustomer){


jmethodIDmethodId; 

 //获得customer对象的句柄

    jclasscls_objClass=env->GetObjectClass(customer); 

 //获得customer对象中特定方法getName的id 

 methodId=env->GetMethodID(cls_objClass,"getName","()Ljava/lang/String;");

 //调用customer对象的特定方法getName

 jstring js_name=(jstring)env->CallObjectMethod(customer,methodId,NULL);


...


}


3.c向java返回对象类型


在c程序中首先要创建要返回的java对象,得到每个属性的id,然后给每个属性赋值,最后返回。举例说明:同样是customer对象,有name等属性值,需要在c程序中给每个属性赋值后返回。


JNIEXPORTjobject JNICALLJava_com_oracle_estt_sc_db_impl_SCQueryODBC__1getCustomer

(JNIEnv*env, jobject,  jobjectcustomer){


......


//发现javaCustomer类,如果失败,程序返回 

 jclass  clazz =env->FindClass("com/oracle/estt/sc/busi/Customer");  

 if(clazz == 0) 

  return  0;    

 //为新的java类对象obj分配内存   

 jobject  obj = env->AllocObject(clazz);    

 //发现类中的属性,如果失败,程序返回  

 jfieldID  fid_id = env->GetFieldID(clazz,"customerID","I"); 

 if (fid_id ==  0) 

  return  0;

 jfieldID  fid_name =env->GetFieldID(clazz,"name","Ljava/lang/String;"); 

 if (fid_name ==  0) 

  return  0;

......


 env->SetIntField(obj,fid_id, 1

 env->SetObjectField(obj,fid_name, jname);


......


returnobj;


}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值