更新 (23/02/13):单独测试了 Hook,它可以工作。问题是您不能printf
在 .dll 中使用,除非您将控制台与其关联。
相反,我将每个替换printf
为fprintf
并将输出写入日志文件。
更新(22/02/13):clazz
以正确的方式初始化变量。
我想在我的 java 应用程序中调用一个方法,如果有任何桌面窗口是created/activated/destroyed
.
我编写了一个带有两个本机函数的简单 Java 类:
public class Hook {
public Hook(){}
public void setstatus(){
System.out.println("status set");
}
public native void starthook();
public native void stophook();
}
在 CI 中写道:
#include "Hook.h"
#include <windows.h>
#include <jni.h>
#include <stdio.h>
#pragma data_seg("Shared")
HHOOK g_hHook = NULL;
FILE *pFile=NULL;
//do mid, clazz and jvm have to be shared ?
//jmethodID mid=NULL;
//jclass clazz=NULL;
//static JavaVM *jvm = NULL;
#pragma data_seg()
HINSTANCE g_hInstance = NULL;
BOOL APIENTRY DllMain( HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ){
switch (ul_reason_for_call){
case DLL_PROCESS_ATTACH:
g_hInstance = (HINSTANCE) hModule;
break;
case DLL_THREAD_ATTACH: break;
case DLL_THREAD_DETACH: break;
case DLL_PROCESS_DETACH: break;
}
return TRUE;
}
LRESULT CALLBACK CBTProc(int nCode, WPARAM wParam, LPARAM lParam){
if (nCode < 0)
return CallNextHookEx(g_hHook, nCode, wParam, lParam);
/*
JNIEnv *env;
int res =(*jvm)->AttachCurrentThread(jvm,(void **)&env, NULL);
if(res<0){
fprintf(pFile,"AttachCurrentThread failed\n");
return 0;
}
*/
HWND hWnd = (HWND)wParam;
if (!hWnd){
fprintf(pFile,"hWnd==NULL\n");
//(*jvm)->DetachCurrentThread(jvm);
return 0;
}
if (nCode == HCBT_ACTIVATE){
// is printed
fprintf(pFile,"activated\n");
// isn't called
//(*env)->CallVoidMethod(env, clazz, mid);
// Nothing is logged
//if((*env)->ExceptionOccurred(env))
// (*env)->ExceptionDescribe(env);
}
else if (nCode == HCBT_DESTROYWND){
fprintf(pFile,"destroyed\n");
}
else if (nCode == HCBT_CREATEWND){
fprintf(pFile,"created\n");
}
//(*jvm)->DetachCurrentThread(jvm);
return 0;
}
JNIEXPORT void JNICALL Java_Hook_starthook(JNIEnv *e, jobject o){
/*
if(jvm==NULL)
if(((*e)->GetJavaVM(e,&jvm))<0){
printf("GetJavaVM failed\n");
return;
}
jclass localRef = (*e)->GetObjectClass(e, o);
clazz = (*e)->NewGlobalRef(e,localRef);
if(clazz==NULL){
printf("GetObjectClass failed\n");
return;
}
mid = (*e)->GetMethodID(e, clazz, "setstatus", "()V");
if(mid==0){
printf("GetMethodID failed\n");
return;
}
*/
pFile = fopen("C:/workspace/CBTHook/log.txt","a");
g_hHook = SetWindowsHookEx(WH_CBT, (HOOKPROC) CBTProc, g_hInstance, 0);
printf("Hook started\n");
}
JNIEXPORT void JNICALL Java_Hook_stophook(JNIEnv *e, jobject o){
if (g_hHook){
UnhookWindowsHookEx(g_hHook);
g_hHook = NULL;
//(*e)->DeleteGlobalRef(e,clazz);
}
if(pFile)
fclose(pFile);
}
printf("Hook stopped\n");
}
有效,CBTHook
但我不能setstatus
从函数内部调用callback
函数。
(*env)->CallVoidMethod(env, clazz, mid);
不做任何事情,也没有抛出异常。
我需要做什么 ?
此外,我是否必须共享全局变量mid
:clazz
和jvm
?中的每个变量
#pragma data_seg("SHARED")
段是“共享的”,这意味着它们不是特定进程所独有的。
如果有必要,附加/分离其他线程的正确方法是什么?