【发布时间】:2016-01-07 12:34:43
【问题描述】:
在我的一个项目下,我需要读取正在运行的 oracle 表单应用程序的 VTextField GUI 对象,并在其中设置新值,我能够将我的 DLL 注入到应用程序中,并且我能够附加下面的当前线程是我的代码
JNIEnv* env;
JavaVM *jvm = NULL;
jsize jvm_count = 0;
jint res = 0;
#ifdef __STATIC_LIB_JVM
res = JNI_GetCreatedJavaVMs(&jvm, 1, &jvm_count);
#else
{
HINSTANCE hLibJVM;
typedef jint(JNICALL GetCreatedJavaVMs_t)(JavaVM**, jsize, jsize*);
GetCreatedJavaVMs_t *MyGetCreatedJavaVMs;
hLibJVM = LoadLibrary(L"jvm.dll");
MyGetCreatedJavaVMs = (GetCreatedJavaVMs_t*)GetProcAddress(hLibJVM, "JNI_GetCreatedJavaVMs");
res = MyGetCreatedJavaVMs(&jvm, 1, &jvm_count);
}
#endif
if (res == 0)
{
if (jvm_count == 0)
{
jvm = NULL;
}
}
else jvm = NULL;
bool mustDetach = false;
//jint retval = jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
jint retval = jvm->GetEnv((void**)&env, JNI_VERSION_1_6);
if (retval == JNI_EDETACHED)
{
JavaVMAttachArgs args;
args.version = JNI_VERSION_1_6;
args.name = NULL;
args.group = NULL;
retval = jvm->AttachCurrentThread((void**)&env, &args);
mustDetach = true; // to clean up afterwards
}
else{
fprintf(JNIStatus, "JNI is not processing\n"); // should never happen
}
if (retval != JNI_OK){
fprintf(JNIStatus, "JNI is not ok\n"); // should never happen
}
else{
fprintf(JNIStatus, "JNI is ok\n"); // should never happen
}
if (retval>=0)
fprintf(JNIStatus, "Attachcurrentthread was successfull\n");
在这里我得到输出,因为附加当前线程成功,但是在此之后当我尝试使用下面的代码查找类时,系统无法为此找到类
char* strin;
strin = "abcdef";
jstring str = env->NewStringUTF(strin);
jfieldID fid;
jclass clazz = env->FindClass("oracle/forms/ui/VTextField");
if (clazz == NULL) {
fprintf(JNIStatus, "Can't find class %s", clazz);
}
即使我认为它是因为本地引用,但我也尝试将 jclass 对象作为全局引用但没有运气:(
/* Create a global reference */
jclass clazzLUSCore = (_jclass*)env->NewGlobalRef(clazz);
/* The local reference is no longer useful */
env->DeleteLocalRef(clazz);
/* Is the global reference created successfully? */
if (clazzLUSCore == NULL) {
fprintf(JNIStatus, "Error - clazzLUSCore is still null when it is suppose to be global\n");
}
我是 C++ 的新手,请帮帮我,我找不到正在运行的应用程序类,我需要在不访问服务器代码的情况下实现这一点。
根据@michael 的评论,我尝试添加它,但我认为它会抛出异常。所以无法获取类名
JavaVM* gJvm = nullptr;
static jobject gClassLoader;
static jmethodID gFindClassMethod;
JNIEXPORT jint JNICALL JNI_OnLoad(JavaVM *pjvm, void *reserved) {
gJvm = pjvm; // cache the JavaVM pointer
auto env = getEnv();
//replace with one of your classes in the line below
auto randomClass = env->FindClass("oracle/forms/ui/VTextField");
jclass classClass = env->GetObjectClass(randomClass);
auto classLoaderClass = env->FindClass("java/lang/ClassLoader");
auto getClassLoaderMethod = env->GetMethodID(classClass, "getClassLoader",
"()Ljava/lang/ClassLoader;");
gClassLoader = env->CallObjectMethod(randomClass, getClassLoaderMethod);
gFindClassMethod = env->GetMethodID(classLoaderClass, "findClass",
"(Ljava/lang/String;)Ljava/lang/Class;");
return JNI_VERSION_1_6;
}
jclass findClass(const char* name) {
return static_cast<jclass>(getEnv()->CallObjectMethod(gClassLoader, gFindClassMethod, getEnv()->NewStringUTF(name)));
}
JNIEnv* getEnv() {
JNIEnv *env;
int status = gJvm->GetEnv((void**)&env, JNI_VERSION_1_6);
if (status < 0) {
status = gJvm->AttachCurrentThread((void**)&env, NULL);
if (status < 0) {
return nullptr;
}
}
return env;
}
【问题讨论】:
-
我不知道您的特定环境是如何工作的,但这里引用了 Android 文档中的一个引用,其中提到了您在使用
FindClass时可能遇到的问题:“您可能会遇到麻烦如果您自己创建一个线程(可能通过调用 pthread_create 然后使用 AttachCurrentThread 附加它)。现在您的应用程序中没有堆栈帧。如果您从该线程调用 FindClass,JavaVM 将在“系统”类加载器中启动,而不是与您的应用程序关联的类,因此尝试查找特定于应用程序的类将失败。” -
(上述报价为Source)。
-
谢谢迈克尔,我会查看您的评论,并会回复您
-
你不能使用任何现有线程的
Thread.getContextClassLoader()来获取正确的类加载器吗? -
@VIP thread.getContextClassLoader() 是 java 的实现方式,问题是我无法从 c++ 连接到 java 类,应用程序已经在运行,我无法访问源代码,只有我能够在那个应用程序中注入我的 dll,但是现在,我想在那个应用程序中编辑文本框,我不能它是一个基于 java 的应用程序,所以 window spy 也无法获得 GUI 对象定义,我想要该对象定义,以便我可以在编辑框或单击按钮中设置值,如果您能指导我这样做,我将非常感激,我现在是 java 但在 c++ 中我的知识很少。
标签: java c++ java-native-interface oracleforms dll-injection