`
javer
  • 浏览: 68879 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

将Java代码打包为exe文件

    博客分类:
  • java
阅读更多

现在有很多的工具将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"" ) 
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;
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 ;
}
// 设置输出流的方法
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虚拟机。本文开头即采用的第二种方法。

 

分享到:
评论

相关推荐

    将Java代码打包为exe文件(绝对可行)

    ### 将Java代码打包为exe文件(绝对可行) #### 知识点概述 本文将详细介绍如何将Java代码打包成exe格式的可执行文件,使得Java应用程序可以在不安装JRE(Java运行环境)的情况下运行。这一过程对于那些希望将Java...

    Eclipse_java文件打包成exe文件详解java代码打包exe

    将Java代码打包为EXE文件主要涉及两个步骤: 1. **编写本地代码**:创建一个能够加载并启动Java虚拟机(JVM)的本地应用程序(通常使用C或C++)。该本地程序负责启动JVM并加载指定的Java主类。 2. **合并文件**:...

    java 代码打包成exe

    ### Java 代码打包成 EXE 文件详解 #### 一、前言 在开发过程中,有时候我们需要将 Java 项目转换为 Windows 下的可执行文件(EXE 文件),这主要是为了提高程序的用户友好度,同时也方便那些没有安装 Java 运行...

    如何把一个java程序打包成exe文件.doc

    ### 如何将Java程序打包成EXE文件 在软件开发领域,尤其是对于Java开发者来说,将Java程序打包成EXE文件是一种常见的需求。这不仅可以让程序在没有安装Java运行环境(JRE)的计算机上运行,还能提高程序的安全性和...

    Eclipse_java文件打包成exe文件详解java代码打包

    Java程序通常运行在Java虚拟机(JVM)上,但为了让非Java用户也能方便地运行程序,我们可以将Java代码打包成可执行的Windows EXE文件。这个过程涉及到Java的跨平台编译和封装技术。本文将详细介绍如何使用Eclipse ...

    java代码打包成exe

    Java代码打包成exe是将Java应用程序转换为可执行文件(.exe)的过程,这样非Java环境的用户也可以在Windows系统上直接运行程序。这通常通过使用特定的工具来实现,如JAR to EXE Converter、Launch4j或Excelsior JET...

    java程序打包成exe文件

    它允许开发者将Java代码、类路径、启动参数等整合到一个独立的.exe文件中,便于分发和执行。下面我们将详细探讨如何使用exe4j进行打包以及涉及的相关知识点: 1. **Java应用程序的基本结构**:在Java中,应用程序由...

    Java打包成可执行文件步骤详解

    本文将通过一个具体的示例来详细介绍如何将Java程序打包成可执行文件。 #### 示例程序代码 首先来看一下示例程序的代码: ```java package com.test.jar; import java.awt.*; import javax.swing.*; public ...

    java打包工具打包成exe文件

    在Java领域,有几个知名的打包工具可以将Java程序转换为EXE文件,其中包括Launch4j、JSmooth、Jar2Exe和Excelsior JET等。这些工具不仅能够生成EXE,还允许我们自定义各种参数,比如设置程序图标,控制启动选项,...

    Java程序打包成exe执行文件工具

    这里提到的“Java程序打包成exe执行文件工具”是指将Java应用转换为可以直接在Windows操作系统上双击运行的exe格式的工具。主要涉及到的技术和步骤如下: 1. **Java程序打包成Jar包**: Java程序通常被打包成JAR...

    JSmooth工具将java文件打包成exe文件

    JSmooth是一款开源的Java应用打包工具,它能将Java的.jar文件转换为Windows平台的.exe可执行程序。JSmooth的主要优势在于它不仅创建.exe文件,还会自动生成一个小型的JRE,这样即使目标计算机上没有Java环境,也能...

    将java程序打包成exe文件的方法

    本文将详细介绍如何使用fatJar插件来打包Java程序为.JAR文件,并通过exe4j工具将其进一步转换为.EXE文件,最后利用install4j创建安装包,实现真正的跨平台部署。 #### 二、使用fatJar插件打包成.JAR文件 **1. 安装...

    java打包成EXE文件过程详解(图解)

    Java程序通常运行在Java虚拟机(JVM)上,但为了让非Java开发人员或用户能够更方便地执行Java应用程序,可以将其打包成可执行的...记住,每次更新Java代码后,都需要重新打包和测试EXE文件,以确保其功能的正确性。

    JAVA程序打包成exe文件

    **exe4j**是由Ejel Technology开发的一款强大的Java应用程序打包工具,它可以将Java程序及其依赖项打包成一个独立的Windows可执行文件(.exe)。这样,用户无需安装Java环境即可直接运行程序。 - **准备工作**: -...

    java打包成exe文件的全过程

    这个过程涉及到Java Swing界面应用的打包和利用Exe4j工具将其转换为.exe文件。下面我们将详细讲解这个全过程。 首先,Java Swing是Java平台上的一个图形用户界面(GUI)工具包,它提供了丰富的组件和布局管理器,...

Global site tag (gtag.js) - Google Analytics