0

簡単な要約:

IKVM でコンパイルされた JAR から DLL へのライブラリは、.NET プロジェクトのいくつかのメソッドとクラスで動作しますが、特定のメソッドとクラスが例外をスローし、IKVM.Runtime.JNI が 64 ビット アドレスを 32 ビット アドレスに格納しようとしていることを示しているようです。変数、システム全体を 32 ビットにしたい場合。これにより、IllegalArgumentException がスローされます。

問題

.NET プロジェクトに統合する必要がある複数の JAR ファイルの形式の JAVA API があります。JAR ファイルは、CLASSPATH 内のディレクトリに基づいて、API のライセンス ファイルと構成ファイルを検索します。JAR ファイルは、java.library.path に含まれる DLL への JNI 呼び出しも使用します。

.NET プロジェクトには x86 ターゲットがあります。JNI に含まれる DLL には win64 と win32 の両方のバージョンがあるため、win32 ディレクトリにあるものを使用します。

これはすべて、.NET Framework 4 を使用して VS2010 で行われています。OS は 64 ビット Windows 7 です。

計画

さて、計画は、IKVM コンパイラを使用して JAR ファイルを DLL にコンパイルすることです。次に、これらの DLL を IKVM ライブラリと共に .NET プロジェクトに含め、その方法で Java API と対話できるようにします。

コンパイル

まず、log4j jar をコンパイルします。

~>ikvmc -target:library log4j-1.2.14.jar

IKVM.NET Compiler version 7.3.4830.0
Copyright (C) 2002-2013 Jeroen Frijters
http://www.ikvm.net/

note IKVMC0002: Output file is "log4j-1.2.14.dll"
warning IKVMC0100: Class "javax.jms.MessageListener" not found
...

ほとんど javax.jms.* と javax.mail.* を扱う約 20 ほどの警告がありますが、正常にコンパイルされるようです。

そして、残りを引き込みます。

~>ikvmc -platform:x86 -target:library -classloader:ikvm.runtime.ClassPathAssemblyClassLoader -r:log4j-1.2.14 { commons-io-1.4.jar } { commons-lang3-3.1.jar } { EngineAPI_PC-1.0.13.jar } { EngineAPI_PC-api-1.0.13.jar } { guice_no_aop-3.0.jar } { guice-assistedinject-3.0.jar } { inject-330.jar } { IVectorsMultiSpeaker4GResources-1.0.1.jar } { IVectorsResources-1.0.6.jar } { slf4j-api-1.7.2.jar } { slf4j-log4j12-1.7.2.jar }
IKVM.NET Compiler version 7.3.4830.0
Copyright (C) 2002-2013 Jeroen Frijters
http://www.ikvm.net/

warning IKVMC0126: Found assembly "log4j-1.2.14" using legacy search rule, pleas
e append '.dll' to the reference
note IKVMC0002: Output file is "commons-io-1.4.dll"
note IKVMC0002: Output file is "commons-lang3-3.1.dll"
note IKVMC0002: Output file is "EngineAPI_PC-1.0.13.dll"
note IKVMC0002: Output file is "EngineAPI_PC-api-1.0.13.dll"
note IKVMC0002: Output file is "guice_no_aop-3.0.dll"
note IKVMC0002: Output file is "guice-assistedinject-3.0.dll"
note IKVMC0002: Output file is "inject-330.dll"
note IKVMC0002: Output file is "IVectorsMultiSpeaker4GResources-1.0.1.dll"
note IKVMC0002: Output file is "IVectorsResources-1.0.6.dll"
note IKVMC0002: Output file is "slf4j-api-1.7.2.dll"
note IKVMC0002: Output file is "slf4j-log4j12-1.7.2.dll"
warning IKVMC0112: Emitted java.lang.IllegalAccessError in "es.agnitio.core3.Voi
ceSampleImpl.getIdentifiableData()Ljava.util.List;"
    ("Try to access class es.agnitio.core3.a from class es.agnitio.core3.VoiceSa
mpleImpl")
    (in EngineAPI_PC-1.0.13.dll)
warning IKVMC0112: Emitted java.lang.IllegalAccessError in "es.agnitio.core3.Voi
ceSampleImpl.getIdentifiableData()Ljava.util.List;"
    ("Try to access method es.agnitio.core3.a.<init>(Les.agnitio.core3.VoiceSamp
leImpl;Les.agnitio.core3.IdentifiableData;)V from class es.agnitio.core3.VoiceSa
mpleImpl")
    (in EngineAPI_PC-1.0.13.dll)

ご覧のとおり、32 ビット DLL を保証するために -platform:x86 が表示されます。-classloader:... を使用すると、後で CLASSPATH を編集して構成ファイルとライセンス ファイルを含むディレクトリを含めることができます。log4j DLL を参照し、残りの JAR をリストします。この後、各ファイルの DLL があります。

プロジェクトの設定

.NET プロジェクトでは、次を参照します。

  • ikvm-native-*.dll を除く、IKVM/bin ディレクトリ内のすべての DLL
  • IKVM/bin-x86 の JVM.DLL
  • 前のステップでコンパイルされた DLL。

プロジェクト ビルドに含まれるリンクとして、ikvm-native-win32-x86.dll をプロジェクトに追加します。プロジェクトに IKVM EXE を追加しません。また、JNI 呼び出しを行うことができるにもかかわらず、プロジェクトのデバッグ出力が、JVM.DLL または ikvm-native-win32-x86.dll を使用していることを示していないことにも注意してください。

私のプロジェクトには、ikvm:java.library.path と ikvm:java.class.path が設定されている App.config があります。

<appSettings>
    <add key="ikvm:java.library.path" value="C:\path\to\DLLs\for\JNI;" />
    <add key="ikvm:java.class.path" value="C:\path\to\config;C:\path\to\license;" />
</appSettings>

App.config には、すべての IKVM ライブラリのアセンブリ バインディングもあります。

プロジェクトのコンパイルと実行

java.io および es.agnitio.* 名前空間を含めます。JAVA プロジェクトのメソッドとクラスを使用して、正常にコンパイルできます。ライブラリは、config、license、および JNI DLL ファイルも正常に検出します。

アプリケーションを実行すると、JAVA ライブラリがロードされる間、JAVA 関数の最初の呼び出しがしばらく停止します。この時点で、次の出力が得られます。

[17:42:38.76691 ] loadLibrary: C:\path\to\DLLs\for\JNI\predj.dll, class loader: ikvm.runtime.ClassPathAssemblyClassLoader@3EDD7A7
[17:42:38.80491 ] Library loaded: C:\path\to\DLLs\for\JNI\predj.dll, handle = 0xF800000

すべての JNI ライブラリに対して、ネイティブ メソッドが正常にリンクされていることがわかります。この後、いくつかの Agnitio JAVA API クラスとメソッドが期待どおりに機能し、JAVA ファイル IO を実行できるようになりました。ただし、特定のメソッドでは次の例外が発生します。

*** exception in native code ***
java.lang.IllegalArgumentException: Can not set long field es.agnitio.data.Nativ
eMemoryJNI.ptrAddress to es.agnitio.core.ArrayForNativeCode
System.Collections.ListDictionaryInternal
Can not set long field es.agnitio.data.NativeMemoryJNI.ptrAddress to es.agnitio.
core.ArrayForNativeCode

   at __<Setter>(IReflectionException , Object , Int64 , Object )
   at IKVM.NativeCode.sun.reflect.ReflectionFactory.FieldAccessorImplBase.FieldA
ccessor`1.lazySet(Object obj, T value)
   at IKVM.NativeCode.sun.reflect.ReflectionFactory.FieldAccessorImplBase.FieldA
ccessor`1.lazySet(Object obj, T value, FieldAccessor`1 acc)
   at IKVM.NativeCode.sun.reflect.ReflectionFactory.FieldAccessorImplBase.LongFi
eld.setLong(Object obj, Int64 value)
   at IKVM.Runtime.JNIEnv.SetLongField(JNIEnv* pEnv, IntPtr obj, IntPtr fieldID,
 Int64 val)
   at es.agnitio.ivectors.IVectorsNative.updateStreaming4GSessionS(ArrayForNativ
eCode afnc1, ArrayForNativeCode afnc2, ArrayForNativeCode afnc3)
   at es.agnitio.ivectors.h.b(FeaturesNoJNA fnjna)
   at es.agnitio.core3.internal.d.a(FrontEndResult fer, Int32 i1, Int32 i2)
   at es.agnitio.core3.internal.d.a(Int32 i1, Int32 i2, List l)
   at es.agnitio.core3.internal.b.extractVoiceSamples(Int32 i, List l)
   at es.agnitio.core3.internal.b.extractVoiceSamples(Int32 i)
   at es.agnitio.core3.internal.b.extractVoiceSample(List l)
   at es.agnitio.modeling.ModelFactoryAbstract.a(List , List , List )
   at es.agnitio.modeling.ModelFactoryAbstract.trainModelFromAudio(AudioStandard
 as, List l)
   at es.agnitio.modeling.ModelFactoryAbstract.trainModelFromAudio(AudioStandard
 as)
   at BS3Test.Program.Main(String[] args) in C:\path\to\source\Program.cs:line 38

私の考え

Agnitio ライブラリはオブジェクトのアドレスを 32 ビット変数に格納しているように見えますが、IKVM ライブラリ メソッドはそれを 64 ビット アドレスに変換しているため、IllegalArgumentException が発生します。オンラインの多くのドキュメントでは、ikvm-native-*.dll が JNI 呼び出しが 32 ビットまたは 64 ビットのどちらで行われるかを判断すると述べていますが、私の JVM.dll または ikvm-native-win32-x86.dll が関与しているようには見えません。このプロセスではまったく。この問題を修正する方法 (またはこの Java ライブラリを統合するより良い方法) に関するアイデアはありますか?

編集:私の最初の印象は間違っていました。ikvm-native-win32-x86.dll と JVM.dll は、32 ビット バージョンのプロジェクトに正常に含まれています。エラーメッセージが何を示しているのか、今、私は少し途方に暮れています。

4

1 に答える 1

3

これはおそらくネイティブ コードのバグです。フィールド NativeMemoryJNI.ptrAddress を設定しようとしているように見えますが、NativeMemoryJNI (またはサブクラス) の代わりに ArrayForNativeCode 型のオブジェクトを渡します。

于 2013-05-17T19:11:50.147 に答える