实现全局hook必须要将hook代码封装在dll里,所以此程序有两个文件:noShiftDeleteHook.dll和noShiftDelete.exe
noShiftDeleteHook.dll
//noShiftDeleteHook.h #ifdef NOSHIFTDELETEHOOK_EXPORTS #define NOSHIFTDELETEHOOKDLL_API __declspec(dllexport) #else #define NOSHIFTDELETEHOOKDLL_API __declspec(dllimport) #endif NOSHIFTDELETEHOOKDLL_API void InstallHook(HINSTANCE); NOSHIFTDELETEHOOKDLL_API void UnInstallHook();
// noShiftDeleteHook.cpp : 定义 DLL 应用程序的导出函数。 // #include "stdafx.h" #include "noShiftDeleteHook.h" HHOOK hook=NULL; LRESULT CALLBACK keyHookCallback (int nCode,WPARAM wParam,LPARAM lParam) { char ch; LRESULT result=::CallNextHookEx(hook,nCode,wParam,lParam); KBDLLHOOKSTRUCT *pkbhs = (KBDLLHOOKSTRUCT *)lParam; BOOL bShiftKeyDown = 0; if (wParam==WM_KEYDOWN && nCode == HC_ACTION) { bShiftKeyDown=GetAsyncKeyState (VK_SHIFT) >> ((sizeof(SHORT) * 8) - 1); if (pkbhs->vkCode == VK_DELETE && bShiftKeyDown) { MessageBox(0,L"拒绝手贱,养成良好习惯,从你做起!",L"不准使用Shift+Delete",MB_OK|MB_SETFOREGROUND|MB_TOPMOST); return TRUE; } } return result; } NOSHIFTDELETEHOOKDLL_API void InstallHook(HINSTANCE _hinstance) { hook=(HHOOK)::SetWindowsHookEx(WH_KEYBOARD_LL,(HOOKPROC)keyHookCallback,_hinstance,NULL); if(hook==NULL) { MessageBox(0,L"安装全局系统钩子失败!",L"提示",MB_OK); } } NOSHIFTDELETEHOOKDLL_API void UnInstallHook() { BOOL result=UnhookWindowsHookEx(hook); }
noShiftDelete.exe
// noShiftDelete.cpp : 定义应用程序的入口点。 // #include "stdafx.h" #include "noShiftDelete.h" #include <shellapi.h> #include "../noShiftDeleteHook/noShiftDeleteHook.h" #pragma comment(lib,"../Release/noShiftDeleteHook.lib") #define MAX_LOADSTRING 100 #define WM_TRAY (WM_USER + 100) #define WM_TASKBAR_CREATED RegisterWindowMessage(TEXT("TaskbarCreated")) // 全局变量: HINSTANCE hInst; // 当前实例 TCHAR szTitle[MAX_LOADSTRING]; // 标题栏文本 TCHAR szWindowClass[MAX_LOADSTRING]; // 主窗口类名 HMENU hMenu; NOTIFYICONDATA nid; // 此代码模块中包含的函数的前向声明: ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); //实例化托盘 void InitTray(HINSTANCE hInstance, HWND hWnd) { nid.cbSize = sizeof(NOTIFYICONDATA); nid.hWnd = hWnd; nid.uID = WM_TRAY; nid.uFlags = NIF_ICON | NIF_MESSAGE | NIF_TIP | NIF_INFO; nid.uCallbackMessage = WM_TRAY; nid.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_SMALL)); lstrcpy(nid.szTip, L"noShiftDelete v1.0"); hMenu = CreatePopupMenu();//生成托盘菜单 //为托盘菜单添加两个选项 AppendMenu(hMenu, MF_STRING,ID_ABOUT, TEXT("关于...")); AppendMenu(hMenu, MF_SEPARATOR,ID_TITLE , TEXT("分割线")); AppendMenu(hMenu, MF_STRING, ID_EXIT, TEXT("退出")); Shell_NotifyIcon(NIM_ADD, &nid); } int APIENTRY _tWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine, int nCmdShow) { UNREFERENCED_PARAMETER(hPrevInstance); UNREFERENCED_PARAMETER(lpCmdLine); //互斥量阻止程序多次运行 HANDLE m_hMutex = CreateMutex(NULL,FALSE, L"noShiftDelete"); if (GetLastError() ==ERROR_ALREADY_EXISTS) { // 如果已有互斥量存在则释放句柄并复位互斥量 CloseHandle(m_hMutex); m_hMutex=NULL; return FALSE; } // TODO: 在此放置代码。 MSG msg; HACCEL hAccelTable; // 初始化全局字符串 LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING); LoadString(hInstance, IDC_NOSHIFTDELETE, szWindowClass, MAX_LOADSTRING); MyRegisterClass(hInstance); // 执行应用程序初始化: if (!InitInstance (hInstance, nCmdShow)) { return FALSE; } hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_NOSHIFTDELETE)); // 主消息循环: while (GetMessage(&msg, NULL, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } } return (int) msg.wParam; } // // 函数: MyRegisterClass() // // 目的: 注册窗口类。 // // 注释: // // 仅当希望 // 此代码与添加到 Windows 95 中的“RegisterClassEx” // 函数之前的 Win32 系统兼容时,才需要此函数及其用法。调用此函数十分重要, // 这样应用程序就可以获得关联的 // “格式正确的”小图标。 // ATOM MyRegisterClass(HINSTANCE hInstance) { WNDCLASSEX wcex; wcex.cbSize = sizeof(WNDCLASSEX); wcex.style = CS_HREDRAW | CS_VREDRAW; wcex.lpfnWndProc = WndProc; wcex.cbClsExtra = 0; wcex.cbWndExtra = 0; wcex.hInstance = hInstance; wcex.hIcon = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_NOSHIFTDELETE)); wcex.hCursor = LoadCursor(NULL, IDC_ARROW); wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); wcex.lpszMenuName = MAKEINTRESOURCE(IDC_NOSHIFTDELETE); wcex.lpszClassName = szWindowClass; wcex.hIconSm = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL)); return RegisterClassEx(&wcex); } // // 函数: InitInstance(HINSTANCE, int) // // 目的: 保存实例句柄并创建主窗口 // // 注释: // // 在此函数中,我们在全局变量中保存实例句柄并 // 创建和显示主程序窗口。 // BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HWND hWnd; hInst = hInstance; // 将实例句柄存储在全局变量中 hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW&~WS_MAXIMIZEBOX, CW_USEDEFAULT, 0, 400, 200, NULL, NULL, hInstance, NULL); //安装钩子 HINSTANCE hinstance=GetModuleHandle(L"noShiftDeleteHook.dll"); InstallHook(hinstance); if (!hWnd) { return FALSE; } ShowWindow(hWnd, SW_HIDE); UpdateWindow(hWnd); //实例化托盘 InitTray(hInstance, hWnd); return TRUE; } // // 函数: WndProc(HWND, UINT, WPARAM, LPARAM) // // 目的: 处理主窗口的消息。 // // WM_COMMAND - 处理应用程序菜单 // WM_PAINT - 绘制主窗口 // WM_DESTROY - 发送退出消息并返回 // // LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) { int wmId, wmEvent; PAINTSTRUCT ps; HDC hdc; switch (message) { case WM_TRAY: switch(lParam) { case WM_RBUTTONDOWN: { //获取鼠标坐标 POINT pt; GetCursorPos(&pt); //解决在菜单外单击左键菜单不消失的问题 SetForegroundWindow(hWnd); //使菜单某项变灰 //EnableMenuItem(hMenu, ID_SHOW, MF_GRAYED); //显示并获取选中的菜单 int cmd = TrackPopupMenu(hMenu, TPM_RETURNCMD, pt.x, pt.y, NULL, hWnd, NULL); if(cmd == ID_EXIT) PostMessage(hWnd, WM_DESTROY, NULL, NULL); if(cmd == ID_ABOUT) MessageBox(0,L"Email: rophie123@foxmail.com",L"noShiftDelete v1.0",MB_OK); } break; } break; case WM_PAINT: hdc = BeginPaint(hWnd, &ps); // TODO: 在此添加任意绘图代码... EndPaint(hWnd, &ps); break; case WM_DESTROY: UnInstallHook(); Shell_NotifyIcon(NIM_DELETE, &nid); PostQuitMessage(0); break; default: return DefWindowProc(hWnd, message, wParam, lParam); } if (message == WM_TASKBAR_CREATED) { //系统Explorer崩溃重启时,重新加载托盘 Shell_NotifyIcon(NIM_ADD, &nid); } return 0; }
启动后窗体隐藏最小化到托盘,使用shift+delete时会提示并阻止
编译后文件:点击下载