Java运用JNI调用dll实现屏蔽系统热键

【前言】

这几天用Java做个锁屏软件需要屏蔽系统热键,就是Win+D,Ctrl+Alt+Del等,

网上找了好多,发现这篇文章:

java运用jni调用dll(含源码)实现屏蔽系统热键和任务栏

http://hi.baidu.com/nowgame/blog/item/4530e11f20f289fee1fe0ba1.html

但是对于只懂Java的人无疑是一种折磨,

好不容易跟着文章做下来又报错,总之很是痛苦,

今天又看了篇文章:

http://wenku.baidu.com/view/51bf0d96daef5ef7ba0d3c54.html

结合这两篇文章终于实现了Java屏蔽系统热键了。

 

下面写出来,图文结合,宣泄一下这几天的郁闷。

 

【说明】

1.本文都是在eclipse下开发的,dos下可以自己尝试。

2.以下源码都是上面第一篇文章中的

 

【1】编写Java文件,编译出class文件,javah出.h文件

——Java源码

package com.uikoo9.JLocker;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;

/** 
* 
* @author Administrator 
*/ 
public class ShieldHotKey { 
    static{ 
    	//下面这部分是为了增加灵活性,dll可以放到jar包中
    	try
    	{
    		File file = File.createTempFile("shieldHK", ".dll");
            FileOutputStream fout = new FileOutputStream(file);
            InputStream in = ShieldHotKey.class.getResourceAsStream("shieldHK.dll");
            
            byte[] b = new byte[1024];
            int len = 0; 
            while((len = in.read(b)) != -1){
                fout.write(b, 0, len);
            }
            
            fout.flush();
            in.close();
            fout.close();
            
            System.load(file.getAbsolutePath());
		} 
    	catch (Exception e) {}
    	
//        System.load("D:/shieldHK.dll"); 
    } 
    public static native void Attach();//启动屏蔽 
    public static native void Detach();//关闭屏蔽 
} 

说明:1.类ShieldHotKey是建在com.uikoo9.JLocker包下的,

            2.将原来的System.load("D:/shieldHK.dll");改写是为了增加灵活性。

 ——Eclipse自动会生成.class文件,找到它,如图:

 

——cmd下,到这个bin的这一层,输入已下命令生成.h文件:

生成的.h文件:

 

 

【2】VC下生成dll文件

——在VC下新建一个dll工程,具体见下图:

说明:1.选择Win32 Dynamic-Link Library工程,

            2.工程名就是将来生成的dll名称,但是无关紧要可以更改。

            3.点确定之后选一个空的dll工程,完成。

 

——找到这个工程在电脑上的地方:

 

——将以下三个.h文件都复制到上面工程文件夹中

第一个.h文件:com_uikoo9_JLocker_ShieldHotKey.h,就是刚才生成的.h文件;

第二个.h文件:jni.h,在jdk下include文件夹下;

第三个.h文件:jni_md.h,在jdk下include文件夹下的win32文件夹中;

 

——VC中导入.h文件

在FileView窗口中,右键Header Files文件夹选添加文件到目录,将上面的三个文件都导入。

 

——VC中编写cpp文件

VC中新建——文件——C++ Source File ——文件名随便起

代码如下:

/* Replace "dll.h" with the name of your header */ 
#include "shieldHK.h" 
#define _WIN32_WINNT 0x0500 //Use WH_KEYBOARD_LL 
#include <windows.h> 
#include <stdio.h> 

//SAS window句柄 
HWND hSASWnd = NULL; 
//原有SAS window回调函数地址 
FARPROC FOldProc = NULL; 
//起屏蔽作用的新SAS window回调函数 
LRESULT CALLBACK SASWindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam); 
//枚举所有窗体句柄的回调函数 
BOOL CALLBACK EnumWindowsProc(HWND hwnd,LPARAM lParam); 
//Dll所创建线程的句柄 
HANDLE hThread = NULL; 
//Dll所创建线程的ID 
DWORD dwThreadId = 0; 
//Dll所创建线程的线程函数 
DWORD WINAPI ThreadFunc(); 
//_H钩子句柄 
HHOOK hHook = NULL; 
//_H低级键盘钩子回调函数 
LRESULT CALLBACK KeyboardProc(int,WPARAM,LPARAM); 
//对外输出字符串 
char szOutput[36]; 

BOOL APIENTRY Attach() 
{ 
     switch(DLL_PROCESS_ATTACH) 
     { 
      case DLL_PROCESS_ATTACH: 
      sprintf(szOutput,"Dll成功加载于 %d 号进程。",GetCurrentProcessId()); 
      OutputDebugString(szOutput); 
      //创建更替SAS window回调函数的线程 
      if(FOldProc == NULL) 
                  hThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadFunc,NULL,0,&dwThreadId); 
      break; 
      case DLL_PROCESS_DETACH: 
      sprintf(szOutput,"Dll成功卸载。",GetCurrentProcessId()); 
      //MessageBox(NULL, szOutput, "ZZ", MB_ICONINFORMATION | MB_OK); 
      OutputDebugString(szOutput); 
      //恢复原有SAS window的回调函数 
      if(FOldProc != NULL) 
                SetWindowLong(hSASWnd,GWL_WNDPROC,long(FOldProc));            
      //_H卸载低级键盘钩子 
      if(hHook != NULL) 
      { 
       if(!UnhookWindowsHookEx(hHook)) 
       { 
        OutputDebugString("Unhook failed.."); 
        //__leave; 
        break; 
       } 
       OutputDebugString("键盘钩子成功取消"); 
      } 
      TerminateThread(hThread,1); 
      CloseHandle(hThread); 
      break; 
      case DLL_THREAD_ATTACH: 
      break; 
      case DLL_THREAD_DETACH: 
      break; 
     } 
     return TRUE; 
} 

BOOL APIENTRY Detach() 
{ 
     switch(DLL_PROCESS_DETACH) 
     { 
      case DLL_PROCESS_ATTACH: 
      sprintf(szOutput,"Dll成功加载于 %d 号进程。",GetCurrentProcessId()); 
      OutputDebugString(szOutput); 
      //创建更替SAS window回调函数的线程 
      if(FOldProc == NULL) 
                  hThread = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)ThreadFunc,NULL,0,&dwThreadId); 
      break; 
      case DLL_PROCESS_DETACH: 
      sprintf(szOutput,"Dll成功卸载。",GetCurrentProcessId()); 
      //MessageBox(NULL, szOutput, "ZZ", MB_ICONINFORMATION | MB_OK); 
      OutputDebugString(szOutput); 
      //恢复原有SAS window的回调函数 
      if(FOldProc != NULL) 
                SetWindowLong(hSASWnd,GWL_WNDPROC,long(FOldProc));            
      //_H卸载低级键盘钩子 
      if(hHook != NULL) 
      { 
       if(!UnhookWindowsHookEx(hHook)) 
       { 
        OutputDebugString("Unhook failed.."); 
        //__leave; 
        break; 
       } 
       OutputDebugString("键盘钩子成功取消"); 
      } 
      TerminateThread(hThread,1); 
      CloseHandle(hThread); 
      break; 
      case DLL_THREAD_ATTACH: 
      break; 
      case DLL_THREAD_DETACH: 
      break; 
     } 
     return TRUE; 
} 

//Dll所创建线程的线程函数 
DWORD WINAPI ThreadFunc() 
{ 
      //打开Winlogon桌面 
      HDESK hDesk = OpenDesktop("Winlogon",0,FALSE,MAXIMUM_ALLOWED); 
      //枚举桌面所有窗体 
      EnumDesktopWindows(hDesk,(WNDENUMPROC)EnumWindowsProc,0); 
      //修改SAS window的回调函数 
      if(hSASWnd != NULL) 
      { 
       FOldProc = (FARPROC)SetWindowLong(hSASWnd,GWL_WNDPROC,long(SASWindowProc)); 
      } 
      CloseHandle(hDesk); 
      //_H同一桌面上进程之间只能发送窗口消息。无法跨进程与其他桌面发送它们。 
      //_H同样,Windows消息是限制应用程序定义挂钩。 
      //_H特定桌面中运行的进程挂钩过程将〈〈只获得针对同一桌面上创建窗口消息。〉〉 
      //_H详见http://support.microsoft.com/kb/171890/zh-cn 
      //_H所以,这里必须设置钩子所在线程的桌面为Default桌面 
      //_H才能使得钩子所在线程能接收到Default桌面的消息 
      hDesk = OpenDesktop("Default",0,FALSE,MAXIMUM_ALLOWED); 
      SetThreadDesktop(hDesk); 
      CloseHandle(hDesk); 
      //_H设置低级键盘钩子,屏蔽非SAS window的热键 
      //_H需要#define _WIN32_WINNT 0x0500 
      hHook = SetWindowsHookEx(WH_KEYBOARD_LL,KeyboardProc,GetModuleHandle(NULL),0); 
      if (hHook == NULL) 
      { 
       OutputDebugString("Set hook failed.."); 
       //__leave; 
       return 1; 
      } 
      OutputDebugString("键盘钩子成功设置"); 
      //_H在非GUI线程中使用消息钩子必须主动接收并分发收到的消息 
      MSG msg; 
      while(GetMessage(&msg, NULL, 0, 0)) 
      { 
       TranslateMessage(&msg); 
       DispatchMessage(&msg); 
      } 
      return 1; 
} 


//枚举所有窗体句柄的回调函数 
BOOL CALLBACK EnumWindowsProc(HWND hwnd,LPARAM lParam) 
{ 
     char ClassBuf[128]; 
     //获得当前窗体的显示文本 
     GetWindowText(hwnd,ClassBuf,sizeof(ClassBuf)); 
     //在"Winlogon"桌面中查询窗口"SAS window"。 
     if(strstr(ClassBuf,"SAS window")!=NULL) 
     { 
      //返回SAS window句柄 
      hSASWnd = hwnd; 
      return FALSE; 
     } 
     return TRUE; 
} 


//起屏蔽作用的新SAS window回调函数 
LRESULT CALLBACK SASWindowProc(HWND hwnd,UINT uMsg,WPARAM wParam,LPARAM lParam) 
{ 
        if(uMsg == WM_HOTKEY) 
        { 
         //屏蔽所有WM_HOTKEY消息 
         OutputDebugString("All SAS window's hotkeys are disabled"); 
         return 1; 
         WORD wKey = HIWORD(lParam); 
         WORD wModifier = LOWORD(lParam); 
         bool IsCtrlDown = ((wModifier & VK_CONTROL) != 0); 
         bool IsAltDown = ((wModifier & VK_MENU) != 0); 
         bool IsShiftDown = ((wModifier & VK_SHIFT) != 0); 
         //Ctrl + Alt + Del组合键 
         if(IsCtrlDown && IsAltDown && wKey == VK_DELETE) 
         { 
          return 1; //屏蔽 
         } 
         //Ctrl + Shift + Esc组合键,这个组合键将显示任务管理器,可根据需要是否屏蔽。 
         else if(IsCtrlDown && IsShiftDown && wKey == VK_ESCAPE) 
         { 
          // Do nothing 
         } 
        } 
        return CallWindowProc((WNDPROC)FOldProc,hwnd,uMsg,wParam,lParam); 
} 


//_H低级键盘钩子回调函数 
LRESULT CALLBACK KeyboardProc(int nCode,WPARAM wParam,LPARAM lParam) 
{ 
        if (nCode == HC_ACTION) 
        { 
         switch (wParam) 
         { 
          case WM_KEYDOWN: case WM_SYSKEYDOWN: 
          //case WM_KEYUP:    case WM_SYSKEYUP: 
          PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT) lParam; 
          if (p->vkCode == VK_F12) 
          { 
           //实现模拟按键代码 
           MessageBox(GetForegroundWindow(),"I'm in position..","ZZ",MB_OK); 
          } 
          //屏蔽ALT+TAB 
          else if ((p->vkCode == VK_TAB) && ((p->flags & LLKHF_ALTDOWN) != 0)) 
          { 
           OutputDebugString("ALT+TAB is disabled"); 
           return 1; 
          } 
          //屏蔽ALT+ESC 
          else if ((p->vkCode == VK_ESCAPE) && ((p->flags & LLKHF_ALTDOWN) != 0)) 
          { 
           OutputDebugString("ALT+ESC is disabled"); 
           return 1; 
          } 
          //屏蔽CTRL+ESC 
          else if ((p->vkCode == VK_ESCAPE) && ((GetKeyState(VK_CONTROL) & 0x8000) != 0)) 
          { 
           OutputDebugString("CTRL+ESC is disabled"); 
           return 1; 
          } 
          //屏蔽CTRL+SHIFT+ESC,(SAS window中也已屏蔽) 
          else if ((p->vkCode == VK_ESCAPE) && 
          ((GetKeyState(VK_CONTROL) & 0x8000) != 0) && 
          ((GetKeyState(VK_SHIFT) & 0x8000) != 0)) 
          { 
           OutputDebugString("CTRL+SHIFT+ESC is disabled"); 
           return 1; 
          } 
          //屏蔽ALT+F4 
          else if ((p->vkCode == VK_F4) && ((p->flags & LLKHF_ALTDOWN) != 0)) 
          { 
           OutputDebugString("ALT+F4 is disabled"); 
           return 1; 
          } 
          //屏蔽左右windows键 
          else if (p->vkCode == VK_LWIN || p->vkCode == VK_RWIN) 
          { 
           OutputDebugString("windows key is disabled"); 
           return 1; 
          } 
          //此处无法屏蔽CTRL+ALT+DEL,已在SAS window中屏蔽 
          else if ((p->vkCode == VK_DELETE) && 
          ((GetKeyState(VK_CONTROL) & 0x8000) != 0) && 
          ((GetKeyState(VK_MENU) & 0x8000) != 0 )) 
                                 return 1; 
          break; 
         } 
        } 
        return CallNextHookEx(hHook,nCode,wParam,lParam); 
} 

JNIEXPORT void JNICALL Java_shieldHK_ShieldHotKey_Attach 
(JNIEnv *env, jclass obj){ 
Attach(); 
} 

JNIEXPORT void JNICALL Java_shieldHK_ShieldHotKey_Detach 
(JNIEnv *env, jclass obj){ 
Detach(); 
} 


 

——对几个文件的修改

将com_uikoo9_JLocker_ShieldHotKey.h中的#include <jni.h>改为#include "jni.h"

将test.cpp中的#include "shieldHK.h"改为#include "com_uikoo9_JLocker_ShieldHotKey.h",也就是上面的.h文件

test.cpp的末尾两个方法的代码如下:

JNIEXPORT void JNICALL Java_shieldHK_ShieldHotKey_Attach 
(JNIEnv *env, jclass obj){ 
Attach(); 
} 

JNIEXPORT void JNICALL Java_shieldHK_ShieldHotKey_Detach 
(JNIEnv *env, jclass obj){ 
Detach(); 
} 

 

com_uikoo9_JLocker_ShieldHotKey.h中的两个方法代码如下:

JNIEXPORT void JNICALL Java_com_uikoo9_JLocker_ShieldHotKey_Attach
  (JNIEnv *, jclass);

/*
 * Class:     com_uikoo9_JLocker_ShieldHotKey
 * Method:    Detach
 * Signature: ()V
 */
JNIEXPORT void JNICALL Java_com_uikoo9_JLocker_ShieldHotKey_Detach
  (JNIEnv *, jclass);


将test.cpp中的两个方法名改为com_uikoo9_JLocker_ShieldHotKey.h中两个对应的方法名,

否则在eclipse中会报错。

 

——VC中编译cpp文件生成dll文件

对test.cpp先Compile再Build,生成dll文件

生成的dll文件在vc项目的debug文件夹中

 

【3】Eclipse中使用

——将testdll.dll文件改名为shieldHK.dll,复制到eclipse中java代码处,如图:

 

——编写test.java测验一下能行不,代码:

package com.uikoo9.JLocker;

public class Test
{
	public static void main(String[] args)
	{
		try
		{
			ShieldHotKey.Attach();
			Thread.sleep(5000);//5秒内键盘热键都被屏蔽了。
		} 
		catch (Exception e) {}
	}
}


 

【后记】

成功了,

从想到到实现,过程是痛苦的,结果是欣喜的,

有不懂得可以留言。

 

感谢上面两篇文章!


 

 

©️2020 CSDN 皮肤主题: 大白 设计师:CSDN官方博客 返回首页