【1】http://www.ccidnet.com/2005/0413/237901.shtml
【2】http://public0821.iteye.com/blog/423941
【3】http://blog.csdn.net/sf0407/article/details/53924174
简单的C++加载jvm实现
这篇文章基本上是靠谱的。有几处小问题:包含文件有两个:jni.h jni_md.h,复制到工程目录下。
【4】如何获取 java class 的签名:https://jingyan.baidu.com/article/d2b1d102b67a905c7e37d425.html
【5】找不到 javap 命令怎么办:https://jingyan.baidu.com/article/1e5468f924210a484961b7f0.html
it Works !
C:\Users\galax\AndroidStudioProjects\testjar2\myjar\build\intermediates\classes\debug\com\eonsoft\android\myjar>javap -s Main.class
Compiled from "Main.java"
public class com.eonsoft.android.myjar.Main {
public com.eonsoft.android.myjar.Main();
descriptor: ()V
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
public java.lang.String getString(java.lang.String);
descriptor: (Ljava/lang/String;)Ljava/lang/String;
}
【6】:【2】【3】的代码都堪用,但是函数名有讲究,象上面那个函数 getString ,可能是和系统函数重名,死活无法 GetMethodID 返回 NULL ,改名后正常。
亲测有效代码:
CString XXX::startJVM(void) {
CString rslt = "";
//获取jvm动态库的路径
TCHAR* jvmPath = _T("C://Program Files//Java//jdk1.8.0_151//jre//bin//server//jvm.dll");
int nOptionCount = 2;//java虚拟机启动时接收的参数,每个参数单独一项
JavaVMOption vmOption[2];
vmOption[0].optionString = "-Xmx256M";//设置JVM最大允许分配的堆内存,按需分配
vmOption[1].optionString = "-Djava.class.path=./mysdk.jar";//设置classpath
JavaVMInitArgs vmInitArgs;
vmInitArgs.version = JNI_VERSION_1_8;
vmInitArgs.options = vmOption;
vmInitArgs.nOptions = nOptionCount;
vmInitArgs.ignoreUnrecognized = JNI_TRUE;//忽略无法识别jvm的情况
const char nameMainClass[] = "com/XXXX/XXXX/myjar/Main";//设置启动类,注意分隔符为"/"
//加载JVM,注意需要传入的字符串为LPCWSTR,指向一个常量Unicode字符串的32位指针,相当于const wchar_t*
HINSTANCE jvmDLL = LoadLibrary(jvmPath);
if (jvmDLL == NULL) {
return "加载JVM动态库错误" + ::GetLastError();
}
//初始化jvm物理地址
JNICREATEPROC jvmProcAddress = (JNICREATEPROC)GetProcAddress(jvmDLL, "JNI_CreateJavaVM");
if (jvmDLL == NULL) {
FreeLibrary(jvmDLL);
return "初始化jvm物理地址错误" + ::GetLastError();
}
//创建JVM
JNIEnv *env;
JavaVM *jvm;
jint jvmProc = (jvmProcAddress)(&jvm, (void **)&env, &vmInitArgs);
if (jvmProc < 0 || jvm == NULL || env == NULL) {
FreeLibrary(jvmDLL);
return "创建JVM错误" + ::GetLastError();
}
//加载启动类
jclass mainclass = env->FindClass(nameMainClass);
if (env->ExceptionCheck() == JNI_TRUE || mainclass == NULL) {
env->ExceptionDescribe();
env->ExceptionClear();
FreeLibrary(jvmDLL);
return "加载启动类失败";
}
//获取类中的方法,最后一个参数是方法的签名,通过javap -s -p 文件名可以获得
jmethodID mid1 = env->GetStaticMethodID(mainclass, "main", "([Ljava/lang/String;)V");
if (env->ExceptionCheck() == JNI_TRUE || mid1 == NULL) {
env->ExceptionDescribe();
env->ExceptionClear();
FreeLibrary(jvmDLL);
return "加载启动方法失败-main-stactic";
}
rslt.Format(_T(";mid1=%d"), mid1);
//获取类中的方法,最后一个参数是方法的签名,通过javap -s -p 文件名可以获得
jmethodID mid = env->GetMethodID(mainclass, "getString2", "(Ljava/lang/String;)Ljava/lang/String;");
if (env->ExceptionCheck() == JNI_TRUE || mid == NULL) {
env->ExceptionDescribe();
env->ExceptionClear();
FreeLibrary(jvmDLL);
rslt += "加载启动方法失败-getString";
return rslt;
}
CString temp = "";
temp.Format(_T(";mid=%d"), mid);
rslt += temp;
//调用对象的方法
jobject obj = env->AllocObject(mainclass);//根据类的CLASS对象获取该类的实例
const char szTest[] = "f";//构造参数
jstring arg = str2jstring(env, szTest);
jstring msg = (jstring)env->CallObjectMethod(obj, mid, arg);
rslt += jstring2CString(env, msg);
return rslt;
}
应注意:下面这段代码要放在使用之前,否则编译会报找不到定义。
CString CDynamicTyperJar::jstring2CString(JNIEnv *m_penv, jstring jnistr)
{
// We modified in this function because we founf if the length is of two chars
// it add a rubish char concatenated at the end of the string
CString dummyCString, retCString;
jsize istringlength;
jboolean isCopy = JNI_TRUE;
const jchar *pChar = m_penv->GetStringChars(jnistr, &isCopy);
istringlength = m_penv->GetStringLength(jnistr);
dummyCString = (BSTR)pChar;
retCString = dummyCString.Mid(0, istringlength);
m_penv->ReleaseStringChars(jnistr, pChar);
return retCString;
}
jstring CDynamicTyperJar::str2jstring(JNIEnv* env, const char* pat)
{
jclass strClass = env->FindClass("Ljava/lang/String;");
jmethodID ctorID = env->GetMethodID(strClass, "<init>", "([BLjava/lang/String;)V");
jbyteArray bytes = env->NewByteArray(strlen(pat));
env->SetByteArrayRegion(bytes, 0, strlen(pat), (jbyte*)pat);
jstring encoding = env->NewStringUTF("utf-8");
return (jstring)env->NewObject(strClass, ctorID, bytes, encoding);
}