10

JNAを使用してJavaから呼び出そうとしているCの関数があります。

int myCfunc(void *s, int *ls);

JNAのドキュメントによると、void*はcom.sun.jna.Pointer関数に渡される必要があります。JNAを使用するJavaでは、上記の関数は次のようにラップされると思います。

public interface myWrapper extends Library{ 
    public int myCfunc(Pointer s, IntByReference ls);
}

ポインタにリンクし、パラメータsを渡す必要があるオブジェクトは、次のようなJNA構造を実装するクラスになります。

public class myClass extends Structure{
    public int x;
    public int y;
    public int z;
}

残念ながら、パラメータlsはクラスの長さをバイト単位で表す整数です。Javaには関数がないsizeofため、これにより複雑さが増します。私が抱えているもう1つの大きな問題は、オブジェクトの内容をネイティブメモリに正しく渡したり戻したりしていることを確認することです。

私のコードは次のようになります。

import com.sun.jna.Native;
import com.sun.jna.Pointer;
import com.sun.jna.Structure;
import com.sun.jna.ptr.IntByReference;

public void foo(){
    myWrapper wrapper = (myWrapper) Native.loadLibrary("SomeDllWithLegacyCode", myWrapper.class);

    myClass myObj = new myClass();
    myObj.x = 1;
    myObj.y = 2;
    Pointer myPointer = myObj.getPointer();

    int size = Native.getNativeSize(myClass.class);
    IntByReference len = new IntByReference(size);

    myObj.write(); //is this required to write the values in myObj into the native memory??
    wrapper.myCfunc(myPointer, len);
    myObj.read();  //does this read in the native memory and push the values into myObj??

    myPointer.clear(size); //is this required to clear the memory and release the Pointer to the GC??
}

渡されたデータのサイズがC関数で予想されるよりも大きいというエラーが発生します。

上記のコードは、同様の問題を扱っている質問に対するこの回答で提供されているのとほぼ同じ種類の手順に従いますが、C#です。私はそれがC#で動作することを試し、テストしました。

私の質問はStackoverflowの別の質問と似ていますが、クラスへのポインターではなく、IntByReferenceへのポインターを扱います。

4

1 に答える 1

6

まず、JNA は自動的に独自のメモリ割り当てを処理します。これは、次の行が役に立たないことを意味します (メモリ スタックを損傷する可能性があります)。

myPointer.clear(size); //is this required to clear the memory and release the Pointer to the GC??

次に、ネイティブ ポインター型も自動的に処理します。これは、以下の両方の行が同じであることを意味します。

public int myCfunc(Pointer s, IntByReference ls);
public int myCfunc(myClass s, IntByReference ls);

したがって、JNAは あなたmyObj.write();readために行います。

以下は 100% 正しいですがlen.getValue()、呼び出しの前後にログを記録することをお勧めしますmyCfunc(これにより 3*4=12 ; 3 int of 4 bytes が返されます):

int size = Native.getNativeSize(myClass.class);
IntByReference len = new IntByReference(size);

これがすべて正しければ、構造のプロトタイプにエラーがある可能性があります。

私の経験から、これは主に古い C ヘッダー ファイルまたは古いライブラリが原因です。

  • 構造体の値がintであると述べているヘッダーバージョン2.0を使用していますが、バイト構造を取るライブラリv1.0にリンクしています
  • 構造体の値が int であることを示すヘッダー バージョン 2.0 を使用していますが、2 つの int と 1 バイトを取るライブラリ v1.9 に対するリンク

最後に、コードは次のようになります。

public void foo(){
    myWrapper wrapper = (myWrapper) Native.loadLibrary("SomeDllWithLegacyCode", myWrapper.class);

    myClass myObj = new myClass();
    myObj.x = 1;
    myObj.y = 2;

    int size = Native.getNativeSize(myClass.class);
    IntByReference len = new IntByReference(size);

    //log len.getValue
    wrapper.myCfunc(myObj, len);
    //log len.getValue
}

また、デバッグ目的で len の値を自発的に減らすこともできます。

IntByReference len = new IntByReference(size-1);
IntByReference len = new IntByReference(size-2);
IntByReference len = new IntByReference(size-3);
//...
IntByReference len = new IntByReference(size-11);

これはあなたが望んでいないことをしませんが、少なくとも正しい「最大長」を与えるはずです

于 2010-12-24T14:24:59.803 に答える