JNAフレームワークを備えたJavaアプリケーションからネイティブのc++dllを使用しています。関数の呼び出しに問題があります。おそらく私はメモリを適切に割り当てていませんか?私は意見がありません、次に何を試すべきか。ドキュメントやフォーラムのスレッドから私を助ける情報がこれ以上得られません。ヒントをいただければ幸いです。
ネイティブ関数を呼び出したい(例FooInterface
)。この関数は、TNativeFoo
入力および出力パラメーターとして構造体を取ります。構造TNativeFoo
にはDouble**
/Double[][]
データが含まれています。このフィールドは多次元配列と見なすことができますが、最初の次元の長さは1のみです。したがって、サイズが。の二重配列を指すポインターになりますItems
。
StringArray
長さのある構造体(char**
/ String[]
)にもaがありますがStringsCount
、使用されていないため、これは不適切です。エラーがこれと関係があるかどうかわからないので、私はそれについて言及します。以下は、ネイティブdllと構造に対して作成された定義です。
public interface Foodll extends StdCallLibrary {
Foodll INSTANCE = (Foodll) Native.loadLibrary("foodll.dll", Foodll.class);
public static class TNativeFoo extends com.sun.jna.Structure {
public TNativeFoo (){
super();
setAlignType(ALIGN_NONE);
}
public TNativeFoo(com.sun.jna.Pointer pointer,int offset) {
super();
setAlignType(ALIGN_NONE);
useMemory(pointer,offset);
read();
}
public TNativeFoo(TNativeFoo struct) {
this(struct.getPointer(),0);
}
public static class ByReference extends TNativeFoo implements com.sun.jna.Structure.ByReference {
ByReference() {}
ByReference(TNativeFoo struct){super(struct.getPointer(),0);}
}
public static class ByValue extends TNativeFoo implements com.sun.jna.Structure.ByValue {
ByValue() {}
ByValue(TNativeFoo struct){super(struct.getPointer(),0);}
}
public PointerByReference Data;
public NativeLong Items;
public PointerByReference IrrelevantStringArray;
public NativeLong StringsCounts = new NativeLong(0);
}
NativeLong FooInterface(TNativeFoo input, TNativeFoo output);
}
関数を呼び出すために、ネイティブヒープにメモリを割り当てて、そこにデータを書き込もうとします。例のようにネイティブヒープにデータを書き込んだ後、代替2の例のようにデータを読み取ることができました(ネイティブ関数を呼び出さずに、から直接これを試しましたinputFoo
)。以下の例のようにネイティブ関数を呼び出すと、致命的な例外が発生します。
呼び出し:
public class FooInvocationClass
{
public static FooInvocationMethod(double[] fooData)
{
Foodll foodllJnaLib = Foodll.INSTANCE;
Foodll.TNativeFoo outputFoo = new Foodll.TNativeFoo();
Foodll.TNativeFoo inputFoo = new Foodll.TNativeFoo();
//Writing input data to the native heap
Memory dataPointer = new Memory (fooData.length * Double.SIZE);
dataPointer.write(0, fooData, 0, fooData.length);
inputFoo.Data = new PointerByReference();
inputFoo.Data.setValue(dataPointer);
outputProfile.Data = new PointerByReference();
inputFoo.Items = outputFoo.Items = new NativeLong(fooData.length);
//Setting some irrelevant StringArray Parameters
inputFoo.IrrelevantStringArray = outputFoo.IrrelevantStringArray = new PointerByReference();
inputFoo.StringsCounts = outputFoo.StringsCounts = new NativeLong(0);
//Invocation
foodllJnaLib.FooInterface(inputFoo, outputFoo);
//Reading Output
Pointer outputFooDataPointer = outputFoo.Data.getValue();
//Reading Output alternative 1
Double[] outDataAlt1 = outputFooDataPointer.getDoubleArray(0, outputFoo.items);
//Reading Output alternative 2
Double[] outDataAlt2 = new Double[outputFoo.items];
for (int x = 0; x < outputFoo.items; x += 1)
{
outDataAlt2[x] = outputFooDataPointer.getDouble(x * 8);
}
}
}
例外:
# A fatal error has been detected by the Java Runtime Environment:
#
# Internal Error (0x0), pid=5904, tid=220
#
# JRE version: 7.0_04-b22
# Java VM: Java HotSpot(TM) Client VM (23.0-b21 mixed mode, sharing windows-x86 )
# Problematic frame:
# C [KERNELBASE.dll+0xb9bc] RaiseException+0x58
#
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# E:\Programme\apache-tomcat-7.0.27\bin\hs_err_pid5904.log
#
また、64ビットシステムで実行されている32ビットJVMとネイティブコードに問題があることも想像できます。JNAが「ネイティブdllが見つかりませんでした」という問題に直面したため、64ビットシステムに32ビットJVMをインストールしました。
編集:
私は自分が犯した間違いを見つけました。同じように見えますが、そうではない間違った構造定義を調べました。だから私は私の質問を変えなければなりません。
しかし、私は自分の質問を間違ったものにしました。皆さんの提案を試してみました。それらは私がトピックを理解するのを助けてくれました、そして私が正しい構造定義を見つけた後に私はそれらを試しました。よろしくお願いします。
ただし、例外は同じままです。おそらく、コードに複数のエラーがあります。ですから、ここでもう一度私の質問をします。うまくいけば、今は正しく、以前よりも多くの情報が含まれています。(会社に関して)いくつかのことをFooする必要がありましたが、セマンティクスは同じままです。
私は実際にはhファイルやソースコードを持っていません。私はプロジェクトに遅れて参加しましたが、パートタイムでしか取り組んでいません。他の誰かがC++/ CLIでネイティブ呼び出しをプログラミングしていて、それは機能しました。そこで、以下のコードを添付しました。c ++ / CLIコードの下には、変更されたJavaコードがあります。
c ++ / CLI:
typedef void (__stdcall *TFooInterface) (
LONGLONG *APrgId,
void *input,
void *output,
double value,
HANDLE AAppHandle,
HANDLE AProgessBar,
char *AText,
char **ReturnText
);
//-APrgID is a ID, which tells the Method, what type of processing it should do.
//-The void Pointers both take a TNativeFOO Structure. One is for the input, the other one is for the output.
//-The double-value is a Parameter for the algorithm.
//-The Handle Parameters are for a programm, the dll was created for. They give status about the processing or something like that. We now use the dll in an other context, so they aren't needed anymore.
//-char *AText amd. char **ReturnText are, also not needed anymore. They are for exception handling as far as I know. We handle the Exception in the new Context more general.
typedef struct {
double *Data;
long Items;
unsigned char *String;
long StringCounts;
double Value1, Value2;
char *FileName;
char *DataObject;
char *Comment;
bool Valid;
} TNativeFoo;
//-*Data is a double Array holding the data to process in TFooInterface
//-Items is the lenght of Data
//-*String and StringCounts are not needed anymore, because the dll is used in another way. I can't tell what it is for.
//-Value1, Value2 are Parameters used in the algorithm
//-FileName is for storing the result. Isn't used.
//-DataObject, Comment is also never used. I can't tell what it is for.
//-Valid is a success-flag of the algorithm.
void FooClass::FooIt(double[] FooData, HMODULE hFooLib)
{
TNativeFoo Input, Output; //Declaration of the Structures
LONGLONG PrgID;
LONGLONG ID;
double value;
double[] OutputData = new double[FooData.length];
ID =-35547318716283305;
//setting up the Structures
memset(&Input, 0, sizeof(TNativeFoo));
memset(&Output, 0, sizeof(TNativeFoo));
Output.Data = new double[FooData.length];
Input.Data = &(FooData[0]);
Input.Items = Output.Items = FooData.length;
Input.Value1 = Output.Value1 = 1.3;
Input.Value2 = Output.Value2 = 2.3;
Input.Valid = Output.Valid = true;
FooInterface = (TFooInterface) GetProcAddress(hFooLib, "FooInterface");
FooInterface(&ID, &Input, &Output, value, 0, 0, "", NULL);
for (long i=0; i<Output.Items; i++)
{
OutputData[i]= Output.Data[i];
}
...
}
Javaの定義:
public interface Foodll extends StdCallLibrary {
Foodll INSTANCE = (Foodll) Native.loadLibrary("foodll.dll", Foodll.class);
//Structure
public static class TNativeFoo extends com.sun.jna.Structure {
public TNativeFoo(){
setAlignType(Structure.ALIGN_NONE);
}
public TNativeFoo(com.sun.jna.Pointer pointer, int offset) {
super(pointer.share(offset));
setAlignType(Structure.ALIGN_NONE); //Tested all align-types. I was told this is the one used by the dlls
read();
}
public TNativeFoo(TNativeProfile struct) {
super(struct.getPointer());
setAlignType(Structure.ALIGN_NONE); //Tested all align-types. I was told this is the one used by the dlls
read();
}
public static class ByReference extends TNativeFoo implements com.sun.jna.Structure.ByReference {
ByReference() {}
ByReferenceTNativeFoo struct){super(struct.getPointer(),0);}
}
public static class ByValue extends TNativeFoo implements com.sun.jna.Structure.ByValue {
ByValue() {}
ByValueTNativeFoo struct){super(struct.getPointer(),0);}
}
public Pointer Data;
public double[] getData() {
if (this.Data == null) return null;
return this.Data.getDoubleArray(0, Items.intValue());
}
public void setData(double[] data) {
if (this.Data == null) {
this.Data = new Memory(data.length * 8);
}
this.Data.write(0, data, 0, data.length);
}
public NativeLong Items;
public String String;
public NativeLong StringCounts = new NativeLong(0);
public double Value1;
public double Value2;
public String FileName;
public String DataObject;
public String Comment;
public boolean Valid;
}
NativeLong FooInterface(DoubleByReference prgid, TNativeFoo input, TNativeFoo output, double value, Pointer aAppHandle, Pointer aProgessBar, String AText, String[] ReturnText);
}
Java-呼び出し:
public class FooInvocationClass
{
public static FooInvocationMethod(double[] fooData, ID)
{
Foodll foodllJnaLib = Foodll.INSTANCE;
Foodll.TNativeFoo outputFoo = new Foodll.TNativeFoo();
Foodll.TNativeFoo inputFoo = new Foodll.TNativeFoo();
inputFoo.setData(fooData);
outputFoo.setData(new double[fooData.length]);
inputFoo.Items = outputFoo.Items = new NativeLong(fooData.length);
inputFoo.String = outputFoo.String = "";
inputFoo.StringCounts = outputFoo.StringCounts = new NativeLong(0);
inputFoo.Value1 = outputFoo.Value1 = 0.1;
inputFoo.Value2 = outputFoo.Value2 = 0.3;
Double ID =-35547318716283305;
double value = 0.025;
impDriveFiltJnaLib.ProfileFilterInterface(new DoubleByReference(ID), input, output, value, null, null, null, null);
Double[] outDataAlt1 = outputFoo.getDate();
}
}
編集2
dllのファイルエラーの問題を解決した後、例外が変更されました。dllを再度コピーする必要がありました。これで、dllを読み込めない問題が解決しました。
#
# A fatal error has been detected by the Java Runtime Environment:
#
# EXCEPTION_ACCESS_VIOLATION (0xc0000005) at pc=0x027047b8, pid=800, tid=7584
#
# JRE version: 7.0_04-b22
# Java VM: Java HotSpot(TM) Client VM (23.0-b21 mixed mode, sharing windows-x86 )
# Problematic frame:
# C [FooDll.dll+0x47b8] FooInterface+0x2288
#
# Failed to write core dump. Minidumps are not enabled by default on client versions of Windows
#
# An error report file with more information is saved as:
# E:\Programme\apache-tomcat-7.0.27\bin\hs_err_pid800.log
#
# If you would like to submit a bug report, please visit:
# http://bugreport.sun.com/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#