Java调用C++含char *类型参数的DLL文件

    技术2022-07-12  70

    最近课程作业完成MD5加密的DLL编写,并使用Java调用DLL,中间遇到几个坑与君共勉。

    一、C++编写MD5加密DLL

    //定义外部调用宏 #ifdef MD5_DLL #else #define MD5_DLL extern "C" _declspec(dllexport) //指的是允许将其给外部调用 #endif //声明接口,内容暂不展示 MD5_DLL void MD5(unsigned char* input, unsigned char* output);

    二、JNA包下载

    java native interface JNA(Java Native Access)框架是一个开源的Java框架,是SUN公司主导开发的,建立在经典的JNI的基础之上的一个框架,比JNI更好用,JNI偏底层,JNA更友好。 JNA下载地址:https://github.com/java-native-access/jna 找到Download下载第一个就OK

    三、DLL转换

    以eclipse为例,右键项目->Properties->Java Build Path->Libraries->Add External JARs 选择JNA

    1、编写charReference类,该类继承com.sun.jna.ptr.ByReference类,该类主要负责Java数据类型到C++中char *类型对应

    import com.sun.jna.ptr.ByReference; public class charReference extends ByReference{ public charReference() { this((byte)0);//无 } public charReference(byte value) { super(1000); this.setValue(value); } public void setValue(byte value) { this.getPointer().setByte(0L, value); } public byte getValue() { return this.getPointer().getByte(0L); } public void Init(String input) { for(int i=0;i<input.length();i++) { this.getPointer().setChar((long)i, input.charAt(i));//字符串初始化 } } public void Init(byte[] bytes) { for(int i=0;i<bytes.length;i++) { this.getPointer().setByte((long)i, bytes[i]);//字节数组初始化 } } }

    因为char可能是中文汉字,中文汉字占两个字节,在setChar时并不会将两个字节都传到对象中,所以有中文时需要先将字符串转化成字节数组再传。

    2、声明接口

    import com.sun.jna.*; import com.sun.jna.ptr.PointerByReference; import tools.charReference; public interface PORT extends Library{ PORT INSTANTCE=(PORT)Native.loadLibrary("MD5",PORT.class);//MD5为DLL文件名 public void MD5(charReference input,charReference output); }

    将DLL文件放在项目bin文件夹下

    3、MD5的JAVA实现

    import java.io.UnsupportedEncodingException; import com.sun.jna.*; import com.sun.jna.ptr.PointerByReference; import tools.byteToString; import tools.PORT; import tools.charReference; public class MD5Encoder { //获得byte数组 private static byte[] getBytes(String input) throws UnsupportedEncodingException { int byteLen=0; byte[] bytes=new byte[3*input.length()]; for(int i=0;i<input.length();i++) { char now=input.charAt(i); byte[] nowCharBytes=null; if(isChinese(now)) { nowCharBytes=(""+now).getBytes("utf-8"); }else { nowCharBytes=(""+now).getBytes(); } for(int j=0;j<nowCharBytes.length;j++) { bytes[byteLen++]=nowCharBytes[j]; } } return bytes; } //判断是否为中文 private static final boolean isChinese(char c) { Character.UnicodeBlock ub = Character.UnicodeBlock.of(c); if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS || ub == Character.UnicodeBlock.CJK_COMPATIBILITY_IDEOGRAPHS || ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A || ub == Character.UnicodeBlock.GENERAL_PUNCTUATION || ub == Character.UnicodeBlock.CJK_SYMBOLS_AND_PUNCTUATION || ub == Character.UnicodeBlock.HALFWIDTH_AND_FULLWIDTH_FORMS) { return true; } return false; } //加密 public static String encoder(String inputString) throws UnsupportedEncodingException { charReference output=new charReference(); charReference input=new charReference(); input.Init(getBytes(inputString)); PORT.INSTANTCE.MD5(input, output); String outputString=""; for(int i =0;i<16;i++) { outputString=outputString+byteToString.bytesToHexString(output.getPointer().getByte(i)); } return outputString; } //测试 public static void main(String[] args) throws UnsupportedEncodingException { charReference output=new charReference(); charReference input=new charReference(); String x="zx哈哈"; input.Init(getBytes(x)); PORT.INSTANTCE.MD5(input, output); String outputString=""; for(int i =0;i<16;i++) { outputString=outputString+byteToString.bytesToHexString(output.getPointer().getByte(i)); } System.out.println(outputString); } }

    byteToString.byteToHexString为另一个类中的字节数组转化成字符串的函数

    public static String bytesToHexString(byte src) { int v = src & 0xFF; String hv = Integer.toHexString(v); if(hv.length()==1) { return "0"+hv; } return hv; }

    运行结果: 与某网站(https://md5jiami.51240.com/)加密结果相同

    Processed: 0.009, SQL: 9