我用WH_JOURNALRECORD记录键盘操作,然后用WH_JOURNALPLAYBACK回放,但回放的时候所有的鼠标和键盘都被屏蔽,我想在回放过程中可以进行回放终止操作,请问各位专家有没有办法可以解决? 

解决方案 »

  1.   

    /*****************HOOKService.h***********************/BOOL InstallOperationsHook(HWND,HINSTANCE);
    BOOL InstallOperationsDisplayHook(HWND,HINSTANCE);
    BOOL UnInstallOperationsHook();
    BOOL UnInstallOperationsDisplayHook();
    BOOL CheckOperationsRecordHookHandle();
    BOOL CheckOperationsDisplayHookHandle();
    LRESULT CALLBACK JournalPlaybackProc(int,WPARAM,LPARAM);
    LRESULT CALLBACK JournalRecordProc(int,WPARAM,LPARAM);
    LPCTSTR GetMsgName(UINT);
    void FreeMsgList();/*****************HOOKService.h***********************/
      

  2.   

    /*****************HOOKService.cpp***********************/#include "stdafx.h"#include "HOOKService.h"BOOL InstallOperationsHook(HWND hWnd,HINSTANCE hInst)
    {
     if (!UnInstallOperationsDisplayHook())
      return FALSE; if (CheckOperationsRecordHookHandle())
      return TRUE; g_AppInstance = hInst; g_Dlg_Hwnd = hWnd; FreeMsgList(); g_hHookOperationsRecord = ::SetWindowsHookEx(WH_JOURNALRECORD,
      JournalRecordProc,
      g_AppInstance,
      0); return g_hHookOperationsRecord ? TRUE : FALSE;
    }BOOL InstallOperationsDisplayHook(HWND hWnd,HINSTANCE hInst)
    {
     if (!UnInstallOperationsHook())
      return FALSE; if (CheckOperationsDisplayHookHandle())
      return TRUE; g_AppInstance = hInst; g_Dlg_Hwnd = hWnd; g_pMsgListPrev = g_pMsgMovePtr = g_pMsgListLast = NULL; RetTime = 0; g_hHookOperationsDisplay = ::SetWindowsHookEx(WH_JOURNALPLAYBACK,
      JournalPlaybackProc,
      g_AppInstance,
      0); return g_hHookOperationsDisplay ? TRUE : FALSE;
    }LRESULT CALLBACK JournalRecordProc(int nCode,WPARAM wParam,LPARAM lParam)
    {
     if (nCode < 0)
      return ::CallNextHookEx(g_hHookOperationsRecord,nCode,wParam,lParam);
     if (nCode == HC_ACTION)
     {
      MsgList* pTmpMsgList = new MsgList;
      pTmpMsgList->Event.hwnd = ((LPEVENTMSG)lParam)->hwnd;
      pTmpMsgList->Event.message = ((LPEVENTMSG)lParam)->message;
      pTmpMsgList->Event.paramH = ((LPEVENTMSG)lParam)->paramH;
      pTmpMsgList->Event.paramL = ((LPEVENTMSG)lParam)->paramL;
      pTmpMsgList->Event.time = ((LPEVENTMSG)lParam)->time;
      if (!g_pMsgMovePtr)
      {
       if (!g_pMsgListHeader)
        g_pMsgListPrev = g_pMsgListHeader = g_pMsgMovePtr = pTmpMsgList;
      }
      else
      {
       g_pMsgListLast = pTmpMsgList;/*将新消息作为最后的消息*/
       g_pMsgListPrev = g_pMsgMovePtr;/*保存上次的消息*/
       g_pMsgMovePtr->lpNext = pTmpMsgList;/*将新消息挂到消息列表*/
       g_pMsgMovePtr = pTmpMsgList;/*将实时指针指向最后的消息*/
      }
      ::PostMessage(g_Dlg_Hwnd,WM_PASSDATA,wParam,(LPARAM)pTmpMsgList);
     } return ::CallNextHookEx(g_hHookOperationsRecord,nCode,wParam,lParam);
    }LRESULT CALLBACK JournalPlaybackProc(int nCode,WPARAM wParam,LPARAM lParam)
    {
     if (nCode < 0)
      return ::CallNextHookEx(g_hHookOperationsDisplay,nCode,wParam,lParam); if (!g_pMsgMovePtr)
     {
      if (!g_pMsgListHeader)
      {
       return UnInstallOperationsDisplayHook();
      }
      g_pMsgMovePtr = g_pMsgListHeader;
      g_pMsgListPrev = g_pMsgListHeader;
     } switch (nCode)
     {
     case HC_GETNEXT:
      /*********************************************************************
       *The hook procedure must copy the current mouse or keyboard message * 
       *to the EVENTMSG structure pointed to by the lParam parameter.      *
       *********************************************************************/
      {
       LPEVENTMSG lpEvent = (LPEVENTMSG)lParam;
       if (g_pMsgMovePtr && g_pMsgListPrev && lpEvent)
       {
        lpEvent->message = g_pMsgListPrev->Event.message;
        lpEvent->paramL = g_pMsgListPrev->Event.paramL;
        lpEvent->paramH = g_pMsgListPrev->Event.paramH;
        lpEvent->time = g_pMsgListPrev->Event.time;
        lpEvent->hwnd = g_pMsgListPrev->Event.hwnd;
        RetTime = g_pMsgMovePtr->Event.time - g_pMsgListPrev->Event.time;    if (g_pMsgMovePtr != g_pMsgListPrev)
        {
         g_pMsgListPrev = g_pMsgMovePtr;
        }
      
       }
       if (RetTime < 0)
         RetTime = 1;
       return RetTime;
      }
     case HC_SKIP:
      /*****************************************************************************
       *The hook procedure must prepare to copy the next mouse or keyboard message * 
       *to the EVENTMSG structure pointed to by lParam.                            *
       *Upon receiving the HC_GETNEXT code,                                        *
       *the hook procedure must copy the message to the structure.                 *
       *****************************************************************************/
      {
       if (!g_pMsgMovePtr->lpNext)
       {
        return UnInstallOperationsDisplayHook();
       }   if (g_pMsgListPrev != g_pMsgMovePtr)
        g_pMsgListPrev = g_pMsgMovePtr;   g_pMsgMovePtr = g_pMsgMovePtr->lpNext;
       return 0;
      }
     default:
      break;
     }
     return ::CallNextHookEx(g_hHookOperationsDisplay,nCode,wParam,lParam);
    }BOOL CheckOperationsRecordHookHandle()
    {
     return g_hHookOperationsRecord ? TRUE : FALSE;
    }BOOL CheckOperationsDisplayHookHandle()
    {
     return g_hHookOperationsDisplay ? TRUE : FALSE;
    }BOOL UnInstallOperationsHook()
    {
     if (!g_hHookOperationsRecord)
      return TRUE; BOOL IsUnInstallSuccess = ::UnhookWindowsHookEx(g_hHookOperationsRecord); g_hHookOperationsRecord = NULL; return IsUnInstallSuccess;
    }BOOL UnInstallOperationsDisplayHook()
    {
     if (!g_hHookOperationsDisplay)
      return TRUE; BOOL IsUnInstallSuccess = ::UnhookWindowsHookEx(g_hHookOperationsDisplay); g_hHookOperationsDisplay = NULL; return IsUnInstallSuccess;
    }LPCTSTR GetMsgName(UINT nCode)
    {
     for(int i=0,nCount=sizeof(messages)/sizeof(MsgStruct);i<nCount;++i)
     {
      if(messages[i].nCode == nCode)
       return messages[i].pszText;
     }
     return "Sorry,I Don't Know.";
    }void FreeMsgList()
    {
     delete g_pMsgListHeader;
     g_pMsgMovePtr = NULL;
     g_pMsgListHeader = NULL;
     g_pMsgListLast = NULL;
     g_pMsgListPrev = NULL;
     RetTime = 0;
    }/*****************HOOKService.cpp***********************/
      

  3.   

    /*****************stdafx.h***********************/
    #pragma once#ifndef VC_EXTRALEAN
    #define VC_EXTRALEAN  // 从 Windows 标头中排除不常使用的资料
    #endif// 如果您必须使用下列所指定的平台之前的平台,则修改下面的定义。
    // 有关不同平台的相应值的最新信息,请参考 MSDN。
    #ifndef WINVER             //允许使用 Windows 95 和 Windows NT 4 或更高版本的特定功能。
    #define WINVER 0x0400  //为 Windows98 和 Windows 2000 及更新版本改变为适当的值。
    #endif#ifndef _WIN32_WINNT  // 允许使用 Windows NT 4 或更高版本的特定功能。
    #define _WIN32_WINNT 0x0400  //为 Windows98 和 Windows 2000 及更新版本改变为适当的值。
    #endif#ifndef _WIN32_WINDOWS  // 允许使用 Windows 98 或更高版本的特定功能。
    #define _WIN32_WINDOWS 0x0410 //为 Windows Me 及更新版本改变为适当的值。
    #endif#ifndef _WIN32_IE          //允许使用 IE 4.0 或更高版本的特定功能。
    #define _WIN32_IE 0x0400 //为 IE 5.0 及更新版本改变为适当的值。
    #endif#define _ATL_CSTRING_EXPLICIT_CONSTRUCTORS // 某些 CString 构造函数将是显式的
    ....
    #ifndef _AFX_NO_AFXCMN_SUPPORT
    #include <afxcmn.h>// Windows 公共控件的 MFC 支持
    #endif // _AFX_NO_AFXCMN_SUPPORT
    #define WM_PASSDATA WM_USER+1982
    #include <vector>
    using namespace std;
    #include <windowsx.h>
    #include <winable.h>struct MsgStruct
    {
     UINT nCode;
     LPCTSTR pszText;
    };struct MsgList
    {
    public:
     MsgList()
     {
      memset(&Event,0,sizeof(EVENTMSG));
      lpNext = NULL;
     }
     ~MsgList()
     {
      if (lpNext && !::IsBadReadPtr(lpNext,sizeof(MsgList)))
       delete lpNext;
      memset(&Event,0,sizeof(EVENTMSG));
      lpNext = NULL;
     }
     EVENTMSG Event;
     MsgList *lpNext;
    };
    static HHOOK g_hHookOperationsRecord = NULL;
    static HHOOK g_hHookOperationsDisplay = NULL;
    static HINSTANCE g_AppInstance = NULL;
    static MsgList* g_pMsgMovePtr = NULL;
    static MsgList* g_pMsgListHeader = NULL;
    static MsgList* g_pMsgListLast = NULL;
    static MsgList* g_pMsgListPrev = NULL;
    static HWND g_Dlg_Hwnd = NULL;
    static DWORD RetTime = 0;
    static MsgStruct messages[] = {
            ...};
    /*****************stdafx.h***********************//*****************MessageTipDlg.h***********************/
    #pragma once
    #include "afxcmn.h"
     
    // CMessageTipDlg 对话框
    class CMessageTipDlg : public CDialog
    {
    // 构造
    public:
     CMessageTipDlg(CWnd* pParent = NULL); // 标准构造函数// 对话框数据
     enum { IDD = IDD_MESSAGETIP_DIALOG }; protected:
     virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
    // 实现
    protected:
     HICON m_hIcon; // 生成的消息映射函数
     virtual BOOL OnInitDialog();
     afx_msg void OnPaint();
     afx_msg HCURSOR OnQueryDragIcon();
     DECLARE_MESSAGE_MAP()
    public:
     afx_msg void OnBnClickedButtonStart();
     afx_msg void OnBnClickedButtonDisplay();
     afx_msg void OnBnClickedButtonExit();
     afx_msg void OnOK();
     afx_msg void OnCancel();
     afx_msg void OnClose();
     afx_msg LRESULT OnPassData(WPARAM,LPARAM);
    private:
     void EnableDisplayFunction(BOOL = TRUE);
     void EnableStartRecordFunction(BOOL = TRUE);
     CListCtrl m_ListCtrl_MsgTip;
     CImageList m_ImageList;
     CFile m_FileOut;
     void InitListCtrl();
    protected:
     virtual LRESULT WindowProc(UINT message, WPARAM wParam, LPARAM lParam);
    public:
     virtual BOOL PreTranslateMessage(MSG* pMsg);
     virtual BOOL DestroyWindow();
     afx_msg void OnBnClickedButtonOpenrecord();
     afx_msg void OnBnClickedButtonSaverecord();
    };
    /*****************MessageTipDlg.h***********************/
      

  4.   

    /*****************MessageTipDlg.cpp***********************/// MessageTipDlg.cpp : 实现文件
    //
    #include "stdafx.h"#include "MessageTip.h"
    #include "MessageTipDlg.h"#include "HOOKService.h"
    #include ".\messagetipdlg.h"#ifdef _DEBUG
    #define new DEBUG_NEW
    #endif
    // CMessageTipDlg 对话框CMessageTipDlg::CMessageTipDlg(CWnd* pParent /*=NULL*/)
     : CDialog(CMessageTipDlg::IDD, pParent)
    {
     m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
    }void CMessageTipDlg::DoDataExchange(CDataExchange* pDX)
    {
     CDialog::DoDataExchange(pDX);
     DDX_Control(pDX, IDC_LIST_MSGTIP, m_ListCtrl_MsgTip);
    }BEGIN_MESSAGE_MAP(CMessageTipDlg, CDialog)
     ON_WM_PAINT()
     ON_WM_QUERYDRAGICON()
     //}}AFX_MSG_MAP
     ON_BN_CLICKED(ID_BUTTON_START, OnBnClickedButtonStart)
     ON_BN_CLICKED(ID_BUTTON_DISPLAY, OnBnClickedButtonDisplay)
     ON_BN_CLICKED(ID_BUTTON_EXIT, OnBnClickedButtonExit)
     ON_MESSAGE(WM_PASSDATA,OnPassData)
    // ON_WM_SIZE()
    ON_BN_CLICKED(ID_BUTTON_OPENRECORD, OnBnClickedButtonOpenrecord)
    ON_BN_CLICKED(ID_BUTTON_SAVERECORD, OnBnClickedButtonSaverecord)
    END_MESSAGE_MAP()
    // CMessageTipDlg 消息处理程序BOOL CMessageTipDlg::OnInitDialog()
    {
     CDialog::OnInitDialog(); // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动
     //  执行此操作
     SetIcon(m_hIcon, TRUE);   // 设置大图标
     SetIcon(m_hIcon, TRUE);  // 设置小图标 // TODO: 在此添加额外的初始化代码
     EnableDisplayFunction(FALSE); m_ImageList.Create(16,16,ILC_COLOR32,1,1);
    // m_ImageList.Add(AfxGetApp()->LoadIcon(IDI_MSGNAME));
    // m_ImageList.Add(AfxGetApp()->LoadIcon(IDI_MSGTIME));
    // m_ImageList.Add(AfxGetApp()->LoadIcon(IDI_MSGPARAM));
     m_ImageList.Add(m_hIcon); InitListCtrl(); return TRUE;  // 除非设置了控件的焦点,否则返回 TRUE
    }// 如果向对话框添加最小化按钮,则需要下面的代码
    //  来绘制该图标。对于使用文档/视图模型的 MFC 应用程序,
    //  这将由框架自动完成。void CMessageTipDlg::OnPaint() 
    {
     if (IsIconic())
     {
      CPaintDC dc(this); // 用于绘制的设备上下文  SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);  // 使图标在工作矩形中居中
      int cxIcon = GetSystemMetrics(SM_CXICON);
      int cyIcon = GetSystemMetrics(SM_CYICON);
      CRect rect;
      GetClientRect(&rect);
      int x = (rect.Width() - cxIcon + 1) / 2;
      int y = (rect.Height() - cyIcon + 1) / 2;  // 绘制图标
      dc.DrawIcon(x, y, m_hIcon);
     }
     else
     {
      CDialog::OnPaint();
     }
    }//当用户拖动最小化窗口时系统调用此函数取得光标显示。
    HCURSOR CMessageTipDlg::OnQueryDragIcon()
    {
     return static_cast<HCURSOR>(m_hIcon);
    }void CMessageTipDlg::OnBnClickedButtonStart()
    {
     // TODO: Add your control notification handler code here
     CFileDialog CommonFileDlg(FALSE,_T("hook"),_T("消息保存文件"));
     if (m_FileOut.m_hFile == INVALID_HANDLE_VALUE)
     {
      if (CommonFileDlg.DoModal() != IDOK)
      {
       AfxMessageBox("请选择消息保存位置^_^");
       return ;
      }
      CFileFind FindFind;
      if (FindFind.FindFile((LPCTSTR)CommonFileDlg.GetPathName(),0))
       m_FileOut.Open((LPCTSTR)CommonFileDlg.GetPathName(),CFile::modeReadWrite);
      else
       m_FileOut.Open((LPCTSTR)CommonFileDlg.GetPathName(),CFile::modeCreate|CFile::modeReadWrite);
     }
     else
      m_FileOut.SeekToBegin(); ULONGLONG ulFileLength = m_FileOut.GetLength();
     if (ulFileLength > 0xffff)
     {
      m_FileOut.Close();
      CString cstrNewFile(_T(""));
      cstrNewFile.Format("%s%I64d",CommonFileDlg.GetPathName(),rand() % ulFileLength);
      CFileFind FindFind;
      if (FindFind.FindFile((LPCTSTR)cstrNewFile,0))
       m_FileOut.Open((LPCTSTR)cstrNewFile,CFile::modeReadWrite);
      else
       m_FileOut.Open((LPCTSTR)cstrNewFile,CFile::modeCreate|CFile::modeReadWrite);
     } if (!InstallOperationsHook(m_hWnd,
      AfxGetApp()->m_hInstance))
     {
      AfxMessageBox("安装系统钩子失败!");
     } EnableStartRecordFunction(FALSE);
     EnableDisplayFunction();
    }void CMessageTipDlg::OnBnClickedButtonDisplay()
    {
     // TODO: Add your control notification handler code here
     if (!InstallOperationsDisplayHook(m_hWnd,
      AfxGetApp()->m_hInstance))
     {
      AfxMessageBox("安装系统钩子失败!");
     } EnableStartRecordFunction();
     EnableDisplayFunction(FALSE);
    }void CMessageTipDlg::OnBnClickedButtonExit()
    {
     // TODO: Add your control notification handler code here
     FreeMsgList();
     UnInstallOperationsHook();
     UnInstallOperationsDisplayHook();
     CDialog::OnOK();
    }void CMessageTipDlg::OnOK()
    {
     return ;
    }void CMessageTipDlg::OnCancel()
    {
     return ;
    }void CMessageTipDlg::OnClose()
    {
     return ;
    }void CMessageTipDlg::EnableDisplayFunction(BOOL IsEnable/* = TRUE */)
    {
     ((CButton*)GetDlgItem(ID_BUTTON_DISPLAY))->EnableWindow(IsEnable);
    }void CMessageTipDlg::EnableStartRecordFunction(BOOL IsEnable/* = TRUE */)
    {
     ((CButton*)GetDlgItem(ID_BUTTON_START))->EnableWindow(IsEnable);
    }
    void CMessageTipDlg::InitListCtrl()
    {
     g_AppInstance = AfxGetApp()->m_hInstance; m_ListCtrl_MsgTip.SetImageList(&m_ImageList,LVSIL_SMALL);
     LVCOLUMN col;
     col.mask = LVCF_FMT|LVCF_IMAGE|LVCF_SUBITEM|LVCF_TEXT|LVCF_WIDTH;
     col.fmt = LVCFMT_CENTER|LVCFMT_IMAGE;
     col.iImage = 0;
     col.cchTextMax = ::lstrlen("消息名称")+1;
     col.pszText = "消息名称";
     col.iSubItem = 0;
     CRect rect(0,0,0,0);
     m_ListCtrl_MsgTip.GetWindowRect(&rect);
     col.cx = 120;
     m_ListCtrl_MsgTip.InsertColumn(0,&col); col.cx = 120;
     col.cchTextMax = ::lstrlen("消息值")+1;
     col.pszText = "消息值";
     m_ListCtrl_MsgTip.InsertColumn(1,&col); col.cx = rect.Width();
     col.cchTextMax = ::lstrlen("消息时间")+1;
     col.pszText = "消息时间";
     m_ListCtrl_MsgTip.InsertColumn(2,&col);
    }LRESULT CMessageTipDlg::WindowProc(UINT message, WPARAM wParam, LPARAM lParam)
    {
     // TODO: Add your specialized code here and/or call the base class
     return CDialog::WindowProc(message, wParam, lParam);
    }BOOL CMessageTipDlg::PreTranslateMessage(MSG* pMsg)
    {
     // TODO: Add your specialized code here and/or call the base class
     return CDialog::PreTranslateMessage(pMsg);
    }LRESULT CMessageTipDlg::OnPassData(WPARAM wParam,LPARAM lParam)
    {
     LPEVENTMSG lpEventMsg = (LPEVENTMSG)lParam;
     CString cstrMsg(_T(""));
     TCHAR TargetWindowName[MAX_PATH] = { '\0' };
     ::GetWindowText(::GetActiveWindow(),TargetWindowName,MAX_PATH);
     COleDateTime cdt(COleDateTime::GetCurrentTime());
     CString cstrMsgName(GetMsgName(lpEventMsg->message));
     cstrMsg.Format("消息名称:%s\r\n消息目标窗体:%s\r\n消息发送时间:%s\r\n---------------------------------------------\r\n",
      cstrMsgName,TargetWindowName,
      cdt.Format("%Y年%m月%d日%H时%M分%S秒"));
     m_FileOut.Write((LPCTSTR)cstrMsg,cstrMsg.GetLength());
     m_ListCtrl_MsgTip.DeleteAllItems();
     m_ListCtrl_MsgTip.InsertItem(0,(LPCTSTR)cstrMsgName,0);
     m_ListCtrl_MsgTip.SetItemText(0,1,(LPCTSTR)TargetWindowName);
     m_ListCtrl_MsgTip.SetItemText(0,2,(LPCTSTR)cdt.Format("%Y年%m月%d日%H时%M分%S秒"));
     return 0;
    }BOOL CMessageTipDlg::DestroyWindow()
    {
     // TODO: Add your specialized code here and/or call the base class
     if (m_FileOut.m_hFile != INVALID_HANDLE_VALUE)
      m_FileOut.Close();
     return CDialog::DestroyWindow();
    }void CMessageTipDlg::OnBnClickedButtonOpenrecord()
    {
     // TODO: Add your control notification handler code here
    }void CMessageTipDlg::OnBnClickedButtonSaverecord()
    {
     // TODO: Add your control notification handler code here
    }
    /*****************MessageTipDlg.cpp***********************/
      

  5.   

    http://blog.csdn.net/BigFanOfCpp/archive/2005/03/27/332159.aspx
      

  6.   

    我用WH_JOURNALRECORD记录键盘操作,然后用WH_JOURNALPLAYBACK回放,但回放的时候所有的鼠标和键盘都被屏蔽,我想在回放过程中可以进行回放终止操作(例如能否让鼠标不被屏蔽?,或者某个键不被屏蔽?),请问各位专家有没有办法可以解决?
    我的本意是在回放过程中,能够点击"停止回放"按钮来达到取消回放的功能。