Одна возможность, как уже упоминалось другими, состоит в том, чтобы создать общую библиотеку (.dll) и вызывать ее из нативного кода и из Java для обмена данными.
Однако,если вы хотите вызвать функцию C, определенную в собственном коде в том же модуле, что и модуль, созданный JVM, вы можете использовать RegisterNatives.
Простой пример
- Программа C создает JVM
- , она вызывает Main класса
- Основные вызовы Javaобратно функцию C с именем connect0 в вызывающем коде C
- , чтобы иметь контрольный пример, нативная функция C создает строку Java и возвращает ее
- сторона Java печатает результат
Java
package com.software7.test;
public class Main {
private native String connect0() ;
public static void main(String[] args) {
Main m = new Main();
m.makeTest(args);
}
private void makeTest(String[] args) {
System.out.println("Java: main called");
for (String arg : args) {
System.out.println(" -> Java: argument: '" + arg + "'");
}
String res = connect0(); //callback into native code
System.out.println("Java: result of connect0() is '" + res + "'"); //process returned String
}
}
Программа C
Можно создать виртуальную машину Java в C, как показано здесь (работает не только с cygwin, но и с VS 2019), а затем регистрируется с помощью обратных вызовов RegisterNatives.Таким образом, используя функцию invoke_class из ссылки выше, она может выглядеть следующим образом:
#include <stdio.h>
#include <windows.h>
#include <jni.h>
#include <stdlib.h>
#include <stdbool.h>
...
void invoke_class(JNIEnv* env) {
jclass helloWorldClass;
jmethodID mainMethod;
jobjectArray applicationArgs;
jstring applicationArg0;
helloWorldClass = (*env)->FindClass(env, "com/software7/test/Main");
mainMethod = (*env)->GetStaticMethodID(env, helloWorldClass, "main", "([Ljava/lang/String;)V");
applicationArgs = (*env)->NewObjectArray(env, 1, (*env)->FindClass(env, "java/lang/String"), NULL);
applicationArg0 = (*env)->NewStringUTF(env, "one argument");
(*env)->SetObjectArrayElement(env, applicationArgs, 0, applicationArg0);
(*env)->CallStaticVoidMethod(env, helloWorldClass, mainMethod, applicationArgs);
}
jstring connect0(JNIEnv* env, jobject thiz);
static JNINativeMethod native_methods[] = {
{ "connect0", "()Ljava/lang/String;", (void*)connect0 },
};
jstring connect0(JNIEnv* env, jobject thiz) {
printf("C: connect0 called\n");
return (*env)->NewStringUTF(env, "Some Result!!");
}
static bool register_native_methods(JNIEnv* env) {
jclass clazz = (*env)->FindClass(env, "com/software7/test/Main");
if (clazz == NULL) {
return false;
}
int num_methods = sizeof(native_methods) / sizeof(native_methods[0]);
if ((*env)->RegisterNatives(env, clazz, native_methods, num_methods) < 0) {
return false;
}
return true;
}
int main() {
printf("C: Program starts, creating VM...\n");
JNIEnv* env = create_vm();
if (env == NULL) {
printf("C: creating JVM failed\n");
return 1;
}
if (!register_native_methods(env)) {
printf("C: registering native methods failed\n");
return 1;
}
invoke_class(env);
destroy_vm();
getchar();
return 0;
}
Результат
Ссылки
Создание JVM из программы на C: http://www.inonit.com/cygwin/jni/invocationApi/c.html
Регистрация собственных методов: https://docs.oracle.com/en/java/javase/11/docs/specs/jni/functions.html#registering-native-methods