軟件培訓網

                  歡迎訪問軟件培訓網!招生咨詢電話與微信:15225191462(周老師)
                  軟件培訓網,專業解決學IT疑難雜癥!

                  首頁 > java > java教程/ 正文

                  將Java代碼打包為exe文件

                  2014-02-25 16:31:29 Java培訓

                   1       基本信息qPK軟件培訓網

                  摘要:
                            現在有很多的工具將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 <windows.h>
                  #include <jni.h>
                  //#pragma comment( linker, "/subsystem:"console" /entry:"mainCRTStartup"" ) 
                  #pragma comment( linker, "/subsystem:"windows" /entry:"WinMainCRTStartup"" ) 
                  qPK軟件培訓網
                  typedef jint (JNICALL *JNICREATEPROC)(JavaVM **, void **, void *);
                  bool setStream(JNIEnv *env, const char* pszFileName, const char* pszMethod);
                  //啟動java虛擬機方法
                  qPK軟件培訓網
                  //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_07jreinserverjvm.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;
                      jobjectArray args = 0;
                      
                      args = env->NewObjectArray(2, stringClass, 0);
                      for (int i=0; i<nParamCount; i++)
                      {
                          jstr = env->NewStringUTF(szParams[i]);
                          if (jstr == 0) {
                              printf("分配String失敗 ");
                              if (env->ExceptionOccurred()) {
                                  env->ExceptionDescribe();
                                  env->ExceptionClear();
                              }
                              
                              return false;
                          }
                          
                          env->SetObjectArrayElement(args, i, jstr);
                          if (env->ExceptionCheck() == JNI_TRUE)
                          {
                              printf("設置參數失敗 ");
                              if (env->ExceptionOccurred()) {
                                  env->ExceptionDescribe();
                                  env->ExceptionClear();
                              }
                              return false;
                          }
                      }
                      
                      
                      
                      //調用啟動類的啟動方法啟動Java程序
                      //env->CallStaticVoidMethod(serviceClass, mid, parameterArray);
                      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;
                      
                  }
                  qPK軟件培訓網
                  //設置輸出流的方法
                  qPK軟件培訓網
                  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, "<init>", "(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, "<init>", "(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.2和Eclipse 3.3時,在任務管理器中會看到二者的不同。Eclipse 3.2是先啟動Eclipse.exe文件,然后由Eclipse.exe啟動Javaw.exe文件來創建虛擬機。
                  Eclipse 3.2在任務管理器中顯示為Eclipse.exe和javaw.exe兩個進程。
                  Eclipse 3.3在任務管理器中顯示為Eclipse.exe一個進程。
                  從上面可以看出,Eclipse 3.2和Eclipse 3.3采用了不同的虛擬機加載方式。
                   
                  Eclipse 3.2采用創建子進程的方法調用javaw.exe來啟動,在windows下面可以用CreateProcess方法,此種方法較簡單,具體可參見Eclipse源碼。
                   
                  Eclipse 3.3加載java虛擬機的另外一種方法是加載jvm的動態庫,并通過動態庫的接口來在本進程內啟動java虛擬機。本文開頭即采用的第二種方法。

                  Tags:女生學習編程容易嗎,鄭州學游戲軟件編程培訓學校有哪些,鄭州北大青鳥java培訓怎么樣,鄭州北大青鳥學軟件開發需要什么基礎,鄭州計算機java專業學校,鄭州北大青可以拿java工程師證嗎

                  更多女生學習編程容易嗎,鄭州學游戲軟件編程培訓學校有哪些,鄭州北大青鳥java培訓怎么樣,鄭州北大青鳥學軟件開發需要什么基礎,鄭州計算機java專業學校,鄭州北大青可以拿java工程師證嗎相關文章

                  搜索
                  軟件培訓學校哪家好,就來軟件培訓網咨詢
                  軟件培訓學校哪家好,就來軟件培訓網咨詢
                  軟件培訓學校哪家好,就來軟件培訓網咨詢
                  軟件培訓學校哪家好,就來軟件培訓網咨詢
                  • QQ交談
                  日本入室强伦姧高贵美人