1

I need to call some Java functions from C code. I've found some tutorial on how create new jvm from C, but I need an existing jvm (I know her PID). Furthermore, in my case, C dll was invocated by Java using JNI, I need to callback that JVM from C.

Here a portion of my code:

JAVA:

public class HelloJNI {

    static {
        // hello.dll on Windows or libhello.so on Linux
        System.loadLibrary("hello");
    }

    // native method for call C dll
    private native String getHello(int jvmProcessId);

    public String doHello(){
        return getHello(myProcessId);
    }
}

C:

#include "hellojni_actions_HelloJNI.h"

void invoke_class(JNIEnv* env) {
    // HERE I NEED TO CALL A METHOD OF JAVA CLASS WHICH LOADED ME (HelloJNI.java) IN THE SAME JVM
}

JNIEXPORT jstring JNICALL Java_hellojni_actions_HelloJNI_getHello
  (JNIEnv *env, jobject thisObj, jint jvmProcessId){
    invoke_class(env);
    return (*env)->NewStringUTF(env, "Testing...");

}
Tommaso DS
  • 211
  • 2
  • 14
  • 1
    Unclear what you are asking, as the code you show seems to imply that the C DLL is already loaded in the JVM process. Anyway, you may read http://stackoverflow.com/questions/22441878/attach-to-already-running-jvm/22450463#22450463 – manuell Jun 17 '14 at 21:21
  • I agree, after re-reading please specify if your native code is already loaded in the JVM or if you are trying to "inject" native code into an already running VM. – Alex Barker Jun 18 '14 at 15:51

2 Answers2

1

I've done something like that some time ago and can paste some code fragments (error checking to be done):

Please note that the method called is an object method of obj

void callJavaMethod( JNIEnv *env, jobject obj )
{
     jclass    cl;
     jmethodID id;
     jstring   js1;
     jstring   js2;
     jobject   byteArray;

     /* Im looking for byte[] javaMethod( String s1, String s2 ) */
     cl = (*env)->GetObjectClass( env, obj );
     id = (*env)->GetMethodID( env, cl, "javaMethod", "(Ljava/lang/String;Ljava/lang/String;)[B" );

     /* and now it's called */
     js1 = (*env)->NewStringUTF(env, "Hello");
     js2 = (*env)->NewStringUTF(env, "Java");

     byteArray = (*env)->CallObjectMethod( env, obj, js1, js2 );
     /* for other return types there are other CallxxxMethod() functions */

     ...
}

The JNI API Documentation for Java 7 can be found here (should be quite the same for Java 6)

Ingo Leonhardt
  • 9,435
  • 2
  • 24
  • 33
  • This is what I've done. But JNIEnv is the one that you receive from calling Java class? If I try to search some classes in it I'll receive ClassDefNotFoundException. – Tommaso DS Jun 18 '14 at 13:10
  • 1
    Yes, `JNIEnv` is the environment of the JVM your C hode has been called from. You should be able to find classes by calling `(*env)->FindClass( env, name )`. Note that `name` has to be fully qualified, e.g. `"java/lang/String"`, not just `"String"` – Ingo Leonhardt Jun 18 '14 at 13:19
  • Instead of finding classes in C and then calling appropriate Constructors etc., it's maybe easier to create an object in Java and pass it as a `jobject` parameter to the jni function – Ingo Leonhardt Jun 18 '14 at 13:22
  • Ok, just done and it works. But when I try to do the same in c++ (changing signature of FindClass, FindMethod... for c++) I'll receive an UnsatisfiedLinkError retrieving my method. Does somithing change in c++? Thanks. – Tommaso DS Jun 19 '14 at 14:20
0

You cannot do this in a cross platform way unless you do the shared library loading from Java or modify your Java code to utilize some kind of IPC. If you only care about Windows, you can abuse SetWindowsHookEx to accomplish your goal or use the CreateRemoteThread function to drop a new thread on the existing JVM pid.

Community
  • 1
  • 1
Alex Barker
  • 4,316
  • 4
  • 28
  • 47
  • The CreateRemoteThread trick wants the LoadLibrary address as entry point. You don't realy end up with a new thread. – manuell Jun 21 '14 at 05:35