2

私は現在、Java アプリケーションからアクセスするネイティブ DLL (C++) を開発する必要があるプロジェクトに取り組んでいます。ブリッジング ジョブに JNA を選択しましたが、正しい int 値を Java から C++ 関数に渡す際に問題に直面しています。

簡単に言えば、C++ で int 値をパラメーターとして受け入れる関数があります: (機密性を維持するためにコードが削除され、メソッドの名前が変更されます)

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;
}

toStringstd::stringを使用して任意のデータ型の値を変換する簡単な方法ですstd::stringstream。実装は次のとおりです。

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

SomeStructureコードで使用している実際の構造体から名前が変更されています。structListの配列ですSomeStructurestructListSizeおよびstructList共有メモリ内のすべてのグローバル変数です。

これは、DLL の Java インターフェイスのメソッド シグネチャです。

SomeStructure.ByValue GetSomeStructureFromIndex(int index);

これは、テスト ケースで Java のメソッドを使用する方法です。

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

libraryStdCallLibraryは、を使用して生成された DLL ファイル ( のサブクラス) のインターフェイスのインスタンスですNative.loadLibrary。上記のコードを Java で実行すると、Windows のデバッグ出力に次のような出力が表示されます。

Received index of 86701080

(配列から構造体を取得する前にindex行のチェックを省略した場合、プログラムはアクセス違反エラーに遭遇するようになります)if (index >= 0 && index < structListSize)

86701080任意の値にすることができます。エクスポートされた関数の署名に応じて変化することに気付きました。ここで何か不足していますか?1関数は、関数の署名がされていた場合の期待値を適切に受け取ります。void PrintIndex(int index)

EDIT(0): サンプル コードを実際のコードに近づけるために修正しました。

EDIT(1): @technomage のポインターによるとByValue、返された構造を収集するすべてのメソッド シグネチャと変数に使用を開始しました。

EDIT(2): Java クラスには、 C++SomeStructureの構造体と比較して、追加の変数と Java メソッドがあります。SomeStructureそれが不一致の原因であるかどうか、現在テスト中です。

問題が解決しました

@technomage は、C++ 関数がその引数を解釈し、期待どおりに値を返すために、戻り値の型として使用される構造体 (および関数パラメーターとして使用されるもの) のサイズが Java の対応するものと異なるべきではないことを説明しました。これは、 の場合SomeStructure、 C++ withsizeof(SomeStructure)および Java with で確認できます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];

: 整数定数は、Java のみを保持するためにMAX_LIST_SIZE宣言されています。private

これらすべての修正を行った後、私のコードは正常に機能し、アクセス違反が発生しなくなりました。

4

1 に答える 1