从C++执行Java的简单性

 2023-01-21    304  

问题描述

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

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

从C++执行Java的简单性

我希望从这个问题中完成的工作:C ++中的一个按钮,单击时,执行Java功能并将结果返回到C ++. (可能通过调用JVM)

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

  • 通过”通用”文件(例如.txt文件)共享数据(但是如何启动Java函数?)
  • 打开一个插座(对于这个问题来说似乎太复杂了)
  • 通过服务器连接(太复杂)
  • 调用C ++的JVM,然后执行Java文件(我认为这是最合理的方法,但这需要很多代码)

现在,我知道Jace,JNI和SWIG的存在,但我认为它们非常方便地制作复杂的程序,而不是简单的接口.我不想制作一个复杂的程序,因此我觉得学习所有命令都很麻烦.

我还阅读了许多堆栈交换问题,问完全相同的事情,但所有这些都给出了非常复杂的答案.

所以这是我的问题:

从C ++执行A(必要的:预编译)Java函数的绝对最简单方法是什么,其中C ++代码将一些参数传递给此Java函数

预先感谢.

推荐答案

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

是的,这绝对是最合理的方法.并与JNI和甚至没有那么多代码.

查找JVM.DLL

您可以尝试使用硬编码到Oracle JVM的jvm.dll的路径,或在程序文件夹中搜索称为jvm.dll的文件,但显然所有这些都非常骇客.但是,显然有一个非常简单的解决方案:注册表.键HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment包含一个称为CurrentVersion的REG_SZ.您可以读取此键的值(当前是1.7),并打开带有该名称的子密钥(在此示例中HKEY_LOCAL_MACHINE\SOFTWARE\JavaSoft\Java Runtime Environment\1.7).然后,该键将包含一个REG_SZ称为RuntimeLib的REG_SZ,这是通往jvm.dll的路径.不用担心Program files vs Program files (x86). WOW64将自动将您的注册表查询重定向到HKLM\SOFTWARE\Wow6432Node如果您是64位窗口上的32位进程,并且该键包含通往32位jvm.dll的路径.代码:

#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:

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

现在您可以调用该功能:

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指针.

获取JNI环境(可选)

因此,现在您创建了JVM,并且您的应用程序正在启动并运行,然后有人单击该按钮.现在您要调用Java代码.如果您是100%确定的,您现在就在上一步中创建JVM的线程上,并且仍然具有env指针,则可以跳过此.否则,请执行快速检查是否将当前线程连接到JVM,并将其连接到:

:

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指针.您想要最简单的解决方案,因此这就是您调用静态方法的方式:

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方法的参数,这些参数都可以是任何原始类型.

.

结束

您有:从Windows上C ++调用Java代码的最简单方法(实际上只有前两个部分是Windows特定的...).哦,也是最有效的.螺丝数据库和文件.使用127.0.0.1插座将是一种选择,但效率明显降低,工作可能并不比这更少.哇,这个答案比我预期的要长.希望它能有所帮助.

以上所述是小编给大家介绍的从C++执行Java的简单性,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对77isp云服务器技术网的支持!

原文链接:https://77isp.com/post/26217.html

=========================================

https://77isp.com/ 为 “云服务器技术网” 唯一官方服务平台,请勿相信其他任何渠道。