49

How can I call Java functions from a C++ application?

I know about calling them from CMD (or similar techniques), but I would rather not use them.

Rakete1111
  • 47,013
  • 16
  • 123
  • 162
user63898
  • 29,839
  • 85
  • 272
  • 514

4 Answers4

25

As an example, check Creating a JVM from C. It shows a sample procedure to create a JVM and invoke a method. If the JVM already exists; e.g. your C program is invoked by the Java program (callback situation), you can cache the JNIEnv* pointer.

As an advice, be careful caching pointers to the JVM from C/C++, there are some semantics involved as to what you can cache and it could be invoked later on. For that, as Brian Agnew pointed out, check the JNI reference.

Daniel H.
  • 1,782
  • 16
  • 18
  • this type of invocation is what im looking for . the question is what is the con's of this method – user63898 Jul 29 '11 at 06:33
  • complexity. but I believe, without 3rd party tools, the only method from what I have read. – bbqchickenrobot Apr 03 '12 at 00:44
  • RE: "If the JVM already exists; e.g. your C program is invoked by the Java program (callback situation), you can cache the JNIEnv* pointer." Each thread has its own JNIEnv, do not share between threads. – Wheezil Oct 22 '21 at 09:45
19

Check out the JNI Invocation interface. This will allow you to embed a JVM within your C (or C++) application.

Note that various easier mechanisms exist to facilitate calling C/C++ from Java (e.g. JNA). It may be worth considering inverting your problem such that you can call from Java (I understand this may well not be possible for your particular application, however)

Favonius
  • 13,959
  • 3
  • 55
  • 95
Brian Agnew
  • 268,207
  • 37
  • 334
  • 440
  • 1
    This isn't your fault, but the JNI Infocation interface link is broken. It seems Oracle moved every JNI resource they had, because broken links are all over the place when looking for JNI information. – StockB Jan 16 '13 at 20:18
  • Looks like that link has been fixed now – Brian Agnew Jul 11 '13 at 11:52
6

This page is helpful: http://hildstrom.com/projects/jni/index.html

Suppose you have a Java class:

package foo;
public class bar {
    public static int timesTen(int input){
        return input * 10;
    }
}

Once you have a JVM and JNIEnv* (details omitted...) you can invoke the Java method from C++ as follows:

jclass myClass = env->FindClass("foo.bar");
jmethodID mid = env->GetStaticMethodID(myClass, "timesTen", "(I)I");
jint hundred = env->CallStaticIntMethod(myClass, mid, (jint)10);

This glosses over a lot of detail, including exception handling, which if omitted will crash your JVM. For all the gory details search on "Java Native Interface" and follow the Oracle links.

Since someone asked... here's how you get an Env*. Note that if the JVM called your native code, it will already have an Env*.

JNIEnv* env(0);
jint rv = vm->GetEnv((void**)&env, JNI_VERSION_1_6);
if (rv == JNI_OK) {
    return env;
} else if (rv == JNI_EDETACHED) {
    // This happens if you created the thread, not the JVM
    rv = vm->AttachCurrentThread((void**)&env, 0);
    if (rv != JNI_OK) {
        // error
    }
} else {
    // error
}

I cannot stress enough that using JNI to call Java from C/C++ is tremendously tedious and error-prone. Errors are cryptic and low-level. You must handle exceptions, and you must detach threads or things will get ugly.

Wheezil
  • 3,157
  • 1
  • 23
  • 36
  • 4
    While this link may answer the question, it is better to include the essential parts of the answer here and provide the link for reference. Link-only answers can become invalid if the linked page changes. – Perception Mar 14 '13 at 19:40
  • Where do you get `env` from? – Nayuki Jan 31 '20 at 05:25
  • That's the "details omitted part" ;-) Basically, you create a JVM, then each thread must have an Env. I added a little snippet. You also have to *detach* native threads from the JVM before they exit, or you will get nasty errors. – Wheezil Feb 01 '20 at 12:58
-5

Another simple way to call java methods from CPP is through batch file.

system() 

Is the method to call exe or bat files from the CPP. Put your class with the java path and the classpath in the batch file and call that batch file from the CPP using system("batch-file-name.bat").

It is easy and straight forward.

Murray Foxcroft
  • 12,785
  • 7
  • 58
  • 86
Aditya
  • 115
  • 1
  • 9