1

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.
#
4

2 に答える 2

2

私は2つの提案があります:-

  1. 指定されたc/c++ヘッダーのJavaコードを生成するためにjnaeratorを使用してみてください。(これは開始するのに非常に良いベースになります)。

  2. 環境に応じて、ネイティブのdouble/floatサイズはJavaのdouble/floatとは異なります。つまり、nativedoubleはJavafloatと同じである可能性があります。したがって、これも確認する必要があります。

したがって、正確にネイティブが必要とするものを取得するには、さまざまな構造の組み合わせを使用して独自の分析を行う必要があります。正確に合格しないと、クラッシュします。

回答も投稿してください。

于 2012-05-21T16:05:25.813 に答える
1

構造に配置を使用しないのはなぜですか?それがクラッシュの最も可能性の高い原因です。Javaのフィールドオフセット(Structure.toString()で通知されます)がネイティブコードのフィールドオフセットと同じであることを確認します。

PointerByReference呼び出し先が呼び出し元から渡されたアドレスにポインターの値を書き込む関数に渡されることを目的としています。あなたの使用法は技術的には正しいですが、それは実際にはあなたの実際の意図を曖昧にします。

構造体に何らかのポインタが含まれている場合は、の型マッピングから始めて、Pointerその後、必要に応じて型マッピングを調整する必要があります。 PointerByReference構造体フィールドとしては決して適切ではありません。

   public static class TNativeFoo extends com.sun.jna.Structure {

       public TNativeFoo (){ }
       public TNativeFoo(com.sun.jna.Pointer pointer, int offset) {
            super(pointer.share(offset));
            read();
        }
        public TNativeFoo(TNativeFoo struct) {
            super(struct.getPointer());
            read();
        }
        // NOTE: use Java conventions for field names, please
        private Pointer buffer;
        public Pointer data = new Memory(Pointer.SIZE);
        public NativeLong items;
        public Pointer irrelevantStringArray = new Memory(Pointer.SIZE);
        public NativeLong stringsCounts = new NativeLong(0);

        public double[] getData() { 
            Pointer p = data.getPointer(0);
            if (p == null) return null;
            return p.getDoubleArray(items.intValue());  
        }
        public void setData(double[] data) {
            Pointer p = this.data.getPointer(0);
            if (p == null) {
               p = buffer = new Memory(data.length * 8);    
               this.data.setPointer(0, buffer);
            }
            p.write(0, data, 0, data.length);
        }
    }

    NativeLong FooInterface(TNativeFoo input, TNativeFoo output);
}

Double.SIZEは、バイトではなくビット単位のdoubleのサイズであるため、実際に必要なサイズの8倍を割り当てることに注意してください。

于 2012-05-21T15:53:10.113 に答える