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

参考资料:

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

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

1.引入依赖

        
            net.java.dev.jna
            jna
            5.5.0
        

2.存放DLL路径

2.1 项目中放在resource目录下

SpringBoot 使用JNA 调用DLL过程以及遇到的问题总结_第1张图片

2.2 或者放在这目录下 

 SpringBoot 使用JNA 调用DLL过程以及遇到的问题总结_第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 Type Size Java Type Common Windows Types
char 8-bit integer byte BYTE, TCHAR
short 16-bit integer short WORD
wchar_t 16/32-bit character char TCHAR
int 32-bit integer int DWORD
int boolean value boolean BOOL
long 32/64-bit integer NativeLong LONG
long long 64-bit integer long __int64
float 32-bit FP float  
double 64-bit FP double  
char* C string String LPCSTR
void* pointer Pointer LPVOID, 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.不支持多线程,调用时需要使用同步代码块

 

你可能感兴趣的:(springboot)