강좌와 팁

저수준 마우스 후킹 예제 날짜:2022-3-15 10:30:27 조회수:363
작성자 : daypark
포인트 : 1039
가입일 : 2020-02-14 10:42:05
방문횟수 : 217
글 153개, 댓글 26개
소개 : 자기소개를 입력하십시오.
작성글 보기
쪽지 보내기
저수준 키보드랑 후킹하는 방법이 거의 같습니다. 
큐에서 메시지를 꺼내기 전에 볼 수 있어 DLL이 없어도 전역 후킹 가능하고
모든 메시지를 다 들여다 볼 수 있습니다.
일부 메시지를 먹어 버릴 수도 있고요. 

#include <windows.h>

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
HINSTANCE g_hInst;
HWND hWndMain;
LPCTSTR lpszClass = TEXT("MouseHookLL");

int APIENTRY WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance
    , _In_ LPSTR lpszCmdParam, _In_ int nCmdShow)
{
    HWND hWnd;
    MSG Message;
    WNDCLASS WndClass;
    g_hInst = hInstance;

    WndClass.cbClsExtra = 0;
    WndClass.cbWndExtra = 0;
    WndClass.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
    WndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
    WndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
    WndClass.hInstance = hInstance;
    WndClass.lpfnWndProc = WndProc;
    WndClass.lpszClassName = lpszClass;
    WndClass.lpszMenuName = NULL;
    WndClass.style = CS_HREDRAW | CS_VREDRAW;
    RegisterClass(&WndClass);

    hWnd = CreateWindow(lpszClass, lpszClass, WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
        NULL, (HMENU)NULL, hInstance, NULL);
    ShowWindow(hWnd, nCmdShow);
    hWndMain = hWnd;

    while (GetMessage(&Message, NULL, 0, 0)) {
        TranslateMessage(&Message);
        DispatchMessage(&Message);
    }
    return (int)Message.wParam;
}

HHOOK hMouseHookLL = NULL;
TCHAR MesName[111];
TCHAR log[256];
TCHAR output[65000];
DWORD lastMsg = 0;
LRESULT CALLBACK MouseHookProcLL(int nCode, WPARAM wParam, LPARAM lParam)
{
    if (nCode >= 0) {
        MSLLHOOKSTRUCT* ms = (MSLLHOOKSTRUCT*)lParam;
        lstrcpy(MesName, "Other");
        if (wParam == WM_LBUTTONDOWN) lstrcpy(MesName, "LDown");
        if (wParam == WM_LBUTTONUP) lstrcpy(MesName, "LUp");
        if (wParam == WM_RBUTTONDOWN) lstrcpy(MesName, "RDown");
        if (wParam == WM_RBUTTONUP) lstrcpy(MesName, "RUp");
        if (wParam == WM_MOUSEMOVE) lstrcpy(MesName, "Move");
        if (wParam == WM_MOUSEWHEEL) lstrcpy(MesName, "Wheel");

        wsprintf(log, "%s (%d, %d), flag=%x, time = %d\r\n",
            MesName, ms->pt.x, ms->pt.y, ms->flags, ms->time);
        // Move 두번 연속은 기록하지 않는다. 
        if (wParam != WM_MOUSEMOVE || lastMsg != WM_MOUSEMOVE) {
            lstrcat(output, log);
            InvalidateRect(hWndMain, NULL, TRUE);
        }
        lastMsg = WM_MOUSEMOVE;

        // 0이 아닌 값을 리턴하여 마우스 클릭을 먹어 버린다. 
        // 화면 좌상단 지점에서는 오른쪽 마우스 클릭을 금지한다. 
        if (ms->pt.x < 200 && ms->pt.y < 200 && (wParam == WM_RBUTTONDOWN || wParam == WM_RBUTTONUP)) {
            return 1;
        }
    }
    return CallNextHookEx(hMouseHookLL, nCode, wParam, lParam);
}

LRESULT CALLBACK WndProc(HWND hWnd, UINT iMessage, WPARAM wParam, LPARAM lParam)
{
    HDC hdc;
    PAINTSTRUCT ps;
    RECT crt;

    switch (iMessage) {
    case WM_CREATE:
        hMouseHookLL = SetWindowsHookEx(WH_MOUSE_LL, MouseHookProcLL, g_hInst, NULL);
        return 0;
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        GetClientRect(hWnd, &crt);
        DrawText(hdc, output, -1, &crt, 0);
        EndPaint(hWnd, &ps);
        return 0;
    case WM_DESTROY:
        if (hMouseHookLL != NULL) UnhookWindowsHookEx(hMouseHookLL);
        PostQuitMessage(0);
        return 0;
    }
    return(DefWindowProc(hWnd, iMessage, wParam, lParam));
}

(200, 200) 안쪽의 좌상단 바탕 화면을 우클릭할 때는 팝업 메뉴가 뜨지 않도록 했습니다. 
이런 용도보다는 주로 메시지를 살펴 보는 용도로만 쓰는게 바람직합니다.

 

목록보기 삭제 수정 신고 스크랩


로그인하셔야 댓글을 달 수 있습니다.