繁体   English   中英

JNA 中的无效 memory 访问

[英]Invalid memory access in JNA

使用 JNA 时,我在调用QLConnect方法时收到 Invalid Memory Access 错误。

这是我映射 DLL 的接口:

import com.sun.jna.Native;
import com.sun.jna.win32.StdCallLibrary;

public interface QuikLimit extends StdCallLibrary {
    
    QuikLimit INSTANCE = (QuikLimit) Native.load(new File("").getAbsolutePath() + "\\QuikLimit.dll", QuikLimit.class);
    
    int QLConnect(String userName, String userPassword, byte[] desc);
    
    //more methods from dll
}

我有另一个带有常量的 class :

public class Const {
    public static final int DESC_SIZE = 1024;
    
    public enum Status {
        //enum values

        int code;

        private Status(int code) {
            this.code = code;
        }
        public int getCode() {
            return code;
        }
    };
}

这是代码中出现的地方:

@Component
public class ConnectionManager {
    
    @Value("${quik.login}")
    private String login;
    @Value("${quik.password}")
    private String password;

    private Logger logger = LoggerFactory.getLogger(this.getClass());

    private boolean connected;

    public synchronized BaseResponse connect() {
        BaseResponse result = new BaseResponse();
        byte[] desc = new byte[Const.DESC_SIZE]; 
        if (connected) {
        //logic if connected
        logger.info("call QLConnect");
        int retVal = QuikLimit.INSTANCE.QLConnect(login, password, desc);
        if (retVal == Const.Status.QL_ACTIVE.getCode()) {       
        //logic from response
        } else if (retVal == Const.Status.QL_CONNECTEDNOTACTIVE.getCode()) {
        //logic from response
        }
        result.setCode(retVal);
        result.setDescription(Util.descToStr(desc));
        QuikLimit.INSTANCE.QLDisconnect();
        return result;
    }
}

我知道 1 假设立即落在 dll 中的类型不匹配的事实。 但是 header 文件明确指出返回类型是 int:

typedef __int32             ql_long;
ql_long _stdcall QLConnect(const char* lpszUserName, const char* lpszUserPassword, char* lpszError);

lpszUserName 是指向包含用户名的 ASCIIZ 字符串的指针。

pszUserPassword 是指向包含用户密码的 ASCIIZ 字符串的指针。

lpszDesc 是一个指向缓冲区的指针,如果发生错误,该行及其描述会被放入该缓冲区。 最小缓冲区大小为 512 字节。

还有什么可能是错误的原因?

当您收到 Invalid Memory 访问错误时,首先要检查的是您的类型映射,您正确地从查看int返回值开始。 结果是另一个 arguments 的String映射在 *nix 系统上工作正常,需要对 Windows 进行一些特殊处理。

默认情况下 Windows 使用 UTF 16 编码,并且 JNA 的默认类型映射在后台尝试将 Java String对象转换为 UTF-16 编码的本机字符串 ( wchar* )。 这适用于 Windows API DLL。

但是,您的自定义 DLL 指定用户名和密码 arguments 应为 ASCIIZ 格式(以 null 结尾的 C 字符串)。

您可以通过在加载 DLL 时将W32APIOptions.ASCII_OPTIONS作为第三个参数包括在内来强制 JNA 使用 ASCII String类型映射器,例如,

QuikLimit INSTANCE = (QuikLimit) Native.load(new File("").getAbsolutePath() + "\\QuikLimit.dll", QuikLimit.class, W32APIOptions.ASCII_OPTIONS);

还有其他更细粒度的方法只处理字符串类型映射,不要尝试同时进行 Function 映射(如果您的任何映射函数以 W 或 A 结尾,这可能会中断。)。 您可以深入了解W32APIOptions class 以了解如何创建自己的自定义选项以通过。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM