我编写了一个全局键盘钩子dll,希望能够在任何进行中,点击F8或F9键时,采用模拟键盘输入的方式(keybd_event)输入某个字符串。现在的问题是:当我的光标在装载钩子的的程序界面上时,能够将预设的字符串用键盘模拟按键的方式输入窗口的Edit控件。但是当焦点在其他可执行文件,例如记事本中,不能模拟键入任何内容。
系统代码如下:
// LaunchDLL.cpp : Defines the initialization routines for the DLL.
//
#define _WIN32_WINNT 0x0500 //设置系统版本, 确保可以使用底层
#include "stdafx.h"
#include <windows.h>
#include "LaunchDLL.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endifHHOOK Hook;
char userID[128];
char userPsw[128];
int  g_nIDlen;
int  g_nPswLen;
LPFNKEYBOARDPROC g_lpfnKeyboardProc;// 键盘钩子回调函数指针LRESULT CALLBACK LowLevelKeyboardProc(int nCode,WPARAM wParam,LPARAM lParam);
int GetCharKey(char ch, BOOL &shift);//
// Note!
//
// If this DLL is dynamically linked against the MFC
// DLLs, any functions exported from this DLL which
// call into MFC must have the AFX_MANAGE_STATE macro
// added at the very beginning of the function.
//
// For example:
//
// extern "C" BOOL PASCAL EXPORT ExportedFunction()
// {
// AFX_MANAGE_STATE(AfxGetStaticModuleState());
// // normal function body here
// }
//
// It is very important that this macro appear in each
// function, prior to any calls into MFC.  This means that
// it must appear as the first statement within the 
// function, even before any object variable declarations
// as their constructors may generate calls into the MFC
// DLL.
//
// Please see MFC Technical Notes 33 and 58 for additional
// details.
///////////////////////////////////////////////////////////////////////////////
// CLaunchDLLAppBEGIN_MESSAGE_MAP(CLaunchDLLApp, CWinApp)
//{{AFX_MSG_MAP(CLaunchDLLApp)
// NOTE - the ClassWizard will add and remove mapping macros here.
//    DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
END_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////
// CLaunchDLLApp construction
CLaunchDLLApp::CLaunchDLLApp()
{
// TODO: add construction code here,
// Place all significant initialization in InitInstance
}/////////////////////////////////////////////////////////////////////////////
// The one and only CLaunchDLLApp objectCLaunchDLLApp theApp;
DllExport void WINAPI InstallLaunchEv()
{
//调用SDK中的API函数SetWindowsHookEx来安装这个钩子函数 Hook=(HHOOK)SetWindowsHookEx(WH_KEYBOARD,
(HOOKPROC)LowLevelKeyboardProc,
theApp.m_hInstance,
0);
}DllExport void WINAPI UnInstallLaunchEv()
{
UnhookWindowsHookEx(Hook);}LRESULT CALLBACK LowLevelKeyboardProc(int nCode,WPARAM wParam,LPARAM lParam)
{

LRESULT Result=CallNextHookEx(Hook,nCode,wParam,lParam);

if(((DWORD)lParam&0x40000000) && (HC_ACTION==nCode))
{

if( wParam == VK_F8 || wParam == VK_F9){
   
int   iCapital=GetKeyState(0x14);   
int   iNumLock=GetKeyState(0x90);   
BOOL   bShift= FALSE;   
BOOL   bCapital=(iCapital&1)==1;   
BOOL   bNumLock=(iNumLock&1)==1; if(bCapital){
keybd_event(0x14,0,0,0);
keybd_event(0x14,0,KEYEVENTF_KEYUP,0);
}
if(bNumLock){
keybd_event(0x90,0,0,0);
keybd_event(0x90,0,KEYEVENTF_KEYUP,0);
} //userID
if(wParam == VK_F8 ){
int &len = g_nIDlen;
int intch = 0;
for(int i=0;i<len;i++)
{

intch = GetCharKey(userID[i],bShift) ;
if(bShift)
keybd_event(0x10,0,0,0);
keybd_event(intch,0,0,0);
keybd_event(intch,0,KEYEVENTF_KEYUP,0);
if(bShift)
keybd_event(0x10,0,KEYEVENTF_KEYUP,0); }


}
else if(wParam == VK_F9 ){
int len = strlen(userPsw);
int intch = 0;
for(int i=0;i<len;i++)
{ intch = GetCharKey(userPsw[i],bShift) ;
if(bShift)
keybd_event(0x10,0,0,0);
keybd_event(intch,0,0,0);
keybd_event(intch,0,KEYEVENTF_KEYUP,0);
if(bShift)
keybd_event(0x10,0,KEYEVENTF_KEYUP,0);
}
} //end if wParam == VK_F9
}// end if( wParam == VK_F8 || wParam == VK_F9)
}//end if(((DWORD)lParam&0x40000000) && (HC_ACTION==nCode))
return Result;

}//void WINAPI SetFuncProc(char**msg,int length,LPFNKEYBOARDPROC lpfnKeyboardProc)
void WINAPI SetFuncProc(char* chID ,char *chPsw )
{
// 将用户传来的 keycode 数组保存在全局变量中
g_nIDlen = strlen(chID);
strcpy(userID,chID);
userID[g_nIDlen] = '\0';
g_nPswLen = strlen(chPsw);
strcpy(userPsw,chPsw);
userPsw[g_nPswLen] = '\0';
// g_lpfnKeyboardProc = lpfnKeyboardProc;


int GetCharKey(char ch, BOOL &shift){ int res = 0;
if (ch >= 'a' && ch <= 'z'){
shift = FALSE;
return 65 + ch -'a' ;
}
else if( ch>='A' && ch <='Z'){
shift = TRUE;
return 65 + ch -'A';
}
else if( ch >='0' && ch <= '9'){
shift = FALSE;
return 48 + ch - '0';
}
else {
switch(ch)   
{   
case '!':   
res = 49;   
shift = TRUE;
break;   
case '@':   
res=50;  
shift = TRUE;
break;   
case  '#' :   
res =51; 
shift = TRUE;
break;   
case  '$':   
res =52;  
shift = TRUE;
break;   
case   '%':   
res=53;  
shift = TRUE;
break;   
case  '^':   
res=  54; 
shift = TRUE;
break;   
case  '&' :   
res=55; 
shift = TRUE;
break;   
case   '*':   
res=56;   
shift = TRUE;
break;   
case  '(' :   
res =57;
shift = TRUE;
break;   
case  ')' :   
res=48; 
shift = TRUE;
                break;  
case  ';' :   
res = 186;
shift = FALSE; 
break;
case  ':' :
res = 186 ;
shift = TRUE;
break;   
case  '=' :
res = 187;
shift = FALSE;
break;
case '+':
res = 187 ;
shift = TRUE;
break;   
case  ',' :   
res = 188;
shift = FALSE;
break;
case '<':
res = 188;
shift = TRUE;
break;   
case  '-' :   
res = 189;
shift = FALSE;
break;
case '_' :
res = 189 ;
shift = TRUE;
break;   
case   '.' :   
res = 190;
shift = FALSE;
break;
case '>' :
res = 190 ;
shift = TRUE;
break;   
case  '/' :   
res = 191;
shift = FALSE;
break;   
case '?':
res = 191;
shift = TRUE;
break;   
case  '`' :   
res = 192;
shift = FALSE;
break;
case '~' :
res = 192;
shift = TRUE;
break;   
case  '[' :   
res = 219;
shift = FALSE;
break;
case '{' :
res = 219;
shift = TRUE;
break;   
case  '\\' :   
res = 220;
shift = FALSE;
break;
case '|' :
res = 220;
shift = TRUE;
break;   
case  ']':   
res = 221;
shift = FALSE;
break;
case '}' :
res = 221;
shift = TRUE;   
break;   
case  '\'' :   
res = 222;
shift = FALSE;
break;
case '\"' :
res = 222;
shift = TRUE;
break; 
case ' ':
res = 32;
shift = FALSE;
default :   
res = 0 ;     
                break;   
}
}// end else
return 0;
}

解决方案 »

  1.   

    头文件
    // LaunchDLL.h : main header file for the LAUNCHDLL DLL
    //#if !defined(AFX_LAUNCHDLL_H__9D42756F_8133_4F5C_9C0C_2983C61070C9__INCLUDED_)
    #define AFX_LAUNCHDLL_H__9D42756F_8133_4F5C_9C0C_2983C61070C9__INCLUDED_#if _MSC_VER > 1000
    #pragma once
    #endif // _MSC_VER > 1000#ifndef __AFXWIN_H__
    #error include 'stdafx.h' before including this file for PCH
    #endif#include "resource.h" // main symbols
    #include "winuser.h"
    /////////////////////////////////////////////////////////////////////////////
    // CLaunchDLLApp
    // See LaunchDLL.cpp for the implementation of this class
    //宏定义和待导出函数的声明#define DllExport __declspec(dllexport)
    // 回调函数指针
    typedef  void (CALLBACK * LPFNKEYBOARDPROC)(int,WPARAM, LPARAM);
    typedef char* LPCHAR;DllExport void WINAPI InstallLaunchEv();
    DllExport void WINAPI UnInstallLaunchEv();
    //void WINAPI SetFuncProc(LPFNKEYBOARDPROC lpfnKeyboardProc);
    // DECLSPEC_IMPORT void WINAPI SetFuncProc(LPCHAR*msg,int length, LPFNKEYBOARDPROC lpfnKeyboardProc);
    DECLSPEC_IMPORT void WINAPI SetFuncProc(char* chID ,char *chPsw );
    //
    class CLaunchDLLApp : public CWinApp
    {
    public:
    CLaunchDLLApp();// Overrides
    // ClassWizard generated virtual function overrides
    //{{AFX_VIRTUAL(CLaunchDLLApp)
    //}}AFX_VIRTUAL //{{AFX_MSG(CLaunchDLLApp)
    // NOTE - the ClassWizard will add and remove member functions here.
    //    DO NOT EDIT what you see in these blocks of generated code !
    //}}AFX_MSG
    DECLARE_MESSAGE_MAP()
    };
    ///////////////////////////////////////////////////////////////////////////////{{AFX_INSERT_LOCATION}}
    // Microsoft Visual C++ will insert additional declarations immediately before the previous line.#endif // !defined(AFX_LAUNCHDLL_H__9D42756F_8133_4F5C_9C0C_2983C61070C9__INCLUDED_)
      

  2.   

    调用钩子程序的源代码
    // KeyHookView.cpp : implementation of the CKeyHookView class
    //#include "stdafx.h"
    #include "KeyHook.h"#include "KeyHookDoc.h"
    #include "KeyHookView.h"
    #include "LaunchDLL.h"
    #include "dlg.h"
    #ifdef _DEBUG
    #define new DEBUG_NEW
    #undef THIS_FILE
    static char THIS_FILE[] = __FILE__;
    #endif/////////////////////////////////////////////////////////////////////////////
    // CKeyHookViewIMPLEMENT_DYNCREATE(CKeyHookView, CView)BEGIN_MESSAGE_MAP(CKeyHookView, CView)
    //{{AFX_MSG_MAP(CKeyHookView)
    ON_COMMAND(ID_MENUITEM32771, OnMenuitem32771)
    ON_COMMAND(ID_MENUITEM32772, OnMenuitem32772)
    //}}AFX_MSG_MAP
    // Standard printing commands
    ON_COMMAND(ID_FILE_PRINT, CView::OnFilePrint)
    ON_COMMAND(ID_FILE_PRINT_DIRECT, CView::OnFilePrint)
    ON_COMMAND(ID_FILE_PRINT_PREVIEW, CView::OnFilePrintPreview)
    END_MESSAGE_MAP()/////////////////////////////////////////////////////////////////////////////
    // CKeyHookView construction/destruction
    CKeyHookView::CKeyHookView()
    {
    // TODO: add construction code here}CKeyHookView::~CKeyHookView()
    {
    UnInstallLaunchEv();
    }BOOL CKeyHookView::PreCreateWindow(CREATESTRUCT& cs)
    {
    // TODO: Modify the Window class or styles here by modifying
    //  the CREATESTRUCT cs return CView::PreCreateWindow(cs);
    }/////////////////////////////////////////////////////////////////////////////
    // CKeyHookView drawingvoid CKeyHookView::OnDraw(CDC* pDC)
    {
    CKeyHookDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    // TODO: add draw code for native data here
    }/////////////////////////////////////////////////////////////////////////////
    // CKeyHookView printingBOOL CKeyHookView::OnPreparePrinting(CPrintInfo* pInfo)
    {
    // default preparation
    return DoPreparePrinting(pInfo);
    }void CKeyHookView::OnBeginPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
    {
    // TODO: add extra initialization before printing
    }void CKeyHookView::OnEndPrinting(CDC* /*pDC*/, CPrintInfo* /*pInfo*/)
    {
    // TODO: add cleanup after printing
    }/////////////////////////////////////////////////////////////////////////////
    // CKeyHookView diagnostics#ifdef _DEBUG
    void CKeyHookView::AssertValid() const
    {
    CView::AssertValid();
    }void CKeyHookView::Dump(CDumpContext& dc) const
    {
    CView::Dump(dc);
    }CKeyHookDoc* CKeyHookView::GetDocument() // non-debug version is inline
    {
    ASSERT(m_pDocument->IsKindOf(RUNTIME_CLASS(CKeyHookDoc)));
    return (CKeyHookDoc*)m_pDocument;
    }
    #endif //_DEBUG/////////////////////////////////////////////////////////////////////////////
    // CKeyHookView message handlersvoid CKeyHookView::OnInitialUpdate() 
    {
    CView::OnInitialUpdate();

    // TODO: Add your specialized code here and/or call the base class
    InstallLaunchEv();}typedef char* LPCHAR;
    void CKeyHookView::OnMenuitem32771() 
    {
    // TODO: Add your command handler code here

    char *userID = new char[10];
    char *userPsw = new char[10];
    for(int i=0;i<9;i++){
    if( i % 2 == 1)
    userID[i] = 'a';
    else
    userID[i] = 'A';
    }
    for( i=0;i<9;i++){
    if( i % 2 ==1)
    userPsw[i] = 'b';
    else
    userPsw[i] = 'B';
    }
    userID[9] = '\0';
    userPsw[9] = '\0';
    SetFuncProc(userID,userPsw);
    delete []userID;
    delete []userPsw;

    }void CKeyHookView::OnMenuitem32772() 
    {
    // TODO: Add your command handler code here
    CDlg dlg;
    dlg.DoModal();
    }
      

  3.   

    当把回调函数的循环语句改成固定的内容时,可以在记事本中显示内容 如下所示,请问这是问什么?。
    LRESULT CALLBACK LowLevelKeyboardProc(int nCode,WPARAM wParam,LPARAM lParam) 
    { LRESULT Result=CallNextHookEx(Hook,nCode,wParam,lParam); if(((DWORD)lParam&0x40000000) && (HC_ACTION==nCode)) 

    //userID 
    if(wParam == VK_F8 ){ .....
    for(int i=0;i <10;i++) 
    {     keybd_event(65,0,0,0); 
        keybd_event(65,0,KEYEVENTF_KEYUP,0); } 
    }
    }
    return Result; } 
      

  4.   

    用不着贴这么多代码,只要把相关的代码贴上就够了。
    钩子DLL也可以调试,在项目属性中,把调试中的命令行写成notepad,然后按F5运行,再自己执行另外的程序来加载Hook就可以了。
      

  5.   

    DLL中的全局变量默认是各个进程相互独立的,如果要让各个进程共享,要用类似这样的方法来定义:
    #pragma data_seg(push, "Shared")
    HHOOK Hook = NULL;
    char userID[128] = "\0";
    char userPsw[128] = "\0";
    int g_nIDlen = 0;
    int  g_nPswLen = 0;
    LPFNKEYBOARDPROC g_lpfnKeyboardProc = null;// 键盘钩子回调函数指针
    #pragma data_seg(pop)
    #pragma comment(linker, "/SECTION:Shared,RWS")