簡體   English   中英

如何使用JNA從Java將int作為C ++函數參數傳遞

[英]How to pass int as a C++ function parameter from Java using JNA

我目前正在從事一個項目,該項目需要開發一個本機DLL(在C ++中)才能由Java應用程序訪問。 我已選擇JNA進行橋接,但是在將正確的int值從Java傳遞到C ++函數時遇到了問題。

簡單地說,我有一個函數可以接受int值作為C ++中的參數:(剝離了代碼,並重命名了方法以保持機密性)

JAVALINK_EXPORT SomeStructure WINAPI GetSomeStructureFromIndex(int index) {
    std::string debugMsg("Received index of ");
    debugMsg.append(toString(index));
    OutputDebugString(debugMsg.c_str());
    SomeStructure result = defaultStructure;
    if (index >= 0 && index < structListSize)
        result = structList[index];

    return result;
}

toString是一種轉換的任何數據類型的值,以一個簡單的方法std::string使用std::stringstream 實現如下:

template <class T>
inline std::string toString (const T& t) {
    std::stringstream ss;
    ss << t;
    return ss.str();
}

SomeStructure從我在代碼中使用的實際結構重命名。 structList是陣列SomeStructure structListSizestructList都是共享內存中的全局變量。

這是DLL的Java接口中的方法簽名:

SomeStructure.ByValue GetSomeStructureFromIndex(int index);

這就是我將Java中的方法用於測試用例的方式:

SomeStructure.ByValue received = library.GetSomeStructureFromIndex(1);

library是使用Native.loadLibrary生成的DLL文件( StdCallLibrary子類)的接口的實例。 當上述代碼在Java中執行時,我的Windows調試輸出中得到類似以下輸出的內容:

Received index of 86701080

(如果我在從數組中獲取結構之前省略了對if (index >= 0 && index < structListSize)行的index檢查,則程序將繼續遇到訪問沖突錯誤)

86701080可以是任意值。 我意識到它會根據導出函數的簽名而變化。 我在這里想念什么嗎? 如果函數簽名為void PrintIndex(int index)該函數正確接收期望值為1void PrintIndex(int index)

EDIT(0):我修改了示例代碼以使其更接近實際代碼。

EDIT(1):根據ByValue的指針,我已開始將ByValue用於所有方法簽名和收集返回結構的變量。

EDIT(2):與C ++中的SomeStructure結構相比,Java類SomeStructure具有一個額外的變量和Java方法。 我目前正在測試是否是導致差異的原因。

問題解決了

@technomage解釋說,對於C ++函數來說,按預期解釋其參數和返回值,用作返回類型的結構(以及用作函數參數的結構)的大小不應與Java對應的大小相同。 SomeStructure的情況下,可以在C ++中使用sizeof(SomeStructure)進行檢查,在Java中使用SomeStructure.size()

基本上,發生的事情是SomeStructure結構的大小與其Java表示的大小不同。 SomeStructure包含一個固定長度的數組,如下面的代碼所示:

#define MAX_LIST_SIZE 256
typedef struct {
    int list[MAX_LIST_SIZE];
    int length;
} SomeStructure;

但是,Java表示沒有指定固定長度數組的大小。 list初始化為包含單個值0

package model;

import com.sun.jna.Structure;

public class SomeStructure extends Structure {
    public static class ByValue extends SomeStructure implements Structure.ByValue { }
    public int[] list = {0};
    public int length = 0;
}

我通過將錯誤的初始化語句替換為以下內容來解決了該問題:

private static final int MAX_LIST_SIZE = 256;
public int[] list = new int[MAX_LIST_SIZE];

注意 :整數常量MAX_LIST_SIZE被聲明為private以使其僅限於Java。

進行所有這些修改后,我的代碼可以正常工作,不再遇到訪問沖突。

“ WINAPI”表示stdcall調用約定,但是您必須確定本地的宏定義才能確定。 如果是這樣,則需要StdCallLibrary而不是Library 這可能會影響您的傳入index參數。

您還將復制結構(通過值語義),而不是指向它的指針。 當按值傳遞結構或按值返回結構時,您需要告訴JNA您正在這樣做

編輯

確保SomeStructure.size()與本機sizeof(SomeStructure)匹配。 通常,實現按值返回的結構,以便調用方在堆棧上分配內存,並將隱式指針傳遞給被調用方,然后該被調用方將其寫入該內存。 如果調用方和被調用方在該內存大小上存在分歧,則可能影響堆棧上的其他內容(例如,參數和返回值)。 您還可以向函數添加更多參數,並打印它們的值(十六進制),以大致了解堆棧中的內容。 如果傳入可識別的參數(例如0x12345678),通常會很清楚是什么在錯誤的方向推動或拉動堆棧。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM