【问题标题】:system-wide hook not run outside main program系统范围的钩子不在主程序之外运行
【发布时间】:2013-11-19 02:34:38
【问题描述】:

我在系统范围内编写 Hook Mouse(当鼠标悬停在屏幕中的任何组件上时,它的句柄、类名、wndproc 将显示在我的程序中)。

但是当鼠标移到主程序外时,我的程序中的系统范围的钩子没有运行

我成功创建了 DLL 文件,但不明白为什么它只能作为本地挂钩运行(它在我的本地程序中运行良好 - 我的程序的屏幕区域)。

这是 hookDLL.cpp(DLL 文件)的源代码:

#include "stdafx.h"
#include "Win32_Iczelion_HookDLL.h"

#define WM_MOUSEHOOK WM_USER+10

HINSTANCE hInstance;
HHOOK hHook;
HWND hWnd;

EXPORT HHOOK CALLBACK InstallHook(HWND);
EXPORT void CALLBACK UninstallHook(void);
EXPORT LRESULT CALLBACK MouseProc(int, WPARAM, LPARAM);

BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        hInstance = hModule;
        break;
    case DLL_THREAD_ATTACH:
    case DLL_THREAD_DETACH:
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

EXPORT HHOOK CALLBACK InstallHook(HWND hwnd)
{
    hWnd = hwnd;
    hHook = SetWindowsHookEx (WH_MOUSE, (HOOKPROC)MouseProc, hInstance, NULL); 
    return hHook;
}

EXPORT void CALLBACK UninstallHook()
{
    UnhookWindowsHookEx(hHook);
}

EXPORT void test()
{
    MessageBox(NULL, L"yeah", L"yeah", MB_OK);
}

EXPORT LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    CallNextHookEx(hHook, nCode, wParam, lParam);
    POINT pt = {0};
    GetCursorPos(&pt);
    HANDLE handle = WindowFromPoint(pt);
    PostMessage(hWnd, WM_MOUSEHOOK, (WPARAM)handle, 0);
    return 0;
}

这是 hook.cpp 的来源(主程序):

#include "stdafx.h"
#include "Win32_Iczelion_Hook.h"
#include "Win32_Iczelion_HookDLL.h"

#define WM_MOUSEHOOK WM_USER+10

#define MAX_LOADSTRING 100

// Global Variables:
HINSTANCE hInst;                                // current instance
TCHAR szTitle[MAX_LOADSTRING];                  // The title bar text
TCHAR szWindowClass[MAX_LOADSTRING];            // the main window class name
HWND hWndEHandle;
HWND hWndEClassName;
HWND hWndEWndProc;
HWND hWndBHook;
HWND hWndBExit;
HHOOK hHook;
BOOL HookFlag = FALSE;

// Forward declarations of functions included in this code module:
ATOM                MyRegisterClass(HINSTANCE hInstance);
BOOL                InitInstance(HINSTANCE, int);
LRESULT CALLBACK    WndProc(HWND, UINT, WPARAM, LPARAM);
INT_PTR CALLBACK    About(HWND, UINT, WPARAM, LPARAM);

int APIENTRY _tWinMain(_In_ HINSTANCE hInstance,
                     _In_opt_ HINSTANCE hPrevInstance,
                     _In_ LPTSTR    lpCmdLine,
                     _In_ int       nCmdShow)
{
    UNREFERENCED_PARAMETER(hPrevInstance);
    UNREFERENCED_PARAMETER(lpCmdLine);

    // TODO: Place code here.
    MSG msg;
    HACCEL hAccelTable;

    // Initialize global strings
    LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
    LoadString(hInstance, IDC_WIN32_ICZELION_HOOK, szWindowClass, MAX_LOADSTRING);
    MyRegisterClass(hInstance);

    // Perform application initialization:
    if (!InitInstance (hInstance, nCmdShow))
    {
        return FALSE;
    }

    hAccelTable = LoadAccelerators(hInstance, MAKEINTRESOURCE(IDC_WIN32_ICZELION_HOOK));

    // Main message loop:
    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    return (int) msg.wParam;
}

ATOM MyRegisterClass(HINSTANCE hInstance)
{
    WNDCLASSEX wcex;

    wcex.cbSize = sizeof(WNDCLASSEX);

    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WndProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_WIN32_ICZELION_HOOK));
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
    wcex.lpszMenuName   = MAKEINTRESOURCE(IDC_WIN32_ICZELION_HOOK);
    wcex.lpszClassName  = szWindowClass;
    wcex.hIconSm        = LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

    return RegisterClassEx(&wcex);
}

BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HWND hWnd;

   hInst = hInstance; // Store instance handle in our global variable

   hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, 600, 300, NULL, NULL, hInstance, NULL);

   hWndEHandle = CreateWindowEx(NULL, L"Edit", NULL,
                        WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_AUTOHSCROLL,
                        100,35,345,25,hWnd,(HMENU)IDC_HANDLE,hInstance,NULL);
   hWndEClassName = CreateWindowEx(NULL, L"Edit", NULL,
                        WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_AUTOHSCROLL,
                        100,65,200,25,hWnd,(HMENU)IDC_CLASSNAME,hInstance,NULL);
   hWndEWndProc = CreateWindowEx(NULL, L"Edit", NULL,
                        WS_CHILD | WS_VISIBLE | WS_BORDER | ES_LEFT | ES_AUTOHSCROLL,
                        100,95,200,25,hWnd,(HMENU)IDC_WNDPROC,hInstance,NULL);

   hWndBHook = CreateWindowEx(NULL, L"Button", L"Hook", 
                        WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
                        305,65,140,25,hWnd,(HMENU)IDC_HOOK,hInstance,NULL);
   hWndBExit = CreateWindowEx(NULL, L"Button", L"Exit", 
                        WS_CHILD | WS_VISIBLE | BS_DEFPUSHBUTTON,
                        305,95,140,25,hWnd,(HMENU)IDC_EXIT,hInstance,NULL);

   if (!hWnd)
   {
      return FALSE;
   }

   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   return TRUE;
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
    int wmId, wmEvent;
    PAINTSTRUCT ps;
    HDC hdc;
    LPWSTR buffer = 0;
    RECT rect;

    switch (message)
    {
    case WM_CREATE:
        GetWindowRect(hWnd, &rect);
        SetWindowPos(hWnd, HWND_TOPMOST, rect.left, rect.top, rect.right, rect.bottom, SWP_SHOWWINDOW);
        break;
    case WM_CLOSE:
        if (HookFlag==TRUE)
            UninstallHook();
        DestroyWindow(hWnd);
    case WM_MOUSEHOOK:
    {
        wchar_t buffer[256];
        wsprintfW(buffer, L"%p", wParam);
        SetDlgItemText(hWnd, IDC_HANDLE, buffer);

        GetClassName((HWND)wParam, buffer, 128);
        SetDlgItemText(hWnd, IDC_CLASSNAME, buffer);

        DWORD buffer2 = GetClassLong((HWND)wParam,GCL_WNDPROC);
        wsprintfW(buffer, L"%p", buffer2);
        SetDlgItemText(hWnd, IDC_WNDPROC, buffer);
        break;
    }
    case WM_COMMAND:
    {
        wmId    = LOWORD(wParam);
        wmEvent = HIWORD(wParam);
        // Parse the menu selections:

        if (wmEvent==BN_CLICKED)
        {
            if (wmId==IDC_HOOK)
            {
                if (HookFlag==FALSE)
                {
                    if (InstallHook(hWnd))
                    {
                        HookFlag = TRUE;
                        SetDlgItemText(hWnd, IDC_HOOK, L"Un hook");
                    }
                }
                else
                {
                     UninstallHook();
                     SetDlgItemText(hWnd,IDC_HOOK,L"Hook");
                     HookFlag = FALSE;
                     SetDlgItemText(hWnd,IDC_CLASSNAME,NULL);
                     SetDlgItemText(hWnd,IDC_HANDLE,NULL);
                     SetDlgItemText(hWnd,IDC_WNDPROC,NULL);
                }
            }
            else if (wmId==IDC_EXIT)
            {
                SendMessage(hWnd,WM_CLOSE,0,0);
            }
        }
        switch (wmId)
        {
        case IDM_ABOUT:
            DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
            break;
        case IDM_EXIT:
            DestroyWindow(hWnd);
            break;
        default:
            return DefWindowProc(hWnd, message, wParam, lParam);
        }
        break;
    }
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        // TODO: Add any drawing code here...
        EndPaint(hWnd, &ps);
        break;
    case WM_DESTROY:
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }
    return 0;
}

任何人都可以帮助我。

【问题讨论】:

  • 请简化您的程序。例如,我敢打赌关于对话框不是必需的。接下来,调试程序。尤其要仔细查看钩子过程中 hWnd 的值。
  • 谢谢,我刚刚编辑了

标签: c++ winapi hook


【解决方案1】:

上次编辑:更正的代码。

如果其他进程与您的主进程具有相同的位数(并且如果它们获得鼠标),则 Windows 会在其他进程中加载​​ DLL。结果:您的 Dll 中的全局 hWnd 变量始终为 NULL,而 PostMessage 失败。

建议:

1 始终检查 API 的返回码。你应该已经注意到 PostMessage 失败了。

2当你准备在你的DLL中PostMessage时,如果你看到一个NULL hWnd,使用FindWindow获取HWND并将它存储在hWnd中以备下次使用。

MouseProc DLL 回调的新版本:

EXPORT LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam)
{
    if ( nCode >= 0 ) {
        PMOUSEHOOKSTRUCT pmhs = reinterpret_cast<PMOUSEHOOKSTRUCT>( lParam );
        if ( hWnd == NULL ) hWnd = FindWindow( L"WIN32_ICZELION_HOOK", NULL );
        if ( hWnd ) PostMessage(hWnd, WM_MOUSEHOOK, (WPARAM)pmhs->hwnd, 0);
    }
    return CallNextHookEx(0, nCode, wParam, lParam);
}

编辑:确保从已重建 DLL 的文件夹中运行程序 (EXE)。创建一个空解决方案 (SLN) 并在其中添加 2 个项目 (vcxproj)。删除所有“旧”的 EXE 和 DLL。重建。

编辑添加截图: 显示资源管理器文件夹栏类名的EXE

【讨论】:

  • 谢谢。但我不明白你的意思是 hWnd 是 DLL 的句柄,还是我的主程序的句柄,或者鼠标悬停在外面的程序?
  • 在 hookDLL.cpp 之上,你有一个全局 HWND hWnd;多变的。您在位于 MouseProc 函数的 PostMessage 调用中使用该变量,同一文件。
  • 对不起,但是我对您的建议非常思考和实践,我仍然不知道,它不能按我的意愿运行。帮助我,请编写代码以澄清您的意思(您能否更详细地解释我 - 关于 hWnd 变量,在挂钩中使用它的原理)?
  • 抱歉,我已经按照您的代码进行了编辑,但它仍然不能按我的意愿运行。我在此链接中向您发送我的项目。可以给我调整吗???谢谢你。 mediafire.com/?md012wzgsph2k7i
  • 我下载了您的代码,并使用 VS2012 构建了它。您已经正确使用了我的代码。它工作正常!当鼠标移出程序窗口时,信息会更新。问题是什么?请不要以为我是某种能读懂你心意的巫师! “不要按我的意愿跑”是什么意思??????
【解决方案2】:

当从另一个程序加载DLL时(当您将鼠标悬停在主程序外部时),hWnd为NULL,因此您必须在PostMessage之前使用FindWindow获取主程序的hWnd值。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-15
    • 2015-05-02
    • 2010-12-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多