1、在WNDOWS中消息分系统消息和自定义消息。系统消息定义从0到0x3FF,使用0x400到0x7FFF定义自己的消息。
Windows把0x400定义为WM_USER。如果想定义自己的一个消息,可以在WM_USER上加上一个值:
#define WM_CONTROLPRINT WM_USER+1001
另一种自定义窗口消息的方法是用RegisterWindowsMessage()函数来注册这个消息。与在WM_USER上加上某个数相比,它的好处是不必考虑所表示的消息标识符是否超出工程的允许范围。如:
const UINT WM_CONTROLPRINT=RegisterWindowMessage("reg_data");
在接收消息的程序中,需要对添加对应消息的响应处理函数,并将消息和消息处理函数关联,要不它不知道消息发给谁:
//函数定义,在//AFX_MSG中
afx_msg LRESULT OnControlPrint(WPARAM wParam,LPARAM lParam);
//函数实现
LRESULT CSendDlg::OnControlPrint(WPARAM wParam,LPARAM lParam)
{
}
//关联映射,在BEGIN_MESSAGE_MAP中
ON_MESSAGE(WM_CONTROLPRINT,OnControlPrint)//使用WM_USER+1001定义的消息
ON_REGISTERED_MESSAGE(WM_CONTROLPRINT,OnControlPrint)//使用RegisterWindowMessage定义的消息
消息如何传递呢?我们需要发送消息时,可以使用PostMessage和SendMessage。这两个消息发送函数不一样的地方就是SendMessage发送完消息后会等待消息处理函数处理完成后返回(同步),PostMessage则不等待(异步)。所以,可以说PostMessage是不可靠的,实际运用中可以根据具体情况来确定用那一个。这两个函数的具体使用请查看MSDN。
例如我向主窗体发送一个消息(第一个参数是接收消息的窗体句柄,第二个参数是要发送的消息,后边两个为随消息发送的参数信息):
::SendMessage(AfxGetApp()->GetMainWnd()->m_hWnd,WM_CONTROLPRINT,NULL,0);
2、消息的发送还可以使用BroadcastSystemMessage()函数,下面主讲此消息:
功能说明
广播特定消息给特定的接收器,接收器可以是应用程序、或者是安装的驱动器、网络驱动器、系统级设备驱动器、或这些系统组件的任何组合。常见于系统将一条系统级消息广播给系统中所有的活动窗口,例如:系统检测到有USB 盘插拔、有光盘放入光驱、或者检测出新硬件等,系统就使用BroadcastSystemMessage 将该消息广播到系统中去,使跟这些设备相关联的程序去处理对应事件。一般用到的情况是使用它给一组应用程序(该组应用程序能够接收到同一个消息)广播统一的消息,例如关闭当前系统所有打开的窗口等。
二者区别在于BroadcastSystemMessageEx 可以从消息接收器返回更多的信息。
函数形式
long BroadcastSystemMessage (
DWORD dwFlags, // 发送消息的方式
LPDWORD lpdwRecipients, // 消息接受器 的信息,消息发送的目标
UINT uiMessage, // 系统消息标识符
WPARAM wParam, // 消息参数
LPARAM lParam // 消息参数
);
long BroadcastSystemMessageEx (
DWORD dwFlags, // 发送消息的方式
LPDWORD lpdwRecipients, // 消息接受器 的信息,消息发送的目标
UINT uiMessage, // 系统消息标识符
WPARAM wParam, // 消息参数
LPARAM lParam // 消息参数
PBSMINFO pBSMInfo // 接收到的附加信息
);
参数说明
1 〉、dwFlags ,【in 】
发送消息的方式,可取下列值的组合:
BSF_FLUSHDISK :消息接收器处理消息之后清理磁盘。
BSF_FORCEIFHUNG :继续广播消息,即使超时周期结束或一个目标已挂起。
BSF_IGNORECURRENTTASK :不发送消息给属于当前任务的窗口,这样,应用程序就不会接收自己的消息。
BSF_NOHANG :强制无反应的应用程序超时,如果一个接收器超时,就不再继续广播消息。
BSF_NOTIMEOUTIFNOTHUNG :只要接收器没挂起,一直等待对消息的响应,且不会出现超时。
BSF_POSTMESSAGE :发送消息,不能跟BSF_QUERY 混合使用。
BSF_QUERY :每次发送消息给一个接受器,只有当前接受器返回TRUE 后,才能发送给下一个接受器。
BSF_SENDNOTIFYMESSAGE :在Windows 2000/XP 中,以SendNotifyMessage 替代,不能跟BSF_QUERY 混合使用。
2 〉、lpdwRecipients
指向变量的指针,该变量包含接收消息的 消息接受器 的信息,或者叫做消息发送的目标。此变量可为下列值的组合:
【in 】,<BroadcastSystemMessage> 取值如下:
BSM_ALLCOMPONENTS :广播到所有的系统组件。
BSM_ALLDESKTOPS :Windows NT 下,广播到所有的桌面。要求SE_TCB_NAME 特权。
BSM_APPLICATIONS :广播到应用程序。
BSM_INSTALLABLEDRIVERS :Windows 95/98/ME 下,广播到安装驱动器。
BSM_INTDRIVER :Windows 95/98/ME 下,广播到网络驱动器。
BSM_VXDS :Windows 95/98/ME 下,广播到所有系统级设备驱动器。
【in, out 】,<BroadcastSystemMessageEx> 取值如下:
BSM_ALLCOMPONENTS :广播到所有的系统组件。
BSM_ALLDESKTOPS :Windows NT 下,广播到所有的桌面。要求SE_TCB_NAME 特权。
BSM_APPLICATIONS :广播到应用程序。
当函数返回时,此变量接受上述值的组合,用于表示哪个接受器真正地接到了消息。如果此参数为NULL ,则将消息广播到所有的组件。
3 〉、uiMessage ,【in 】
系统消息标识符,也就是所谓的消息ID ,例如WM_LBUTTON 、WM_RBUTTON 、WM_KEY 等,都属于消息ID
4 〉、Wparam ,【in 】
消息参数之一,属于字消息,是对 uiMessage 指定的字信息,其意义取决于具体的 uiMessage 的值。
5 〉、Iparam ,【in 】
消息参数之一,属于值消息,是对 uiMessage 指定的值信息,其意义取决于具体的 uiMessage 的值,有时也称LPARAM为事件。
6> 、pBSMInfo, 【out 】
针对函数BroadcastSystemMessageEx 的参数,是 BSMINFO 类型的指针,如果请求被拒绝或者传入的参数dwFlags 被设置为BSF_QUERY 时,函数所能接收到的附加信息。
返回值
函数调用成功,返回值为正;
如果函数不能广播消息,返回值是-1 ;
如果参数dwFlags 为BSF_QUERY 且至少一个接受器返回BROADCAST_QUERY_DENY 给对应的消息,则返回值是零。若想获得更多的错误信息,请调用GetLastError 函数。
备注
如果dwFlags 没有包含BSF_QUERY ,则函数向所有请求的接受器发送指定的消息,并忽略这些接受器返回的值。
应用举例
当设备被热插拔的时候(例如U 盘),WINDOWS 会向系统广播WM_DEVICECHANGE 消息。如果字消息(wParam )的值为 DBT_DEVICEARRIVAL ,则表示设备插入并且已经可用;如果字消息(wParam )的值为DBT_DEVICEREMOVECOMPLETE ,则表示设备已经移出。它们值消息(lParam )的值 为一个DEV_BROADCAST_HDR 类型的指针,DEV_BROADCAST_HDR 定义如下:
typedef struct _DEV_BROADCAST_HDR
{
DWORD dbch_size;
DWORD dbch_devicetype;
DWORD dbch_reserved;
} DEV_BROADCAST_HDR, *PDEV_BROADCAST_HDR;
成员含义:
dbch_size 结构体大小,以字节数衡量;如果所传递的事件属于用户自定义事件,则dbch_size 的值等于该结构体大小,再加上_DEV_BROADCAST_USERDEFINED 中其它变量的总长度。
dbch_devicetype 设备类型,其值跟设备数据相关联,该关联具体如下:
VALUE | 含义 |
DBT_DEVTYP_DEVICEINTERFACE | 设备类,lParam 为一个指向DEV_BROADCAST_DEVICEINTERFACE 数据结构的指针 |
DBT_DEVTYP_HANDLE | 文件系统处理,lParam 为一个指向DEV_BROADCAST_HANDLE 数据结构的指针 |
DBT_DEVTYP_OEM | OEM 或者IHV 定义的设备类型,lParam为一个指向DEV_BROADCAST_OEM 数据结构的指针 |
DBT_DEVTYP_PORT | 端口设备(串口或者并口),lParam 为一指向DEV_BROADCAST_PORT 数据结构的指针 |
DBT_DEVTYP_VOLUME | 逻辑驱动器,lParam 为一指向DEV_BROADCAST_VOLUME 数据结构的指针 |
例一,这段代码用于检测CD-ROM 中光盘的状态
#include <windows.h>
#include <dbt.h>
#include <strsafe.h>
// 函数声明
void Main_OnDeviceChange(HWND hwnd, WPARAM wParam, LPARAM lParam);
// 函数声明
char FirstDriveFromMask(ULONG unitmask);
// 功能说明 Handles WM_DEVICECHANGE messages sent to the application's top-level window.
void Main_OnDeviceChange (HWND hwnd, WPARAM wParam, LPARAM lParam)
{
PDEV_BROADCAST_HDR lpdb = (PDEV_BROADCAST_HDR)lParam;
char szMsg[80];
switch (wParam)
{
case DBT_DEVICEARRIVAL:
// Check whether a CD or DVD was inserted into a drive.
if (lpdb -> dbch_devicetype == DBT_DEVTYP_VOLUME)
{
PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
if (lpdbv -> dbcv_flags & DBTF_MEDIA)
{
StringCchPrintf(szMsg, 80, _T("Drive %c: Media has arrived./n" ),
FirstDriveFromMask(lpdbv ->dbcv_unitmask));
MessageBox (hwnd, szMsg, _T("WM_DEVICECHANGE" ), MB_OK);
}
}
break ;
case DBT_DEVICEREMOVECOMPLETE:
// Check whether a CD or DVD was removed from a drive.
if (lpdb -> dbch_devicetype == DBT_DEVTYP_VOLUME)
{
PDEV_BROADCAST_VOLUME lpdbv = (PDEV_BROADCAST_VOLUME)lpdb;
if (lpdbv -> dbcv_flags & DBTF_MEDIA)
{
StringCchPrintf(szMsg, 80, _T("Drive %c: Media was removed./n" ),
FirstDriveFromMask(lpdbv ->dbcv_unitmask));
MessageBox (hwnd, szMsg, _T("WM_DEVICECHANGE" ), MB_OK);
}
}
break ;
default : // 处理其余WM_DEVICECHANGE 事件
break ;
}
}
// 功能说明 Finds the first valid drive letter from a mask of drive letters. The mask must be in the
// format bit 0 = A, bit 1 = B, bit 3 = C, etc. A valid drive letter is defined when the corresponding
// bit is set to 1.
// Returns the first drive letter that was found.
char FirstDriveFromMask (ULONG unitmask)
{
char i;
for (i = 0; i < 26; ++i)
{
if (unitmask & 0x1) break ;
unitmask = unitmask >> 1;
}
return (i + 'A' );
}
例二,关闭IE 及其它应用程序
// 关闭IE 及其它应用程序
void CloseAllApplication()
{
int app = BSM_APPLICATIONS;
unsigned long bsm_app = (unsigned long)app;
BroadcastSystemMessage (BSF_POSTMESSAGE, &bsm_app, WM_CLOSE, NULL, NULL);
}