SpringBoot 使用JNA 调用DLL过程以及遇到的问题总结

参考资料:

https://blog.csdn.net/ctwy291314/article/details/82895604 Java JNA (三)—— 结构体使用及简单示例

https://www.jianshu.com/p/ead89497c403   JNA 教程

1.引入依赖

        <dependency>
            <groupId>net.java.dev.jna</groupId>
            <artifactId>jna</artifactId>
            <version>5.5.0</version>
        </dependency>

2.存放DLL路径

2.1 项目中放在resource目录下

2.2 或者放在这目录下 

 

2.3 打成jar包后,路径

linux: /usr/lib/
 win:所有DLL放同级目录

2.4 自定义路径


    public boolean addDllLocationToPath(String dllLocation)
    {
        try
        {
            System.setProperty("java.library.path", System.getProperty("java.library.path") + ";" + dllLocation);
            Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
            fieldSysPath.setAccessible(true);
            fieldSysPath.set(null, null);
        }
        catch (Exception e)
        {
            System.err.println("Could not modify path");
            return false;
        }
        return true;
    }
}

 

3.继承library

import com.sun.jna.Library;
import com.sun.jna.Native;
import com.sun.jna.Platform;
 
/** Simple example of JNA interface mapping and usage. */
public class HelloWorld {
 
    // This is the standard, stable way of mapping, which supports extensive
    // customization and mapping of Java to native types.
 
    public interface CLibrary extends Library {
        CLibrary INSTANCE = (CLibrary)
            Native.loadLibrary((Platform.isWindows() ? "msvcrt" : "c"),
                               CLibrary.class);
 
        void printf(String format, Object... args);
    }
 
    public static void main(String[] args) {
        CLibrary.INSTANCE.printf("Hello, World\n");
        for (int i=0;i < args.length;i++) {
            CLibrary.INSTANCE.printf("Argument %d: %s\n", i, args[i]);
        }
    }
}

 

4.数据类型映射

Java primitive types (and their object equivalents) map directly to the native C type of the same size.

Native TypeSizeJava TypeCommon Windows Types
char8-bit integerbyteBYTE, TCHAR
short16-bit integershortWORD
wchar_t16/32-bit charactercharTCHAR
int32-bit integerintDWORD
intboolean valuebooleanBOOL
long32/64-bit integerNativeLongLONG
long long64-bit integerlong__int64
float32-bit FPfloat 
double64-bit FPdouble 
char*C stringStringLPCSTR
void*pointerPointerLPVOID, HANDLE, LPXXX

Unsigned types use the same mappings as signed types. C enums are usually interchangeable with "int".

无符号类型的映射等同于有符号类型,如 unsigned short ->short ,枚举等同于int

5.结构体映射

struct CodeData  
{
    unsigned char  code[4096];           
    unsigned short codeLen;              
    unsigned char  orgId[8];          
    unsigned short orgIdLen;          
};
    @Structure.FieldOrder({"code", "codeLen", "orgId", "orgIdLen"})
    public static class CodeData extends Structure {
        //二维码数据 4096,要和dll的大小一致
        public byte[] code = new byte[4096];
        // 二维码数据长度 4096
        public short codeLen;
        //机构id
        public byte[] orgId;
        //机构id长度8
        public short orgIdLen;


        //这个类代表结构体指针
        public static class ByReference extends CodeData implements Structure.ByReference {
        }

        //这个类代表结构体本身
        public static class ByValue extends CodeData implements Structure.ByValue {
        }
    }

注意事项:

1.Structure 子类中的公共字段的顺序,必须与C 语言中的结构的顺序一致。否则会报错!

2.C语言结构中的char数组指定了大小,则使用byte需要指定大小,不能使用String,原因我猜是因为内存块?

3.或者使用指针,初始化时指定大小

6.函数映射

unsigned char getData (struct  CodeData  *code,unsigned char *str,unsigned short len, unsigned char *data,unsigned short *dataLen);
    /**
     *  获取数据
     *
     * @param codeData  结构体指针入参
     * @param str 字符串入参
     * @param len 基础类型入参
     * @param data 字符串出参
     * @param dataLen 基础类型出参
     * @return
     */
    byte getData(CodeData.ByReference codeData,String str, short len, byte[] data, ShortByReference dataLen);

7.调用函数

    public static String getData() {
        String orgId = "12345678";
        String code = "123456789";
        String str = "test";
        String len = 4;
        CtidLibrary.CodeData.ByReference codeData = new CtidLibrary.CodeData.ByReference();
        codeData.orgId = orgId.getBytes();
        codeData.orgIdLen = 8;
        byte[] codeTmp = code.getBytes();
        for (int i = 0; i < codeTmp.length; i++) {
            codeData.code[i] = codeTmp[i];
        }
        codeData.codeLen = (short) code.length();
        byte[] data = new byte[1024];
        ShortByReference dataLen = new ShortByReference();
        byte resp = CtidLibrary.INSTANCE.getData(codeData, str, len, data, dataLen);
        System.out.println(resp);
        String result = new String(data);
        System.out.println(result);
        return result;
    }

注:出参和入参格式可能不一样

8.注意事项

1.dll库如果是32位的,JDK也要改成32位的。

2.dll存在依赖关系,先引入父级的依赖,具体如下:

 2.1  依赖项

public interface MklIntelThreadLibrary extends Library {
    MklIntelThreadLibrary INSTANCE = Native.load("mkl_intel_thread", MklIntelThreadLibrary.class);
}

2.2 需要调用的dll

public interface AntiSpoofLibrary extends Library {
    MklIntelThreadLibrary mkl = MklIntelThreadLibrary.INSTANCE;
    AntiSpoofLibrary INSTANCE = Native.load("AntiSpoof", AntiSpoofLibrary.class);

    /**
     * 初始化接口,返回:true正确,false错误
     *
     * @return
     */
    boolean InitSpoof(String modelPath);

    /**
     * 活体检测接口 ,返回:true 活体,false:假体
     *
     * @return
     */
    boolean AntiSpoofBase64(String rgbBase, String irBase, boolean print);
}

3.Invalid memory access 

可能原因:1.数据类型映射不对

                  2.不支持多线程,调用时需要使用同步代码块

 

  • 3
    点赞
  • 41
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值