2011-09-24 6 views
16

estoy tratando de invocar la máquina virtual de Java desde C++ siguiendo el ejemplo encontró here:invocación de Java desde C++

Básicamente tengo un pequeño programa en Java:

public class TestJNIInvoke 
{ 
    public static void main(String[] args) 
    { 
    System.out.println(args[0]); 
    } 
} 

entonces tengo un programa en C++ que Quiero crear una JVM y llamar a la clase TestJNIInvoke:

#include <jni.h> 
#include <cstdlib> 
#define PATH_SEPARATOR ';' /* define it to be ':' on Solaris */ 
#define USER_CLASSPATH "." /* where Prog.class is */ 

using namespace std; 

int main() { 
    JNIEnv *env; 
    JavaVM *jvm; 
    jint res; 
    jclass cls; 
    jmethodID mid; 
    jstring jstr; 
    jclass stringClass; 
    jobjectArray args; 

#ifdef JNI_VERSION_1_2 
    JavaVMInitArgs vm_args; 
    JavaVMOption options[1]; 
    options[0].optionString = 
     "-Djava.class.path=" USER_CLASSPATH; 
    vm_args.version = 0x00010002; 
    vm_args.options = options; 
    vm_args.nOptions = 1; 
    vm_args.ignoreUnrecognized = JNI_TRUE; 
    /* Create the Java VM */ 
    res = JNI_CreateJavaVM(&jvm, (void**)&env, &vm_args); 
#else 
    JDK1_1InitArgs vm_args; 
    char classpath[1024]; 
    vm_args.version = 0x00010001; 
    JNI_GetDefaultJavaVMInitArgs(&vm_args); 
    /* Append USER_CLASSPATH to the default system class path */ 
    sprintf(classpath, "%s%c%s", 
      vm_args.classpath, PATH_SEPARATOR, USER_CLASSPATH); 
    vm_args.classpath = classpath; 
    /* Create the Java VM */ 
    res = JNI_CreateJavaVM(&jvm, &env, &vm_args); 
#endif /* JNI_VERSION_1_2 */ 

    if (res < 0) { 
     fprintf(stderr, "Can't create Java VM\n"); 
     exit(1); 
    } 
    cls = (*env)->FindClass(env, "TestJNIInvoke"); 
    if (cls == NULL) { 
     goto destroy; 
    } 

    mid = (*env)->GetStaticMethodID(env, cls, "main", 
            "([Ljava/lang/String;)V"); 
    if (mid == NULL) { 
     goto destroy; 
    } 
    jstr = (*env)->NewStringUTF(env, " from CPP!"); 
    if (jstr == NULL) { 
     goto destroy; 
    } 
    stringClass = (*env)->FindClass(env, "java/lang/String"); 
    args = (*env)->NewObjectArray(env, 1, stringClass, jstr); 
    if (args == NULL) { 
     goto destroy; 
    } 
    (*env)->CallStaticVoidMethod(env, cls, mid, args); 

destroy: 
    if ((*env)->ExceptionOccurred(env)) { 
     (*env)->ExceptionDescribe(env); 
    } 
    (*jvm)->DestroyJavaVM(jvm); 
} 

pero cuando intento compilar el programa C++ consigo este error:

c:\java\JNI> g++ -I"c:\Program Files\Java\jdk1.7.0\include"-I"c:\ProgramFiles\Java\jdk1.7.0\include\win32" -c TestJNIInvoke.cpp 


TestJNIInvoke.cpp: In function 'int main()': 
TestJNIInvoke.cpp:20:31: warning: deprecated conversion from string constant to 
'char*' 
TestJNIInvoke.cpp:44:18: error: base operand of '->' has non-pointer type 'JNIEn 
v' 
TestJNIInvoke.cpp:49:18: error: base operand of '->' has non-pointer type 'JNIEn 
v' 
TestJNIInvoke.cpp:54:19: error: base operand of '->' has non-pointer type 'JNIEn 
v' 
TestJNIInvoke.cpp:58:26: error: base operand of '->' has non-pointer type 'JNIEn 
v' 
TestJNIInvoke.cpp:59:19: error: base operand of '->' has non-pointer type 'JNIEn 
v' 
TestJNIInvoke.cpp:63:12: error: base operand of '->' has non-pointer type 'JNIEn 
v' 
TestJNIInvoke.cpp:66:16: error: base operand of '->' has non-pointer type 'JNIEn 
v' 
TestJNIInvoke.cpp:67:16: error: base operand of '->' has non-pointer type 'JNIEn 
v' 
TestJNIInvoke.cpp:69:12: error: base operand of '->' has non-pointer type 'JavaVM' 

¿Alguna idea?

Gracias

+0

Debe incluir un comentario sobre lo que no funciona con su código. ¿Recibes un error o simplemente no funciona? –

+0

No sé nada acerca de invocar Java desde C++, pero declaraste 'env' como un puntero (' JNIEnv * env'), así que por supuesto cuando haces '(* env) -> anything' se quejará porque' * env' no es un puntero. Prueba 'env-> anything'. – dantswain

+0

O alternativamente: use el operador de punto ('.') en lugar de la flecha (' -> '). El mismo problema ocurre con el objeto JVM, también: '(* jvm)'. Además, en algún lugar, un literal de cadena * se convierte * implícitamente en 'char *', por lo que es posible que desee realizar este lanzamiento _explicit_ en su lugar. (Esto eliminará la advertencia). – user268396

Respuesta

38

Aunque incluya el mismo archivo de encabezado, Java Native Interface utiliza dos interfaces diferentes para C y C++.

En C++, que es:

jclass cls = env->FindClass("java/lang/String"); 

en lugar de (para C):

jclass cls = (*env)->FindClass(env, "java/lang/String"); 

Así que la llamada a la función C que requiere env en dos lugares se convierte en un cómodo llamada a la función miembro en C++.

Esto se menciona en la sección Native Method Arguments del Java Native Interface 6.0 Specification.

+0

Muchas gracias, no sabía que había interfaces diferentes. Esto hará que mi vida sea mucho más fácil. :) –

1

Mi conjetura sería que usted está tratando de recopilar contra los encabezados de Win32 dada la línea de comandos que está utilizando. ¿Has probado -I"c:\ProgramFiles\Java\jdk1.7.0\include\solaris en su lugar (suponiendo que esa es tu plataforma basada en el comentario más arriba en la fuente).

+0

No es un problema de encabezados, es un problema de sintaxis incorrecta. La sintaxis para acceder a los miembros/métodos de objetos a través de un puntero (->) se usa cuando los valores se suministran mediante desreferenciación de punteros (* env). – user268396

+0

Ah, lo siento, de acuerdo. No vi la barra de desplazamiento y solo miré el código en la parte superior del fragmento que no incluía el código del problema. –

Cuestiones relacionadas