从C ++执行Java的简单性 [英] Simplicity for executing Java from C++

查看:135
本文介绍了从C ++执行Java的简单性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景信息:我习惯于用Java编程,我知道如何使用Eclipse和Visual Studio。

Background info: I am used to program in Java and I know how to use Eclipse and Visual Studio.

目标:创建一个GUI,最好在Visual Studio中执行Java函数。

Final objective: to create a GUI, preferably in Visual Studio, which executes Java functions.

>:C ++中的按钮,在单击时,执行Java函数并将结果返回给C ++。 (可能是通过调用JVM)

What I wish to accomplish from this question: a button in C++ which, on click, executes a Java function and returns the results to C++. (probably by invoking a JVM)

我真的怀疑在这里发布这个问题,但我找不到一个直接的答案,因此,我希望有人能为这个问题显示最简单的解决方案。

I have really doubt about posting this question here but I couldn't find a 'straightforward' answer anywhere; hence I hope someone can show the simplest solution possible for this question.

我目前考虑了以下数据结构:

I've currently considered the following datastructures:


  • 通过common文件(如.txt文件)共享数据(但是如何启动Java功能?)

  • 打开套接字

  • 通过服务器连接(过于复杂)

  • 从C ++调用JVM,然后执行Java文件这是最合理的方法,但这需要很多代码)

  • Sharing data through 'common' files such as .txt files (but then how do I start the Java functions?)
  • Opening a socket (seems too complicated for this problem)
  • Connecting through a server (too complicated)
  • Invoking a JVM from C++ which then executes the Java file (I think this is the most reasonable way but this needs a lot of code)

现在我知道了 Jace JNI SWIG ,但我认为他们非常方便制作复杂的程序,不容易接口。我不想制作一个复杂的程序,因此我觉得学习他们所有的命令是很麻烦。

Now I know about the existence of Jace, JNI and SWIG but I think they are very handy for making complicated programs, not easy interfaces. I don't want to make a complicated program hence I feel that learning all their commands is quite bothersome.

我也读了很多Stack Exchange问​​题完全相同但是所有的人似乎都给出非常复杂的答案。

I have also read up on a lot of Stack Exchange questions asking the exact same thing but all of them seem to give very complicated answers.

这里是我的问题:

从C ++执行(如果需要:预编译)Java函数的绝对最简单的方法是C ++代码将一些参数传递给此Java函数

提前感谢。

推荐答案


从C ++调用JVM,然后执行Java文件(我认为这是最合理的方法,但这需要很多代码)

Invoking a JVM from C++ which then executes the Java file (I think this is the most reasonable way but this needs a lot of code)

是的,这绝对是最合理的方法。使用JNI和调用API ,它甚至不会这些代码。

Yes, it definitely is the most reasonable way. And with JNI and the invocation API it's not even that much code.

您可以尝试像硬编码Oracle的路径JVM的 jvm.dll 或在程序文件夹中搜索名为 jvm.dll 的文件, hacky。但是,显然有一个很容易的解决方案:注册表。键 HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java运行时环境包含 REG_SZ 调用 CurrentVersion 。您可以读取此键的值(目前为 1.7 ),并使用该名称打开子键( HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\ Java Runtime Environment \ 1..7 )。该键将包含一个 REG_SZ RuntimeLib ,它是您的 jvm.dll 。不要担心程序文件 vs 程序文件(x86)。 WOW64将自动将您的注册表查询重定向到 HKLM \SOFTWARE\Wow6432Node 如果你是一个32位进程在64位窗口,该键包含32位的路径 jvm.dll 。代码:

You could try things like hardcoding the path to the Oracle JVM's jvm.dll or searching for a file called jvm.dll in the programs folder, but all that is obviously extremely hacky. However, there is apparently a pretty easy solution: The registry. The key HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment contains a REG_SZ called CurrentVersion. You can read the value of this key (currently it's 1.7) and open a child key with that name (HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment\1.7 in this example). That key will then contain a REG_SZ called RuntimeLib which is the path to your jvm.dll. Don't worry about Program files vs Program files (x86). WOW64 will automatically redirect your registry query to HKLM\SOFTWARE\Wow6432Node if you're a 32bit process on a 64bit windows and that key contains the path to the 32 bit jvm.dll. Code:

#include <Windows.h>
#include <jni.h> // C:\Program Files\Java\jdk1.7.0_10\include\jni.h

// ...

DWORD retval;
// fetch jvm.dll path from registry
HKEY jKey;
if (retval = RegOpenKeyEx(HKEY_LOCAL_MACHINE, TEXT("SOFTWARE\\JavaSoft\\Java Runtime Environment"), 0, KEY_READ, &jKey))
{
    RegCloseKey(jKey);
    // assuming you're using C++/CLI
    throw gcnew System::ComponentModel::Win32Exception(retval);
}

TCHAR versionString[16]; // version numbers shouldn't be longer than 16 chars
DWORD bufsize = 16 * sizeof(TCHAR);
if (retval = RegGetValue(jKey, NULL, TEXT("CurrentVersion"), RRF_RT_REG_SZ, NULL, versionString, &bufsize))
{
    RegCloseKey(jKey);
    // assuming you're using C++/CLI
    throw gcnew System::ComponentModel::Win32Exception(retval);
}

TCHAR* dllpath = new TCHAR[512];
bufsize = 512 * sizeof(TCHAR);
retval = RegGetValue(jKey, versionString, TEXT("RuntimeLib"), RRF_RT_REG_SZ, NULL, dllpath, &bufsize)
RegCloseKey(jKey);
if (retval)
{
    delete[] dllpath;
    // assuming you're using C++/CLI
    throw gcnew System::ComponentModel::Win32Exception(retval);
}



加载jvm.dll并获取CreateJavaVM函数



这部分很简单,你只需使用 LoadLibrary GetProcAddress



Loading the jvm.dll and getting the CreateJavaVM function

This part is pretty straightforward, you just use LoadLibrary and GetProcAddress:

HMODULE jniModule = LoadLibrary(dllpath);
delete[] dllpath;
if (jniModule == NULL)
    throw gcnew System::ComponentModel::Win32Exception();
typedef int (JNICALL * JNI_CreateJavaVM)(JavaVM** jvm, JNIEnv** env, JavaVMInitArgs* initargs);
JNI_CreateJavaVM createJavaVM = (JNI_CreateJavaVM)GetProcAddress(jniModule, "JNI_CreateJavaVM");



创建JVM



调用该函数:

Creating the JVM

Now you can invoke that function:

JavaVMInitArgs initArgs;
initArgs.version = JNI_VERSION_1_6;
initArgs.nOptions = 0;
JavaVM* jvm;
JNIEnv* env;
if ((retval = createJavaVM(&jvm, &env, &initArgs)) != JNI_OK)
    throw gcnew System::Exception(); // beyond the scope of this answer

现在有一个JVM正在你的进程中运行!您可能在启动应用程序时启动JVM。除非你是100%肯定,你只会从刚刚创建JVM的线程中调用Java代码,你可以丢弃 env 指针,但您必须保留 jvm 指针。

Congratulations! There's now a JVM running right inside your process! You would probably launch the JVM at the startup of your application. Unless you are 100% sure that you will only ever invoke Java code from the thread that just created the JVM, you can throw away the env pointer, but you have to keep the jvm pointer.

现在你创建了JVM,你的应用程序启动并运行,然后有人点击该按钮。现在你想调用Java代码。如果你是100%肯定,你现在是在上一步创建JVM的线程,并且仍然有 env 指针,那么你可以跳过这个。否则,执行快速检查当前线程是否附加到JVM并附加它,如果不是:

So now you created the JVM and your application is up and running and then somebody clicks that button. Now you want to invoke Java code. If you are 100% sure that you are right now on the thread that created the JVM in the previous step and you still have the env pointer, then you can skip this. Otherwise, perform a quick check if the current thread is attached to the JVM and attach it if it isn't:

JNIEnv* env;
bool mustDetach = false;
jint retval = jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
if (retval == JNI_EDETACHED)
{
    JavaVMAttachArgs args;
    args.version = JNI_VERSION_1_6;
    args.name = NULL;
    args.group = NULL;
    retval = jvm->AttachCurrentThread(&env, &args);
    mustDetach = true; // to clean up afterwards
}
if (retval != JNI_OK)
    throw gcnew System::Exception(); // should never happen
invokeJavaCode(env); // next step
if (mustDetach)
    jvm->DetachCurrentThread();



调用Java代码



在那里,你想调用那个Java代码,你甚至有 env 指针。你想要最简单的解决方案,所以这是你如何调用一个静态方法:

Invoking Java code

Now you are right there, you want to invoke that Java code and you even have the env pointer. You want the easiest solution, so this is how you call a static method:

jclass clazz = env->FindClass("com/myself/MyClass");
if (clazz == NULL)
    throw gcnew System::Exception();
jmethodID mid = env->GetStaticMethodID(clazz, "myStaticMethod", "<signature>");
if (mid == NULL)
    throw gcnew System::Exception();
<type> returnedValue = env->CallStatic<type>Method(clazz, mid, <arguments>);

您可以使用 javap -s 线工具)来确定方法的签名。 < type> 可以是任何原始类型(它必须与Java方法的返回类型相匹配)。参数可以是任何原始类型,只要它们匹配Java方法的参数。

You can use javap -s (command line tool) to determine a method's signature. <type> can be any primitive type (it must match the return type of the Java method). The arguments can be of any primitive type, as long as they match the arguments of the Java method.

有它:在Windows上从C ++调用Java代码的最简单的方法(实际上只有前两个部分是windows特定的...)。哦,也是最有效的一个。螺钉数据库和文件。使用 127.0.0.1 套接字将是一个选项,但是效率显着降低,可能不会比这更少的工作。哇,这个答案比我预期的有点长。希望它有帮助。

And there you have it: The easiest way to invoke Java code from C++ on Windows (actually only the first two parts are windows-specific...). Oh, and also the most efficient one. Screw databases and files. Using 127.0.0.1 sockets would be an option but that's significantly less efficient and probably not less work than this. Wow, this answer is a bit longer than I expected. Hopefully it helps.

这篇关于从C ++执行Java的简单性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆