消息窗口的三种使用方法

转载 2004年07月07日 10:26:00

作者:陆其明

关键字 Message map SetWindowLong Hook
代码下载(13.2K)

大家知道,Windows是消息驱动的。写Windows应用程序,我们不可避免要跟窗口消息打交道。有一种情况,需要接收指定的消息,然后由消息来驱动执行某种操作。比如,使用第三方SDK进行视频采集,一种常见的方式就是,每当采集卡采集/准备好一块数据后,SDK就以消息的方式通知指定的窗口;应用程序接收到该消息后,必须及时读出SDK中的数据。这种情况下,我们在应用程序级必须指定给SDK一个窗口,用以响应这个特定的消息。我们称这样的窗口为“消息窗口”。

消息窗口有多种实现方法,笔者下面就列出常见的三种。没有哪一种是最好的,但或许你可以找到一种适合你的。接下去,我们来结合一个基于对话框的应用程序来讲解。

第一种方法:使用消息映射。这是一种最直接、最简单的方法。
a) 依赖主窗口
最简单的方法,我们可以在主窗口中定义消息映射。但有时候我们的主窗口类中已经有很多代码了,显得很凌乱;我们希望把这个特定消息的响应独立出来。这时,我们需要另外创建一个窗口。我们从CWnd类派生了自己的一个类CMsgWnd。
定义消息映射(假设WM_USER_MSG就是那个特定的消息):
在CMsgWnd.cpp中,加入
BEGIN_MESSAGE_MAP(CMsgWnd, CWnd)
//{{AFX_MSG_MAP(CMsgWnd)
// NOTE - the ClassWizard will add and remove mapping macros here.
//}}AFX_MSG_MAP
ON_MESSAGE(WM_USER_MSG, OnUserMsg)
END_MESSAGE_MAP()
以及定义消息响应函数(只是演示接收到了消息):
LRESULT CMsgWnd::OnUserMsg(WPARAM wParam, LPARAM lParam)
{
CString strMsg = "Receive message using message map(CommonWnd): ";
CString strParam;
strParam.Format("Method %d!", wParam);
::AfxMessageBox(strMsg + strParam);
return 0;
}
在CMsgWnd.h中,加入函数声明:
afx_msg LRESULT OnUserMsg(WPARAM wParam, LPARAM lParam);
演示时,我们在主窗口类(CMsgWindowDlg)中定义一个该类的一个实例,然后如下创建窗口:mMsgWnd.Create(NULL, "Msg", WS_CHILD, CRect(0,0,1,1), this, 0);
b) 不依赖其它窗口
上述的方法,我们创建的消息窗口作为主窗口的子窗口。但是,如果我们不想牵扯到其他窗口,我们应该怎么做呢?很简单,修改基类,从CFrameWnd类派生。为此,我们又生成了一个类CMsgFrameWnd。接下去,定义消息映射的过程跟上述方法是相似的。
值得注意的是:我们在演示时,使用new操作在系统的堆(Heap)上创建这个窗口,如下:
mMsgFrameWnd = new CMsgFrameWnd(); // creat window in heap
mMsgFrameWnd->Create(0, "Msg", WS_POPUPWINDOW, CRect(0,0,1,1), 0, 0);
在销毁这个窗口时,千万不要使用delete,而要使用DestroyWindow,如下:
if (mMsgFrameWnd)
{
::DestroyWindow(mMsgFrameWnd->GetSafeHwnd());
mMsgFrameWnd = NULL;
}
因为CFrameWnd基类实现中会自动调用delete this来释放窗口对象内存。

第二种方法:使用SetWindowLong替换窗口处理函数。这也是一种比较方便的方法。
如果我们不想自定义类,或者不想使用MFC的窗口类,更或者我们在DLL中完成我们的工作,根本不关心也很难利用其它的窗口,那么,就使用Windows API来创建一个消息窗口吧。参考如下:
// create an overlapped window with an MFC window class
LPCTSTR lpszClass = AfxRegisterWndClass(NULL);
HWND hWnd=::CreateWindow(lpszClass, // windows class name
"Msg Hub", // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, CW_USEDEFAULT, // position and dimensions
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, // owner window handle--NULL is Desktop
NULL, // for popup and overlapped windows: window menu handle
AfxGetInstanceHandle(), // handle to application instance
NULL // pointer to window-creation data
);
gWindowMethod2.Attach(hWnd);
// change the window procdure address
gOriginalProc = (WNDPROC) SetWindowLong(hWnd, GWL_WNDPROC, (LONG)NewWndProc);
窗口创建成功后,使用SetWindowLong给这个窗口指定一个新的消息处理函数,定义为:
LRESULT WINAPI NewWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_USER_MSG)
{
CString strMsg = "Receive message using SetWindowLong: ";
CString strParam;
strParam.Format("Method %d!", wParam);
::AfxMessageBox(strMsg + strParam);
return 1;
}
return CallWindowProc(gOriginalProc,hWnd,uMsg,wParam,lParam);
}
注意在不再使用该消息窗口时销毁它:
if (gWindowMethod2.GetSafeHwnd())
{
HWND hWnd = gWindowMethod2.Detach();
::DestroyWindow(hWnd);
}

第三种方法:使用Hook替换截获消息。这是一种小题大做、“牛刀杀鸡”的方法。
与第二种方法相似的是,我们同样创建一个窗口,如下:
// create an overlapped window with an MFC window class
LPCTSTR lpszClass = AfxRegisterWndClass(NULL);
HWND hWnd=::CreateWindow(lpszClass, // windows class name
"Msg Hub", // window caption
WS_OVERLAPPEDWINDOW, // window style
CW_USEDEFAULT, CW_USEDEFAULT, // position and dimensions
CW_USEDEFAULT, CW_USEDEFAULT,
NULL, // owner window handle--NULL is Desktop
NULL, // for popup and overlapped windows: window menu handle
AfxGetInstanceHandle(), // handle to application instance
NULL // pointer to window-creation data
);
gWindowMethod2.Attach(hWnd);
// Install hook for the current thread
glhHook = SetWindowsHookEx(WH_CALLWNDPROC,CallWndProc,AfxGetInstanceHandle(),GetCurrentThreadId());
窗口创建成功后,我们就使用SetWindowsHookEx安装一个WH_CALLWNDPROC类型的钩子(Hook)。钩子函数定义如下:
LRESULT CALLBACK CallWndProc(int nCode, WPARAM wParam, LPARAM lParam)
{
if (nCode == HC_ACTION)
{
CWPSTRUCT * pMsg = (CWPSTRUCT*) lParam;
if (pMsg->hwnd == gWindowMethod3.GetSafeHwnd() &&
pMsg->message == WM_USER_MSG)
{
CString strMsg = "Receive message using Hook: ";
CString strParam;
strParam.Format("Method %d!", pMsg->wParam);
::AfxMessageBox(strMsg + strParam);
return TRUE;
}
}
return CallNextHookEx(glhHook, nCode, wParam, lParam);
}
注意在不再使用该消息窗口时销毁它,并卸载消息钩子:
UnhookWindowsHookEx(glhHook);
if (gWindowMethod3.GetSafeHwnd())
{
HWND hWnd = gWindowMethod3.Detach();
::DestroyWindow(hWnd);
}

演示说明:
主窗口界面如下:
MsgWndDemo.jpg
我们使用SendMessage函数来发送WM_USER_MSG消息,消息通过界面上的一系列“Send_Msg”按钮触发。当按下按钮,会弹出相应的消息框,说明当前使用的方法能够正确接收消息。

Js中三种弹出式消息提醒的命令是什么?(警告,确认,信息输入)

1、警告框alert,在js中直接运用alert("警告"); 2、确认框confirm。 confirm() 方法用于显示一个带有指定消息和 OK 及取消按钮的对话框,根据用户点击确认框...
  • devincob
  • devincob
  • 2017年04月30日 11:30
  • 1109

JS中的三种弹出式消息提醒(警告窗口、确认窗口、信息输入窗口)的命令是什么?

alert() 弹出个提示框 (确定)  confirm() 弹出个确认框 (确定,取消)  prompt() 弹出个输入框 让你输入东西 例解:   window.alert("警告...
  • ccrzzu
  • ccrzzu
  • 2013年04月24日 01:24
  • 4732

JavaScript之消息对话框

JavaScript弹起对话框的形式有以下三种: 1.只是提醒,不能对脚本产生任何改变; 2.一般用于确认,返回true或者false,所以可以用于if...else...判断; 3.一个带输入的对话...
  • aaaa99996666
  • aaaa99996666
  • 2017年01月12日 17:33
  • 170

window窗口消息大全

Public Const WM_NULL = &H0 '空消息 Public Const WM_NCCREATE = &H81 '当窗口第一次被创建时,此消息在WM_CREATE...
  • rankun1
  • rankun1
  • 2016年06月16日 15:18
  • 919

MFC应用程序传输的消息有三种类型:窗口消息、命令消息和控件通知

在MFC应用程序中传输的消息有三种类型:窗口消息、命令消息和控件通知。窗口消息(Window Message)一般与窗口的内部运作有关,如创建窗口、绘制窗口和销毁窗口等。通常,消息是从系统发送到窗口,...
  • liujuanjuan996
  • liujuanjuan996
  • 2012年08月01日 09:55
  • 1620

C# 窗口消息传递

与MFC类似,通过SendMessage和窗口句柄实现消息之间的传递 当然,这东西可以在线程和进程间通讯,实现线程消息的互相传递,文件系统升级卸载等功能 作用空间 using System.Run...
  • b510030
  • b510030
  • 2016年09月27日 10:45
  • 712

关于HOOK,如何通过钩子截获指定窗口的所有消息 SetWindowsHookEx demo

SetWindowsHookEx   第三个参数为HINSTANCE,通过FindWindow找到指定窗口句柄后如何      得到该进程的HINSTANCE呢? 这个参数应该是你调用SetWind...
  • q610098308
  • q610098308
  • 2017年09月11日 21:11
  • 857

windows基础编程----第三篇(窗口的消息处理机制)

这一篇,给大家深入理解一下windows编程中的消息机制。
  • qq_30501909
  • qq_30501909
  • 2016年02月29日 21:02
  • 922

如何捕捉窗口按钮消息

如何捕捉一个未知窗口的按钮按下的消息?方法多种多样,这里我就介绍一种比较常见的方法——钩子。       原理上很简单也很容易理解,安装一个系统的全局钩子,过滤所有的系统消息,当然了,可以过滤制定的系...
  • yiyefangzhou24
  • yiyefangzhou24
  • 2011年07月24日 10:01
  • 4064

关于HOOK,如何通过钩子截获指定窗口的所有消息

SetWindowsHookEx   第三个参数为HINSTANCE,通过FindWindow找到指定窗口句柄后如何      得到该进程的HINSTANCE呢? 这个参数应该是你调用SetWind...
  • ccx_john
  • ccx_john
  • 2014年03月31日 19:41
  • 1959
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:消息窗口的三种使用方法
举报原因:
原因补充:

(最多只允许输入30个字)