[英]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.