通过exe启动class
昨天下载了号称纯java版的网游《海天英雄传》, 发现其将包括jvm.dll在内的所有组件及所有class全部封装使用,觉得这种方式比较可行,既保证了理论上的纯java开发,又避免了核心代码被反编译的风险;于是自己也尝试着写了点类似方法,摘录其中一个直接以exe文件调用main函数的发表。

本方法通过jni方式实现。

/**
 * 直接通过exe启动class(免外部配置)
 *
 * project:loonframework
 * author:chenpeng
 * email:ceponline@yahoo.com.cn
 */
// PS:好长时间不写C/C++,已然快不会用了,顺便复习一下……有错大家提,大家帮忙优化……
#include "stdafx.h"
#include "jni.h"

//用于提示框显示
void MessageBox(LPCTSTR text);
//用于路径过滤
char* DirPath(char * path);
//MessageBox标题名称。
static const char MessageBoxTitle[] = "Loonframework提供";   
//本程序默认的jvm.dll相对路径位置。
const static char _DEFAULT_JVM[]="//jre//bin//client//jvm.dll";  
//主函数名,也可改为其他名称,JVM以此查询启动接口。
const char MainName[] ="main";
//虚拟机启动参数总数。
const int JVMOptionCount = 5;
//JVM编译器设定,none为使用默认编译器。
static char Compiler[] = "-Djava.compiler=NONE";
//最小内存
static char MinMB[] = "-Xms256M";
//最大内存
static char MaxMB[] = "-Xmx512M";
//jar包中主函数class所在路径。
static char AppClass[] = "org/loon/framework/game/Main";       
//需要执行的jar包所在路径,'./'为当前路径简写,多jar包以';'分割。
static char ClassPath[] = "-Djava.class.path=./loonlangrisser0.01.jar";  
static char LibraryPath[] = "-Djava.library.path=./";                       
typedef jint (WINAPI* JNICreateJavaVM)(JavaVM**, JNIEnv**, void *);
/**
 * Win主函数
 **/
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
 
    //JVM路径(PS:本写法不支持中文路径)。
    char JVMPath[MAX_PATH];
    /**
     *本程序通过注册表查找JVM.DLL位置。如未注册安装虚拟机,本程序将在执行文件相对路径下直接获得。)
     */
    //设定空间大小
    char SubKey[MAX_PATH * 2];
    //将注册表路径字符串拷贝到SubKey
    lstrcpy(SubKey, "Software//JavaSoft//Java Runtime Environment");
    HKEY hk;
    //查询注册表,并返回结果
    LONG result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, SubKey, 0, KEY_READ, &hk);
    //承载JVM.DLL句柄
    HMODULE JVM_DLL;
    //当注册表中不存在Software//JavaSoft//Java Runtime Environment时,则从本地读取JVM.DLL
    if (result != ERROR_SUCCESS) {
          //PS:此处用于从本地路径直接获得JVM.DLL时的其他处理。
          //获得文件所在绝对路径,PathLength为返回的路径长度
           int PathLength = GetModuleFileName(NULL, JVMPath, MAX_PATH);
           //拼装实际路径
           lstrcat(DirPath(JVMPath),_DEFAULT_JVM);
        //MessageBox("Software//JavaSoft//Java Runtime Environment不存在!");
       // return -1;
    //注册表中已存在时
    }else{
        char feedback[MAX_PATH];
        //获得空间大小
        DWORD feedback_Length = sizeof(feedback) * sizeof(feedback[0]);
        result = RegQueryValueEx(hk, "CurrentVersion", NULL, NULL, (LPBYTE)feedback, &feedback_Length);
        //关闭注册表
        RegCloseKey(hk);
        if (result != ERROR_SUCCESS) {
            MessageBox("Software//JavaSoft//Java Runtime Environment中CurrentVersion读取失败!");
            return -1;
        }
        //获得路径(lstrcat用于将第二个串和第一个连起来赋值给第一个字符串)
        lstrcat(SubKey, "//");
        lstrcat(SubKey, feedback);
        //查询注册表
        result = RegOpenKeyEx(HKEY_LOCAL_MACHINE, SubKey, 0, KEY_READ, &hk);
        if (result != ERROR_SUCCESS) {
            lstrcat(SubKey, "未找到!");
            MessageBox(SubKey);
            return -1;
        }

feedback_Length = sizeof(feedback) * sizeof(feedback[0]);
        result = RegQueryValueEx(hk, "RuntimeLib", NULL, NULL, (LPBYTE)feedback, &feedback_Length);
        RegCloseKey(hk);
        if (result != ERROR_SUCCESS) {
            lstrcat(SubKey, "Runtime Lib读取失败!");
            MessageBox(SubKey);
            return -1;
        }
        //获得JVM.DLL路径 
        lstrcpy(JVMPath, feedback);
    }
        //获得JVM.DLL启动实体
        JVM_DLL = LoadLibrary(JVMPath);
        if (JVM_DLL == NULL) {
            lstrcpy(SubKey, JVMPath);
            lstrcat(SubKey, "载入失败!");
            MessageBox(SubKey);
            return -1;
        }

//JVM内部函数JNI_CreateJavaVM读取
    JNICreateJavaVM createJavaVM = (JNICreateJavaVM)GetProcAddress(JVM_DLL, "JNI_CreateJavaVM");
    if (createJavaVM == NULL) {
        MessageBox("JNI_CreateJavaVM函数读取失败!");
        return -1;
    }

//指向本地方法调用接口
    JNIEnv* env;
    //表示Java虚拟机
    JavaVM* jvm;

//设定JVM启动参数
    JavaVMInitArgs vm_args;
    JavaVMOption options[JVMOptionCount];

/**
      *jtl(Java Tools Language)设定:JVM的缺省行为是用“即时”编译器(或JIT[字节代码编译器])执行字节码。
      *当加载类时,JIT将类字节码转换成本机代码。使用JIT会导致在每个类加载后有短暂延迟,
      *但可提高程序的总体性能。在某些情况下,执行时间可缩短十分之一。
      *可用Compiler指定jtl,如将Compiler=foo后,该例中虚拟机将查找名为foo.dll的JIT编译器。
      *搜索其它编译器是在jre/bin目录中和系统的PATH上进行的。
      *若找不到这样的编译器,虚拟机将缺省使用解释器。
      */
      options[0].optionString = Compiler;  
       //类地址
      options[1].optionString = ClassPath;      
      //lib地址
      options[2].optionString = LibraryPath;
      //最小内存
      options[3].optionString = MinMB;
      //最大内存
      options[4].optionString = MaxMB;
      //PS:此参数用于设定跟踪运行时的信息,暂不需要。
      //options[3].optionString = "-verbose:jni";

//使用的jni版本,目前最高为JNI_VERSION_1_6。
      vm_args.version  = JNI_VERSION_1_4;
      vm_args.options  = options;
      vm_args.nOptions = JVMOptionCount;
      vm_args.ignoreUnrecognized = JNI_TRUE;

//启动JVM,并返回结果
    int res = createJavaVM(&jvm, &env, &vm_args);
    if (res < 0) {
        MessageBox("JVM启动失败!");
        return -1;
    }

//查找目的类
    jclass clazz = env->FindClass(AppClass);
    if (clazz == 0) {
        lstrcpy(SubKey, AppClass);
        lstrcat(SubKey, "类没有找到!");
        MessageBox(SubKey);
        return -1;
    }

//取得入口主函数序列号
    jmethodID mid = env->GetStaticMethodID(clazz, MainName, "([Ljava/lang/String;)V");
    if (mid == 0) {
        lstrcpy(SubKey, AppClass);
        lstrcat(SubKey, "没有找到主函数!");
        MessageBox(SubKey);
        return -1;
    }

//main启动
    env->CallStaticVoidMethod(clazz, mid, NULL);

//JVM释放
    jvm->DestroyJavaVM();

return 0;
}

/**
 * 提示框,封装原有MessageBox
 */
void MessageBox(LPCTSTR text) {
    MessageBox(NULL, text, MessageBoxTitle, MB_ICONEXCLAMATION | MB_APPLMODAL | MB_OK | MB_SETFOREGROUND);
}

/**
 * 过滤文件所在绝对路径,去掉最后'/'后字符。
 */
char* DirPath(char * path)
{
 char *ph = path;
 char *tag = ph;
 while (*ph)
 {
  if ( (*ph) == '//' )
   tag = ph;
   ++ph;
 }
 *tag = '/0';
 return path;
}

运行效果图如下:

源码如下,请该后缀为.rar

posted on 2007-10-27 11:53 cping 阅读(...) 评论(...) 编辑 收藏

转载于:https://www.cnblogs.com/cping1982/archive/2007/10/27/2258098.html

通过exe启动class相关推荐

  1. MFC的exe启动时提示应用程序配置不正确,应用程序未能启动错误

    MFC的exe启动时提示应用程序配置不正确,应用程序未能启动错误 老姐笔记本中毒太深于病入膏肓,无奈迫写一程序"曲线救国".刚启动自己写的程序就出现应用程序配置不正确,应用程序未能 ...

  2. 外部开发:部件属性 外部exe启动UG NX

    NX支持外部读取修改部件属性,修改后注意需要保存,UF_PART_save(); 外部exe启动UG NX 1 用.net2003建立一个控制台应用程序   2 将目录ugii\managed下除Ma ...

  3. svchost.exe启动服务原理

    svchost.exe本身只是作为服务宿主,并不实现任何服务功能,需要svchost.exe启动的服务以动态链接库形式实现,在安装这些服务时,把服务的可执行程序指向svchost.exe,启动这些服务 ...

  4. 无法使用tomcat6.exe启动服务

    无法使用tomcat6.exe启动服务, 错误信息: [2019-07-19 11:04:58] [warn] The system cannot find the Registry key for ...

  5. tomcat.exe java home,tomcat.exe启动和startup.bat启动的不同

    一.tomcat7.exe与startup.bat的区别: 1.这两个都可以启动tomcat,但tomcat7.exe必须安装了服务才能启动,而startup.bat不需要 2.另外一个区别是它们启动 ...

  6. Windows下rocketmq mqnamesrv.exe 启动成功,但是mqbroker.exe启动失败

    1.mqnamesrv.exe启动成功 2.启动mqbroker.exe失败 解决办法,删除C:\Users\"当前系统用户名"\store下的所有文件,就可以了 转载于:http ...

  7. mysql按照设置向导mysqlinstanceconfig.exe启动失败

    因为应用程序的并行配置不正确,导致mysql按照设置向导mysqlinstanceconfig.exe启动失败, 原因:是exe执行权限的问题. 解决方法: 下载 rescource hacker 在 ...

  8. tomcat7w.exe启动失败,未注册成服务,以及配置Tomcat系统环境变量

    今天弄了个绿色解压版的Tomcat,结果 tomcat7w.exe 启动失败, 提示我没有将Tomcat注册成服务,我想这可能是因为直接解压缩的原因吧,先把 Tomcat 注册一下吧, 1. 找到解压 ...

  9. svchost.exe启动服务原理(如何查看系统服务究竟启动了哪个文件)

    引言: 本来是不想研究这些东西的,但是米老大指示要求禁用网上邻居,顺便研究一下. 其实禁用网上邻居,可以简单的从注册表禁用,不过这样太苍白无力了,既然做,就做强悍点,直接从服务入手,彻底kill网上邻 ...

最新文章

  1. VC++ 剪贴板编程
  2. logisim设计alu设计报告_【新】PowerBI 报告设计思想 结构布局篇
  3. 为什么不推荐使用存储过程
  4. thymeleaf 异常:SpelEvaluationException: EL1008E: Property or field ‘url‘ cannot be found
  5. LeetCode MySQL 1126. 查询活跃业务
  6. Redis的常用JavaAPI(Jedis)实现
  7. Ambari--服务管理
  8. 2019 谷歌年度搜索关键词揭晓,技术宅的英雄梦!
  9. bash的快捷键、特殊参数、历史命令、相关文件
  10. G502使用计算机配置,Logitech G502,G402游戏鼠标宏设置教程一目了然
  11. 计算机的硬件软件组成
  12. 【爬虫实战】起点中文网小说的爬取
  13. 百度收录如何API提交(java、python)
  14. 计算机二级考试C语言编程解读:统计N名学生的成绩
  15. Learning a Proposal Classifier for Multiple Object Tracking
  16. Parallel Scavenge无法和CMS共同使用
  17. 牛客网练习2-《网络基础》
  18. 搜狗Sogou拼音输入法,搜狗高速浏览器(IE浏览器内核)
  19. 人民币为什么 不继续升值
  20. Jmeter-----保存到响应文件

热门文章

  1. java length()函数_小猿圈介绍java函数式编码结构及优势
  2. Linux服务器日常巡检脚本分享
  3. 常用网络故障集锦,收藏备用
  4. 华为HCIE RS都考什么?(含选择及面试题)
  5. html输入框数字无法读取,关于input无法获取小数点的问题!!!!-汗血宝马
  6. 首个沉浸式云原生 Serverless 技术实践营开启报名
  7. 应云而生,幽灵的威胁 - 云原生应用交付与运维的思考
  8. 应用编排与管理:Job DaemonSet
  9. 进击的 Spring Cloud Alibaba —— 框架与服务
  10. 弗洛伊德算法_弗洛伊德算法