private unsafe static long LoadLibrary(string filename, ClassLoaderWrapper loader) { Tracer.Info(Tracer.Jni, "loadLibrary: {0}, class loader: {1}", filename, loader); lock(JniLock) { IntPtr p = ikvm_LoadLibrary(filename); if(p == IntPtr.Zero) { Tracer.Info(Tracer.Jni, "Library not found: {0}", filename); return 0; } try { foreach(IntPtr tmp in loader.GetNativeLibraries()) { if(tmp == p) { // the library was already loaded by the current class loader, // no need to do anything ikvm_FreeLibrary(p); Tracer.Warning(Tracer.Jni, "Library was already loaded: {0}", filename); return p.ToInt64(); } } if(nativeLibraries.Contains(p)) { string msg = string.Format("Native library {0} already loaded in another classloader", filename); Tracer.Error(Tracer.Jni, "UnsatisfiedLinkError: {0}", msg); throw new java.lang.UnsatisfiedLinkError(msg); } Tracer.Info(Tracer.Jni, "Library loaded: {0}, handle = 0x{1:X}", filename, p.ToInt64()); IntPtr onload = ikvm_GetProcAddress(p, "JNI_OnLoad", IntPtr.Size * 2); if(onload != IntPtr.Zero) { Tracer.Info(Tracer.Jni, "Calling JNI_OnLoad on: {0}", filename); JNI.Frame f = new JNI.Frame(); int version; ClassLoaderWrapper prevLoader = f.Enter(loader); try { // TODO on Whidbey we should be able to use Marshal.GetDelegateForFunctionPointer to call OnLoad version = ikvm_CallOnLoad(onload, JavaVM.pJavaVM, null); Tracer.Info(Tracer.Jni, "JNI_OnLoad returned: 0x{0:X8}", version); } finally { f.Leave(prevLoader); } if(!JNI.IsSupportedJniVersion(version)) { string msg = string.Format("Unsupported JNI version 0x{0:X} required by {1}", version, filename); Tracer.Error(Tracer.Jni, "UnsatisfiedLinkError: {0}", msg); throw new java.lang.UnsatisfiedLinkError(msg); } } nativeLibraries.Add(p); loader.RegisterNativeLibrary(p); return p.ToInt64(); } catch { ikvm_FreeLibrary(p); throw; } } }