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