将Java代码打包为exe文件+

发布时间:2010-11-25 22:09:43   来源:文档文库   
字号:

1       基本信息

摘要:

          现在有很多的工具将Java代码打包为exe文件,执行时不需要再编写批处理文件,或者在命令行输入长长的classpath信息,为用户使用提供了很大的方便。这也是很多商业软件常常使用的方法。

 

2       Java代码打包为exe文件

       现在有很多的工具将Java代码打包为exe文件,执行时不需要再编写批处理文件,或者在命令行输入长长的classpath信息,为用户使用提供了很大的方便。这也是很多商业软件常常使用的方法。

       Java代码打包为exe文件,一般需要两个步骤:

1.       编写本地代码,创建虚拟机,加载并执行Main Class

2.       Java代码打包为jar文件,并与本地代码exe文件合并。

下面的代码,会加载jvm.dll,并调用JNI_CreateJavaVM导出函数创建Java虚拟机,得到JNIEnv指针,然后调用FindClass查找Main Class,之后调用GetStaticMethodID方法得到main方法,并执行main方法。代码如下:

#include 

#include 

//#pragma comment( linker, "/subsystem:"console" /entry:"mainCRTStartup"" ) 

#pragma comment( linker, "/subsystem:"windows" /entry:"WinMainCRTStartup"" ) 



typedef jint (JNICALL *JNICREATEPROC)(JavaVM **, void **, void *);

bool setStream(JNIEnv *env, const char* pszFileName, const char* pszMethod);

//启动java虚拟机方法



//bool main(int argc,char *argv[])

int WINAPI WinMain (HINSTANCE hInst, HINSTANCE hPrevInstance,PSTR szCmdLine, int iCmdShow)

...{

    //jvm动态库的路径

    const char szJvmPath[] = "d:\jdk1.5.0_07\jre\bin\server\jvm.dll";

    

    //java 虚拟机的启动参数,每个参数写一项,不能合在一起写

    int nOptionCount = 2;

    JavaVMOption options[2];

    options[1].optionString = "-Xmx256M";

    

    //设置classpath

    options[0].optionString = "-Djava.class.path=./Test.exe";

    

    JavaVMInitArgs vm_args;

    vm_args.version = JNI_VERSION_1_4;

    vm_args.options = options;

    vm_args.nOptions = nOptionCount;

    vm_args.ignoreUnrecognized = JNI_TRUE;

    

    //启动类,注意分割符是/,例如启动类test.JTest应该写成 test/JTest

    const char szStartClass[] = "com/primeton/test/TestClass";

    

    //启动方法,通常是main函数,你也可以设定成其他函数

    const char szStartMethod[] = "main";

    

    //重导向文件

    const char szStdoutFileName[] = "stdout.txt";

    const char szStderrFileName[] = "stderr.txt";

    

    //java程序的命令行参数

    int nParamCount = 2;

    const char *szParams[2] = ...{"arg1","arg2"};

    

    //加载JVM

    HINSTANCE jvmDll = LoadLibrary(szJvmPath);

    if (jvmDll == NULL)

    ...{

        printf("加载JVM动态库错误。%l", ::GetLastError());

        return false;

    }

    

    //查找JNI_CreateJavaVM过程。

    JNICREATEPROC jvmCreateProc = (JNICREATEPROC)GetProcAddress(jvmDll, "JNI_CreateJavaVM");

    if (jvmCreateProc == NULL)

    ...{

        FreeLibrary(jvmDll);

        printf("查找JNI_CreateJavaVM过程错误。%l", ::GetLastError());

        return false;

    }

    

    //创建JVM

    JNIEnv *env;

    JavaVM *jvm;

    jint r = (jvmCreateProc)(&jvm, (void **)&env, &vm_args);

    if (r < 0 || jvm == NULL || env == NULL)

    ...{

        FreeLibrary(jvmDll);

        printf( "创建JVM发生错误。");

        return false;

    }

    

    //重导向stdout, stderr到输出文件

    if (!setStream(env, szStdoutFileName, "setOut"))

    ...{

        printf("设置stdout输出文件失败");

        return false;

    }

    

    if (!setStream(env, szStderrFileName, "setErr"))

    ...{

        printf("设置stderr输出文件失败");

        return false;

    }

    

    //加载启动类。

    jclass serviceClass = env->FindClass(szStartClass);

    if (env->ExceptionCheck() == JNI_TRUE || serviceClass == NULL)

    ...{

        env->ExceptionDescribe();

        env->ExceptionClear();

        FreeLibrary(jvmDll);

        printf("加载启动类失败。");

        return false;

    }

    

    //启动方法

    jmethodID mid = env->GetStaticMethodID(serviceClass, szStartMethod , "([Ljava/lang/String;)V");

    if (env->ExceptionCheck() == JNI_TRUE || mid == NULL)

    ...{

        env->ExceptionDescribe();

        env->ExceptionClear();

        FreeLibrary(jvmDll);

        printf("查找启动方法失败。");

        return false;

    }

    

    

    

    //查找String类。

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

    if (env->ExceptionCheck() == JNI_TRUE || stringClass == NULL)

    ...{

        env->ExceptionDescribe();

        env->ExceptionClear();

        FreeLibrary(jvmDll);

        

        printf("查找String类失败。");

        return false;

    }

    

    

    

    jstring jstr;

    jobject args = 0;

    

    args = env->NewObject(2, stringClass, 0);

    for (int i=0; i

    ...{

        jstr = env->NewStringUTF(szParams[i]);

        if (jstr == 0) ...{

            printf("分配String失败 ");

            if (env->ExceptionOccurred()) ...{

                env->ExceptionDescribe();

                env->ExceptionClear();

            }

            

            return false;

        }

        

        env->SetObjectElement(args, i, jstr);

        if (env->ExceptionCheck() == JNI_TRUE)

        ...{

            printf("设置参数失败 ");

            if (env->ExceptionOccurred()) ...{

                env->ExceptionDescribe();

                env->ExceptionClear();

            }

            return false;

        }

    }

    

    

    

    //调用启动类的启动方法启动Java程序

    //env->CallStaticVoidMethod(serviceClass, mid, parameter);

    env->CallStaticVoidMethod(serviceClass, mid, args);

    

    if (env->ExceptionCheck() == JNI_TRUE)

    ...{

        env->ExceptionDescribe();

        env->ExceptionClear();

        FreeLibrary(jvmDll);

        return false;

    }

    

    MSG  msg ;

    while (GetMessage (&msg, NULL, 0, 0))

    ...{

        TranslateMessage (&msg) ;

        DispatchMessage (&msg) ;

    }

    return true;

    

}



//设置输出流的方法



bool setStream(JNIEnv *env, const char* pszFileName, const char* pszMethod)

...{

    int pBufferSize = 1024;

    char* pBuffer = new char[pBufferSize];

    

    //创建字符串对象。

    jstring pathString = env->NewStringUTF(pszFileName);

    if (env->ExceptionCheck() == JNI_TRUE || pathString == NULL)

    ...{

        env->ExceptionDescribe();

        env->ExceptionClear();

        printf("创建字符串失败。");

        return false;

    }

    

    //查找FileOutputStream类。

    jclass fileOutputStreamClass = env->FindClass("java/io/FileOutputStream");

    if (env->ExceptionCheck() == JNI_TRUE || fileOutputStreamClass == NULL)

    ...{

        env->ExceptionDescribe();

        env->ExceptionClear();

        printf("查找FileOutputStream类失败。");

        return false;

    }

    

    //查找FileOutputStream类构造方法。

    jmethodID fileOutputStreamConstructor = env->GetMethodID(fileOutputStreamClass, "", "(Ljava/lang/String;)V");

    if (env->ExceptionCheck() == JNI_TRUE || fileOutputStreamConstructor == NULL)

    ...{

        env->ExceptionDescribe();

        env->ExceptionClear();

        printf("查找FileOutputStream类构造方法失败。");

        return false;

    }

    

    //创建FileOutputStream类的对象。

    jobject fileOutputStream = env->NewObject(fileOutputStreamClass, fileOutputStreamConstructor, pathString);

    if (env->ExceptionCheck() == JNI_TRUE || fileOutputStream == NULL)

    ...{

        env->ExceptionDescribe();

        env->ExceptionClear();

        printf("创建FileOutputStream类的对象失败。");

        return false;

    }

    

    //查找PrintStream类。

    jclass printStreamClass = env->FindClass("java/io/PrintStream");

    if (env->ExceptionCheck() == JNI_TRUE || printStreamClass == NULL)

    ...{

        env->ExceptionDescribe();

        env->ExceptionClear();

        

        printf("查找PrintStream类失败。");

        return false;

    }

    

    //查找PrintStream类构造方法。

    jmethodID printStreamConstructor = env->GetMethodID(printStreamClass, "", "(Ljava/io/OutputStream;)V");

    if (env->ExceptionCheck() == JNI_TRUE || printStreamConstructor == NULL)

    ...{

        env->ExceptionDescribe();

        env->ExceptionClear();

        printf("查找PrintStream类构造方法失败。");

        return false;

    }

    

    //创建PrintStream类的对象。

    jobject printStream = env->NewObject(printStreamClass, printStreamConstructor, fileOutputStream);

    if (env->ExceptionCheck() == JNI_TRUE || printStream == NULL)

    ...{

        env->ExceptionDescribe();

        env->ExceptionClear();

        printf("创建PrintStream类的对象失败。");

        return false;

    }

    

    //查找System类。

    jclass systemClass = env->FindClass("java/lang/System");

    if (env->ExceptionCheck() == JNI_TRUE || systemClass == NULL)

    ...{

        env->ExceptionDescribe();

        env->ExceptionClear();

        printf( "查找System类失败。");

        return false;

    }

    

    //查找System类设置方法。

    jmethodID setStreamMethod = env->GetStaticMethodID(systemClass, pszMethod, "(Ljava/io/PrintStream;)V");

    if (env->ExceptionCheck() == JNI_TRUE || setStreamMethod == NULL)

    ...{

        env->ExceptionDescribe();

        env->ExceptionClear();

        printf("查找System类设置方法失败。");

        return false;

    }

    

    //设置System类的流。

    env->CallStaticVoidMethod(systemClass, setStreamMethod, printStream);

    if (env->ExceptionCheck() == JNI_TRUE)

    ...{

        env->ExceptionDescribe();

        env->ExceptionClear();

        printf("设置System类的流失败。");

        return false;

    }

    

    return true;

}

 

第二步,将Java文件打包为exe文件,也很简单。在Dos提示符下执行copy命令:

C:\>copy test.exe+test.jar test.exe

其实,就是将Java打包文件追加到exe文件尾部。打开文件属性对话框,可看到有压缩文件属性页。老牌的JBuilder.exe开发工具编译生成的exe文件即采用如下方式生成。

后记:大家在使用Eclipse 3.2Eclipse 3.3时,在任务管理器中会看到二者的不同。Eclipse 3.2是先启动Eclipse.exe文件,然后由Eclipse.exe启动Javaw.exe文件来创建虚拟机。

Eclipse 3.2在任务管理器中显示为Eclipse.exejavaw.exe两个进程。

Eclipse 3.3在任务管理器中显示为Eclipse.exe一个进程。

从上面可以看出,Eclipse 3.2Eclipse 3.3采用了不同的虚拟机加载方式。

 

Eclipse 3.2采用创建子进程的方法调用javaw.exe来启动,在windows下面可以用CreateProcess方法,此种方法较简单,具体可参见Eclipse源码。

 

Eclipse 3.3加载java虚拟机的另外一种方法是加载jvm的动态库,并通过动态库的接口来在本进程内启动java虚拟机。本文开头即采用的第二种方法。

本文来源:https://www.2haoxitong.net/k/doc/635e4068a98271fe910ef950.html

《将Java代码打包为exe文件+.doc》
将本文的Word文档下载到电脑,方便收藏和打印
推荐度:
点击下载文档

文档为doc格式