2014-01-09 27 views
2

我正在用MacOSX上的JNI編寫Java啓動程序,以顯示SplashScreen和AWT窗口。我幾乎已經完成了該程序,它已成功運行JDK6,但如果顯示SplashScreen,它將與JDK7一起崩潰。當我在MacOSX上用JDK7顯示SplashScreen時,我的java啓動程序崩潰

整個程序是:

#include <dlfcn.h> 
#include <jni.h> 
#include <stdio.h> 
#include <string.h> 
#include <pthread.h> 
#include <CoreServices/CoreServices.h> 

typedef jint (JNICALL * FARPROC_JNI_CreateJavaVM)(JavaVM **pvm, void **penv, void *args); 

int JavaMain(); 
void ShowSplashWindow(); 

#define USEJDK6 0 

int main() 
{ 
    ShowSplashWindow(); 

    // start java in a new thread 
    pthread_attr_t thread_attr; 
    pthread_attr_init(&thread_attr); 
    pthread_attr_setscope(&thread_attr, PTHREAD_SCOPE_SYSTEM); 
    pthread_attr_setdetachstate(&thread_attr, PTHREAD_CREATE_JOINABLE); 
    pthread_t vmthread; 
    pthread_create(&vmthread, &thread_attr, (void *(*)(void*))JavaMain, NULL); 

    // start run loop 
    CFRunLoopSourceContext sourceContext = { 
     .version = 0, .info = NULL, .retain = NULL, .release = NULL, 
     .copyDescription = NULL, .equal = NULL, .hash = NULL, 
     .schedule = NULL, .cancel = NULL, .perform = NULL }; 
    CFRunLoopSourceRef sourceRef = CFRunLoopSourceCreate(NULL, 0, &sourceContext); 
    CFRunLoopAddSource(CFRunLoopGetCurrent(), sourceRef, kCFRunLoopCommonModes); 
    CFRunLoopRun(); 
    CFRelease(sourceRef); 
} 

// the old main to run java 
int JavaMain() 
{ 
#if USEJDK6 
    // load JDK with MacOSX 
    void * handle = dlopen("/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Libraries/libserver.dylib", RTLD_LAZY); 
#else 
    // --- or SUN JDK 1.7 --- 
    void * handle = dlopen("/Library/Java/JavaVirtualMachines/jdk1.7.0_45.jdk/Contents/Home/jre/lib/server/libjvm.dylib", RTLD_LAZY); 
#endif 

    // get JNI_CreateJavaVM 
    FARPROC_JNI_CreateJavaVM FN_JNI_CreateJavaVM = (FARPROC_JNI_CreateJavaVM)dlsym(handle, "JNI_CreateJavaVM"); 
    if(FN_JNI_CreateJavaVM == NULL) FN_JNI_CreateJavaVM = (FARPROC_JNI_CreateJavaVM)dlsym(handle, "JNI_CreateJavaVM_Impl"); 

    // Start JVM 
    JavaVMOption * options = new JavaVMOption[1]; 
    memset(options, 0, sizeof(JavaVMOption) * 1); 
    options[0].optionString = "-Djava.class.path=."; 

    JavaVMInitArgs vm_args; 
    vm_args.version   = JNI_VERSION_1_2; 
    vm_args.nOptions   = 1; 
    vm_args.ignoreUnrecognized = JNI_TRUE; 
    vm_args.options   = options; 

    JavaVM * pJvm = NULL; 
    JNIEnv * pEnv = NULL; 

    int result = FN_JNI_CreateJavaVM(&pJvm, (void**)&pEnv, &vm_args); 

    // class 
    jclass clazz = pEnv->FindClass("test/HelloWorld"); 
    if(clazz == NULL) { 
     pEnv->ExceptionDescribe(); 
     pEnv->ExceptionClear(); 
     return 1; 
    } 

    // method 
    jmethodID main = pEnv->GetStaticMethodID(clazz, "main", "([Ljava/lang/String;)V"); 

    jclass stringClass = pEnv->FindClass("java/lang/String"); 
    jobjectArray java_argv = pEnv->NewObjectArray(0, stringClass, NULL); 
    pEnv->CallStaticVoidMethod(clazz, main, java_argv); 

    // close 
    pJvm->DetachCurrentThread(); 
    pJvm->DestroyJavaVM(); 

    return 0; 
} 

typedef int (*SplashLoadMemory_t)(void* pdata, int size); 
typedef void (*SplashInit_t)(void); 
typedef int (*SplashLoadFile_t)(const char* filename); 

void ShowSplashWindow() 
{ 
#if USEJDK6 
    // load JDK with MacOSX 
    void * handle = dlopen("/System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Libraries/libsplashscreen.jnilib", RTLD_LAZY); 
#else 
    // --- or SUN JDK 1.7 --- 
    void * handle = dlopen("/Library/Java/JavaVirtualMachines/jdk1.7.0_45.jdk/Contents/Home/jre/lib/libsplashscreen.dylib", RTLD_LAZY); 
#endif 

    SplashInit_t SplashInit = (SplashInit_t)dlsym(handle, "SplashInit"); 
    SplashLoadMemory_t SplashLoadMemory = (SplashLoadMemory_t)dlsym(handle, "SplashLoadMemory"); 
    SplashLoadFile_t SplashLoadFile = (SplashLoadFile_t)dlsym(handle, "SplashLoadFile"); 

    SplashInit(); 
    SplashLoadFile("test/s.jpg"); 
} 

環境:

  1. 我的操作系統是MacOSX的10.8。
  2. JDK6附帶System,可能從App Store安裝,它有2個內核(32位和64位)。
  3. JDK7是從oracle.com下載的,它只有一個64位內核。
  4. 該程序由LLVM編譯器在Xcode命令工具中編譯。
  5. 程序被編譯成64位程序。

程序結果:

  1. 如果#define USEJDK6 1使用JDK6,是否顯示閃屏與否,程序會成功運行。
  2. 如果#define USEJDK6 0要使用JDK7,程序將在顯示SplashScreen時崩潰。
  3. 如果#define USEJDK6 0要使用JDK7,如果在開始時刪除ShowSplashWindow();,程序將成功運行。

該錯誤消息是SIGSEGV (0xb),堆棧:

Stack: [0x00007fff56715000,0x00007fff56f15000], sp=0x00007fff56f13b80, free space=8186k 
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code) 
C [libosxapp.dylib+0x3998] +[ThreadUtilities getJNIEnv]+0x5b 
C [libosxapp.dylib+0x1a77] -[NSApplicationAWT registerWithProcessManager]+0x7c 
C [libosxapp.dylib+0x1493] -[NSApplicationAWT init]+0x8c 
C [AppKit+0xf1864] +[NSApplication sharedApplication]+0x8f 
C [libsplashscreen.dylib+0x796d] __SplashInitPlatform_block_invoke_1+0x2d 
C [libdispatch.dylib+0x5f01] _dispatch_call_block_and_release+0xf 
C [libdispatch.dylib+0x20b6] _dispatch_client_callout+0x8 
C [libdispatch.dylib+0x70c8] _dispatch_main_queue_callback_4CF+0x113 
C [CoreFoundation+0x35b4c] __CFRunLoopRun+0x66c 
C [CoreFoundation+0x350e2] CFRunLoopRunSpecific+0x122 
C [CoreFoundation+0x43dd1] CFRunLoopRun+0x61 
C [launcherV3+0x159e] main+0xee 
C [libdyld.dylib+0x27e1] start+0x0 

任何人都可以幫助我如何正確顯示閃屏與JDK7 MacOSX上?任何人都可以指出我的程序中哪裏出錯了?

您可以在這裏下載該程序:

+0

是你的C代碼編譯爲32位或64位處理器? JRE7僅在OS X上爲64位。 – Valentin

+0

感謝@Valentin,然後我將添加此信息 –

+0

我想知道該JRE實際上是否在您的系統上運行(僅涵蓋顯而易見的內容)。因此,你是否能夠在命令行上運行'java -version',以便它用'java version「1.7.0_45」'作出響應? – einnocent

回答

3

如果你正在試圖做的一切都顯示閃現屏幕,然後可能有一個更簡單的答案,通過解決方法。顯然你可以show a splash screen在應用程序加載時做:

java -splash:filename.gif MainClass 
+0

謝謝。但是我正在編寫像'java'這樣的自己的啓動器,而不是使用'java'。我想知道'java'是如何實現的。 –

相關問題