예제 #1
0
        /// <summary>
        /// Create the Java VM and wrap it.
        /// </summary>
        /// <param name="jvmDllPath">(Optional) Path to jvm.dll where we'll load the JNI library. If not provided we'll try to infer its location from the Java install path.</param>
        /// <param name="attemptVmReuse">
        /// This is an annoying workaround to a fundamental JNI problem: you can't host a JVM within the process again once you've hosted it once
        /// (ever, even if you destroy the first one). So if this flag is <c>true</c>, we'll attempt to find an existing JVM in the process and use that
        /// if available, and we won't destroy the JVM on dispose so subsequent constructions of this object will succeed.
        /// The downside of reuse of course is that if we're reusing it then we won't be able to construct it with fresh arguments.
        /// </param>
        internal JniWrapper(string jvmDllPath, bool attemptVmReuse, IEnumerable <JavaOption> options)
        {
            _currentThreadEnv = new ThreadLocal <IntPtr>(() =>
            {
                IntPtr ret;
                unsafe
                {
                    if (_vm.GetDelegate <GetEnv>()(_vmP, (IntPtr)(&ret), _jniVersion) == -2)
                    {
                        _vm.GetDelegate <AttachCurrentThread>()(_vmP, (IntPtr)(&ret), IntPtr.Zero);
                    }
                    return(ret);
                }
            });
            if (String.IsNullOrEmpty(jvmDllPath))
            {
                string javaHome = GetJavaInstallationPath();
                _vmDll = Path.Combine(javaHome, "bin", "server", "jvm.dll");
            }
            else
            {
                _vmDll = jvmDllPath;
            }
            if (!File.Exists(_vmDll))
            {
                throw new InvalidOperationException("Couldn't find the runtime library for Java at: " + _vmDll);
            }
            IntPtr envP;
            IntPtr vmP;

            _vmDllModule = LoadLibrary(_vmDll);
            if (_vmDllModule == IntPtr.Zero)
            {
                throw new Win32Exception();
            }
            if (attemptVmReuse)
            {
                _vmReuse = true;
                int numVms;
                unsafe
                {
                    ThrowOnBadResult(GetDelegateFromJni <GetCreatedJavaVMs>("JNI_GetCreatedJavaVMs")(&vmP, 1, out numVms), "GetCreatedJavaVMs");
                    if (numVms >= 1)
                    {
                        _vmP = vmP;
                        _vm  = (JavaVM)Marshal.PtrToStructure(vmP, typeof(JavaVM));
                        ThrowOnBadResult(_vm.GetDelegate <AttachCurrentThread>()(_vmP, (IntPtr)(&envP), IntPtr.Zero), "AttachCurrentThread");
                        _envP = envP;
                        _env  = (JniEnv)Marshal.PtrToStructure(envP, typeof(JniEnv));
                        return;
                    }
                }
            }
            JavaVMInitArgs vmArgs = new JavaVMInitArgs();

            GetDelegateFromJni <GetDefaultJavaVMInitArgs>("JNI_GetDefaultJavaVMInitArgs")(ref vmArgs);
            vmArgs.Version   = _jniVersion;
            vmArgs._nOptions = options.Count();
            vmArgs._options  = Marshal.AllocHGlobal(vmArgs._nOptions * Marshal.SizeOf(typeof(JavaVMOption)));
            IntPtr vmArgsP = Marshal.AllocHGlobal(Marshal.SizeOf(vmArgs));

            try
            {
                int optionsLocation = 0;
                foreach (JavaOption currentOption in options)
                {
                    Marshal.StructureToPtr(currentOption.ActualOption, vmArgs._options + optionsLocation * Marshal.SizeOf(typeof(JavaVMOption)), false);
                    optionsLocation++;
                }
                Marshal.StructureToPtr(vmArgs, vmArgsP, false);
                unsafe
                {
                    ThrowOnBadResult(GetDelegateFromJni <CreateJavaVM>("JNI_CreateJavaVM")(&vmP, &envP, vmArgsP), "CreateJavaVM");
                    _vm   = (JavaVM)Marshal.PtrToStructure(vmP, typeof(JavaVM));
                    _env  = (JniEnv)Marshal.PtrToStructure(envP, typeof(JniEnv));
                    _envP = envP;
                    _vmP  = vmP;
                }
            }
            finally
            {
                Marshal.DestroyStructure(vmArgsP, typeof(JavaVMInitArgs));
                Marshal.FreeHGlobal(vmArgsP);
                Marshal.FreeHGlobal(vmArgs._options);
            }
        }