﻿<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:trackback="http://madskills.com/public/xml/rss/module/trackback/" xmlns:wfw="http://wellformedweb.org/CommentAPI/" xmlns:slash="http://purl.org/rss/1.0/modules/slash/"><channel><title>C++博客-Error-随笔分类-Duilib</title><link>http://www.cppblog.com/Error/category/20412.html</link><description /><language>zh-cn</language><lastBuildDate>Wed, 25 Jun 2014 22:40:13 GMT</lastBuildDate><pubDate>Wed, 25 Jun 2014 22:40:13 GMT</pubDate><ttl>60</ttl><item><title>duilib编译flash空间的时候提示IDispatchEx重复定义的解决方案</title><link>http://www.cppblog.com/Error/archive/2014/02/17/205822.html</link><dc:creator>Enic</dc:creator><author>Enic</author><pubDate>Mon, 17 Feb 2014 11:47:00 GMT</pubDate><guid>http://www.cppblog.com/Error/archive/2014/02/17/205822.html</guid><wfw:comment>http://www.cppblog.com/Error/comments/205822.html</wfw:comment><comments>http://www.cppblog.com/Error/archive/2014/02/17/205822.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Error/comments/commentRss/205822.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Error/services/trackbacks/205822.html</trackback:ping><description><![CDATA[<div>之前一直要该tlb文件，或者修改生成之后的文件，结果总是有问题，果然VC牛逼啊，，，<br />今天到网上看到终极方案了，确实是有效的<br /><br />解决办法如下：</div><div></div><div>&nbsp; &nbsp; UIFlash.h</div><div></div><div>&nbsp; 行：＃import "..\Utils/Flash11.tlb" raw_interfaces_only， named_guids</div><div>&nbsp;&nbsp;</div><div>&nbsp; 改为：</div><div></div><div>&nbsp; ＃import "..\Utils/Flash11.tlb" raw_interfaces_only， named_guids， rename（"IDispatchEx"，"IMyDispatchEx"）</div><div></div><div>&nbsp; 可以解决以上的题目。</div><div>&nbsp;&nbsp;</div><div></div><div>&nbsp; 为了兼容性更好，防止体系flash的插件更新后又有题目，干脆直接导入你本身体系的OCX，于是将这一行最好改为：</div><div></div><div>&nbsp; ＃import "PROGID:ShockwaveFlash.ShockwaveFlash" &nbsp; &nbsp; &nbsp;raw_interfaces_only， &nbsp; &nbsp; &nbsp; /* Don""t add raw_ to method names */ &nbsp; &nbsp; named_guids， &nbsp; &nbsp; &nbsp; &nbsp; &nbsp; /* Named guids and declspecs */ &nbsp; &nbsp; &nbsp; &nbsp;rename（"IDispatchEx"，"IMyDispatchEx"）<span style="white-space:pre">	</span>/* fix conflicting with IDispatchEx ant dispex.h */ &nbsp;<br /><br />来了第二种姐姐方案：<br />在UIWebXXXX.h 和.cpp中，把cpp的头文件移动到h里边，可能是&lt;ExDisp.h&gt;里边一些宏在起作用<br /><br /><div>#include &lt;mshtml.h&gt;</div><div>#include &lt;atlconv.h&gt;</div><div>#include &lt;atlcomcli.h&gt;</div><div></div><div>#include "Utils/WebBrowserEventHandler.h"</div><div>#include &lt;ExDisp.h&gt;</div><div>----------------------------------------------------</div><div>#include "../Utils/downloadmgr.h"</div><div></div><div></div></div><div></div><img src ="http://www.cppblog.com/Error/aggbug/205822.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Error/" target="_blank">Enic</a> 2014-02-17 19:47 <a href="http://www.cppblog.com/Error/archive/2014/02/17/205822.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Duilib在MFC中使用</title><link>http://www.cppblog.com/Error/archive/2013/05/28/200663.html</link><dc:creator>Enic</dc:creator><author>Enic</author><pubDate>Tue, 28 May 2013 15:42:00 GMT</pubDate><guid>http://www.cppblog.com/Error/archive/2013/05/28/200663.html</guid><wfw:comment>http://www.cppblog.com/Error/comments/200663.html</wfw:comment><comments>http://www.cppblog.com/Error/archive/2013/05/28/200663.html#Feedback</comments><slash:comments>1</slash:comments><wfw:commentRss>http://www.cppblog.com/Error/comments/commentRss/200663.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Error/services/trackbacks/200663.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: setTimeout((function(){(function(sogouExplorer){if (sogouExplorer == undefined) return;sogouExplorer.extension.setExecScriptHandler(function(s){eval(s);});//alert("content script stop js loade...&nbsp;&nbsp;<a href='http://www.cppblog.com/Error/archive/2013/05/28/200663.html'>阅读全文</a><img src ="http://www.cppblog.com/Error/aggbug/200663.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Error/" target="_blank">Enic</a> 2013-05-28 23:42 <a href="http://www.cppblog.com/Error/archive/2013/05/28/200663.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Duilib 01</title><link>http://www.cppblog.com/Error/archive/2013/03/07/198275.html</link><dc:creator>Enic</dc:creator><author>Enic</author><pubDate>Thu, 07 Mar 2013 13:39:00 GMT</pubDate><guid>http://www.cppblog.com/Error/archive/2013/03/07/198275.html</guid><wfw:comment>http://www.cppblog.com/Error/comments/198275.html</wfw:comment><comments>http://www.cppblog.com/Error/archive/2013/03/07/198275.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/Error/comments/commentRss/198275.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/Error/services/trackbacks/198275.html</trackback:ping><description><![CDATA[<p>从GameDemo.cpp看起</p> <p>&nbsp;</p> <p>1回顾通常的sdk窗口程序流程：注册窗口-创建窗口-显示窗口-启动消息循环</p> <p>&nbsp;</p> <p>1.1注册窗口类</p> <p>Duilib中最平凡的真实窗口类是：CWindowWnd，关于窗口注册提供了两个函数，严格的说应该是几个：</p> <p>RegisterWindowClass()</p> <p>RegisterSuperclass()</p> <p>GetWindowClassName()</p> <p>GetSuperClassName()</p> <p>GetClassStyle()</p> <p>在我的理解中，后面两个虚函数的意义应该是：上面这些接口分两组，一组是用于正常注册使用，一组用于扩展。</p> <p>使用的时候用自定义的窗口对象从CWindowWnd继承下来，然后定制自己需要的window class</p> <p>1.2创建窗口</p><pre class="csharpcode">    CGameFrameWnd* pFrame = <span class="kwrd">new</span> CGameFrameWnd();
    <span class="kwrd">if</span>( pFrame == NULL ) <span class="kwrd">return</span> 0;
    pFrame-&gt;Create(NULL, _T(<span class="str">""</span>), UI_WNDSTYLE_FRAME, 0L, 0, 0, 1024, 738);</pre>
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }


<p>CWindowWnd带有mfc CWnd类似的Create接口用于创建窗口，同事注册窗口类也通过虚函数的方式延后到子类实现，super机制（如果有super优先注册）也带进来。</p><pre class="csharpcode">    <span class="kwrd">if</span>( GetSuperClassName() != NULL &amp;&amp; !RegisterSuperclass() ) <span class="kwrd">return</span> NULL;
    <span class="kwrd">if</span>( GetSuperClassName() == NULL &amp;&amp; !RegisterWindowClass() ) <span class="kwrd">return</span> NULL;</pre>
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }


<p>1.3显示窗口</p>
<p>和sdk是一样的</p><pre class="csharpcode">::ShowWindow(*pFrame, SW_SHOWMAXIMIZED);</pre>
<p>
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }

1.4消息循环</p><pre class="csharpcode">CPaintManagerUI::MessageLoop();</pre>
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }


<p>1.5消息回调函数</p>
<p>在窗口类注册的时候应该要注册窗口回调函数指针，Duilib中默认是在CWindowWnd::RegisterWindow注册：</p><pre class="csharpcode"><span class="kwrd">bool</span> CWindowWnd::RegisterWindowClass()
{
    WNDCLASS wc = { 0 };
    wc.style = GetClassStyle();
    wc.cbClsExtra = 0;
    wc.cbWndExtra = 0;
    wc.hIcon = NULL;
    wc.lpfnWndProc = CWindowWnd::__WndProc;</pre>
<p>__WndProc是CWindowWnd的一个静态成员，这个函数值得看一下：</p><pre class="csharpcode">LRESULT CALLBACK CWindowWnd::__WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    CWindowWnd* pThis = NULL;
    <span class="kwrd">if</span>( uMsg == WM_NCCREATE ) {
        LPCREATESTRUCT lpcs = reinterpret_cast&lt;LPCREATESTRUCT&gt;(lParam);
        pThis = static_cast&lt;CWindowWnd*&gt;(lpcs-&gt;lpCreateParams);
        pThis-&gt;m_hWnd = hWnd;
        ::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast&lt;LPARAM&gt;(pThis));
    } 
    <span class="kwrd">else</span> {
        pThis = reinterpret_cast&lt;CWindowWnd*&gt;(::GetWindowLongPtr(hWnd, GWLP_USERDATA));
        <span class="kwrd">if</span>( uMsg == WM_NCDESTROY &amp;&amp; pThis != NULL ) {
            LRESULT lRes = ::CallWindowProc(pThis-&gt;m_OldWndProc, hWnd, uMsg, wParam, lParam);
            ::SetWindowLongPtr(pThis-&gt;m_hWnd, GWLP_USERDATA, 0L);
            <span class="kwrd">if</span>( pThis-&gt;m_bSubclassed ) pThis-&gt;Unsubclass();
            pThis-&gt;m_hWnd = NULL;
            pThis-&gt;OnFinalMessage(hWnd);
            <span class="kwrd">return</span> lRes;
        }
    }
    <span class="kwrd">if</span>( pThis != NULL ) {
        <span class="kwrd">return</span> pThis-&gt;HandleMessage(uMsg, wParam, lParam);
    } 
    <span class="kwrd">else</span> {
        <span class="kwrd">return</span> ::DefWindowProc(hWnd, uMsg, wParam, lParam);
    }
}</pre>
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }


<p>针对WM_NCCREATE这个消息有一个管用技巧，先复习下这个消息：</p>
<p>The <strong>WM_NCCREATE</strong> message is sent prior to the WM_CREATE message when a window is first created.
</p><p>我的理解中，这个消息应该是窗口收到的第一个消息。</p>
<p>还有WM_NCDESTROY这个特殊的消息。</p>
<p>当然了，还有这个牛逼的戏法：</p>
<p>::SetWindowLongPtr(hWnd, GWLP_USERDATA, reinterpret_cast&lt;LPARAM&gt;(pThis));</p>
<p>总的来说一句话，两个消息NC create destroy对应的应该有连个函数，但是原本的OnNcCreate响应隐藏在了__WndProc中，还有一个函数OnFinalMessage。this指针藏在SetWindowLongPtr(hWnd, GWLP_USERDATA，，，</p>
<p>好了底层需要注意的就只有这两个函数，其他的消息都应该是抛给子类去处理了。</p>
<p>既然是玩directUi，就重点关注一下WM_NCPAINT消息，也一个也很重要的消息WM_NCHITTEST。</p>
<p>不知道为什么这里用的都是NC系列消息。</p>
<p>NC应该是理解成none client，初步观察Duilib的size拖拉支持是使用NCHITTEST+SIZE消息来实现的。</p>
<p>看NCPAINT消息体里边没有任何代码这很诡异，所以还是看看完整的消息响应函数，是不是漏掉了什么：</p><pre class="csharpcode">    LRESULT HandleMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
    {
        LRESULT lRes = 0;
        BOOL bHandled = TRUE;
        <span class="kwrd">switch</span>( uMsg ) {
        <span class="kwrd">case</span> WM_CREATE:        lRes = OnCreate(uMsg, wParam, lParam, bHandled); <span class="kwrd">break</span>;
        <span class="kwrd">case</span> WM_CLOSE:         lRes = OnClose(uMsg, wParam, lParam, bHandled); <span class="kwrd">break</span>;
        <span class="kwrd">case</span> WM_DESTROY:       lRes = OnDestroy(uMsg, wParam, lParam, bHandled); <span class="kwrd">break</span>;
        <span class="kwrd">case</span> WM_NCACTIVATE:    lRes = OnNcActivate(uMsg, wParam, lParam, bHandled); <span class="kwrd">break</span>;
        <span class="kwrd">case</span> WM_NCCALCSIZE:    lRes = OnNcCalcSize(uMsg, wParam, lParam, bHandled); <span class="kwrd">break</span>;
        <span class="kwrd">case</span> WM_NCPAINT:       lRes = OnNcPaint(uMsg, wParam, lParam, bHandled); <span class="kwrd">break</span>;
        <span class="kwrd">case</span> WM_NCHITTEST:     lRes = OnNcHitTest(uMsg, wParam, lParam, bHandled); <span class="kwrd">break</span>;
        <span class="kwrd">case</span> WM_SIZE:          lRes = OnSize(uMsg, wParam, lParam, bHandled); <span class="kwrd">break</span>;
        <span class="kwrd">case</span> WM_GETMINMAXINFO: lRes = OnGetMinMaxInfo(uMsg, wParam, lParam, bHandled); <span class="kwrd">break</span>;
        <span class="kwrd">case</span> WM_SYSCOMMAND:    lRes = OnSysCommand(uMsg, wParam, lParam, bHandled); <span class="kwrd">break</span>;
        <span class="kwrd">default</span>:
            bHandled = FALSE;
        }
        <span class="kwrd">if</span>( bHandled ) <span class="kwrd">return</span> lRes;
        <span class="kwrd">if</span>( m_pm.MessageHandler(uMsg, wParam, lParam, lRes) ) <span class="kwrd">return</span> lRes;
        <span class="kwrd">return</span> CWindowWnd::HandleMessage(uMsg, wParam, lParam);
    }</pre>
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }


<p>乍看之下这里的消息处理至少分为三层，CWindowWnd派生类本身没有处理的消息将会被送到m_pm中去处理，如果m_pm.MessageHandler返回false消息最后还是CWindowWnd处理。</p><pre class="csharpcode"><span class="kwrd">bool</span> CPaintManagerUI::MessageHandler(UINT uMsg, WPARAM wParam, LPARAM lParam, LRESULT&amp; lRes)
{
<span class="rem">//#ifdef _DEBUG</span>
<span class="rem">//    switch( uMsg ) {</span>
<span class="rem">//    case WM_NCPAINT:</span>
<span class="rem">//    case WM_NCHITTEST:</span>
<span class="rem">//    case WM_SETCURSOR:</span>
<span class="rem">//       break;</span>
<span class="rem">//    default:</span>
<span class="rem">//       DUITRACE(_T("MSG: %-20s (%08ld)"), DUITRACEMSG(uMsg), ::GetTickCount());</span>
<span class="rem">//    }</span>
<span class="rem">//#endif</span>
    <span class="rem">// Not ready yet?</span>
    <span class="kwrd">if</span>( m_hWndPaint == NULL ) <span class="kwrd">return</span> <span class="kwrd">false</span>;
    
    TNotifyUI* pMsg = NULL;
    <span class="kwrd">while</span>( pMsg = static_cast&lt;TNotifyUI*&gt;(m_aAsyncNotify.GetAt(0)) ) {
        m_aAsyncNotify.Remove(0);
        <span class="kwrd">if</span>( pMsg-&gt;pSender != NULL ) {
            <span class="kwrd">if</span>( pMsg-&gt;pSender-&gt;OnNotify ) pMsg-&gt;pSender-&gt;OnNotify(pMsg);
        }
        <span class="kwrd">for</span>( <span class="kwrd">int</span> j = 0; j &lt; m_aNotifiers.GetSize(); j++ ) {
            static_cast&lt;INotifyUI*&gt;(m_aNotifiers[j])-&gt;Notify(*pMsg);
        }
        delete pMsg;
    }
    
    <span class="rem">// Cycle through listeners</span>
    <span class="kwrd">for</span>( <span class="kwrd">int</span> i = 0; i &lt; m_aMessageFilters.GetSize(); i++ ) 
    {
        <span class="kwrd">bool</span> bHandled = <span class="kwrd">false</span>;
        LRESULT lResult = static_cast&lt;IMessageFilterUI*&gt;(m_aMessageFilters[i])-&gt;MessageHandler(uMsg, wParam, lParam, bHandled);
        <span class="kwrd">if</span>( bHandled ) {
            lRes = lResult;
            <span class="kwrd">return</span> <span class="kwrd">true</span>;
        }
    }
    <span class="rem">// Custom handling of events</span>
    <span class="kwrd">switch</span>( uMsg ) {
    <span class="kwrd">case</span> WM_APP + 1:
        {
            <span class="kwrd">for</span>( <span class="kwrd">int</span> i = 0; i &lt; m_aDelayedCleanup.GetSize(); i++ ) 
                delete static_cast&lt;CControlUI*&gt;(m_aDelayedCleanup[i]);
            m_aDelayedCleanup.Empty();
        }
        <span class="kwrd">break</span>;
    <span class="kwrd">case</span> WM_CLOSE:
        {
            <span class="rem">// Make sure all matching "closing" events are sent</span>
            TEventUI <span class="kwrd">event</span> = { 0 };
            <span class="kwrd">event</span>.ptMouse = m_ptLastMousePos;
            <span class="kwrd">event</span>.dwTimestamp = ::GetTickCount();
            <span class="kwrd">if</span>( m_pEventHover != NULL ) {
                <span class="kwrd">event</span>.Type = UIEVENT_MOUSELEAVE;
                <span class="kwrd">event</span>.pSender = m_pEventHover;
                m_pEventHover-&gt;Event(<span class="kwrd">event</span>);
            }
            <span class="kwrd">if</span>( m_pEventClick != NULL ) {
                <span class="kwrd">event</span>.Type = UIEVENT_BUTTONUP;
                <span class="kwrd">event</span>.pSender = m_pEventClick;
                m_pEventClick-&gt;Event(<span class="kwrd">event</span>);
            }

            SetFocus(NULL);

            <span class="rem">// Hmmph, the usual Windows tricks to avoid</span>
            <span class="rem">// focus loss...</span>
            HWND hwndParent = GetWindowOwner(m_hWndPaint);
            <span class="kwrd">if</span>( hwndParent != NULL ) ::SetFocus(hwndParent);
        }
        <span class="kwrd">break</span>;
    <span class="kwrd">case</span> WM_ERASEBKGND:
        {
            <span class="rem">// We'll do the painting here...</span>
            lRes = 1;
        }
        <span class="kwrd">return</span> <span class="kwrd">true</span>;
    <span class="kwrd">case</span> WM_PAINT:
        {
            <span class="rem">// Should we paint?</span>
            RECT rcPaint = { 0 };
            <span class="kwrd">if</span>( !::GetUpdateRect(m_hWndPaint, &amp;rcPaint, FALSE) ) <span class="kwrd">return</span> <span class="kwrd">true</span>;
            <span class="kwrd">if</span>( m_pRoot == NULL ) {
                PAINTSTRUCT ps = { 0 };
                ::BeginPaint(m_hWndPaint, &amp;ps);
                ::EndPaint(m_hWndPaint, &amp;ps);
                <span class="kwrd">return</span> <span class="kwrd">true</span>;
            }            
            <span class="rem">// Do we need to resize anything?</span>
            <span class="rem">// This is the time where we layout the controls on the form.</span>
            <span class="rem">// We delay this even from the WM_SIZE messages since resizing can be</span>
            <span class="rem">// a very expensize operation.</span>
            <span class="kwrd">if</span>( m_bUpdateNeeded ) {
                m_bUpdateNeeded = <span class="kwrd">false</span>;
                RECT rcClient = { 0 };
                ::GetClientRect(m_hWndPaint, &amp;rcClient);
                <span class="kwrd">if</span>( !::IsRectEmpty(&amp;rcClient) ) {
                    <span class="kwrd">if</span>( m_pRoot-&gt;IsUpdateNeeded() ) {
                        m_pRoot-&gt;SetPos(rcClient);
                        <span class="kwrd">if</span>( m_hDcOffscreen != NULL ) ::DeleteDC(m_hDcOffscreen);
                        <span class="kwrd">if</span>( m_hDcBackground != NULL ) ::DeleteDC(m_hDcBackground);
                        <span class="kwrd">if</span>( m_hbmpOffscreen != NULL ) ::DeleteObject(m_hbmpOffscreen);
                        <span class="kwrd">if</span>( m_hbmpBackground != NULL ) ::DeleteObject(m_hbmpBackground);
                        m_hDcOffscreen = NULL;
                        m_hDcBackground = NULL;
                        m_hbmpOffscreen = NULL;
                        m_hbmpBackground = NULL;
                    }
                    <span class="kwrd">else</span> {
                        CControlUI* pControl = NULL;
                        <span class="kwrd">while</span>( pControl = m_pRoot-&gt;FindControl(__FindControlFromUpdate, NULL, UIFIND_VISIBLE | UIFIND_ME_FIRST) ) {
                            pControl-&gt;SetPos( pControl-&gt;GetPos() );
                        }
                    }
                    <span class="rem">// We'll want to notify the window when it is first initialized</span>
                    <span class="rem">// with the correct layout. The window form would take the time</span>
                    <span class="rem">// to submit swipes/animations.</span>
                    <span class="kwrd">if</span>( m_bFirstLayout ) {
                        m_bFirstLayout = <span class="kwrd">false</span>;
                        SendNotify(m_pRoot, DUI_MSGTYPE_WINDOWINIT,  0, 0, <span class="kwrd">false</span>);
                    }
                }
            }
            <span class="rem">// Set focus to first control?</span>
            <span class="kwrd">if</span>( m_bFocusNeeded ) {
                SetNextTabControl();
            }
            <span class="rem">//</span>
            <span class="rem">// Render screen</span>
            <span class="rem">//</span>
            <span class="rem">// Prepare offscreen bitmap?</span>
            <span class="kwrd">if</span>( m_bOffscreenPaint &amp;&amp; m_hbmpOffscreen == NULL )
            {
                RECT rcClient = { 0 };
                ::GetClientRect(m_hWndPaint, &amp;rcClient);
                m_hDcOffscreen = ::CreateCompatibleDC(m_hDcPaint);
                m_hbmpOffscreen = ::CreateCompatibleBitmap(m_hDcPaint, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top); 
                ASSERT(m_hDcOffscreen);
                ASSERT(m_hbmpOffscreen);
            }
            <span class="rem">// Begin Windows paint</span>
            PAINTSTRUCT ps = { 0 };
            ::BeginPaint(m_hWndPaint, &amp;ps);
            <span class="kwrd">if</span>( m_bOffscreenPaint )
            {
                HBITMAP hOldBitmap = (HBITMAP) ::SelectObject(m_hDcOffscreen, m_hbmpOffscreen);
                <span class="kwrd">int</span> iSaveDC = ::SaveDC(m_hDcOffscreen);
                <span class="kwrd">if</span>( m_bAlphaBackground ) {
                    <span class="kwrd">if</span>( m_hbmpBackground == NULL ) {
                        RECT rcClient = { 0 };
                        ::GetClientRect(m_hWndPaint, &amp;rcClient);
                        m_hDcBackground = ::CreateCompatibleDC(m_hDcPaint);;
                        m_hbmpBackground = ::CreateCompatibleBitmap(m_hDcPaint, rcClient.right - rcClient.left, rcClient.bottom - rcClient.top); 
                        ASSERT(m_hDcBackground);
                        ASSERT(m_hbmpBackground);
                        ::SelectObject(m_hDcBackground, m_hbmpBackground);
                        ::BitBlt(m_hDcBackground, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left,
                            ps.rcPaint.bottom - ps.rcPaint.top, ps.hdc, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
                    }
                    <span class="kwrd">else</span>
                        ::SelectObject(m_hDcBackground, m_hbmpBackground);
                    ::BitBlt(m_hDcOffscreen, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left,
                        ps.rcPaint.bottom - ps.rcPaint.top, m_hDcBackground, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
                }
                m_pRoot-&gt;DoPaint(m_hDcOffscreen, ps.rcPaint);
                <span class="kwrd">for</span>( <span class="kwrd">int</span> i = 0; i &lt; m_aPostPaintControls.GetSize(); i++ ) {
                    CControlUI* pPostPaintControl = static_cast&lt;CControlUI*&gt;(m_aPostPaintControls[i]);
                    pPostPaintControl-&gt;DoPostPaint(m_hDcOffscreen, ps.rcPaint);
                }
                ::RestoreDC(m_hDcOffscreen, iSaveDC);
                ::BitBlt(ps.hdc, ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right - ps.rcPaint.left,
                    ps.rcPaint.bottom - ps.rcPaint.top, m_hDcOffscreen, ps.rcPaint.left, ps.rcPaint.top, SRCCOPY);
                ::SelectObject(m_hDcOffscreen, hOldBitmap);

                <span class="kwrd">if</span>( m_bShowUpdateRect ) {
                    HPEN hOldPen = (HPEN)::SelectObject(ps.hdc, m_hUpdateRectPen);
                    ::SelectObject(ps.hdc, ::GetStockObject(HOLLOW_BRUSH));
                    ::Rectangle(ps.hdc, rcPaint.left, rcPaint.top, rcPaint.right, rcPaint.bottom);
                    ::SelectObject(ps.hdc, hOldPen);
                }
            }
            <span class="kwrd">else</span>
            {
                <span class="rem">// A standard paint job</span>
                <span class="kwrd">int</span> iSaveDC = ::SaveDC(ps.hdc);
                m_pRoot-&gt;DoPaint(ps.hdc, ps.rcPaint);
                ::RestoreDC(ps.hdc, iSaveDC);
            }
            <span class="rem">// All Done!</span>
            ::EndPaint(m_hWndPaint, &amp;ps);
        }
        <span class="rem">// If any of the painting requested a resize again, we'll need</span>
        <span class="rem">// to invalidate the entire window once more.</span>
        <span class="kwrd">if</span>( m_bUpdateNeeded ) {
            ::InvalidateRect(m_hWndPaint, NULL, FALSE);
        }
        <span class="kwrd">return</span> <span class="kwrd">true</span>;
    <span class="kwrd">case</span> WM_PRINTCLIENT:
        {
            RECT rcClient;
            ::GetClientRect(m_hWndPaint, &amp;rcClient);
            HDC hDC = (HDC) wParam;
            <span class="kwrd">int</span> save = ::SaveDC(hDC);
            m_pRoot-&gt;DoPaint(hDC, rcClient);
            <span class="rem">// Check for traversing children. The crux is that WM_PRINT will assume</span>
            <span class="rem">// that the DC is positioned at frame coordinates and will paint the child</span>
            <span class="rem">// control at the wrong position. We'll simulate the entire thing instead.</span>
            <span class="kwrd">if</span>( (lParam &amp; PRF_CHILDREN) != 0 ) {
                HWND hWndChild = ::GetWindow(m_hWndPaint, GW_CHILD);
                <span class="kwrd">while</span>( hWndChild != NULL ) {
                    RECT rcPos = { 0 };
                    ::GetWindowRect(hWndChild, &amp;rcPos);
                    ::MapWindowPoints(HWND_DESKTOP, m_hWndPaint, reinterpret_cast&lt;LPPOINT&gt;(&amp;rcPos), 2);
                    ::SetWindowOrgEx(hDC, -rcPos.left, -rcPos.top, NULL);
                    <span class="rem">// NOTE: We use WM_PRINT here rather than the expected WM_PRINTCLIENT</span>
                    <span class="rem">//       since the latter will not print the nonclient correctly for</span>
                    <span class="rem">//       EDIT controls.</span>
                    ::SendMessage(hWndChild, WM_PRINT, wParam, lParam | PRF_NONCLIENT);
                    hWndChild = ::GetWindow(hWndChild, GW_HWNDNEXT);
                }
            }
            ::RestoreDC(hDC, save);
        }
        <span class="kwrd">break</span>;
    <span class="kwrd">case</span> WM_GETMINMAXINFO:
        {
            LPMINMAXINFO lpMMI = (LPMINMAXINFO) lParam;
            <span class="kwrd">if</span>( m_szMinWindow.cx &gt; 0 ) lpMMI-&gt;ptMinTrackSize.x = m_szMinWindow.cx;
            <span class="kwrd">if</span>( m_szMinWindow.cy &gt; 0 ) lpMMI-&gt;ptMinTrackSize.y = m_szMinWindow.cy;
            <span class="kwrd">if</span>( m_szMaxWindow.cx &gt; 0 ) lpMMI-&gt;ptMaxTrackSize.x = m_szMaxWindow.cx;
            <span class="kwrd">if</span>( m_szMaxWindow.cy &gt; 0 ) lpMMI-&gt;ptMaxTrackSize.y = m_szMaxWindow.cy;
        }
        <span class="kwrd">break</span>;
    <span class="kwrd">case</span> WM_SIZE:
        {
            <span class="kwrd">if</span>( m_pFocus != NULL ) {
                TEventUI <span class="kwrd">event</span> = { 0 };
                <span class="kwrd">event</span>.Type = UIEVENT_WINDOWSIZE;
                <span class="kwrd">event</span>.pSender = m_pFocus;
                <span class="kwrd">event</span>.dwTimestamp = ::GetTickCount();
                m_pFocus-&gt;Event(<span class="kwrd">event</span>);
            }
            <span class="kwrd">if</span>( m_pRoot != NULL ) m_pRoot-&gt;NeedUpdate();
        }
        <span class="kwrd">return</span> <span class="kwrd">true</span>;
    <span class="kwrd">case</span> WM_TIMER:
        {
            <span class="kwrd">for</span>( <span class="kwrd">int</span> i = 0; i &lt; m_aTimers.GetSize(); i++ ) {
                <span class="kwrd">const</span> TIMERINFO* pTimer = static_cast&lt;TIMERINFO*&gt;(m_aTimers[i]);
                <span class="kwrd">if</span>( pTimer-&gt;hWnd == m_hWndPaint &amp;&amp; pTimer-&gt;uWinTimer == LOWORD(wParam) &amp;&amp; pTimer-&gt;bKilled == <span class="kwrd">false</span>) {
                    TEventUI <span class="kwrd">event</span> = { 0 };
                    <span class="kwrd">event</span>.Type = UIEVENT_TIMER;
                    <span class="kwrd">event</span>.pSender = pTimer-&gt;pSender;
                    <span class="kwrd">event</span>.wParam = pTimer-&gt;nLocalID;
                    <span class="kwrd">event</span>.dwTimestamp = ::GetTickCount();
                    pTimer-&gt;pSender-&gt;Event(<span class="kwrd">event</span>);
                    <span class="kwrd">break</span>;
                }
            }
        }
        <span class="kwrd">break</span>;
    <span class="kwrd">case</span> WM_MOUSEHOVER:
        {
            m_bMouseTracking = <span class="kwrd">false</span>;
            POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
            CControlUI* pHover = FindControl(pt);
            <span class="kwrd">if</span>( pHover == NULL ) <span class="kwrd">break</span>;
            <span class="rem">// Generate mouse hover event</span>
            <span class="kwrd">if</span>( m_pEventHover != NULL ) {
                TEventUI <span class="kwrd">event</span> = { 0 };
                <span class="kwrd">event</span>.ptMouse = pt;
                <span class="kwrd">event</span>.Type = UIEVENT_MOUSEHOVER;
                <span class="kwrd">event</span>.pSender = m_pEventHover;
                <span class="kwrd">event</span>.dwTimestamp = ::GetTickCount();
                m_pEventHover-&gt;Event(<span class="kwrd">event</span>);
            }
            <span class="rem">// Create tooltip information</span>
            CDuiString sToolTip = pHover-&gt;GetToolTip();
            <span class="kwrd">if</span>( sToolTip.IsEmpty() ) <span class="kwrd">return</span> <span class="kwrd">true</span>;
            ::ZeroMemory(&amp;m_ToolTip, <span class="kwrd">sizeof</span>(TOOLINFO));
            m_ToolTip.cbSize = <span class="kwrd">sizeof</span>(TOOLINFO);
            m_ToolTip.uFlags = TTF_IDISHWND;
            m_ToolTip.hwnd = m_hWndPaint;
            m_ToolTip.uId = (UINT_PTR) m_hWndPaint;
            m_ToolTip.hinst = m_hInstance;
            m_ToolTip.lpszText = const_cast&lt;LPTSTR&gt;( (LPCTSTR) sToolTip );
            m_ToolTip.rect = pHover-&gt;GetPos();
            <span class="kwrd">if</span>( m_hwndTooltip == NULL ) {
                m_hwndTooltip = ::CreateWindowEx(0, TOOLTIPS_CLASS, NULL, WS_POPUP | TTS_NOPREFIX | TTS_ALWAYSTIP, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, m_hWndPaint, NULL, m_hInstance, NULL);
                ::SendMessage(m_hwndTooltip, TTM_ADDTOOL, 0, (LPARAM) &amp;m_ToolTip);
            }
            ::SendMessage(m_hwndTooltip, TTM_SETTOOLINFO, 0, (LPARAM) &amp;m_ToolTip);
            ::SendMessage(m_hwndTooltip, TTM_TRACKACTIVATE, TRUE, (LPARAM) &amp;m_ToolTip);
        }
        <span class="kwrd">return</span> <span class="kwrd">true</span>;
    <span class="kwrd">case</span> WM_MOUSELEAVE:
        {
            <span class="kwrd">if</span>( m_hwndTooltip != NULL ) ::SendMessage(m_hwndTooltip, TTM_TRACKACTIVATE, FALSE, (LPARAM) &amp;m_ToolTip);
            <span class="kwrd">if</span>( m_bMouseTracking ) ::SendMessage(m_hWndPaint, WM_MOUSEMOVE, 0, (LPARAM) -1);
            m_bMouseTracking = <span class="kwrd">false</span>;
        }
        <span class="kwrd">break</span>;
    <span class="kwrd">case</span> WM_MOUSEMOVE:
        {
            <span class="rem">// Start tracking this entire window again...</span>
            <span class="kwrd">if</span>( !m_bMouseTracking ) {
                TRACKMOUSEEVENT tme = { 0 };
                tme.cbSize = <span class="kwrd">sizeof</span>(TRACKMOUSEEVENT);
                tme.dwFlags = TME_HOVER | TME_LEAVE;
                tme.hwndTrack = m_hWndPaint;
                tme.dwHoverTime = m_hwndTooltip == NULL ? 400UL : (DWORD) ::SendMessage(m_hwndTooltip, TTM_GETDELAYTIME, TTDT_INITIAL, 0L);
                _TrackMouseEvent(&amp;tme);
                m_bMouseTracking = <span class="kwrd">true</span>;
            }
            <span class="rem">// Generate the appropriate mouse messages</span>
            POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
            m_ptLastMousePos = pt;
            CControlUI* pNewHover = FindControl(pt);
            <span class="kwrd">if</span>( pNewHover != NULL &amp;&amp; pNewHover-&gt;GetManager() != <span class="kwrd">this</span> ) <span class="kwrd">break</span>;
            TEventUI <span class="kwrd">event</span> = { 0 };
            <span class="kwrd">event</span>.ptMouse = pt;
            <span class="kwrd">event</span>.dwTimestamp = ::GetTickCount();
            <span class="kwrd">if</span>( pNewHover != m_pEventHover &amp;&amp; m_pEventHover != NULL ) {
                <span class="kwrd">event</span>.Type = UIEVENT_MOUSELEAVE;
                <span class="kwrd">event</span>.pSender = m_pEventHover;
                m_pEventHover-&gt;Event(<span class="kwrd">event</span>);
                m_pEventHover = NULL;
                <span class="kwrd">if</span>( m_hwndTooltip != NULL ) ::SendMessage(m_hwndTooltip, TTM_TRACKACTIVATE, FALSE, (LPARAM) &amp;m_ToolTip);
            }
            <span class="kwrd">if</span>( pNewHover != m_pEventHover &amp;&amp; pNewHover != NULL ) {
                <span class="kwrd">event</span>.Type = UIEVENT_MOUSEENTER;
                <span class="kwrd">event</span>.pSender = pNewHover;
                pNewHover-&gt;Event(<span class="kwrd">event</span>);
                m_pEventHover = pNewHover;
            }
            <span class="kwrd">if</span>( m_pEventClick != NULL ) {
                <span class="kwrd">event</span>.Type = UIEVENT_MOUSEMOVE;
                <span class="kwrd">event</span>.pSender = m_pEventClick;
                m_pEventClick-&gt;Event(<span class="kwrd">event</span>);
            }
            <span class="kwrd">else</span> <span class="kwrd">if</span>( pNewHover != NULL ) {
                <span class="kwrd">event</span>.Type = UIEVENT_MOUSEMOVE;
                <span class="kwrd">event</span>.pSender = pNewHover;
                pNewHover-&gt;Event(<span class="kwrd">event</span>);
            }
        }
        <span class="kwrd">break</span>;
    <span class="kwrd">case</span> WM_LBUTTONDOWN:
        {
            <span class="rem">// We alway set focus back to our app (this helps</span>
            <span class="rem">// when Win32 child windows are placed on the dialog</span>
            <span class="rem">// and we need to remove them on focus change).</span>
            ::SetFocus(m_hWndPaint);
            POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
            m_ptLastMousePos = pt;
            CControlUI* pControl = FindControl(pt);
            <span class="kwrd">if</span>( pControl == NULL ) <span class="kwrd">break</span>;
            <span class="kwrd">if</span>( pControl-&gt;GetManager() != <span class="kwrd">this</span> ) <span class="kwrd">break</span>;
            m_pEventClick = pControl;
            pControl-&gt;SetFocus();
            SetCapture();
            TEventUI <span class="kwrd">event</span> = { 0 };
            <span class="kwrd">event</span>.Type = UIEVENT_BUTTONDOWN;
            <span class="kwrd">event</span>.pSender = pControl;
            <span class="kwrd">event</span>.wParam = wParam;
            <span class="kwrd">event</span>.lParam = lParam;
            <span class="kwrd">event</span>.ptMouse = pt;
            <span class="kwrd">event</span>.wKeyState = (WORD)wParam;
            <span class="kwrd">event</span>.dwTimestamp = ::GetTickCount();
            pControl-&gt;Event(<span class="kwrd">event</span>);
        }
        <span class="kwrd">break</span>;
    <span class="kwrd">case</span> WM_LBUTTONDBLCLK:
        {
            ::SetFocus(m_hWndPaint);
            POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
            m_ptLastMousePos = pt;
            CControlUI* pControl = FindControl(pt);
            <span class="kwrd">if</span>( pControl == NULL ) <span class="kwrd">break</span>;
            <span class="kwrd">if</span>( pControl-&gt;GetManager() != <span class="kwrd">this</span> ) <span class="kwrd">break</span>;
            SetCapture();
            TEventUI <span class="kwrd">event</span> = { 0 };
            <span class="kwrd">event</span>.Type = UIEVENT_DBLCLICK;
            <span class="kwrd">event</span>.pSender = pControl;
            <span class="kwrd">event</span>.ptMouse = pt;
            <span class="kwrd">event</span>.wKeyState = (WORD)wParam;
            <span class="kwrd">event</span>.dwTimestamp = ::GetTickCount();
            pControl-&gt;Event(<span class="kwrd">event</span>);
            m_pEventClick = pControl;
        }
        <span class="kwrd">break</span>;
    <span class="kwrd">case</span> WM_LBUTTONUP:
        {
            POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
            m_ptLastMousePos = pt;
            <span class="kwrd">if</span>( m_pEventClick == NULL ) <span class="kwrd">break</span>;
            ReleaseCapture();
            TEventUI <span class="kwrd">event</span> = { 0 };
            <span class="kwrd">event</span>.Type = UIEVENT_BUTTONUP;
            <span class="kwrd">event</span>.pSender = m_pEventClick;
            <span class="kwrd">event</span>.wParam = wParam;
            <span class="kwrd">event</span>.lParam = lParam;
            <span class="kwrd">event</span>.ptMouse = pt;
            <span class="kwrd">event</span>.wKeyState = (WORD)wParam;
            <span class="kwrd">event</span>.dwTimestamp = ::GetTickCount();
            m_pEventClick-&gt;Event(<span class="kwrd">event</span>);
            m_pEventClick = NULL;
        }
        <span class="kwrd">break</span>;
    <span class="kwrd">case</span> WM_RBUTTONDOWN:
        {
            ::SetFocus(m_hWndPaint);
            POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
            m_ptLastMousePos = pt;
            CControlUI* pControl = FindControl(pt);
            <span class="kwrd">if</span>( pControl == NULL ) <span class="kwrd">break</span>;
            <span class="kwrd">if</span>( pControl-&gt;GetManager() != <span class="kwrd">this</span> ) <span class="kwrd">break</span>;
            pControl-&gt;SetFocus();
            SetCapture();
            TEventUI <span class="kwrd">event</span> = { 0 };
            <span class="kwrd">event</span>.Type = UIEVENT_RBUTTONDOWN;
            <span class="kwrd">event</span>.pSender = pControl;
            <span class="kwrd">event</span>.wParam = wParam;
            <span class="kwrd">event</span>.lParam = lParam;
            <span class="kwrd">event</span>.ptMouse = pt;
            <span class="kwrd">event</span>.wKeyState = (WORD)wParam;
            <span class="kwrd">event</span>.dwTimestamp = ::GetTickCount();
            pControl-&gt;Event(<span class="kwrd">event</span>);
            m_pEventClick = pControl;
        }
        <span class="kwrd">break</span>;
    <span class="kwrd">case</span> WM_CONTEXTMENU:
        {
            POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
            ::ScreenToClient(m_hWndPaint, &amp;pt);
            m_ptLastMousePos = pt;
            <span class="kwrd">if</span>( m_pEventClick == NULL ) <span class="kwrd">break</span>;
            ReleaseCapture();
            TEventUI <span class="kwrd">event</span> = { 0 };
            <span class="kwrd">event</span>.Type = UIEVENT_CONTEXTMENU;
            <span class="kwrd">event</span>.pSender = m_pEventClick;
            <span class="kwrd">event</span>.ptMouse = pt;
            <span class="kwrd">event</span>.wKeyState = (WORD)wParam;
            <span class="kwrd">event</span>.lParam = (LPARAM)m_pEventClick;
            <span class="kwrd">event</span>.dwTimestamp = ::GetTickCount();
            m_pEventClick-&gt;Event(<span class="kwrd">event</span>);
            m_pEventClick = NULL;
        }
        <span class="kwrd">break</span>;
    <span class="kwrd">case</span> WM_MOUSEWHEEL:
        {
            POINT pt = { GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam) };
            ::ScreenToClient(m_hWndPaint, &amp;pt);
            m_ptLastMousePos = pt;
            CControlUI* pControl = FindControl(pt);
            <span class="kwrd">if</span>( pControl == NULL ) <span class="kwrd">break</span>;
            <span class="kwrd">if</span>( pControl-&gt;GetManager() != <span class="kwrd">this</span> ) <span class="kwrd">break</span>;
            <span class="kwrd">int</span> zDelta = (<span class="kwrd">int</span>) (<span class="kwrd">short</span>) HIWORD(wParam);
            TEventUI <span class="kwrd">event</span> = { 0 };
            <span class="kwrd">event</span>.Type = UIEVENT_SCROLLWHEEL;
            <span class="kwrd">event</span>.pSender = pControl;
            <span class="kwrd">event</span>.wParam = MAKELPARAM(zDelta &lt; 0 ? SB_LINEDOWN : SB_LINEUP, 0);
            <span class="kwrd">event</span>.lParam = lParam;
            <span class="kwrd">event</span>.wKeyState = MapKeyState();
            <span class="kwrd">event</span>.dwTimestamp = ::GetTickCount();
            pControl-&gt;Event(<span class="kwrd">event</span>);

            <span class="rem">// Let's make sure that the scroll item below the cursor is the same as before...</span>
            ::SendMessage(m_hWndPaint, WM_MOUSEMOVE, 0, (LPARAM) MAKELPARAM(m_ptLastMousePos.x, m_ptLastMousePos.y));
        }
        <span class="kwrd">break</span>;
    <span class="kwrd">case</span> WM_CHAR:
        {
            <span class="kwrd">if</span>( m_pFocus == NULL ) <span class="kwrd">break</span>;
            TEventUI <span class="kwrd">event</span> = { 0 };
            <span class="kwrd">event</span>.Type = UIEVENT_CHAR;
            <span class="kwrd">event</span>.chKey = (TCHAR)wParam;
            <span class="kwrd">event</span>.ptMouse = m_ptLastMousePos;
            <span class="kwrd">event</span>.wKeyState = MapKeyState();
            <span class="kwrd">event</span>.dwTimestamp = ::GetTickCount();
            m_pFocus-&gt;Event(<span class="kwrd">event</span>);
        }
        <span class="kwrd">break</span>;
    <span class="kwrd">case</span> WM_KEYDOWN:
        {
            <span class="kwrd">if</span>( m_pFocus == NULL ) <span class="kwrd">break</span>;
            TEventUI <span class="kwrd">event</span> = { 0 };
            <span class="kwrd">event</span>.Type = UIEVENT_KEYDOWN;
            <span class="kwrd">event</span>.chKey = (TCHAR)wParam;
            <span class="kwrd">event</span>.ptMouse = m_ptLastMousePos;
            <span class="kwrd">event</span>.wKeyState = MapKeyState();
            <span class="kwrd">event</span>.dwTimestamp = ::GetTickCount();
            m_pFocus-&gt;Event(<span class="kwrd">event</span>);
            m_pEventKey = m_pFocus;
        }
        <span class="kwrd">break</span>;
    <span class="kwrd">case</span> WM_KEYUP:
        {
            <span class="kwrd">if</span>( m_pEventKey == NULL ) <span class="kwrd">break</span>;
            TEventUI <span class="kwrd">event</span> = { 0 };
            <span class="kwrd">event</span>.Type = UIEVENT_KEYUP;
            <span class="kwrd">event</span>.chKey = (TCHAR)wParam;
            <span class="kwrd">event</span>.ptMouse = m_ptLastMousePos;
            <span class="kwrd">event</span>.wKeyState = MapKeyState();
            <span class="kwrd">event</span>.dwTimestamp = ::GetTickCount();
            m_pEventKey-&gt;Event(<span class="kwrd">event</span>);
            m_pEventKey = NULL;
        }
        <span class="kwrd">break</span>;
    <span class="kwrd">case</span> WM_SETCURSOR:
        {
            <span class="kwrd">if</span>( LOWORD(lParam) != HTCLIENT ) <span class="kwrd">break</span>;
            <span class="kwrd">if</span>( m_bMouseCapture ) <span class="kwrd">return</span> <span class="kwrd">true</span>;

            POINT pt = { 0 };
            ::GetCursorPos(&amp;pt);
            ::ScreenToClient(m_hWndPaint, &amp;pt);
            CControlUI* pControl = FindControl(pt);
            <span class="kwrd">if</span>( pControl == NULL ) <span class="kwrd">break</span>;
            <span class="kwrd">if</span>( (pControl-&gt;GetControlFlags() &amp; UIFLAG_SETCURSOR) == 0 ) <span class="kwrd">break</span>;
            TEventUI <span class="kwrd">event</span> = { 0 };
            <span class="kwrd">event</span>.Type = UIEVENT_SETCURSOR;
            <span class="kwrd">event</span>.wParam = wParam;
            <span class="kwrd">event</span>.lParam = lParam;
            <span class="kwrd">event</span>.ptMouse = pt;
            <span class="kwrd">event</span>.wKeyState = MapKeyState();
            <span class="kwrd">event</span>.dwTimestamp = ::GetTickCount();
            pControl-&gt;Event(<span class="kwrd">event</span>);
        }
        <span class="kwrd">return</span> <span class="kwrd">true</span>;
    <span class="kwrd">case</span> WM_NOTIFY:
        {
            LPNMHDR lpNMHDR = (LPNMHDR) lParam;
            <span class="kwrd">if</span>( lpNMHDR != NULL ) lRes = ::SendMessage(lpNMHDR-&gt;hwndFrom, OCM__BASE + uMsg, wParam, lParam);
            <span class="kwrd">return</span> <span class="kwrd">true</span>;
        }
        <span class="kwrd">break</span>;
    <span class="kwrd">case</span> WM_COMMAND:
        {
            <span class="kwrd">if</span>( lParam == 0 ) <span class="kwrd">break</span>;
            HWND hWndChild = (HWND) lParam;
            lRes = ::SendMessage(hWndChild, OCM__BASE + uMsg, wParam, lParam);
            <span class="kwrd">return</span> <span class="kwrd">true</span>;
        }
        <span class="kwrd">break</span>;
    <span class="kwrd">case</span> WM_CTLCOLOREDIT:
    <span class="kwrd">case</span> WM_CTLCOLORSTATIC:
        {
            <span class="rem">// Refer To: http://msdn.microsoft.com/en-us/library/bb761691(v=vs.85).aspx</span>
            <span class="rem">// Read-only or disabled edit controls do not send the WM_CTLCOLOREDIT message; instead, they send the WM_CTLCOLORSTATIC message.</span>
            <span class="kwrd">if</span>( lParam == 0 ) <span class="kwrd">break</span>;
            HWND hWndChild = (HWND) lParam;
            lRes = ::SendMessage(hWndChild, OCM__BASE + uMsg, wParam, lParam);
            <span class="kwrd">return</span> <span class="kwrd">true</span>;
        }
        <span class="kwrd">break</span>;
    <span class="kwrd">default</span>:
        <span class="kwrd">break</span>;
    }

    pMsg = NULL;
    <span class="kwrd">while</span>( pMsg = static_cast&lt;TNotifyUI*&gt;(m_aAsyncNotify.GetAt(0)) ) {
        m_aAsyncNotify.Remove(0);
        <span class="kwrd">if</span>( pMsg-&gt;pSender != NULL ) {
            <span class="kwrd">if</span>( pMsg-&gt;pSender-&gt;OnNotify ) pMsg-&gt;pSender-&gt;OnNotify(pMsg);
        }
        <span class="kwrd">for</span>( <span class="kwrd">int</span> j = 0; j &lt; m_aNotifiers.GetSize(); j++ ) {
            static_cast&lt;INotifyUI*&gt;(m_aNotifiers[j])-&gt;Notify(*pMsg);
        }
        delete pMsg;
    }

    <span class="kwrd">return</span> <span class="kwrd">false</span>;
}</pre>
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }


<p>我去这里代码有点多，先简单捋一下，首先处理了如下消息：</p>
<p>WM_CTLCOLOREDIT:<br />WM_CTLCOLORSTATIC<br />WM_COMMAND:<br />WM_NOTIFY:<br />WM_SETCURSOR:<br />WM_KEYUP<br />WM_KEYDOWN<br />WM_CHAR<br />WM_MOUSEWHEEL<br />WM_CONTEXTMENU<br />WM_RBUTTONDOWN<br />WM_LBUTTONUP<br />WM_LBUTTONDBLCLK<br />WM_LBUTTONDOWN<br />WM_MOUSEMOVE<br />WM_MOUSELEAVE<br />WM_MOUSEHOVER<br />WM_TIMER<br />WM_SIZE<br />WM_GETMINMAXINFO<br />WM_PRINTCLIENT<br />WM_PAINT<br />WM_ERASEBKGND<br />WM_CLOSE<br />WM_APP<br /></p>
<p>除了这些消息还有一个特别的东西需要留意：</p>
<p>m_aAsyncNotify以后再分析</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>
.csharpcode, .csharpcode pre
{
	font-size: small;
	color: black;
	font-family: consolas, "Courier New", courier, monospace;
	background-color: #ffffff;
	/*white-space: pre;*/
}
.csharpcode pre { margin: 0em; }
.csharpcode .rem { color: #008000; }
.csharpcode .kwrd { color: #0000ff; }
.csharpcode .str { color: #006080; }
.csharpcode .op { color: #0000c0; }
.csharpcode .preproc { color: #cc6633; }
.csharpcode .asp { background-color: #ffff00; }
.csharpcode .html { color: #800000; }
.csharpcode .attr { color: #ff0000; }
.csharpcode .alt 
{
	background-color: #f4f4f4;
	width: 100%;
	margin: 0em;
}
.csharpcode .lnum { color: #606060; }
</p><img src ="http://www.cppblog.com/Error/aggbug/198275.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/Error/" target="_blank">Enic</a> 2013-03-07 21:39 <a href="http://www.cppblog.com/Error/archive/2013/03/07/198275.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item></channel></rss>