在MacOS上显示带有JDK 7的Splash Screen时,我的java启动程序崩溃了

时间:2014-01-09 13:16:47

标签: java macos awt splash-screen

我正在MacOSX上使用JNI编写java启动程序,以显示SplashScreen和AWT窗口。我几乎完成了程序,它成功运行JDK6,但如果显示SplashScreen,它将与JDK7一起崩溃。

整个计划是:

#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. 该程序由Xcode命令工具中的LLVM编译器编译。
  5. 程序被编译成64位程序。
  6. 计划结果:

    1. 如果#define USEJDK6 1使用JDK6,无论是否显示SplashScreen,程序都将成功运行。
    2. 如果#define USEJDK6 0使用JDK7,如果显示SplashScreen,程序将崩溃。
    3. 如果#define USEJDK6 0使用JDK7,如果在开头删除ShowSplashWindow();,程序将成功运行。
    4. 错误消息为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
      

      任何人都可以帮助我如何在MacOSX上使用JDK7正确显示SplashScreen?任何人都可以指出我的程序出错了吗?

      您可以在此处下载该程序:

1 个答案:

答案 0 :(得分:3)

如果您要做的只是显示启动画面,那么通过解决方法可能会有一个更简单的答案。显然,您可以通过执行以下操作加载show a splash screen

java -splash:filename.gif MainClass