网站地图
高级搜索
首页
技术论坛
博客
派计划
产品中心
资源中心
银弹在线
商城
goCom - SOA中国第一社区
SOA和WebService
|
面向构件
|
业务流程
|
EOS
|
综合技术
|
goCom吧
|
版务区
|
商务专区
SOA和WebService
|
面向构件
|
业务流程
|
EOS
|
综合
专家组计划
|
论坛版主计划
|
技术日讲师计划
Primeton EOS
|
Primeton BPS
OSOA专区
|
专题
|
技术日
|
活动
|
下载
推荐阅读
|
封面报道
|
特别报道
|
CIO锦囊
|
专栏
|
公司
|
银弹讨论
最新上架
|
银弹推荐
|
普通书籍
|
音像
|
护肤
|
生活
|
数码
goCom - 面向构件与SOA社区 讨论区
-
综合技术论坛
Share
Eclipse
RIA
数据库
Java
Wicket
企业应用
应用服务器
操作系统
平台厂商
主题选项
点击展开
HOVER展开
--------
打印主题
[无发表权] 请登录或者注册
版主:
jiaoly
cljspn
yanfei
个人资料
Email
主页
将Java代码打包为exe文件
#1楼
总分
7739 分
财富
6596
威望
8229
排名
第 2 名
段位
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 <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虚拟机。本文开头即采用的第二种方法。
2008/1/7 10:36
锐捷工作流 - BPS Express产品发布,
免费下载
参与RIA产品调研 赢取goCom纪念T恤
动量ODE
普元SOA业务流程平台BPS 6.1即将发布
普元融资成功新闻发布会
Primeton EOS 产品下载
Primeton BPS 产品下载
dezi745
个人资料
Re: 将Java代码打包为exe文件
#2楼
初级会员
好文章,好的药引子!
2008/1/14 18:08
锐捷工作流 - BPS Express产品发布,
免费下载
参与RIA产品调研 赢取goCom纪念T恤
动量ODE
普元SOA业务流程平台BPS 6.1即将发布
普元融资成功新闻发布会
Primeton EOS 产品下载
Primeton BPS 产品下载
ymd
个人资料
Re: 将Java代码打包为exe文件
#3楼
总分
21 分
财富
120
威望
122
排名
:(
段位
很详细,学习。
2008/3/14 10:17
锐捷工作流 - BPS Express产品发布,
免费下载
参与RIA产品调研 赢取goCom纪念T恤
动量ODE
普元SOA业务流程平台BPS 6.1即将发布
普元融资成功新闻发布会
Primeton EOS 产品下载
Primeton BPS 产品下载
[无发表权] 请登录或者注册
发表回复
账号
用户名
密码
登录
内容:
字体大小
xx-small
x-small
small
medium
large
x-large
xx-large
字体
Arial
Courier
Georgia
Helvetica
Impact
Verdana
字体颜色
#000000
#000033
#000066
#000099
#0000CC
#0000FF
#003300
#003333
#003366
#003399
#0033CC
#0033FF
#006600
#006633
#006666
#006699
#0066CC
#0066FF
#009900
#009933
#009966
#009999
#0099CC
#0099FF
#00CC00
#00CC33
#00CC66
#00CC99
#00CCCC
#00CCFF
#00FF00
#00FF33
#00FF66
#00FF99
#00FFCC
#00FFFF
#330000
#330033
#330066
#330099
#3300CC
#3300FF
#333300
#333333
#333366
#333399
#3333CC
#3333FF
#336600
#336633
#336666
#336699
#3366CC
#3366FF
#339900
#339933
#339966
#339999
#3399CC
#3399FF
#33CC00
#33CC33
#33CC66
#33CC99
#33CCCC
#33CCFF
#33FF00
#33FF33
#33FF66
#33FF99
#33FFCC
#33FFFF
#660000
#660033
#660066
#660099
#6600CC
#6600FF
#663300
#663333
#663366
#663399
#6633CC
#6633FF
#666600
#666633
#666666
#666699
#6666CC
#6666FF
#669900
#669933
#669966
#669999
#6699CC
#6699FF
#66CC00
#66CC33
#66CC66
#66CC99
#66CCCC
#66CCFF
#66FF00
#66FF33
#66FF66
#66FF99
#66FFCC
#66FFFF
#990000
#990033
#990066
#990099
#9900CC
#9900FF
#993300
#993333
#993366
#993399
#9933CC
#9933FF
#996600
#996633
#996666
#996699
#9966CC
#9966FF
#999900
#999933
#999966
#999999
#9999CC
#9999FF
#99CC00
#99CC33
#99CC66
#99CC99
#99CCCC
#99CCFF
#99FF00
#99FF33
#99FF66
#99FF99
#99FFCC
#99FFFF
#CC0000
#CC0033
#CC0066
#CC0099
#CC00CC
#CC00FF
#CC3300
#CC3333
#CC3366
#CC3399
#CC33CC
#CC33FF
#CC6600
#CC6633
#CC6666
#CC6699
#CC66CC
#CC66FF
#CC9900
#CC9933
#CC9966
#CC9999
#CC99CC
#CC99FF
#CCCC00
#CCCC33
#CCCC66
#CCCC99
#CCCCCC
#CCCCFF
#CCFF00
#CCFF33
#CCFF66
#CCFF99
#CCFFCC
#CCFFFF
#FF0000
#FF0033
#FF0066
#FF0099
#FF00CC
#FF00FF
#FF3300
#FF3333
#FF3366
#FF3399
#FF33CC
#FF33FF
#FF6600
#FF6633
#FF6666
#FF6699
#FF66CC
#FF66FF
#FF9900
#FF9933
#FF9966
#FF9999
#FF99CC
#FF99FF
#FFCC00
#FFCC33
#FFCC66
#FFCC99
#FFCCCC
#FFCCFF
#FFFF00
#FFFF33
#FFFF66
#FFFF99
#FFFFCC
#FFFFFF
范例 Example
[
更多...
]
版权归Primeton普元公司所有 沪ICP备05008205号
关于goCom
|
联系我们
|
联系普元
|
隐私权声明
|
XOOPS