2011-09-24 47 views
16

C++ Tôi cố gắng để gọi máy ảo Java từ C++ sau ví dụ tìm thấy here:Gọi Java từ

Về cơ bản tôi có một chương trình Java nhỏ:

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

Sau đó, tôi có một chương trình C++ mà tôi muốn tạo ra một JVM và gọi lớp 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); 
} 

Nhưng Khi tôi cố gắng để biên dịch chương trình C++ tôi nhận được lỗi này:

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' 

Bất kỳ ý tưởng nào?

Cảm ơn

+0

Bạn nên bao gồm nhận xét về những gì không hoạt động với mã của bạn. Bạn nhận được một lỗi hoặc không nó chỉ không hoạt động? –

+0

Tôi không biết gì về việc gọi Java từ C++, nhưng bạn đã khai báo 'env' làm con trỏ (' JNIEnv * env'), vì vậy tất nhiên khi bạn làm '(* env) -> bất cứ thứ gì' nó sẽ khiếu nại vì' * env' không phải là một con trỏ. Thử 'env-> bất cứ thứ gì'. – dantswain

+0

Hoặc cách khác: sử dụng toán tử dấu chấm ('.') thay vì mũi tên (' -> '). Vấn đề tương tự cũng xảy ra với đối tượng JVM: '(* jvm)'. Ngoài ra một nơi nào đó một chuỗi chữ là * ngầm * đúc thành 'char *', vì vậy bạn có thể muốn làm cho diễn viên này _explicit_ thay thế. (Điều này sẽ thoát khỏi cảnh báo). – user268396

Trả lời

38

Mặc dù bạn bao gồm cùng một tệp tiêu đề, Giao diện bản địa Java sử dụng hai giao diện khác nhau cho C và C++.

Trong C++, đó là:

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

thay vì (cho C):

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

Vì vậy, C gọi hàm đòi hỏi env ở hai nơi trở thành thành viên gọi hàm thuận tiện trong C++.

Điều này được đề cập trong phần Native Method Arguments của Java Native Interface 6.0 Specification.

+0

Cảm ơn bạn rất nhiều, tôi không biết rằng có những giao diện khác nhau. Điều này sẽ làm cho cuộc sống của tôi dễ dàng hơn nhiều. :) –

1

Tôi đoán là bạn đang cố gắng biên dịch các tiêu đề win32 cho dòng lệnh bạn đang sử dụng. Bạn đã thử thay thế -I"c:\ProgramFiles\Java\jdk1.7.0\include\solaris (giả sử đó là nền tảng của bạn dựa trên nhận xét cao hơn trong nguồn).

+0

Nó không phải là một vấn đề của tiêu đề, đó là một vấn đề cú pháp không chính xác. Cú pháp để truy cập các thành viên/phương thức của các đối tượng thông qua con trỏ (->) được sử dụng khi các giá trị được cung cấp thông qua dereferencing con trỏ (* env). – user268396

+0

Ah, xin lỗi, đã đồng ý. Tôi đã không phát hiện ra thanh cuộn và chỉ xem mã ở đầu đoạn trích không bao gồm bất kỳ mã vấn đề nào. –