WM_NOTITY消息

这个技术文章介绍了关于新WM_NOTIFY消息, 还描述了建议使用的一种在你的MFC应用程序中处理WM_NOTIFY消息的方法。

Windows 3.x 的 通告消息

在Windows 3.x下,控件通过发送一个消息给它的父窗口来告知诸如目标点击,内容的变化与选中,控件北京绘制等等之类的事件。简单的通告消息以特殊的WM_COMMAND消息形式来发送,通知码(如BN_CLICKED)与控件ID存放在wParam里,lParam保存控件的句柄。此时注意,wParamlParam已经装满了数据,再也传递不了别的数据了,这些消息只能是简单的通告消息。举个例子,BN_CLICKED通告消息,无法发送按下鼠标按键时鼠标的位置信息。

当Windows 3.x下的控件需要发送包括额外数据的通告消息时,它们使用各种特殊目的的消息,包括WM_CTLCOLOR, WM_VSCROLL, WM_HSCROLL, WM_DRAWITEM, WM_MEASUREITEM, WM_COMPAREITEM, WM_DELETEITEM, WM_CHARTOITEM, WM_VKEYTOITEM等等。这些消息能够被反射回给发送它们的的控件,要看更多信息,查阅 TN062: Message Reflection for Windows Controls. (TN062: Windows控件的消息反射)

Win32下的通告消息

对于那些Windows 3.1的控件, Win32 API使用那些曾在Windows3.x有的绝大部分通告消息。However, Win32 also adds a number of sophisticated, complex controls to those supported in Windows 3.x.这些控件经常发送带附加数据的通告消息。设计者们没有为每一个需要附加数据的通告消息增加一个新的WM_* 消息,而是只增加了一个消息,WM_NOTIFY,这个消息可以通过一标准化格式传递任意多的额外数据。

WM_NOTIFY消息包括 保存发送消息控件ID的wParam和保存一个结构指针的lParam两部分。那个结构可以是一个NMHDR结构或者某些更大点的、以NMHDR结构为第一个成员的结构。这样的话,一个指向该结构的指针可以是NMHDR结构指针,也可以是那个更大点的结构指针,看你怎么转换他了。

在大多数情况下,那个指针会指向更大点的结构,当你用到的时候就需要转换它。 只有几个通告消息,如 common通告消息(名字以NM_开始),工具提示控件的TTN_SHOWTTN_POP,是实际上用到NMHDR结构的。

那个NMHDR结构或者为首成员的结构,包含发送消息的控件句柄和ID,还有通知码(如TTN_SHOW)。NMHDR结构格式如下:

typedef struct tagNMHDR {
                   HWND hwndFrom;
                   UINT idFrom;
                   UINT code;
} NMHDR;

对于TTN_SHOW消息,成员code应被设置成TTN_SHOW

大多数通告消息传递一个指向更大的把NMHDR结构作为第一个成员的结构的指针。举个例子,看看list view控件的LVN_KEYDOWN通告消息所使用的结构,在list view控件里键盘按键被按下时发送这个消息。那个指针就指向LV_KEYDOWN结构体,定义如下:

typedef struct tagLV_KEYDOWN {
                   NMHDR hdr;                  
                   WORD wVKey;  
                   UINT flags;  
} LV_KEYDOWN;

这样,因为NMHDR是这个结构的第一个成员,那个指针既可以转换为NMHDR型指针也可以转换为LV_KEYDOWN型指针。

(笔者注:标准命名约定,LV_KEYDOWN已经改名为:NMLVKEYDOWN。MSDN Library - October 2001上是这么说的呵呵。)

对新Windows控件通用的通告消息

一些通告消息对所有新的Windows控件来说是通用的,这些通告消息传递一个指向NMHDR结构体的指针。

Notification codeSent because
NM_CLICK用户在控件内单击鼠标左键
NM_DBLCLK用户在控件内双击鼠标左键
NM_RCLICK用户在控件内单击鼠标右键
NM_RDBLCLK用户在控件内双击鼠标右键
NM_RETURN用户在控件具有输入焦点的时候按下回车
NM_SETFOCUS控件获得输入焦点
NM_KILLFOCUS控件失去输入焦点
NM_OUTOFMEMORY控件因为没有足够的可用内存而不能完成一项操作

ON_NOTIFY: 在MFC应用程序里处理 WM_NOTIFY 消息

函数CWnd::OnNotify处理通告消息。其默认实现是检查通告消息处理函数的消息映射,然后调用。(checks the message map for notification handlers to call.)一般说来,你不用重载OnNotify。你可以写一个处理函数,然后在你自己的窗口类的消息映射表里添加一个该函数的消息映射入口。

ClassWizard,通过ClassWizard属性页或者WizardBar工具条,能够创建ON_NOTIFY消息映射入口,并且给您提供了一个处理函数的框架。更多关于通过ClassWizard使得添加消息映射更容易的信息,请看Visual C++ Programmer's GuideMapping Messages to Functions

ON_NOTIFY 消息映射宏的语法如下:

ON_NOTIFY( wNotifyCode, id, memberFxn )

斜体字的参数被替换为:

wNotifyCode

    要被处理的通告消息代码,如 LVN_KEYDOWN

id

    发送通告消息的控件ID。

memberFxn

    通告消息发送后被调用的成员函数。

你的成员函数必须按照如下形式声明:

afx_msg void memberFxn( NMHDR * pNotifyStruct, LRESULT * result );

斜体字参数为::

pNotifyStruct

    指向通告消息结构的指针,类型如上声明。

result

    指向函数返回之前要被设置结果值的变量指针。

代码实例

现指定你要成员函数OnKeydownList1函去处理ID为IDC_LIST1的CListCtrl控件的LVN_KEYDOWN消息,你可以通过ClassWizard把下面的内容加入到你的消息映射表里:

ON_NOTIFY( LVN_KEYDOWN, IDC_LIST1, OnKeydownList1 )

在上面的例子里,ClassWizard提供的函数是:

void CMessageReflectionDlg::OnKeydownList1(NMHDR* pNMHDR, LRESULT* pResult)
{
   LV_KEYDOWN* pLVKeyDow = (LV_KEYDOWN*)pNMHDR;
   // TODO: Add your control notification handler
   //                  code here
   
   *pResult = 0;
}

ClassWizard自动生成合适类型的指针。你可以通过pNMHDR或者pLVKeyDow访问通告消息结构体。

ON_NOTIFY_RANGE

如果你需要处理一组控件的同一个WM_NOTIFY消息,你可使用ON_NOTIFY_RANGE而不是ON_NOTIFY。例如,你有一组按钮,想让它们对某一通告消息执行相同的动作。

When you use ON_NOTIFY_RANGE, you specify a contiguous range of child identifiers for which to handle the notification message by specifying the beginning and ending child identifiers of the range.

(不太会翻译,大意就是,使用ON_NOTIFY_RANGE的时候,要指定一个你所需要相同相同消息处理函数控件的ID范围)

ClassWizard不去处理ON_NOTIFY_RANGE的使用,要用它,就自己在消息映射表里编辑。

ON_NOTIFY_RANGE的消息映射入口与函数原型如下表示:

ON_NOTIFY_RANGE( wNotifyCode, id, idLast, memberFxn )

斜体字参数被替换为:

wNotifyCode

    要被处理的通告消息代码,如 LVN_KEYDOWN

id

    连续ID范围里的第一个。

idLast

    连续ID范围里的最后一个。

memberFxn

    通告消息发送后被调用的成员函数。

你的成员函数必须按照如下形式声明:

afx_msg void memberFxn( UINT id, NMHDR * pNotifyStruct, LRESULT * result );

斜体字参数为:

id

    发送通告消息的控件ID。

pNotifyStruct

    指向通告消息结构的指针,类型如上声明。

result

    指向函数返回之前要被设置结果值的变量指针

帮我解释一些ubus方法的代码含义 /****************************************************************************** * Copyright (c) 2016-2018 TP-Link Technologies CO.,LTD. * * �ļ�����: ubus_server.c * �� ��: 1.0 * ժ Ҫ: nvrcore ubus server * �� ��: xxj<xiaoxiangjian@tp-link.net> * ����ʱ��: 2016-02-02 ******************************************************************************/ #include <unistd.h> #include <fcntl.h> #include <libubus.h> #include <json/json.h> #include <libubox/uloop.h> #include <sys/prctl.h> #include "nvrcore_dbg.h" #include "ubus_server.h" #include "web_ubus.h" #include "play_ubus.h" #include "msglog_ubus.h" #include "resource_ubus.h" #if defined(FAN_ENABLE) #include "fan_control_ubus.h" #endif #ifdef PREVIEW_MI9280 #include "mi_set_env.h" #endif #include "nvrcore_ubus_client.h" #include "preview_ubus.h" #ifdef MSG_PUSH_SUPPORT #include "msg_push_ubus_s.h" #endif #ifdef CLOUD_STORAGE_SUPPORT #include "cs_ubus_server.h" #endif struct ubus_context *ctx; struct blob_buf b; LOCAL void nvrcore_ubus_add_fd(struct ubus_context *ctx) { ubus_add_uloop(ctx); #ifdef FD_CLOEXEC fcntl(ctx->sock.fd, F_SETFD, fcntl(ctx->sock.fd, F_GETFD) | FD_CLOEXEC); #endif } LOCAL void nvrcore_ubus_reconnect_timer(struct ubus_context *ctx, struct uloop_timeout *timeout) { LOCAL struct uloop_timeout retry = { .cb = nvrcore_ubus_reconnect_timer, }; S32 t = 2; if (ubus_reconnect(ctx, NULL) != 0) { uloop_timeout_set(&retry, t * 1000); return; } nvrcore_ubus_add_fd(ctx); } LOCAL void ubus_connection_lost(struct ubus_context *ctx) { nvrcore_ubus_reconnect_timer(ctx, NULL); } STATUS nvrcore_ubus_server_init() { ctx = NULL; uloop_init(); ctx = ubus_connect(NULL); if (!ctx) { NVRCORE_PRINT(LOG_PRIO_ERROR, "ubus connect failed\n"); return ERROR; } ctx->connection_lost = ubus_connection_lost; nvrcore_ubus_add_fd(ctx); return OK; } STATUS nvrcore_ubus_add_objs() { if (OK != display_ubus_init(ctx, NULL)) { return ERROR; } if (OK != media_ubus_init(ctx, NULL)) { return ERROR; } if (OK != record_ubus_init(ctx, NULL)) { return ERROR; } if (OK != rtspm_ubus_init(ctx)) { return ERROR; } if (OK != playback_ubus_init(ctx, NULL)) { return ERROR; } #ifdef MSG_PUSH_SUPPORT if (OK != msg_push_ubus_init(ctx, NULL)) { return ERROR; } #endif #ifdef CLOUD_STORAGE_SUPPORT if (OK != cloud_storage_ubus_init(ctx, NULL)) { return ERROR; } #endif if (OK != msglog_ubus_init(ctx, NULL)) { return ERROR; } #ifdef PREVIEW_MI9280 if (OK != mi_ubus_init(ctx, NULL)) { return ERROR; } #endif if (OK != resource_ubus_init(ctx, NULL)) { return ERROR; } #if defined(FAN_ENABLE) if (OK != fan_control_ubus_init(ctx, NULL)) { return ERROR; } #endif return OK; } /**************************************************************************** * Function : nvrcore_ubus_server_start * Description: ����ubus������ * Input : N/A * Output : N/A * Return : N/A ****************************************************************************/ void nvrcore_ubus_server_start() { uloop_set_uloop_fd_ptr(&ctx->sock); /*!< preview need the layout information when start up*/ nvrcore_ubus_call_nvrgui(UBUS_NOTITY_REFRESH_PREVIEW_LAYOUT); uloop_run(); } /**************************************************************************** * Function : nvrcore_ubus_done * Description: ubus�˳������������ * Input : N/A * Output : N/A * Return : N/A ****************************************************************************/ void nvrcore_ubus_done() { uloop_done(); ubus_free(ctx); if(b.buf) { blob_buf_free(&b); } } void * nvrcore_ubus_thread(void * arg) { char * path = (char *)arg; prctl(PR_SET_NAME, "nvrcoreUbus"); if (ERROR == nvrcore_ubus_server_init()) { printf("ubus connect failed!\n"); return NULL; } if (ERROR == nvrcore_ubus_add_objs()) { printf("ubus connect failed!\n"); return NULL; } nvrcore_ubus_server_start(); nvrcore_ubus_done(); pthread_exit((void *)0); }
最新发布
09-04
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值