0

更新(23/02/13):フックを個別にテストしました。動作します。printf問題は、コンソールを.dllに関連付けない限り、.dllで使用できないことでした。

代わりに、すべてをに置き換えてprintffprintf出力をログファイルに書き込みました。

更新(22/02/13):変数clazzを正しい方法で初期化しました。

デスクトップウィンドウが。の場合、Javaアプリケーションでメソッドを呼び出したいcreated/activated/destroyed

2つのネイティブ関数を使用して単純な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呼び出すことができません。setstatuscallback

(*env)->CallVoidMethod(env, clazz, mid);

何もせず、例外はスローされません。

私は何をしなければなりませんか?

さらに、グローバル変数を共有する必要があります:mid、、?のすべての変数clazzjvm

#pragma data_seg("SHARED")

セグメントは「共有」されます。これは、特定のプロセスに固有ではないことを意味します。

そして、これが必要な場合、他のスレッドをアタッチ/デタッチする正しい方法は何でしょうか?

4

1 に答える 1

0

「メッセージを受信しない」が正確に何を意味するかについての明確な説明がないことを考えると、私はあなたCBTProc が呼び出されていると推測し、JVM コールバックを取得していません。が呼び出されない場合CBTProc、それは JNI の問題ではありません

あなたはそれをほぼ正しく行いました。jmethodIDスレッド間および JNI 呼び出し間で再利用できるため、キャッシュすることができます。JavaVM*入ってキャッシュする方法starthook()も正しいです。あなたは についてだけ間違っていjclass clazzます。それをキャッシュしてからstarthook()、別の呼び出しだけでなく、おそらく別のスレッドでも使用しようとします。取得するGetObjectClassのはローカル参照です。つまり、現在の JNI 呼び出しが終了して JVM に戻った後は有効性が保証されません。うまくいくかもしれませんが、それに頼ることはできません。また、別のスレッドから使​​用すると、間違いなく機能しません。グローバル参照を作成する必要があります:

jclass localRef = (*e)->GetObjectClass(e,o);
clazz = (*e)->NewGlobalRef(e,localRef);

clazzその後、すでにCBTProcコメントアウトされている方法で使用できます。残っている唯一の作業は次のstophookとおりです。

(*e)->DeleteGlobalRef(e,clazz);

漏れないようにね。

一番下のメモ:「グローバル変数を共有する」という意味がわかりません。

于 2013-02-22T14:37:31.570 に答える