簡體   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