获取窗口激活消息的钩子函数

http://blog.sina.com.cn/s/blog_498c7cd50100mdjv.html

自己尝试做了一个获取窗口激活消息的钩子函数,能顺利编译运行,特将过程和代码贴在下面:

目的:有窗口被点击,钩子函数就能拦截到该消息,并通知给主程序。
钩子程序:使用全局钩子,建立dll。
主程序:使用控制台程序
环境:使用visual studio 2005 c++
1.创建dll程序
 文件->新建项目->visual c++->win32->win32 项目,输入dll文件名为:dlltest,点击下一步,在提示框中选择DLL,点击完成,建立了一个非mfc的dll项目。添加dlltext.h头文件,添加dlltest.def文件
 a) 建立钩子
   在dlltest.cpp中建立钩子启动函数BOOL startHOOK(HWND hwnd),和钩子卸载函数BOOL stopHOOK(),钩子回调函数LRESULT  CALLBACK WindowsProc(int nCode,WPARAM wparam,LPARAM lparam)。
dlltest.cpp代码如下:
#include "stdafx.h"
#include "Log.h"
#ifdef _MANAGED
#pragma managed(push, off)
#endif
#pragma data_seg(".mydata")
HHOOK hkb = NULL; //安装窗口钩子句柄;
HWND hwndmain=NULL; //调用钩子的主窗体句柄
HINSTANCE hins = NULL;//DLL实例句柄
#pragma data_seg()
#pragma comment(linker,"/SECTION:.mydata,RWS") // tell linker: make it shared
#define WM_THREADFIREEVENT1 WM_APP+111  //自定义消息
BOOL APIENTRY DllMain( HMODULE hModule,
                       DWORD  ul_reason_for_call,
                       LPVOID lpReserved
                     )
{
    switch (ul_reason_for_call)
    {
    case DLL_PROCESS_ATTACH:
        hins = (HINSTANCE)hModule; //给dll实例句柄赋值
        break;
    case DLL_PROCESS_DETACH:
        break;
    }
    return TRUE;
}

#ifdef _MANAGED
#pragma managed(pop)
#endif

LRESULT  CALLBACK WindowsProc(int nCode,WPARAM wparam,LPARAM lparam)
{
    if (HCBT_ACTIVATE==nCode)
    {
        PostMessageA(hwndmain,WM_THREADFIREEVENT1,wparam,lparam);
    }
    return CallNextHookEx(hkb,nCode,wparam,lparam);
}

extern "C" BOOL _declspec(dllexport) stopHOOK()
{
    BOOL bResult = FALSE;
    if (hkb)
    {
        bResult = UnhookWindowsHookEx(hkb);
        if (bResult)
        {
            hkb = NULL;
        }
    }
    return bResult;
}

extern "C" BOOL _declspec(dllexport) startHOOK(HWND m_hwnd)
{
    Log logger;
    BOOL bResult = FALSE;
    hwndmain = m_hwnd;
    hkb = SetWindowsHookExW(WH_CBT,(HOOKPROC)WindowsProc,hins,0);
    if (hkb!=NULL)
    {
        bResult = true;
    }
    return bResult;

}
2.在dlltest.p中将startHOOK()和stopHOOK()设置为可供外部调用的函数,代码如下:
#ifndef DLLTEST_H
#define DLLTEST_H
extern "C" BOOL _declspec(dllexport) startHOOK(HWND m_hwnd);
extern "C" BOOL _declspec(dllexport) stopHOOK();
#endif
3.在dlltest.def中设置共享变量和外部调用函数,代码如下:
LIBRARY    "dlltest"
EXPORTS
startHOOK
stopHOOK
SECTIONS
.mydata READ WRITE SHARED

以上是dll的部分,接下来是主程序的部分,主程序由于是非mfc程序,所以没有窗口,为了接收dll传过来的消息,在主程序中通过api函数建立了一个隐藏窗口,用以接收从dll中获取的消息。具体代码如下:
// dllCall.cpp : 定义控制台应用程序的入口点。

#include "stdafx.h"
#include <Windows.h>
#include <iostream>
#include <string>
#include <WinUser.h>
//#include <IMessage.h>
#pragma comment(lib,"..\\Release\\dlltest.lib") //静态调用dll文件,必须将上面生成的dlltest.lib和dlltest.dll文件放到主程序的运行目录下
using namespace std;
extern "C" BOOL _declspec(dllimport)startHOOK(HWND hwnd);
extern "C" BOOL _declspec(dllimport)stopHOOK();
#define WM_THREADFIREEVENT1 WM_APP+111  //自定义用户接收消息类型,必须和dll中的消息类型一致,否则无法接收
LRESULT CALLBACK WndProc(HWND hwnd,UINT uMsg,WPARAM wparam,LPARAM lparam); //定义窗口过程函数
int _tmain(int argc, _TCHAR* argv[])
{
    {
        MSG msg;
        HINSTANCE  hInstance = (HINSTANCE)GetModuleHandleW(0);//获取当前程序实例句柄
       //创建窗口
       HMENU hMenu = CreateMenu();
        WNDCLASS wndclass;
        wndclass.hbrBackground = (HBRUSH)GetStockObject(DKGRAY_BRUSH);
        wndclass.hCursor = LoadCursor(NULL,IDC_ARROW);
        wndclass.hIcon = LoadIcon(NULL,IDI_APPLICATION);
        wndclass.hInstance =hInstance;
        wndclass.lpfnWndProc = WndProc;
        wndclass.lpszClassName = L"HELLO";
        wndclass.lpszMenuName=NULL;
        wndclass.style = CS_HREDRAW;
        wndclass.cbClsExtra = 0;
        wndclass.cbWndExtra = 0;
        RegisterClass(&wndclass);
        HWND hwnd_y = CreateWindowExW(WS_ACTIVECAPTION,L"hello",L"hello",WS_ACTIVECAPTION,
            960,720,CW_USEDEFAULT,CW_USEDEFAULT,NULL,hMenu,hInstance,NULL);
        //隐藏窗口
        ShowWindow(hwnd_y,SW_HIDE);
       startHOOK(hwnd_y);  //启动钩子函数
       //进行消息循环
        while (GetMessageW(&msg,hwnd_y,0,0))
        {
            if (msg.message == WM_THREADFIREEVENT1)
            {
                cout<<"收到消息"<<endl;  //当有窗口激活消息收到,则打印该行
            }
        }
    return 0;
}

LRESULT CALLBACK WndProc(HWND hwnd_y,UINT uMsg,WPARAM wparam,LPARAM lparam)
{
    switch (uMsg)
    {
    case WM_QUIT:
        {stopHOOK();cout<<"停止钩子函数"<<endl;break;}  //收到WM_QUIT消息则卸载钩子函数,这里用不到,但是以后如果换成线程来做,这个就需要
    default:
        return DefWindowProc(hwnd_y,uMsg,wparam,lparam);
    }
    return 0;
}

通过release方式进行编译,当用户点击任何一个窗口的时候都会在cmd.exe中出现提示消息。

总结:
1. sendmessage和postmessage区别
  sendmessage是直接发送给窗口的,所以需要在窗口过程函数中取到该消息,不能用getmessage或peekmessage。而postmessage是发送到消息队列中的,可以上述两个函数获取消息。
2. 非mfc接收消息
   在baidu上找了半天,也只找到说是用窗口接收,其他没有看到,所以只能建立一个隐藏窗口了。
3. dll共享
  在程序中设置了一些句柄称为全局共享数据,但是我要在主程序中调用这些个数值,就不知道怎么做了,在baidu中找到的都是同一种方法,网上的方法如下:
#pragma   data_seg( "MYSEC ")
char   MySharedData[4096]={0};
#pragma   data_seg()

然后在用户的DEF文件中为有名的数据区设定共享属性。
LIBRARY   TEST
DATA   READ   WRITE
SECTIONS
.MYSEC   READ   WRITE   SHARED

在应用程序(进程)按外部变量引用共享数据。
extern   _export "C "{char   *   MySharedData[];}
进程中使用该变量应注意间接引用。
m_pStatic=(CEdit*)GetDlgItem(IDC_SHARED);
m_pStatic-> GetLine(0,*MySharedData,80);

但是也没有说m_pStatic是个什么类型的,所以最后没有用起来。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值