爱悠闲 > note : Call SetWindowsHookEx In DLL

note : Call SetWindowsHookEx In DLL

分类: DLL  |  作者: lostspeed 相关  |  发布日期 : 2013-07-25  |  热度 : 1170°

在DLL 中调用SetWindowsHookEx, 要在DLL建立一个隐藏的窗体.

在消息循环有了之后, 才能调用SetWindowsHookEx.


调用DLL的代码

void CsrcExeToLoadDllDlg::OnBnClickedButtonHook()
{
    /// 加载dll, 由DllMain 去SetWindowsHookEx
    if (NULL == g_hDll)
    {
        g_hDll = LoadLibraryW(L"DllBeTest.dll");
        DbgPrtW(L"LoadLibraryW(L\"DllBeTest.dll\") = 0x%p\r\n", g_hDll);
    }
}


void CsrcExeToLoadDllDlg::OnDestroy()
{
    if (NULL != g_hDll)
    {
        DbgPrtW(L"FreeLibrary(0x%p)\r\n", g_hDll);
        FreeLibrary(g_hDll);
    }

    CDialogEx::OnDestroy();
}



DLL 代码

// dllmain.cpp : Defines the entry point for the DLL application.
#include "stdafx.h"
#include "resource.h"
#include "DllBeTest.h"

#define G_MY_WND_CLASS_NAME L"my wnd class name"
#define G_MY_WND_TITLE_NAME L"my wnd title name"

HWND    g_hMsgWnd = NULL; ///< 自己建立的消息窗口句柄
HHOOK   g_hHookMouse = NULL;

/// @fn     DbgPrtW
/// @brief  打印调试信息
void DbgPrtW(wchar_t *fmt,...);

/// @fn     Thread_CreateMyWnd
/// @brief  线程, 建立DLL自己的窗体, 为了使DLL拥有消息循环
UINT Thread_CreateMyWnd(LPVOID lParam);

/// @fn     CreateMyWindow
/// @brief  建立自己的窗体
BOOL CreateMyWindow(
    HINSTANCE hInstance, 
    int nCmdShow, 
    wchar_t * lpcWndClass, 
    wchar_t * lpcWndTitleName, 
    HWND & hWndParent);

ATOM MyRegisterClass(HINSTANCE hInstance, wchar_t * pcClassName);
LRESULT CALLBACK WindowProc(      
    HWND hwnd,
    UINT uMsg,
    WPARAM wParam,
    LPARAM lParam);

void SetWndHook();
void UnSetWndHook();

void SetWndHook_Mouse();
LRESULT CALLBACK cbProcMouse(int iCode, WPARAM wParam, LPARAM lParam);

BOOL APIENTRY DllMain( HMODULE hModule,
    DWORD  ul_reason_for_call,
    LPVOID lpReserved)
{
    HANDLE  hThread = INVALID_HANDLE_VALUE;
    DWORD   nThreadId = 0;

    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        {
            /// DLL被加载时, 就创建自己的窗口消息处理
            /// 由窗口消息处理例程, 完成Hook的任务
            DbgPrtW(L">> DllBeTest.dll DLL_PROCESS_ATTACH");
            hThread = ::CreateThread(
                NULL, 
                0, 
                (LPTHREAD_START_ROUTINE)Thread_CreateMyWnd, 
                0, 
                0, 
                &nThreadId);
            CloseHandle(hThread);
        }
        break;

    case DLL_THREAD_ATTACH:
        break;

    case DLL_THREAD_DETACH:
        break;

    case DLL_PROCESS_DETACH:
        {
            /// 让窗口自然消失, 会调到UnHook
            if (NULL != g_hMsgWnd)
                SendMessage(g_hMsgWnd, WM_CLOSE, 0, 0);

            DbgPrtW(L">> DllBeTest.dll DLL_PROCESS_DETACH");
        }
        break;
    }
    return TRUE;
}

DLLBETEST_API void __stdcall fnTest()
{
    /// 为了exe加载DLL用的, 空函数就行
    /// 如果exe动态调用DLL, 这个函数不用调用

    return;
}

void DbgPrtW(wchar_t *fmt,...)
{
    va_list marker;
    wchar_t szBufW[4096];

    ::ZeroMemory(szBufW, sizeof(szBufW));

    va_start(marker, fmt);
    wvsprintfW(szBufW, fmt, marker);
    va_end(marker);

    OutputDebugStringW(szBufW);
}

UINT Thread_CreateMyWnd(LPVOID lParam)
{
    BOOL        bRc = FALSE;
    HWND        hWndParent = NULL;
    HMODULE     hModule = NULL;
    ATOM        atom;
    MSG         msg;
    HACCEL      hAccelTable = NULL;
    HINSTANCE   hInst = NULL;

    UNREFERENCED_PARAMETER(lParam);
    hWndParent = ::GetConsoleWindow();

    hModule = ::GetModuleHandle(NULL);
    atom = MyRegisterClass(hModule, G_MY_WND_CLASS_NAME);
    if (0 == atom)
    {
        DbgPrtW(L"ERROR : MyRegisterClass\n");
    }

    /// 窗口实例化过程一定要成功, 否则在这不停的尝试创建窗口
    /// 窗口必须有资源ID(accelerator, icon, menu), 才能创建成功
    do
    {
        bRc = CreateMyWindow(
            hModule,
            SW_HIDE, 
            G_MY_WND_CLASS_NAME, 
            G_MY_WND_TITLE_NAME, 
            hWndParent);

        DbgPrtW(L"CreateMyWindow [%s]\n", bRc ? L"TRUE" : L"FALSE");
        Sleep(1000);
    } while (!bRc);

    hAccelTable = LoadAccelerators(
        hModule, 
        MAKEINTRESOURCE(IDR_ACCELERATOR_XX));

    DbgPrtW(L">> message loop");
    while (GetMessage(&msg, NULL, 0, 0))
    {
        if (!TranslateAccelerator(msg.hwnd, hAccelTable, &msg))
        {
            TranslateMessage(&msg);
            DispatchMessage(&msg);
        }
    }

    DbgPrtW(L"<< Thread_CreateMyWnd, msg.wParam = 0x%x", msg.wParam);
    return (int) msg.wParam;
}

BOOL CreateMyWindow(
    HINSTANCE hInstance,
    int nCmdShow,
    wchar_t * pcWndClass,
    wchar_t * pcWndTitleName,
    HWND & hWndParent)
{
    g_hMsgWnd = CreateWindowW(
        pcWndClass,
        pcWndTitleName,
        WS_OVERLAPPEDWINDOW,
        0,
        0,
        0,
        0,
        hWndParent,
        NULL, 
        hInstance, 
        NULL);
    if (NULL == g_hMsgWnd)
    {
        DbgPrtW(L"error : CreateWindowW\r\n");
        return FALSE;
    }

    ShowWindow(g_hMsgWnd, nCmdShow);
    UpdateWindow(g_hMsgWnd);

    DbgPrtW(L"OK : CreateWindowW\r\n");
    return TRUE;
}

ATOM MyRegisterClass(HINSTANCE hInstance, wchar_t * pcClassName)
{
    WNDCLASSEXW	wcex;

    wcex.cbSize         = sizeof(WNDCLASSEX);
    wcex.style          = CS_HREDRAW | CS_VREDRAW;
    wcex.lpfnWndProc    = WindowProc;
    wcex.cbClsExtra     = 0;
    wcex.cbWndExtra     = 0;
    wcex.hInstance      = hInstance;
    wcex.hIcon          = LoadIcon(hInstance, MAKEINTRESOURCE(IDI_ICON_XX));
    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW + 1);
    wcex.lpszMenuName   = MAKEINTRESOURCE(IDR_MENU_XX);
    wcex.lpszClassName  = pcClassName;
    wcex.hIconSm        = 
        LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_ICON_XX));

    return RegisterClassExW(&wcex);
}

LRESULT CALLBACK WindowProc(
    HWND hWnd, 
    UINT message, 
    WPARAM wParam, 
    LPARAM lParam)
{
    PAINTSTRUCT ps;
    HDC hdc;

    switch (message)
    {
    case WM_CREATE:
        SetWndHook();   ///< 消息循环已经有了, 可以SetWindowsHookEx
        return DefWindowProc(hWnd, message, wParam, lParam);
    case WM_PAINT:
        hdc = BeginPaint(hWnd, &ps);
        // TODO: Add any drawing code here...
        EndPaint(hWnd, &ps);
        break;

        /// 窗口关闭时, WM_CLOSE >> WM_DESTROY
    case WM_CLOSE:
        DbgPrtW(L">> WM_CLOSE\r\n");

    case WM_DESTROY:
        DbgPrtW(L">> WM_DESTROY\r\n");
        UnSetWndHook();///< 这里UnHook, 在窗体被销毁之前
        PostQuitMessage(0);
        break;
    default:
        return DefWindowProc(hWnd, message, wParam, lParam);
    }

    return 0;
}

void SetWndHook()
{
    if (NULL == g_hHookMouse)
        SetWndHook_Mouse();

    /// Set Other Wnd Hook
}

void UnSetWndHook()
{
    if (NULL != g_hHookMouse)
    {
        DbgPrtW(L"UnhookWindowsHookEx(0x%p)\r\n", g_hHookMouse);
        UnhookWindowsHookEx(g_hHookMouse);
        g_hHookMouse = NULL;
    }
    else
    {
        DbgPrtW(L"NULL == g_hHookMouse, need not unHook\r\n");
    }

    /// UnSet Other Wnd Hook
}

void SetWndHook_Mouse()
{
    DWORD dwTid = 0;
    DWORD dwID = 0;
    HWND hIEModule = NULL;


    hIEModule = (HWND)GetModuleHandle(NULL);
    DbgPrtW(L"[hIEModule] hIEModule is:0x%x \n",hIEModule);
    dwTid = GetWindowThreadProcessId(hIEModule,&dwID);

    g_hHookMouse = SetWindowsHookEx(
        WH_MOUSE,
        cbProcMouse,
        GetModuleHandle(NULL),
        dwTid);

    DbgPrtW(L"[g_hHookMouse] g_hHookMouse = 0x%p\r\n", g_hHookMouse);
}

LRESULT CALLBACK cbProcMouse(int iCode, WPARAM wParam, LPARAM lParam)
{
    DbgPrtW(L">> callback cbProcMouse\r\n");

    if (wParam == WM_LBUTTONDOWN)
        DbgPrtW(L"WM_LBUTTONDOWN hit~\r\n");

    return CallNextHookEx(g_hHookMouse, iCode, wParam, lParam);
}