通过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
  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 7
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值