转自:

https://msdn.microsoft.com/en-us/library/eeah46xd.aspx

TN062: Message Reflection for Windows Controls

Visual Studio 2015
 
Note

The following technical note has not been updated since it was first included in the online documentation. As a result, some procedures and topics might be out of date or incorrect. For the latest information, it is recommended that you search for the topic of interest in the online documentation index.

This technical note describes message reflection, a new feature in MFC 4.0. It also contains directions for creating a simple reusable control that uses message reflection.

This technical note does not discuss message reflection as it applies to ActiveX controls (formerly called OLE controls). Please see the articleActiveX Controls: Subclassing a Windows Control.

What Is Message Reflection?

Windows controls frequently send notification messages to their parent windows. For instance, many controls send a control color notification message (WM_CTLCOLOR or one of its variants) to their parent to allow the parent to supply a brush for painting the background of the control.

In Windows and in MFC before version 4.0, the parent window, often a dialog box, is responsible for handling these messages. This means that the code for handling the message needs to be in the parent window's class and that it has to be duplicated in every class that needs to handle that message. In the case above, every dialog box that wanted controls with custom backgrounds would have to handle the control color notification message. It would be much easier to reuse code if a control class could be written that would handle its own background color.

In MFC 4.0, the old mechanism still works — parent windows can handle notification messages. In addition, however, MFC 4.0 facilitates reuse by providing a feature called "message reflection" that allows these notification messages to be handled in either the child control window or the parent window, or in both. In the control background color example, you can now write a control class that sets its own background color by handling the reflected WM_CTLCOLOR message — all without relying on the parent. (Note that since message reflection is implemented by MFC, not by Windows, the parent window class must be derived from CWnd for message reflection to work.)

Older versions of MFC did something similar to message reflection by providing virtual functions for a few messages, such as messages for owner-drawn list boxes (WM_DRAWITEM, and so on). The new message reflection mechanism is generalized and consistent.

Message reflection is backward compatible with code written for versions of MFC before 4.0.

If you have supplied a handler for a specific message, or for a range of messages, in your parent window's class, it will override reflected message handlers for the same message provided you don't call the base class handler function in your own handler. For example, if you handleWM_CTLCOLOR in your dialog box class, your handling will override any reflected message handlers.

If, in your parent window class, you supply a handler for a specific WM_NOTIFY message or a range of WM_NOTIFY messages, your handler will be called only if the child control sending those messages does not have a reflected message handler through ON_NOTIFY_REFLECT(). If you useON_NOTIFY_REFLECT_EX() in your message map, your message handler may or may not allow the parent window to handle the message. If the handler returns FALSE, the message will be handled by the parent as well, while a call that returns TRUE does not allow the parent to handle it. Note that the reflected message is handled before the notification message.

When a WM_NOTIFY message is sent, the control is offered the first chance to handle it. If any other reflected message is sent, the parent window has the first chance to handle it and the control will receive the reflected message. To do so, it will need a handler function and an appropriate entry in the control's class message map.

The message-map macro for reflected messages is slightly different than for regular notifications: it has _REFLECT appended to its usual name. For instance, to handle a WM_NOTIFY message in the parent, you use the macro ON_NOTIFY in the parent's message map. To handle the reflected message in the child control, use the ON_NOTIFY_REFLECT macro in the child control's message map. In some cases, the parameters are different, as well. Note that ClassWizard can usually add the message-map entries for you and provide skeleton function implementations with correct parameters.

See TN061: ON_NOTIFY and WM_NOTIFY Messages for information on the new WM_NOTIFY message.

Message-Map Entries and Handler Function Prototypes for Reflected Messages

To handle a reflected control notification message, use the message-map macros and function prototypes listed in the table below.

ClassWizard can usually add these message-map entries for you and provide skeleton function implementations. See Defining a Message Handler for a Reflected Message for information about how to define handlers for reflected messages.

To convert from the message name to the reflected macro name, prepend ON_ and append _REFLECT. For example, WM_CTLCOLOR becomesON_WM_CTLCOLOR_REFLECT. (To see which messages can be reflected, do the opposite conversion on the macro entries in the table below.)

The three exceptions to the rule above are as follows:

  • The macro for WM_COMMAND notifications is ON_CONTROL_REFLECT.

  • The macro for WM_NOTIFY reflections is ON_NOTIFY_REFLECT.

  • The macro for ON_UPDATE_COMMAND_UI reflections is ON_UPDATE_COMMAND_UI_REFLECT.

In each of the above special cases, you must specify the name of the handler member function. In the other cases, you must use the standard name for your handler function.

The meanings of the parameters and return values of the functions are documented under either the function name or the function name with Onprepended. For instance, CtlColor is documented in OnCtlColor. Several reflected message handlers need fewer parameters than the similar handlers in a parent window. Just match the names in the table below with the names of the formal parameters in the documentation.

Map entry

Function prototype

ON_CONTROL_REFLECT( wNotifyCodememberFxn )

afx_msg void memberFxn ( );

ON_NOTIFY_REFLECT( wNotifyCodememberFxn )

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

ON_UPDATE_COMMAND_UI_REFLECT( memberFxn )

afx_msg void memberFxn ( CCmdUI* pCmdUI );

ON_WM_CTLCOLOR_REFLECT( )

afx_msg HBRUSH CtlColor ( CDC* pDC, UINT nCtlColor );

ON_WM_DRAWITEM_REFLECT( )

afx_msg void DrawItem ( LPDRAWITEMSTRUCT lpDrawItemStruct );

ON_WM_MEASUREITEM_REFLECT( )

afx_msg void MeasureItem ( LPMEASUREITEMSTRUCT lpMeasureItemStruct );

ON_WM_DELETEITEM_REFLECT( )

afx_msg void DeleteItem ( LPDELETEITEMSTRUCT lpDeleteItemStruct );

ON_WM_COMPAREITEM_REFLECT( )

afx_msg int CompareItem ( LPCOMPAREITEMSTRUCT lpCompareItemStruct );

ON_WM_CHARTOITEM_REFLECT( )

afx_msg int CharToItem ( UINT nKey, UINT nIndex );

ON_WM_VKEYTOITEM_REFLECT( )

afx_msg int VKeyToItem ( UINT nKey, UINT nIndex );

ON_WM_HSCROLL_REFLECT( )

afx_msg void HScroll ( UINT nSBCode, UINT nPos );

ON_WM_VSCROLL_REFLECT( )

afx_msg void VScroll ( UINT nSBCode, UINT nPos );

ON_WM_PARENTNOTIFY_REFLECT( )

afx_msg void ParentNotify ( UINT message, LPARAM lParam );

The ON_NOTIFY_REFLECT and ON_CONTROL_REFLECT macros have variations that allow more than one object (such as the control and its parent) to handle a given message.

Map entry

Function prototype

ON_NOTIFY_REFLECT_EX( wNotifyCodememberFxn )

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

ON_CONTROL_REFLECT_EX( wNotifyCodememberFxn )

afx_msg BOOL memberFxn ( );

Handling Reflected Messages: An Example of a Reusable control

 

This simple example creates a reusable control called CYellowEdit. The control works the same as a regular edit control except that it displays black text on a yellow background. It would be easy to add member functions that would allow the CYellowEdit control to display different colors.

To try the example that creates a reusable control

  1. Create a new dialog box in an existing application. For more information, see the dialog editor topic.

    You must have an application in which to develop the reusable control. If you don't have an existing application to use, create a dialog-based application using AppWizard.

  2. With your project loaded into Visual C++, use ClassWizard to create a new class called CYellowEdit based on CEdit.

  3. Add three member variables to your CYellowEdit class. The first two will be COLORREF variables to hold the text color and the background color. The third will be a CBrush object that will hold the brush for painting the background. The CBrush object allows you to create the brush once, merely referencing it after that, and to destroy the brush automatically when the CYellowEdit control is destroyed.

  4. Initialize the member variables by writing the constructor as follows:

     
     
    CYellowEdit::CYellowEdit()
    {
    m_clrText = RGB( 0, 0, 0 );
    m_clrBkgnd = RGB( 255, 255, 0 );
    m_brBkgnd.CreateSolidBrush( m_clrBkgnd );
    }
  5. Using ClassWizard, add a handler for the reflected WM_CTLCOLOR message to your CYellowEdit class. Note that the equal sign in front of the message name in the list of messages you can handle indicates that the message is reflected. This is described in Defining a Message Handler for a Reflected Message.

    ClassWizard adds the following message-map macro and skeleton function for you:

     
     
    ON_WM_CTLCOLOR_REFLECT()
    
    // Note: other code will be in between....
    
    HBRUSH CYellowEdit::CtlColor(CDC* pDC, UINT nCtlColor)
    {
    // TODO: Change any attributes of the DC here // TODO: Return a non-NULL brush if the
    // parent's handler should not be called
    return NULL;
    }
  6. Replace the body of the function with the following code. The code specifies the text color, the text background color, and the background color for rest of the control.

     
     
    pDC->SetTextColor( m_clrText );   // text
    pDC->SetBkColor( m_clrBkgnd ); // text bkgnd
    return m_brBkgnd; // ctl bkgnd
  7. Create an edit control in your dialog box, then attach it to a member variable by double-clicking the edit control while holding a control key down. In the Add Member Variable dialog box, finish the variable name and choose "Control" for the category, then "CYellowEdit" for the variable type. Don't forget to set the tab order in the dialog box. Also, be sure to include the header file for the CYellowEdit control in your dialog box's header file.

  8. Build and run your application. The edit control will have a yellow background.

ON_NOTIFY_REFLECT : Message Reflection for Windows Controls的更多相关文章

  1. 用 .NET Reflector 8 查看 System.Windows.Controls 命名空间下的类

    为了学习自定义控件,就想看看WPF基本元素的代码.使用到工具.NET Reflector. System.Windows.Controls 命名空间在PresentationFramework.dll ...

  2. 无法将类型为“System.Windows.Controls.SelectedItemCollection”的对象强制转换为类型“System.Collections.Generic.IList`1

    在WPF中DataGrid 选择事件中获取SelectedItems 报错如下 无法将类型为“System.Windows.Controls.SelectedItemCollection”的对象强制转 ...

  3. Microsoft.Windows.Controls.Ribbon.RibbonWindow 碰到 AvalonDock出现的诡异现象

    部分一 14年底进入目前公司时,领导准备开发一款新软件平台以取代原有平台.原平台采用C++Build开发界面(window c/s客户端) .Visual Studio(封装dll模块).过完年,领导 ...

  4. How to Change Error Message Colors in Windows 10 PowerShell Console

    While this was a really easy way to change some of the settings, what if you want to do more extensi ...

  5. dotnet core linux 接入支付宝H5支付,提示:System.PlatformNotSupportedException","Message":"'CspParameters' requires Windows Cryptographic API (CAPI), which is not available on this platform.

    用的官方提供的demo,实际上部署后却出现了上图的错误.和技术支持沟通无效后,走上了不归路. 在微软的github dotnet/core开源库提交了issue后,终于获得了解决.附上链接:https ...

  6. WPF CoboxItem控件使用SelectedItem去调System.Windows.Controls.ComboBoxItem: 前缀方法

    textComBox.SelectedItem as ComboBoxItem).Content textConbox: 控件Combobox 的Name 在Combobox控件SelectionCh ...

  7. WPF 应用 - 通过 js 缩放 System.Windows.Controls.WebBrowser 的内容

    1. 前提 原本是在大屏上展示系统,系统有个功能是加载第三方的网站,第三方网站按照大屏的分辨率写死了宽高: 现需要改到小屏展示系统,而这个第三方的网站不能随着 WebBrowser 窗口的尺寸调整网站 ...

  8. 网络负载均衡环境下wsHttpBinding+Message Security+Windows Authentication的常见异常

    提高Windows Communication Foundation (WCF) 应用程序负载能力的方法之一就是通过把它们部署到负载均衡的服务器场中. 其中可以使用标准的负载均衡技术, Windows ...

  9. windows消息机制详解(转载)

    消息,就是指Windows发出的一个通知,告诉应用程序某个事情发生了.例如,单击鼠标.改变窗口尺寸.按下键盘上的一个键都会使Windows发送一个消息给应用程序.消息本身是作为一个记录传递给应用程序的 ...

随机推荐

  1. pod 安装 Masonry 遇到问题

    pod 导入第三方库 Masonry: 在工程masonryTest的文件下新建一个Podfile文件 编辑如下内容: platform :ios, '8.0'xcodeproj 'mansoryTe ...

  2. The resource could not be loaded because the App Transport Security policy requires the use of a secure connection

    xmpp 项目中遇到的问题,用苹果的通信API 写一个PUT 方法,向服务器上传一张图片.遇到如题问题. Plist 文件没有NSAppTransportSecurity属性 Dic,添加该属性,再添 ...

  3. Nginx 笔记与总结(2)信号控制

    开启.关闭.重启 Nginx 官方地址:http://wiki.nginx.org/CommandLine 开启: /usr/local/nginx/sbin/nginx 关闭,用信号控制,语法: k ...

  4. PHP 错误与异常 笔记与总结(3)PHP 配置文件(php.ini)中与错误相关的选项 与 设置错误级别

    [PHP 配置文件中与错误相关的选项 ] 选项 描述 error_reporting 设置错误报告的级别 display_errors 是否显示错误 log_errors 设置是否将错误信息记录到日志 ...

  5. mysq数据库再次理解

    1.表中的一条记录就是一个object,object有很多属性,对应表中的字段.object的属性对应的值就是字段值 2.外键是关联表关系用的.表关系的确立只能通过外键 但更高效的策略是,在数据库中部 ...

  6. 使用 Linux 搭建 VPN

    http://blog.csdn.net/catoop/article/details/7537012 VPN服务器的配置与应用 实验场景 通过将Linux配置VPN服务器允许远程计算机能够访问内网. ...

  7. Android轻量缓存框架--ASimpleCache

    [转] 大神真面目 稀土掘金,这是一个针对技术开发者的一个应用,你可以在掘金上获取最新最优质的技术干货,不仅仅是Android知识.前端.后端以至于产品和设计都有涉猎,想成为全栈工程师的朋友不要错过! ...

  8. [dpdk] 读官方文档(2)

    续前节.切好继续: 一,文档里提到uio_pci_generic, igb_uio, vfio_pci三个内核模块,完全搞不懂,以及dpdk-devbind.py用来查看网卡状态,我得到了下边的输出: ...

  9. 关于FireMonkey TGrid赋值的一点小研究

    FireMoneky的TStringGrid用法和VCL里面的差不多, 但是另一个TGrid实在是奇葩, 几乎找不到给单元格赋值的方法(除了使用LiveBind) 看了其源码, 发现只要给某个Colu ...

  10. X-UA-Compatible是神马

    X-UA-Compatible是神马 X-UA-Compatible是IE8的一个专有<meta>属性,它告诉IE8采用何种IE版本去渲染网页,在html的<head>标签中使 ...