私は現在、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;
}
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
。structListSize
およびstructList
共有メモリ内のすべてのグローバル変数です。
これは、DLL の Java インターフェイスのメソッド シグネチャです。
SomeStructure.ByValue GetSomeStructureFromIndex(int index);
これは、テスト ケースで Java のメソッドを使用する方法です。
SomeStructure.ByValue received = library.GetSomeStructureFromIndex(1);
library
StdCallLibrary
は、を使用して生成された 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
これらすべての修正を行った後、私のコードは正常に機能し、アクセス違反が発生しなくなりました。