IKVM编译的DLL中的IllegalArgumentException

时间:2013-05-17 14:33:29

标签: .net dll x86 32-bit ikvm

快速摘要:

我的IKVM编译的JAR到DLL库使用.NET项目中的一些方法和类,但是特定的一个是抛出异常,似乎表明我的IKVM.Runtime.JNI正在尝试存储64位地址到32位变量,当我希望整个系统是32位。这会导致抛出IllegalArgumentException。

问题

我有多个JAR文件形式的JAVA API需要集成到.NET项目中。 JAR文件根据CLASSPATH中的目录搜索API的许可证和配置文件。 JAR文件还使用对java.library.path中包含的DLL的JNI调用。

.NET项目有一个x86目标。 JNI包含的DLL都有win64和win32版本,因此我使用win32目录中的DLL。

这一切都发生在使用.NET Framework 4的VS2010中。操作系统是64位Windows 7。

计划

好的,所以计划是使用IKVM编译器将JAR文件编译为DLL。然后,在.NET项目中包含这些DLL以及IKVM库,并能够以这种方式与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
...

大约有20个左右的警告处理javax.jms。*和javax.mail。*,但似乎编译正常。

然后,我拉其余的。

~>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)

如您所见,我看到-platform:x86以确保32位DLL。使用-classloader:...是必要的,以便稍后可以编辑CLASSPATH包含带有配置和许可证文件的目录。我引用了log4j DLL并列出了剩余的JAR。在此之后,我为每个文件都有DLL。

设置项目

在.NET项目中,我引用:

  • IKVM / bin目录中除ikvm-native之外的所有DLL - * .dll
  • IKVM / bin-x86中的JVM.DLL
  • 上一步中编译的DLL。

我将ikvm-native-win32-x86.dll添加到项目中,作为项目构建中包含的链接。我没有将任何IKVM EXE添加到项目中。我还应该注意,项目调试输出在任何时候都没有表明它使用JVM.DLL或ikvm-native-win32-x86.dll,尽管能够进行JNI调用。

我的项目有一个App.config,其中设置了ikvm:java.library.path和ikvm:java.class.path:

<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项目中的方法和类并成功编译。该库还成功找到配置,许可证和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位版本成功包含在项目中。我现在对错误信息的含义感到有点失落。

1 个答案:

答案 0 :(得分:3)

这可能是本机代码中的一个错误。看起来它试图设置字段NativeMemoryJNI.ptrAddress,但它传递一个ArrayForNativeCode类型的对象而不是NativeMemoryJNI(或子类)。