﻿<?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++博客-幽幽-随笔分类-MFC</title><link>http://www.cppblog.com/justin-shi/category/6152.html</link><description>努力做一个合格的男人。。。</description><language>zh-cn</language><lastBuildDate>Sun, 28 Sep 2008 09:02:40 GMT</lastBuildDate><pubDate>Sun, 28 Sep 2008 09:02:40 GMT</pubDate><ttl>60</ttl><item><title>一种给窗口添加阴影的方法 </title><link>http://www.cppblog.com/justin-shi/archive/2008/08/17/59105.html</link><dc:creator>幽幽</dc:creator><author>幽幽</author><pubDate>Sun, 17 Aug 2008 04:18:00 GMT</pubDate><guid>http://www.cppblog.com/justin-shi/archive/2008/08/17/59105.html</guid><wfw:comment>http://www.cppblog.com/justin-shi/comments/59105.html</wfw:comment><comments>http://www.cppblog.com/justin-shi/archive/2008/08/17/59105.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/justin-shi/comments/commentRss/59105.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/justin-shi/services/trackbacks/59105.html</trackback:ping><description><![CDATA[<table cellSpacing=0 cellPadding=0 width=776 align=center border=0>
    <tbody>
        <tr>
            <td class=title vAlign=center align=middle background=images/up2.gif height=62>一种给窗口添加阴影的方法 <br><span class=text>华南理工大学微软技术俱乐部</span></td>
        </tr>
    </tbody>
</table>
<table height=83 cellSpacing=0 cellPadding=0 width=776 align=center border=0>
    <tbody>
        <tr>
            <td width=60 background=images/mid2.gif height=56></td>
            <td vAlign=top>
            <p class=new-text>因为自己很喜欢那些界面做得很漂亮的软件或者使用各种美化界面的软件，如avedesk，samurize等等。其中美化界面的一个重要的方面就是给窗口添加上阴影。虽然OS X已经原生的支持窗口阴影，但是windows要到Longhorn才开始支持原生的窗口阴影。现在如果想实现窗口阴影，一般都会借助第三方的软件，例如windowFX或者YzShadow。其中YzShadow是一个免费软件，我自己也在使用。但是这个软件有个弱点，就是无法为Layered Window添加阴影。而我自己编写的一个简易便条程序Stickies（功能类似OneNote，但是功能简单，小巧。）就是运用了Layered Window来作为软件的界面，于是便自己尝试添加窗口阴影。以下便是添加阴影的方法，写下来与大家讨论一下。</p>
            <p class=new-text>我的程序是在Visual Studio.NET 2003下编写的MFC应用程序。我为了实现窗口阴影创建了一个Shadow的类。首先我们看看各类之间的关系：</p>
            <p class=new-text><img height=257 src="http://www.mscenter.edu.cn/zhuanti/dianziqikan/11/childpage/images/7.gif" width=550><br><br>1. Class ShadowCastingWindow<br>该类是一个应用程序的窗口，它会在桌面上投射下阴影。这个类是从CWnd继承而来。<br>ShadowCastingWindow成员变量：<br>m_Alpha<br>保存该窗口的透明度值。</p>
            <p class=new-text>ShadowCastingWindow成员函数：<br>BOOL ShadowCastingWindow::CreateWindow( CString wndName, CWnd * pParentWnd )<br>{<br>BOOL tmp = CWnd::CreateEx( WS_EX_TOOLWINDOW|WS_EX_LAYERED<br>, &#8230;<br>, WS_POPUP|WS_VISIBLE<br>, &#8230; );<br>m_Shadow.CreateShadow( this, m_Alpha );<br>}</p>
            <p class=new-text>该函数用于创建应用程序的窗口并创建阴影。请留意CreateEx中窗口属性WS_EX_...和WS_...的取值，这使得该应用程序的窗口是一个没有标题栏的Layered Windows。是否有标题栏对于下文Shadow类中求遮挡窗口的大小会有所不同，这必须通过一个判断逻辑或者根据程序的应用不同编写好代码。对于Layered Windows会有两种刷新模式，一种就是传统的消息机制，就是操作系统自动地在适当的时候发送WM_PAINT的消息给应用程序窗口，应用程序窗口则相应该消息，对窗口进行刷新；另一种方式则是在Windows2000以后才支持的UpdateLayeredWindow的机制，在这种机制下，应用程序不再处理WM_PAINT消息，所有的刷新均由用户在内存中的一个绘图上下文中绘制好图像之后再通过UpdateLayeredWindow绘制到屏幕上，只要经过一次绘制，窗口的图像便会保存在一块预订好的内存区域内，如果窗口的图像没有改变那么操作系统便会自动地处理刷新。</p>
            <p class=new-text>void ShadowCastingWindow::OnSizing(UINT fwSide, LPRECT pRect)<br>{<br>CWnd::OnSizing(fwSide, pRect);<br>m_Shadow.OnShadowCastingWndNewSize(pRect-&gt;right - pRect-&gt;left, pRect-&gt;bottom - pRect-&gt;top);<br>}</p>
            <p class=new-text>void ShadowCastingWindow::OnSize(UINT nType, int cx, int cy)<br>{<br>CWnd::OnSize(nType, cx, cy);<br>m_Shadow.OnShadowCastingWndNewSize(cx,cy);<br>}</p>
            <p class=new-text>void ShadowCastingWindow::OnMoving(UINT fwSide, LPRECT pRect)<br>{<br>CWnd::OnMoving(fwSide, pRect);<br>m_Shadow.OnShadowCastingWndNewPos(pRect-&gt;left, pRect-&gt;top );<br>}</p>
            <p class=new-text>void ShadowCastingWindow::OnMove(int x, int y)<br>{<br>CWnd::OnMove(x, y);<br>m_Shadow.OnShadowCastingWndNewPos(x, y );<br>}</p>
            <p class=new-text>这四个事件函数都是处理应用程序窗口大小或者位置变化的。只需要在其中调用Shadow类中相应的处理函数即可，Shadow便会自动地更改大小或者移动位置。可能有人会问为什么需要显式地调整Shadow的位置和大小？因为从下文可以看到Shadow其实也是一个Layered Window，没有父窗口，所以操作系统不可以自动地保持两者的相对位置。</p>
            <p class=new-text>void ShadowCastingWindow::SetOpacity( int alpha )<br>{<br>m_Alpha = alpha;<br>m_Shadow.SetAlpha( alpha );<br>SetLayeredWindowAttributes( 0, (BYTE)m_Alpha, LWA_ALPHA );<br>Invalidate();<br>}</p>
            <p class=new-text>处理应用程序窗口透明度变化的函数，其中调用了阴影Shadow对于透明度变化的处理函数。并刷新应用程序窗口。</p>
            <p class=new-text>2. Class Shadow<br>该类继承与CWnd类。<br>Shadow成员变量：<br>CWnd * m_pShadowCastingWindow;<br>指向父窗口—需要投射阴影的窗口的指针。<br>int m_Alpha;<br>当前阴影的透明度。<br>int m_DeltaTop;<br>int m_DeltaLeft;<br>int m_DeltaRight;<br>int m_DeltaButtom;<br>用于表示阴影的尺寸。计算方法如下：</p>
            <p class=new-text><img height=286 src="http://www.mscenter.edu.cn/zhuanti/dianziqikan/11/childpage/images/8.gif" width=469><br></p>
            <p class=new-text>Shadow成员函数：<br>BOOL Shadow::CreateShadow(CWnd * pShadowCastingWnd, int alpha )<br>{<br>//根据投射阴影的窗口的尺寸和各参数计算出阴影的尺寸。<br>CRect rect;<br>pShadowCastingWnd-&gt;GetWindowRect(&amp;rect);<br>rect.top += m_DeltaTop;<br>rect.left -= m_DeltaLeft;<br>rect.right += m_DeltaRight;<br>rect.bottom += m_DeltaButtom;<br>m_Alpha = alpha;<br>BOOL tmp = CWnd::CreateEx( WS_EX_TOOLWINDOW|WS_EX_LAYERED<br>,&#8230;<br>, WS_POPUP|WS_VISIBLE<br>, rect <br>, &#8230;);</p>
            <p class=new-text>m_IsCreated = true;<br>CustomizedPaint();<br>return tmp;<br>}</p>
            <p class=new-text>创建阴影，由于阴影必须是没有标题栏的，而且因为要绘制半透明的像素所以必须使用Layered Window。</p>
            <p class=new-text>void Shadow::CustomizedPaint(void)<br>{<br>if ( !m_IsCreated )<br>return;</p>
            <p class=new-text>BLENDFUNCTION blendPixelFunction= {AC_SRC_OVER, 0, m_Alpha, AC_SRC_ALPHA};<br>POINT ptWindowScreenPosition = {rect.left, rect.top};<br>POINT ptSrc = {0, 0};<br>SIZE szWindow = {rect.Width(), rect.Height()};</p>
            <p class=new-text>CDC * dcScreen = GetDesktopWindow()-&gt;GetDC();<br>CDC dcMemory;<br>dcMemory.CreateCompatibleDC( dcScreen );</p>
            <p class=new-text>//-----------------------------------<br>//把要绘制的内容绘制在dcMemory里。对于Shadow需要把投射阴影窗口所覆盖的区<br>//域剪裁掉<br>//-----------------------------------</p>
            <p class=new-text>UpdateLayeredWindow( dcScreen, &amp;ptWindowScreenPosition, &amp;szWindow, &amp;dcMemory, &amp;ptSrc, 0, &amp;blendPixelFunction, ULW_ALPHA);</p>
            <p class=new-text>GetDesktopWindow()-&gt;ReleaseDC(dcScreen);<br>dcMemory.DeleteDC();<br>}<br>根据不同程序需要加上适当的绘制流程。比如可以通过画一个长方形来表示阴影，这个效果自然就比较差；也可以利用一些在Photoshop中处理好的阴影图片把它做适当的大小调整作为窗口的阴影这样更容易做出阴影边缘柔化的效果。这个CustomizedPaint只需要在窗口的内容被改变的时候才需要重新调用，其他时候系统会自动管理已经绘制的图像，用它来刷新窗口，而不需要重新绘制。</p>
            <p class=new-text>BOOL Shadow::PreCreateWindow(CREATESTRUCT&amp; cs)<br>{<br>cs.style &amp;= ~WS_BORDER;<br>cs.lpszClass = AfxRegisterWndClass(CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS, <br>::LoadCursor( NULL, IDC_CURSOR ), NULL, NULL); <br>return CWnd::PreCreateWindow(cs);<br>}<br>通过修改默认的cs.lpszClass使得窗口不再自动重画背景。</p>
            <p class=new-text>void Shadow::OnShadowCastingWndNewSize( int x, int y )<br>{<br>if ( !m_IsCreated )<br>return;<br>SetWindowPos( m_pShadowCastingWindow,0,0,x+m_DeltaLeft+m_DeltaRight,y-m_DeltaTop+m_DeltaButtom, SWP_NOMOVE );<br>CustomizedPaint();<br>}</p>
            <p class=new-text>提供该投射阴影的窗口的接口函数，当投射阴影的窗口大小改变的时候便调用这个函数把新的窗口位置传给Shadow，Shadow便会改变自己的大小，并重绘窗口。</p>
            <p class=new-text>void Shadow::OnShadowCastingWndNewPos( int x, int y )<br>{<br>if ( !m_IsCreated )<br>return;<br>SetWindowPos( m_pShadowCastingWindow, x-m_DeltaLeft, y+m_DeltaTop, 0, 0, SWP_NOSIZE );<br>}</p>
            <p class=new-text>提供该投射阴影的窗口的接口函数，当投射阴影的窗口位置改变的时候便调用这个函数把新的窗口位置传给Shadow，Shadow便会改变自己的位置。注意了，这里并不需要重绘窗口，因为窗口的内容并没有改变。</p>
            <p class=new-text>void Shadow::SetAlpha( int alpha )<br>{<br>m_Alpha = alpha;<br>CustomizedPaint();<br>}</p>
            <p class=new-text>提供该投射阴影的窗口的接口函数，当投射阴影的窗口的透明度改变的时候便调用这个函数把新透明度传给Shadow，Shadow便会改变自己的透明度，并重绘窗口。</p>
            <p class=new-text>下面给出一个我自己写的程序的效果图：</p>
            <p class=new-text><img height=183 src="http://www.mscenter.edu.cn/zhuanti/dianziqikan/11/childpage/images/9.gif" width=263></p>
            <p class=new-text>3. 结论：</p>
            <p class=new-text>上面就简单地介绍了一个绘制窗口阴影的方法。这种方法基本上可以适用于各种类型的窗口，其中需要注意一下几点：</p>
            <p class=new-text>1. 在于Shadow::CreateShadow中如何正确取得投射阴影窗口m_pShadowCastingWindow的大小然后计算出阴影窗口的大小。</p>
            <p class=new-text>2. Shadow::CustomizedPaint中如何更高效的绘制阴影，例如剪裁掉投射阴影窗口遮挡住的窗口内容，避免绘制时出现闪烁。同时如何正确使用好UpdateLayeredWindow这个系统调用会是实现绘制阴影的关键。当然在当前的设计下，我们可以在CustomizePaint中绘制任何的东西，而不一定是阴影。? 大家可以在这里发挥想象力，让窗口更加绚丽多彩。</p>
            <p class=new-text>其实这个程序只要让他通过钩子函数与特定的Win32API挂钩，完全可以写出一个可以给系统中所有窗口加上阴影效果的小软件。大家不妨试试。如果做出来了，记得给我一份。</p>
            <p class=new-text>注：文章中的代码都是示意性的，都是通过我自己写的程序删减后得到，未必能通过测试。旨在说明一些关键步骤需要注意的地方。如果问题欢迎email讨论。</p>
            </td>
        </tr>
    </tbody>
</table>
<br>
<img src ="http://www.cppblog.com/justin-shi/aggbug/59105.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/justin-shi/" target="_blank">幽幽</a> 2008-08-17 12:18 <a href="http://www.cppblog.com/justin-shi/archive/2008/08/17/59105.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>Window下拖放操作Drag &amp; Drop 全解析</title><link>http://www.cppblog.com/justin-shi/archive/2008/08/14/58866.html</link><dc:creator>幽幽</dc:creator><author>幽幽</author><pubDate>Thu, 14 Aug 2008 11:19:00 GMT</pubDate><guid>http://www.cppblog.com/justin-shi/archive/2008/08/14/58866.html</guid><wfw:comment>http://www.cppblog.com/justin-shi/comments/58866.html</wfw:comment><comments>http://www.cppblog.com/justin-shi/archive/2008/08/14/58866.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/justin-shi/comments/commentRss/58866.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/justin-shi/services/trackbacks/58866.html</trackback:ping><description><![CDATA[<p><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><strong>OLE</strong><strong>拖放实现</strong></font></span></p>
<p><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>MFC</font>本身的<font face=Tahoma>CView</font>类是支持拖放操作的，通过研究<font face=Tahoma>CView</font>类的源码，大体知道它的实现原理是这样的：<font face=Tahoma>CView</font>类中有一个<font face=Tahoma>COleDropTarget</font>类的对象，在视图窗口初始化时，调用<font face=Tahoma>COleDropTarget</font>类成员函数<font face=Tahoma>Register()</font>，以此在系统中注册该视图窗口为拖放接收窗口。当进行拖放操作的鼠标指针处于视图窗口范围内时，<font face=Tahoma>COleDropTarge</font>类会做出反应，它的<font face=Tahoma>OnDragEnter</font>、<font face=Tahoma>OnDragOver</font>、<font face=Tahoma>OnDropEx</font>、<font face=Tahoma>OnDrop</font>等成员函数被依次调用，这些函数默认均是调用与其相对应的<font face=Tahoma>CView</font>类成员函数<font face=Tahoma>OnDragEnter</font>、<font face=Tahoma>OnDragOver</font>、<font face=Tahoma>OnDropEx</font>、<font face=Tahoma>OnDrop</font>等，程序员只需重载这些<font face=Tahoma>CView</font>类成员函数，即可对拖动的过程及结果进行控制。</font></span></p>
<p><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>因为<font face=Tahoma>COleDropTarget</font>默认只对<font face=Tahoma>CView</font>提供支持，所以如果要让其他的窗口支持拖放，我们必须同时对要支持拖放的窗口类和<font face=Tahoma>COleDropTarget</font>类进行派生。把对拖放操作具体进行处理的代码封装成派生窗口类的成员函数，然后重载<font face=Tahoma>COleDropTarget</font>中对应的五个虚函数，当它接收到拖放动作时，调用窗口派生类的处理函数即可。但这里有一个问题，就是我们怎么知道何时调用派生类的处理函数呢？答案是运用<font face=Tahoma>RTTI</font>技术。如果<font face=Tahoma>COleDropTarget</font>派生类收到的窗口指针类型，就是我们派生的窗口类，那么就调用它的处理函数，否则调用基类进行处理。</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>首先生成一个对话框工程，添加二个新类。</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>第一个类名为<font face=Tahoma>CListCtrlEx</font>，父类为<font face=Tahoma>CListCtrl</font>。添加完毕后，在<font face=Tahoma>CListCtrlEx</font>的定义头文件中加入<font face=Tahoma>DECLARE_DYNAMIC(CListCtrlEx)</font>，在其实现文件中加入<font face=Tahoma>IMPLEMENT_DYNAMIC(CListCtrlEx,CListCtrl)</font>，这样就对<font face=Tahoma>CListCtrlEx</font>类添加了<font face=Tahoma>RTTI</font>运行期类型识别（<font face=Tahoma>Run Time Type Information</font>）支持。</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>第二个类名为<font face=Tahoma>COleDropTargetEx</font>，父类为<font face=Tahoma>COleDataTarget</font>。</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>在<font face=Tahoma>CListCtrlEx</font>中添加<font face=Tahoma>COleDropTargetEx</font>类的对象，并添加下列公有虚函数的声明：</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; virtual BOOL Initialize();</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; virtual DROPEFFECT OnDragOver(CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point);</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; virtual DROPEFFECT OnDropEx(CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, DROPEFFECT dropList, CPoint point);</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; virtual BOOL OnDrop(CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point);</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; virtual void OnDragLeave(CWnd* pWnd);</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>Initialize</font>函数用于注册<font face=Tahoma>CListCtrlEx</font>成为拖放接收窗口；</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>OnDragOver</font>在拖放鼠标进入窗口时被调用。此函数的返回值决定了后续的动作的类型：如果返回<font face=Tahoma>DROPEFFECT_MOVE</font>，则产生一个剪切动作；如果返回<font face=Tahoma>DROPEFFECT_COPY</font>，则产生一个复制动作，如果返回<font face=Tahoma>DROPEFFECT_NONE</font>，则不会产生拖放动作，因为<font face=Tahoma>OnDropEx</font>、<font face=Tahoma>OnDrop</font>函数将不会被调用（<font face=Tahoma>OnDragLeave</font>函数仍会被调用）。</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>OnDropEx</font>函数会在<font face=Tahoma>OnDrop</font>函数之前调用，如果<font face=Tahoma>OnDropEx</font>函数没有对拖放动作进行处理，则应用程序框架会接着调用<font face=Tahoma>OnDrop</font>函数进行处理。所以必须要在派生类中重载<font face=Tahoma>OnDropEx</font>函数——即使什么动作都都没有做——否则我们的<font face=Tahoma>OnDrop</font>函数将不会被执行到，因为没有重载的话，将会调用基类的<font face=Tahoma>OnDropEx</font>函数，而基类的<font face=Tahoma>OnDropEx</font>函数对拖放是进行了处理的——尽管不是我们所想要的动作。当然你也可以把对拖放进行处理的动作放在<font face=Tahoma>OnDropEx</font>中——那样就不需要重载<font face=Tahoma>OnDrop</font>了。</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>OnDragLeave</font>函数会在鼠标离开窗口时被调用，在此可以进行一些简单的清理工作。譬如在<font face=Tahoma>OnDragEnter</font>或者<font face=Tahoma>OnDragOver</font>函数中，我们改变了光标的形态，那么此时我们就应该把光标恢复过来。</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>这些函数中最重要的是<font face=Tahoma>OnDrop</font>函数，拖放动作将在此进行处理，它的全部源码如下：</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>BOOL CListCtrlEx::OnDrop(CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point)</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>{</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; UINT&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nFileCount = 0;</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HDROP&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hDropFiles = NULL;</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; HGLOBAL &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hMemData = NULL;</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma size=2>&nbsp;</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AfxMessageBox("OnDrop");</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(pDataObject-&gt;IsDataAvailable(CF_HDROP)) </font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hMemData = pDataObject-&gt;GetGlobalData(CF_HDROP);</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; hDropFiles = (HDROP)GlobalLock((HGLOBAL)hMemData); //</font>锁定内存块</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(hDropFiles != NULL)</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; char chTemp[_MAX_PATH+1] = {0};</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; nFileCount = DragQueryFile(hDropFiles, 0xFFFFFFFF, NULL, 0);</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(UINT nCur=0; nCur&lt;nFileCount; ++nCur) //</font>遍历取得每个文件名</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ZeroMemory(chTemp, _MAX_PATH+1);</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DragQueryFile(hDropFiles, nCur, (LPTSTR)chTemp, _MAX_PATH+1);</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; AddAllFiles(chTemp);</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GlobalUnlock(hMemData);</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return TRUE;</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return FALSE;</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>}</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>在第二个类<font face=Tahoma>COleDropTarget</font>中添加如下对应的函数：</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp; virtual DROPEFFECT OnDragEnter(CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point);</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp; virtual DROPEFFECT OnDragOver(CWnd* pWnd, COleDataObject* pDataObject, DWORD dwKeyState, CPoint point);</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; virtual DROPEFFECT OnDropEx(CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, DROPEFFECT dropList, CPoint point);</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; virtual BOOL OnDrop(CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point);</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; virtual void OnDragLeave(CWnd* pWnd);</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>它们的动作都差不多：先用<font face=Tahoma>RTTI</font>判断窗口指针<font face=Tahoma>pWnd</font>的类型，如果是<font face=Tahoma>CListCtrlEx</font>，则调用<font face=Tahoma>CListCtrlEx</font>中对应的处理函数，否则调用基类的处理函数。以<font face=Tahoma>OnDrop</font>为例：</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>BOOL COleDropTargetEx::OnDrop(CWnd* pWnd, COleDataObject* pDataObject, DROPEFFECT dropEffect, CPoint point)</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>{</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CListCtrlEx*&nbsp;&nbsp;&nbsp;&nbsp; pListCtrlEx = NULL;</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ASSERT_VALID(this);</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ASSERT(IsWindow(pWnd-&gt;m_hWnd));</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(pWnd-&gt;IsKindOf(RUNTIME_CLASS(CListCtrlEx)))</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pListCtrlEx = (CListCtrlEx*)pWnd;</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return pListCtrlEx-&gt;OnDrop(pWnd, pDataObject, dropEffect, point);</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return COleDropTarget::OnDrop(pWnd, pDataObject, dropEffect, point);&nbsp;&nbsp;&nbsp;&nbsp; </font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>}</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2></font></font></span>&nbsp;</p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>//倒霉的64K限制，只能再截断了：（<br><br></font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>至此，我们成功地为<font face=Tahoma>CListCtrlEx</font>添加了文件拖入操作的支持。一个完整的拖放操作，还包括拖出动作，所以必须要为该类再添加拖出操作，即，将列表中的某一项或者多项拖出成为一个文件。这就需要用到另一个类：<font face=Tahoma>COleDataSource</font>。具体步骤如下：<br></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>在<font face=Tahoma>CListCtrlEx</font>中加入一个<font face=Tahoma>COleDataSource</font>的实例，并映射列表框的<font face=Tahoma>LVN_BEGINDRAG</font>消息处理函数，在此我们添加拖出操作的代码。</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>实现拖出非常简单，只需要依次调用<font face=Tahoma>COleDataSource</font>的三个函数即可：<font face=Tahoma>Empty</font>用于清空原先对象中缓存的数据，<font face=Tahoma>CacheGlobalData</font>用来缓存数据以进行拖放操作，最后调用<font face=Tahoma>DoDragDrop</font>启动本次拖放操作。</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>但在调用之前，必须要做一些准备工作。主要的任务就是创建一个<font face=Tahoma>DROPFILES</font>结构体，并拷贝要拖放的文件名到结构体后的内存中。<font face=Tahoma>DROPFILES</font>结构体定义了<font face=Tahoma>CF_HDROP</font>剪贴板格式，紧跟它后面的是一系列被拖放文件的路径名。它的定义如下：</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>typedef struct _DROPFILES</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>{</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>&nbsp;&nbsp;&nbsp; DWORD &nbsp;&nbsp;&nbsp; pFiles;&nbsp; //</font>文件名起始地址</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>&nbsp;&nbsp;&nbsp; POINT &nbsp;&nbsp;&nbsp;&nbsp; pt;&nbsp;&nbsp;&nbsp;&nbsp; //</font>鼠标放下的位置，坐标由<font face=Tahoma>fNC</font>成员指定</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>&nbsp;&nbsp;&nbsp; BOOL&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fNC;&nbsp;&nbsp;&nbsp; //</font>为<font face=Tahoma>TRUE</font>表示适用屏幕坐标系，否则使用客户坐标系</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>&nbsp;&nbsp;&nbsp; BOOL &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fWide;&nbsp; //</font>文件名字符串是否使用宽字符</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>} DROPFILES, FAR* LPDROPFILES; </font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>拖放之前的准备动作的代码如下：</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>uBufferSize = sizeof(DROPFILES) + uBufferSize + 1;</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp; hMemData = GlobalAlloc(GPTR,uBufferSize);</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp; ASSERT(hMemData != NULL);</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lpDropFiles = (LPDROPFILES)GlobalLock(hMemData); //</font>锁定之<font face=Tahoma>,</font>并设置相关成员</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ASSERT(lpDropFiles != NULL);</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lpDropFiles-&gt;pFiles = sizeof(DROPFILES);</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>#ifdef _UNICODE</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lpDropFiles-&gt;fWide = TRUE;</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>#else</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lpDropFiles-&gt;fWide = FALSE;</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>#endif</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma size=2>&nbsp;</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //</font>把选中的所有文件名依次复制到<font face=Tahoma>DROPFILES</font>结构体后面<font face=Tahoma>(</font>全局内存中<font face=Tahoma>)</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pItemPos = strSelectedList.GetHeadPosition();</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pszStart = (char*)((LPBYTE)lpDropFiles + sizeof(DROPFILES));</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; while(pItemPos != NULL)</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; lstrcpy(pszStart, (LPCTSTR)strSelectedList.GetNext(pItemPos));</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pszStart = strchr(pszStart,'\0') + 1; //</font>下次的起始位置是上一次结尾<font face=Tahoma>+1</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>准备完毕之后就可以进行拖放了，拖放动作有<font face=Tahoma>DoDragDrop</font>函数触发，其原型如下：</font></span></p>
<p><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>DROPEFFECT DoDragDrop( </font></font></span></p>
<p><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>DWORD dwEffects = DROPEFFECT_COPY|DROPEFFECT_MOVE|DROPEFFECT_LINK, LPCRECT lpRectStartDrag = NULL, </font></font></span></p>
<p><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>COleDropSource* pDropSource = NULL </font></font></span></p>
<p><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>);</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>这里，<font face=Tahoma>dwEffects</font>指定了允许施加于本<font face=Tahoma>COleDataSource</font>实例之上的动作集：剪切、复制或无动作。</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>&nbsp;&nbsp;&nbsp; lpRectStartDrag</font>指示拖放操作真正开始的矩形，如果鼠标没有移出该矩形，则拖放操作视作放弃处理。如果本成员设为<font face=Tahoma>NULL</font>，则该起始矩形将为一个像素大小。</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>&nbsp;&nbsp;&nbsp; pDropSource</font>表明拖放所使用的<font face=Tahoma>COleDataSource</font>对象。</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>而该函数的返回值，则表明本次拖放操作所实际产生的效果，至于具体产生何种效果，则由系统决定。譬如在拖放时按住<font face=Tahoma>Shift</font>键，将产生剪切效果；按住<font face=Tahoma>Ctrl</font>键，将产生复制效果，等等。</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>拖放的代码如下：</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_oleDataSource.Empty();</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; m_oleDataSource.CacheGlobalData(CF_HDROP, hMemData);</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font face=Tahoma><font size=2>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DropResult = m_oleDataSource.DoDragDrop(DROPEFFECT_MOVE|DROPEFFECT_COPY);</font></font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2>最后一点要注意的是，在<font face=Tahoma>Windows NT 4.0</font>以上的系统中，即使实际产生的是<font face=Tahoma>DROPEFFECT_MOVE</font>动作，<font face=Tahoma>DoDragDrop</font>函数也只返回<font face=Tahoma>DROPEFFECT_NONE</font>。产生这个问题的原因在于，<font face=Tahoma>Windows NT 4.0</font>的<font face=Tahoma>Shell</font>会直接移动文件本身来对移动操作进行优化。返回值<font face=Tahoma>DROPEFFECT_MOVE</font>最初的含义，就是通知执行拖放操作的应用程序去删除原位置上的文件。但是因为<font face=Tahoma>Shell</font>已经替应用程序完成了这个（删除）动作，所以，函数返回<font face=Tahoma>DROPEFFECT_NONE</font>。要想知道文件是否真的被移动了也很简单，只要在函数返回之后检查一下原位置上的文件是否存在就可以了。</font></span></p>
<p align=left><span id=ArticleContent1_ArticleContent1_lblContent><font size=2><font face=Tahoma>Windows 9x</font>系列的操作系统也会对移动进行同样的优化动作，但是它不会返回<font face=Tahoma>DROPEFFECT_NONE</font>来代替<font face=Tahoma>DROPEFFECT_MOVE</font>。详细的解释参见<font face=Tahoma>MS</font>知识库<font face=Tahoma>Q182219</font>。</font></span></p>
<img src ="http://www.cppblog.com/justin-shi/aggbug/58866.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/justin-shi/" target="_blank">幽幽</a> 2008-08-14 19:19 <a href="http://www.cppblog.com/justin-shi/archive/2008/08/14/58866.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>从快捷方式中读取目标路径</title><link>http://www.cppblog.com/justin-shi/archive/2008/08/14/58799.html</link><dc:creator>幽幽</dc:creator><author>幽幽</author><pubDate>Wed, 13 Aug 2008 22:02:00 GMT</pubDate><guid>http://www.cppblog.com/justin-shi/archive/2008/08/14/58799.html</guid><wfw:comment>http://www.cppblog.com/justin-shi/comments/58799.html</wfw:comment><comments>http://www.cppblog.com/justin-shi/archive/2008/08/14/58799.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/justin-shi/comments/commentRss/58799.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/justin-shi/services/trackbacks/58799.html</trackback:ping><description><![CDATA[<h3>Sample Code</h3>
<p>The following code shows how to obtain the filename or path and description of a given link file:
<p>
<pre>   #include &lt;windows.h&gt;
#include &lt;shlobj.h&gt;
// GetLinkInfo() fills the filename and path buffer
// with relevant information.
// hWnd         - calling application's window handle.
//
// lpszLinkName - name of the link file passed into the function.
//
// lpszPath     - the buffer that receives the file's path name.
//
// lpszDescription - the buffer that receives the file's
// description.
HRESULT
GetLinkInfo( HWND    hWnd,
LPCTSTR lpszLinkName,
LPSTR   lpszPath,
LPSTR   lpszDescription)
{
HRESULT hres;
<font style="BACKGROUND-COLOR: #002468" color=#ffffff>IShellLink</font> *pShLink;
WIN32_FIND_DATA wfd;
// Initialize the return parameters to null strings.
*lpszPath = '\0';
*lpszDescription = '\0';
// Call CoCreateInstance to obtain the <font style="BACKGROUND-COLOR: #002468" color=#ffffff>IShellLink</font>
// Interface pointer. This call fails if
// CoInitialize is not called, so it is assumed that
// CoInitialize has been called.
hres = CoCreateInstance( &amp;CLSID_ShellLink,
NULL,
CLSCTX_INPROC_SERVER,
&amp;IID_<font style="BACKGROUND-COLOR: #002468" color=#ffffff>IShellLink</font>,
(LPVOID *)&amp;pShLink );
if (SUCCEEDED(hres))
{
IPersistFile *ppf;
// The <font style="BACKGROUND-COLOR: #002468" color=#ffffff>IShellLink</font> Interface supports the IPersistFile
// interface. Get an interface pointer to it.
hres = pShLink-&gt;lpVtbl-&gt;QueryInterface(pShLink,
&amp;IID_IPersistFile,
(LPVOID *)&amp;ppf );
if (SUCCEEDED(hres))
{
WORD wsz[MAX_PATH];
// Convert the given link name string to a wide character string.
MultiByteToWideChar( CP_ACP, 0,
lpszLinkName,
-1, wsz, MAX_PATH );
// Load the file.
hres = ppf-&gt;lpVtbl-&gt;Load(ppf, wsz, STGM_READ );
if (SUCCEEDED(hres))
{
// Resolve the link by calling the Resolve() interface function.
// This enables us to find the file the link points to even if
// it has been moved or renamed.
hres = pShLink-&gt;lpVtbl-&gt;Resolve(pShLink,  hWnd,
SLR_ANY_MATCH | SLR_NO_UI);
if (SUCCEEDED(hres))
{
// Get the path of the file the link points to.
hres = pShLink-&gt;lpVtbl-&gt;GetPath( pShLink, lpszPath,
MAX_PATH,
&amp;wfd,
SLGP_SHORTPATH );
// Only get the description if we successfully got the path
// (We can't return immediately because we need to release ppf &amp;
//  pShLink.)
if(SUCCEEDED(hres))
{
// Get the description of the link.
hres = pShLink-&gt;lpVtbl-&gt;GetDescription(pShLink,
lpszDescription,
MAX_PATH );
}
}
}
ppf-&gt;lpVtbl-&gt;Release(ppf);
}
pShLink-&gt;lpVtbl-&gt;Release(pShLink);
}
return hres;
}
</pre>
<img height=1 src="http://www.moon-soft.com/doc/down_info.asp?id=4714" width=1 border=0><br>
<img src ="http://www.cppblog.com/justin-shi/aggbug/58799.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/justin-shi/" target="_blank">幽幽</a> 2008-08-14 06:02 <a href="http://www.cppblog.com/justin-shi/archive/2008/08/14/58799.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>FontFamily 和Font 的区别</title><link>http://www.cppblog.com/justin-shi/archive/2008/08/14/58798.html</link><dc:creator>幽幽</dc:creator><author>幽幽</author><pubDate>Wed, 13 Aug 2008 19:51:00 GMT</pubDate><guid>http://www.cppblog.com/justin-shi/archive/2008/08/14/58798.html</guid><wfw:comment>http://www.cppblog.com/justin-shi/comments/58798.html</wfw:comment><comments>http://www.cppblog.com/justin-shi/archive/2008/08/14/58798.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/justin-shi/comments/commentRss/58798.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/justin-shi/services/trackbacks/58798.html</trackback:ping><description><![CDATA[<p>GDI+ 将字样相同但字形不同的字体分组为字体系列。例如，Arial 字体系列中包含以下字体： </p>
<ul>
    <li>
    <p>Arial Regular</p>
    <li>
    <p>Arial Bold</p>
    <li>
    <p>Arial Italic</p>
    <li>
    <p>Arial Bold Italic</p>
    </li>
</ul>
<p>GDI+ 使用四种字形形成字体系列：常规、粗体、倾斜和粗斜体。像 narrow 和 rounded 之类的形容词不被视为字形；而是作为字体系列名的一部分。例如，Arial Narrow 是包含以下成员的字体系列： </p>
<ul>
    <li>
    <p>Arial Narrow Regular</p>
    <li>
    <p>Arial Narrow Bold</p>
    <li>
    <p>Arial Narrow Italic</p>
    <li>
    <p>Arial Narrow Bold Italic</p>
    </li>
</ul>
<p>在可以使用 GDI+ 绘制文本之前，您需要构造一个 <mshelp:link keywords="T:System.Drawing.FontFamily">FontFamily</mshelp:link> 对象和一个 <mshelp:link keywords="T:System.Drawing.Font">Font</mshelp:link> 对象。FontFamily 对象指定字样（例如 Arial），而 Font 对象指定字号、字形和单位。</p>
<h1 class=heading>示例</h1>
<p>下面的示例构造一个字号为 16 像素、常规字形的 Arial 字体。在下面的代码中，传递给 <mshelp:link keywords="Overload:System.Drawing.Font.#ctor">Font</mshelp:link> 构造函数的第一个参数是 FontFamily 对象。第二个参数指定字体的大小，其单位由第四个参数确定。第三个参数确定字形。</p>
<p><mshelp:link keywords="F:System.Drawing.GraphicsUnit.Pixel">Pixel</mshelp:link> 为 <mshelp:link keywords="T:System.Drawing.GraphicsUnit">GraphicsUnit</mshelp:link> 枚举的一个成员，<mshelp:link keywords="F:System.Drawing.FontStyle.Regular">Regular</mshelp:link> 是 <mshelp:link keywords="T:System.Drawing.FontStyle">FontStyle</mshelp:link> 枚举的一个成员。<br></p>
<pre>FontFamily fontFamily = new FontFamily("Arial");
Font font = new Font(
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; fontFamily,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 16,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; FontStyle.Regular,
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; GraphicsUnit.Pixel);</pre>
<pre>&nbsp;</pre>
<pre>&nbsp;</pre>
<img src ="http://www.cppblog.com/justin-shi/aggbug/58798.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/justin-shi/" target="_blank">幽幽</a> 2008-08-14 03:51 <a href="http://www.cppblog.com/justin-shi/archive/2008/08/14/58798.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>GDI+与GDI屏幕抓图比较</title><link>http://www.cppblog.com/justin-shi/archive/2008/08/13/58777.html</link><dc:creator>幽幽</dc:creator><author>幽幽</author><pubDate>Wed, 13 Aug 2008 15:02:00 GMT</pubDate><guid>http://www.cppblog.com/justin-shi/archive/2008/08/13/58777.html</guid><wfw:comment>http://www.cppblog.com/justin-shi/comments/58777.html</wfw:comment><comments>http://www.cppblog.com/justin-shi/archive/2008/08/13/58777.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/justin-shi/comments/commentRss/58777.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/justin-shi/services/trackbacks/58777.html</trackback:ping><description><![CDATA[一、 简介<br><br>屏幕抓图程序在处理图形中应用广泛。作为Windows&nbsp;XP及以后版本操作系统的图形处理内核，GDI+在二维几何图形处理、图像显示与转换和字符排版等方面简直是传统GDI程序员的一种解脱。但是，至少在目前情况下，GDI+尚不能完全代替GDI。与GDI相比，它至少还存在以下不足：<br><br>不支持从内存到屏幕的位传输操作；<br><br>不支持光栅&#8220;位运算&#8221;操作；<br><br>如果程序性能、速度要求比较严格，在图片输出方面的表现较差时，GDI往往能取代实现高性能的输出。<br><br>本文通过对流行的屏幕抓图程序工作原理的剖析，力图向读者阐明GDI+与GDI各自在图形处理方面的优缺点，并给出相应的VC++&nbsp;.NET代码实现。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;二、 GDI在抓图中的关键作用<br><br>&nbsp;&nbsp;&nbsp;&nbsp;要实现屏幕抓图，关键有两点：一是获取图片所在窗口的窗口句柄，即在何处捕获图片；二是保存抓取的图片，实现这一点正是GDI+的强项。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;对于问题一，可以利用SetCapture函数，它能够追踪鼠标指针的移动（包括在屏幕抓图程序窗口之外的窗口）。在移动鼠标的过程中，它还可以根据鼠标的指针所在位置来判断当前窗口的窗口句柄。我们还可以使用函数WindowFromPoint，这个函数能够找出鼠标指针当前位置所对应的窗口句柄。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;使用过知名的抓图软件SnagIT的读者都知道，在选择抓图窗口时，鼠标指针所在位置的窗口都会出现加粗的红色边框，以提醒目前所选择的窗口，这个功能实现起来有些复杂。下面介绍在GDI中如何使这个红色边框出现。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;【注意】正是由于这个红色边框的实现，读者才能发现GDI+在这方面的弱点。<br><br>在GDI中，一个最基本的概念就是设备环境（DC），每一个窗口都具有自己的DC。如果能够找到窗口的DC，那么，用户就能够在该窗口的任何位置绘图。然而，在屏幕抓图程序中，由于用户所选择的窗口不固定，所以，要想得到鼠标指针所处窗口的DC并不容易。这一问题的答案在于GetDC函数。下面是GetDC的函数声明：<br><br>HDC&nbsp;GetDC(HWND&nbsp;hWnd);<br><br>&nbsp;&nbsp;&nbsp;&nbsp;这里，hWnd是DC对应的窗口句柄。注意，当hWnd为空时，该函数返回的是整个屏幕的设备环境句柄。这就意味着，开发人员可以在屏幕上的任何位置进行任意的绘图操作。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;在鼠标指针所处的窗口绘图时，绘图的目的只是为了提醒用户目前所选择的窗口，所以，在绘图时，必须保证不会破坏窗口原有的画面。这时可将窗口的绘图模式设为RS_NOTXORPEN，将画笔颜色与屏幕颜色进行异或运算之后，再对屏幕颜色取反即可。RS_NOTXORPEN运算方式的特点在于：对同一像素进行两次RS_NOTXORPEN运算后，像素值并不会发生变化。这样，在同一个地方进行两次绘图后，窗口的画面并不会发生任何变化。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;【注意】这些功能在GDI+中很难实现。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;三、 编码实现<br><br>由上可知，屏幕抓图至少分为3个步骤：<br><br>&nbsp;&nbsp;&nbsp;&nbsp;（1） 启用鼠标指针捕获。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;（2） 在鼠标指针所在处的窗口进行绘图，提示抓图的目标。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;（3） 选定目标窗口时，将目标窗口的画面保存为自定义的位图并终止鼠标指针捕获。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;以下是具体的编程步骤：<br><br>&nbsp;&nbsp;&nbsp;&nbsp;（1）在Visual&nbsp;C++&nbsp;.NET中按照GDI+程序的框架新建一个基于对话框的项目ScreenCapture，然后准备好一个外形为相机的光标文件（*.cur），将之引入资源管理器（IDC_CAMERA）。接着在CScreenCaptureDlg类中加入以下两个全局变量：<br><br>HWND&nbsp;hwndCapture;<br><br>Crect&nbsp;rectCapture;<br><br>&nbsp;&nbsp;&nbsp;（2）通过类向导加入对WM＿MOUSEMOVE及WM＿LBUTTONUP事件的响应函数，分别如下所示。<br><br>void&nbsp;CScreenCaptureDlg::OnMouseMove(UINT&nbsp;nFlags,&nbsp;CPoint&nbsp;point)<br><br>{<br><br>//如果用户按隹鼠标左键不放，则开始抓取图片<br><br>if(nFlags==MK_LBUTTON){<br><br>//隐藏程序窗口，以免影响在抓取时的&#8220;视野&#8221;<br><br>ShowWindow(SW_HIDE);<br><br>//载入&#8220;照相机&#8221;鼠标指针，开始追踪鼠标指针的移动<br><br>HCURSOR&nbsp;cur=LoadCursor(AfxGetInstanceHandle(),MAKEINTRESOURCE(IDC_CAMERA));<br><br>SetCursor(cur);<br><br>SetCapture();<br><br>//获得鼠标指针所在窗口的句柄<br><br>this-&gt;ClientToScreen(&amp;point);<br><br>hwndCapture=(HWND)::WindowFromPoint(point);<br><br>//取得屏幕的设备环境句柄，以便在屏幕的任何位置绘图<br><br>HDC&nbsp;hDC=::GetDC(NULL);<br><br>//建立一个红色的画笔<br><br>HPEN&nbsp;hPen=CreatePen(PS_INSIDEFRAME,6,RGB(255,0,0));<br><br>//将绘图模式设为R2_NOTXORPEN，在绘图时可以不破坏原有的背景<br><br>int&nbsp;nMode=SetROP2(hDC,R2_NOTXORPEN);<br><br>HPEN&nbsp;hpenOld=(HPEN)SelectObject(hDC,hPen);<br><br>//得到鼠标指针所在窗口的区域<br><br>::GetWindowRect(hwndCapture,&amp;rectCapture);<br><br>//在鼠标指针所在处的窗口四周画一红色的矩形，做为选定时的提示<br><br>POINT&nbsp;pt[5];<br><br>pt[0]=CPoint(rectCapture.left,rectCapture.top);<br><br>pt[1]=CPoint(rectCapture.right,rectCapture.top);<br><br>pt[2]=CPoint(rectCapture.right,rectCapture.bottom);<br><br>pt[3]=CPoint(rectCapture.left,rectCapture.bottom);<br><br>pt[4]=CPoint(rectCapture.left,rectCapture.top);<br><br>::Polyline(hDC,pt,5);<br><br>//延时后再重绘红色矩形，这样不会破坏原有的内容<br><br>Sleep(100);<br><br>::Polyline(hDC,pt,5);<br><br>::SelectObject(hDC,hpenOld);<br><br>::ReleaseDC(NULL,hDC);<br><br>}<br><br>CDialog::OnMouseMove(nFlags,&nbsp;point);<br><br>}<br><br>void&nbsp;CScreenCaptureDlg::OnLButtonUp(UINT&nbsp;nFlags,&nbsp;CPoint&nbsp;point)<br><br>{<br><br>//&nbsp;得到鼠标指针所在窗口的区域宽、高<br><br>int&nbsp;nWidth=rectCapture.Width();<br><br>int&nbsp;nHeight=rectCapture.Height();<br><br>HDC&nbsp;hdcScreen,hMemDC;<br><br>HBITMAP&nbsp;hBitmap,hOldBitmap;<br><br>//建立一个屏幕设备环境句柄<br><br>hdcScreen=CreateDC("DISPLAY",NULL,NULL,NULL);<br><br>hMemDC=CreateCompatibleDC(hdcScreen);<br><br>//建立一个与屏幕设备环境句柄兼容、与鼠标指针所在窗口的区域等大的位图<br><br>hBitmap=CreateCompatibleBitmap(hdcScreen,nWidth,nHeight);<br><br>//把新位图选到内存设备描述表中<br><br>hOldBitmap=(HBITMAP)SelectObject(hMemDC,hBitmap);<br><br>//把屏幕设备描述表拷贝到内存设备描述表中<br><br>BitBlt(hMemDC,0,0,nWidth,nHeight,hdcScreen,rectCapture.left,rectCapture.top,SRCCOPY);<br><br>DeleteDC(hdcScreen);<br><br>DeleteDC(hMemDC);<br><br>//返回位图句柄<br><br>//打开剪贴板，并将位图拷到剪贴板上<br><br>OpenClipboard();<br><br>EmptyClipboard();<br><br>SetClipboardData(CF_BITMAP,hBitmap);<br><br>//关闭剪贴板<br><br>CloseClipboard();<br><br>MessageBox("屏幕内容已经拷到剪贴板！");<br><br>ReleaseCapture();<br><br>//恢复窗口显示模式<br><br>ShowWindow(SW_NORMAL);<br><br>CDialog::OnLButtonUp(nFlags,&nbsp;point);<br><br>}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;至此，一个具有专业效果的屏幕抓图程序的核心已经搞定。<br><br>&nbsp;&nbsp;&nbsp;&nbsp;四、 用GDI+实现画面的保存<br><br>&nbsp;&nbsp;&nbsp;&nbsp;经过上面两步，如果用户在对话框中按住鼠标左键不放，程序便开始&#8220;抓图&#8221;。当选择好抓图的目标后，松开鼠标左键，抓图的目标窗口的画面就自动保存到剪贴板中了。但是，把画面保存到文件中更为重要。如果用GDI的方式来操作，需要对各种类位图的结构有详尽的了解，极其麻烦。但如果用GDI+来实现之则极为容易。下面介绍如何将已经抓到的图片保存到一个BMP文件中。<br><br>由上面知，抓图程序已经得到了所捕获的窗口的位图句柄，接下来要将位图句柄保存为相应的位图文件。这一切归功于GDI+的Bitmap类，详见下列代码。<br><br>void&nbsp;CScreenCaptureDlg::OnLButtonUp(UINT&nbsp;nFlags,&nbsp;CPoint&nbsp;point)<br><br>{<br><br>//&#8230;&#8230;省略<br><br>if(GetSaveFileName(&amp;ofn))<br><br>{<br><br>CLSID&nbsp;pngClsid;<br><br>Bitmap&nbsp;bmp(hBitmap,NULL);<br><br>//获取BMP文件的编码方式<br><br>GetEncoderClsid(L"image/bmp",&amp;pngClsid);//帮助函数<br><br>CString&nbsp;tmp(ofn.lpstrFile);<br><br>CStringW&nbsp;filename((LPCSTR)tmp);<br><br>//保存所截取的屏幕图片<br><br>bmp.Save(filename,&amp;pngClsid);<br><br>}<br><br>ReleaseCapture();<br><br>MessageBox("屏幕内容已经保存到文件中！");<br><br>//恢复窗口显示模式<br><br>ShowWindow(SW_NORMAL);<br><br>CDialog::OnLButtonUp(nFlags,&nbsp;point);<br><br>}<br><br>&nbsp;&nbsp;&nbsp;&nbsp;五、 小结<br><br>&nbsp;&nbsp;&nbsp;&nbsp;本文通过一个专业的屏幕抓图程序的核心实现，对比分析了GDI与GDI+各自的优缺点。但我们相信，GDI+作为新一代图形引擎，随着版本的不断升级，其迟早要淘汰掉GDI。本人拙见，不足处还望读者指正。<br><br>另外，本文源码在Windows&nbsp;2000/VC++.NET&nbsp;2003环境中调试通过。调试过程中注意：<br><br>确保工程对GDI+库的正确引用：在头文件stdafx.h中要加入相应引用；在应用程序类的InitInstance成员函数前后及其析构函数中加适当的操作；工程编译时要加入对gdiplus.lib的引用（&#8220;项目&#8221;｜&#8220;添加现有项&#8221;，我的机器上是在C:\Program&nbsp;Files\Microsoft&nbsp;Visual&nbsp;Studio.NET\vc7\platformSDK\lib下找到库文件）。<br>
<p>&nbsp;</p>
<img src ="http://www.cppblog.com/justin-shi/aggbug/58777.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/justin-shi/" target="_blank">幽幽</a> 2008-08-13 23:02 <a href="http://www.cppblog.com/justin-shi/archive/2008/08/13/58777.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>解决绘图时闪烁问题的一点经验</title><link>http://www.cppblog.com/justin-shi/archive/2008/08/04/58020.html</link><dc:creator>幽幽</dc:creator><author>幽幽</author><pubDate>Mon, 04 Aug 2008 15:39:00 GMT</pubDate><guid>http://www.cppblog.com/justin-shi/archive/2008/08/04/58020.html</guid><wfw:comment>http://www.cppblog.com/justin-shi/comments/58020.html</wfw:comment><comments>http://www.cppblog.com/justin-shi/archive/2008/08/04/58020.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/justin-shi/comments/commentRss/58020.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/justin-shi/services/trackbacks/58020.html</trackback:ping><description><![CDATA[<div align=center><font face="黑体, Simhei" size=4>清除屏幕闪烁</font></div>
<div align=center><font face=黑体 size=2>(转自网上)</font></div>
<div align=center><font face=黑体 size=2><strong>&lt;一&gt;</strong></font></div>
<p>由于作图过于复杂和频繁，所以时常出现闪烁的情况，一些防止闪烁的方法，如下：
<p>(1)将Invalidate()替换为InvalidateRect()。<br>Invalidate()会导致整个窗口的图象重画，需要的时间比较长，而InvalidateRect()仅仅重画Rect区域内的内容，所以所需时间会少一些。不要为一小块区域的重画就调用Invalidate()，不愿意自己去计算需要重画的Rect，事实上，如果你确实需要改善闪烁的情况，计算一个Rect所用的时间比起重画那些不需要重画的内容所需要的时间要少得多。
<p>(2)禁止系统擦除你的窗口。<br>系统在需要重画窗口的时候会帮你用指定的背景色来擦除窗口。可是，也许需要重画的区域也许非常小。或者，在你重画这些东西之间还要经过大量的计算才能开始.这个时候你可以禁止系统擦掉原来的图象。直到你已经计算好了所有的数据，自己把那些需要擦掉的部分用背景色覆盖掉（如：dc.FillRect(rect，&amp;brush)；rect是需要擦除的区域，brush是带背景色的刷子），再画上新的图形。要禁止系统擦除你的窗口，可以重载OnEraseBkgnd()函数，让其直接返回TRUE就可以了。如<br>BOOL CmyWin::OnEraseBkgnd(CDC* pDC) <br>{<br>&nbsp;return TRUE;<br>&nbsp;//return CWnd::OnEraseBkgnd(pDC);//把系统原来的这条语句注释掉。<br>}
<p>(3)有效的进行擦除。<br>擦除背景的时候，不要该擦不该擦的地方都擦。比如，你在一个窗口上放了一个很大的Edit框，几乎占了整个窗口，那么你频繁的擦除整个窗口背景将导致Edit不停重画形成剧烈的闪烁.事实上你可以CRgn创建一个需要擦除的区域，只擦除这一部分.如
<p>GetClientRect(rectClient);<br>rgn1.CreateRectRgnIndirect(rectClient);<br>rgn2.CreateRectRgnIndirect(m_rectEdit);
<p>if(rgn1.CombineRgn(&amp;rgn1,&amp;rgn2,RGN_XOR)= ERROR)<br>//处理后的rgn1只包括了Edit框之外的客户区域，这样，Edit将不会被我的背景覆盖而导致重画.<br>{<br>&nbsp;ASSERT(FALSE);<br>&nbsp;return ;<br>}<br>brush.CreateSolidBrush(m_clrBackgnd);<br>pDC-&gt;FillRgn(&amp;rgn1,&amp;brush);<br>brush.DeleteObject();<br>注意：在使用这个方法的时候要同时使用方法二。
<p>(4).使用MemoryDC先在内存里把图画好，再复制到屏幕上。<br>这对于一次画图过程很长的情况比较管用。毕竟内存操作比较快，而且复制到屏幕又是一次性的，至少不会出现可以明显看出一个东西从左画到右的情况。
<p>void CMyWiew：：OnDraw() //CScrollView下双缓冲内存的实现：<br>{<br>&nbsp;CRect rect;<br>&nbsp;GetClientRect(&amp;rect);
<p>&nbsp;CDC* m_pMemoryDC = new CDC();<br>&nbsp;CBitmap * m_pBitmap = new CBitmap();
<p>&nbsp;CPoint ScrollPoint=GetScrollPosition();
<p>&nbsp;m_pMemoryDC-&gt;CreateCompatibleDC(pDC);<br>&nbsp;&nbsp;<br>&nbsp;m_pBitmap-&gt;CreateCompatibleBitmap(pDC,rect.right+1,rect.bottom+1);//这里的Bitmap是必须的，否则当心弄出一个大黑块.&nbsp;<br>&nbsp;CBitmap * pOldbmp=m_pMemoryDC-&gt;SelectObject(m_pBitmap);
<p>&nbsp;//m_pMemoryDC-&gt;SelectStockObject(WHITE_BRUSH);//画出白色背景方法一<br>&nbsp;//m_pMemoryDC-&gt;Rectangle(-1,-1,rect.right + 2 , rect.bottom + 2 );<br>&nbsp;//m_pMemoryDC-&gt;SelectStockObject(NULL_BRUSH);
<p>&nbsp;m_pMemoryDC-&gt;PatBlt(0,0,rect.right, rect.bottom,WHITENESS);//画出白色背景方法二
<p>&nbsp;//-----------------如下是显示图片的方法----------------------------------------------------------<br>&nbsp;//BITMAP BM;<br>&nbsp;//CBitmap&nbsp; pBitmap;<br>&nbsp;//pBitmap.LoadBitmap(IDB_BITMAP2);<br>&nbsp;<br>&nbsp;//CDC * pTdc = new CDC();<br>&nbsp;//pTdc-&gt;CreateCompatibleDC(pDC);<br>&nbsp;//CBitmap* pom = pTdc-&gt;SelectObject(&amp;pBitmap);<br>&nbsp;//pBitmap-&gt;GetObject(sizeof(BM),&amp;BM);<br>&nbsp;//m_pMemoryDC-&gt;BitBlt(0-ScrollPoint.x,0-ScrollPoint.y, BM.bmWidth,BM.bmHeight, pTdc,0,0,SRCCOPY);<br>&nbsp;//pTdc-&gt;DeleteDC();<br>&nbsp;//delete pTdc;<br>&nbsp;//--------------图片显示完毕----------------------------------------------------------------------
<p>&nbsp;//m_pMemoryDC-&gt;SetROP2(R2_NOT);//设定绘图模式
<p>&nbsp;m_pMemoryDC-&gt;MoveTo(0-ScrollPoint.x,0-ScrollPoint.y);<br>&nbsp;m_pMemoryDC-&gt;LineTo(1000-ScrollPoint.x,5000-ScrollPoint.y);
<p><br>&nbsp;pDC-&gt;BitBlt(ScrollPoint.x, ScrollPoint.y, rect.right, rect.bottom, m_pMemoryDC, 0, 0, SRCCOPY);
<p>&nbsp;m_pMemoryDC-&gt;SelectObject(pOldbmp);&nbsp;<br>&nbsp;m_pBitmap-&gt;DeleteObject();<br>&nbsp;m_pMemoryDC-&gt;DeleteDC();
<p>&nbsp;delete m_pBitmap;<br>&nbsp;delete m_pMemoryDC;<br>}
<p>*******************************
<div align=center><font face="黑体, Simhei" size=4>解决<font face="Arial Black, Geneva, Arial, Sans-serif">Windows</font>程序界面闪烁问题的一些经验</font></div>
<div align=center><font face=黑体 size=2>(转自网上)</font></div>
<div align=center><font face=黑体 size=2><strong>&lt;二&gt;</strong></font></div>
<p>一般的windows 复杂的界面需要使用多层窗口而且要用贴图来美化，所以不可避免在窗口移动或者改变大小的时候出现闪烁。
<p>先来谈谈闪烁产生的原因
<p>原因一：<br>如果熟悉显卡原理的话，调用GDI函数向屏幕输出的时候并不是立刻就显示在屏幕<br>上只是写到了显存里，而显卡每隔一段时间把显存的内容输出到屏幕上，这就是刷新周期。
<p>一般显卡的刷新周期是 1/80秒左右，具体数字可以自己设置的。
<p>这样问题就来了，一般画图都是先画背景色，然后再把内容画上去，如果这两次操作不在同一个<br>刷新周期内完成，那么给人的视觉感受就是，先看到只有背景色的图像，然后看到画上内容的图像，<br>这样就会感觉闪烁了。
<p>解决方法：尽量快的输出图像，使输出在一个刷新周期内完成，如果输出内容很多比较慢，那么采用<br>内存缓冲的方法，先把要输出的内容在内存准备好，然后一次输出到显存。要知道一次API调用一般可以<br>在一个刷新周期内完成。
<p>对于GDI，用创建内存DC的方法就可以了
<p>原因二：
<p>复杂的界面有多层窗口组成，当windows在窗口改变大小的时候是先重画父窗口，然后重画子窗口，子父<br>窗口重画的过程一般无法在一个刷新周期内完成，所以会呈现闪烁。
<p>我们知道父窗口上被子窗口挡住的部分其实没必要重画的
<p>解决方法：给窗口加个风格 WS_CLIPCHILDREN ,这样父窗口上被子窗口挡住的部分就不会重画了。
<p>如果同级窗口之间有重叠，那么需要再加上 WS_CLIPSIBLINGS 风格
<p>原因三：
<p>有时候需要在窗口上使用一些控件，比如IE，当你的窗口改变大小的时候IE会闪烁，即使你有了WS_CLIPCHILDREN<br>也没用。原因在于窗口的类风格有CS_HREDRAW 或者 CS_VREDRAW，这两个风格表示窗口在宽度或者高度变化的时候<br>重画，但是这样就会引起IE闪烁
<p>解决方法：注册窗口类的时候不要使用这两个风格，如果窗口需要在改变大小的时候重画，那么可以在WM_SIZE的时候<br>调用RedrawWindow。
<p>原因四：
<p>界面上窗口很多，而且改变大小时很多窗口都要移动和改变大小，如果使用MoveWindow或者SetWindowPos两个API来<br>改变窗口的大小和位置，由于他们是等待窗口重画完成后才返回，所以过程很慢，这样视觉效果就可能会闪烁。
<p>解决方法：
<p>使用以下API来处理窗口移动，BeginDeferWindowPos, DeferWindowPos，EndDeferWindowPos<br>先调用 BeginDeferWindowPos 设定需要移动的窗口的个数<br>使用DeferWindowPos，来移动窗口，这个API并不真的造成窗口移动<br>EndDeferWindowPos 一次性完成所有窗口的大小和位置的改变。
<p>有个地方要特别注意，要仔细计算清楚要移动多少个窗口，BeginDeferWindowPos设定<br>的个数一定要和实际的个数一致，否则在Win9x下，如果实际移动的窗口数多于调用BeginDeferWindowPos<br>时设定的个数，可能会造成系统崩溃。在Windows NT系列下不会有这样的问题。
<p>*******************************
<p align=center><font face="黑体, Simhei" size=4>使用内存DC解决重画闪烁问题</font>
<div align=center><font face=黑体 size=2>(转自网上)</font></div>
<div align=center><font face=黑体 size=2><strong>&lt;三&gt;</strong></font></div>
<p>&nbsp;<br>下述代码在OnDraw时绘图：
<p>void CRedrawDemoView::OnDraw(CDC* pDC)
<p>{
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CRedrawDemoDoc* pDoc = GetDocument();
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ASSERT_VALID(pDoc);
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // TODO: add draw code for native data here
<p>&nbsp;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static const char* pText = "解决重画闪烁问题！";
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RECT clRect;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ::GetClientRect(m_hWnd, &amp;clRect);
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pDC-&gt;FillSolidRect(&amp;clRect, RGB(255, 255, 255));
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int x = 100, y = 100;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RECT rect = { x - 20, y - 20};
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rect.right = rect.left + 160;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rect.bottom = rect.top + 60;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pDC-&gt;FillSolidRect(&amp;rect, RGB(0, 255, 0));
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pDC-&gt;TextOut(x, y, pText, strlen(pText));
<p>}
<p>&nbsp;
<p>首先将背景填充白色，然后画一绿色的矩形，再在矩形上输出一段文字，如此过程必然会引起画面闪烁，<br>解决办法：使用内存DC，先将图形绘制到内存DC，然后拷贝到屏幕，实现无闪烁绘图。<br>修改后的代码如下：
<p>&nbsp;
<p>void CRedrawDemoView::OnDraw(CDC* pDC)
<p>{
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CRedrawDemoDoc* pDoc = GetDocument();
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ASSERT_VALID(pDoc);
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // TODO: add draw code for native data here
<p>&nbsp;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; static const char* pText = "解决重画闪烁问题！";
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CRect clRect;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ::GetClientRect(m_hWnd, &amp;clRect);
<p>&nbsp;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CDC memDC;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; memDC.CreateCompatibleDC(pDC);
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CBitmap bitmap;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; bitmap.CreateCompatibleBitmap(pDC, clRect.Width(), clRect.Height());
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; CBitmap * pOldBitmap = memDC.SelectObject(&amp;bitmap);
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; memDC.FillSolidRect(&amp;clRect, RGB(255, 255, 255));
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; int x = 100, y = 100;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; RECT rect = { x - 20, y - 20};
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rect.right = rect.left + 160;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; rect.bottom = rect.top + 60;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; memDC.FillSolidRect(&amp;rect, RGB(0, 255, 0));
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; memDC.TextOut(x, y, pText, strlen(pText));
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; pDC-&gt;BitBlt(0, 0, clRect.Width(), clRect.Height(), &amp;memDC, 0, 0, SRCCOPY);
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; memDC.SelectObject(pOldBitmap);
<p>}
<p><br>也可以在上述代码中加入绘制Bitmap位图代码，注意应该阻止窗口擦除背景，重载OnEraseBkgnd函数
<p><br>BOOL CRedrawDemoView::OnEraseBkgnd(CDC* pDC)
<p>{
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // TODO: Add your message handler code here and/or call default
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; return TRUE;
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // return CView::OnEraseBkgnd(pDC);
<p>}
<p><br>为易于理解，以上代码未经优化。
<p>&nbsp;
<p>&nbsp;</p>
<div>*******************************</div>
<div>用:</div>
<div>CreateCompatibleBitmap&nbsp;<br>CreateCompatibleDC<br>等函数在内存中把要画的图先画出来,然后使用&nbsp;&nbsp; <br>BitBlt复制到设备上就OK!</div>
<div>*******************************</div>
<img src ="http://www.cppblog.com/justin-shi/aggbug/58020.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/justin-shi/" target="_blank">幽幽</a> 2008-08-04 23:39 <a href="http://www.cppblog.com/justin-shi/archive/2008/08/04/58020.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>把C++类成员方法直接作为线程回调函数</title><link>http://www.cppblog.com/justin-shi/archive/2008/07/22/56813.html</link><dc:creator>幽幽</dc:creator><author>幽幽</author><pubDate>Mon, 21 Jul 2008 19:13:00 GMT</pubDate><guid>http://www.cppblog.com/justin-shi/archive/2008/07/22/56813.html</guid><wfw:comment>http://www.cppblog.com/justin-shi/comments/56813.html</wfw:comment><comments>http://www.cppblog.com/justin-shi/archive/2008/07/22/56813.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/justin-shi/comments/commentRss/56813.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/justin-shi/services/trackbacks/56813.html</trackback:ping><description><![CDATA[<p>我以前写线程时要么老老实实照着声明写,要么使用C++类的静态成员函数来作为回调函数,经常会因为线程代码而破坏封装.之前虽然知道类成员函数的展开形式，但从没想过利用过它，昨天看深入ATL时无意中学会了这一招:)&nbsp;</p>
<p>类成员方法是一个比较特殊的函数，它在编译时会被转化成普通函数，比如有TMyClass类:<br>class TMyClass{<br>&nbsp;&nbsp;&nbsp; void Func();<br>};</p>
<p>这个TMyClass::Func最终会转化成 void Func(TMyClass *this); 也就是说在原第一个参数前插入指向对象本身的this指针。</p>
<p>我们可以利用这个特性写一个非静态类成员方法来直接作为线程回调函数，先看_beginthread函数的定义:<br>unsigned long _RTLENTRY _EXPFUNC _beginthread (void (_USERENTRY *__start)(void *),unsigned __stksize, void *__arg);<br>其中的第一个参数就是作为线程执行主体的回调函数。它的原型是:void Func(void *)，这个void*参数是作为自定义数据传入的。对比一下上面所说的TMyClass::Func的最终形式，它正好可以符合这里的要求。</p>
<p>现在做个实验:<br>#include &lt;stdio.h&gt;<br>#include &lt;process.h&gt;</p>
<p>class TMyClass{<br>&nbsp;&nbsp;&nbsp; int m_nCount;<br>&nbsp;&nbsp;&nbsp; int m_nId;<br>public:<br>&nbsp;&nbsp;&nbsp; TMyClass(int nId,int nCount)<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; :m_nId(nId),m_nCount(nCount)<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp; }</p>
<p>&nbsp;&nbsp;&nbsp; void _USERENTRY ThreadProc()&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 类成员方法<br>&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; for(int i=0; i&lt;m_nCount; i++)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 根据m_nCount成员打印一排数字<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; {<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; printf("Class%d : %d\n",m_nId,i);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; }<br>&nbsp;&nbsp;&nbsp; }<br>};</p>
<p>int main(int argc, char* argv[])<br>{<br>&nbsp;&nbsp;&nbsp; union {&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 联合类，用于转换类成员方法指针到普通函数指针（试过编译器不允许在这两种函数之间强制转换），不知道有没有更好的方法。<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void (_USERENTRY *ThreadProc)(void *);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; void (_USERENTRY TMyClass::*MemberProc)();<br>&nbsp;&nbsp;&nbsp; } Proc;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 尽管联合里的两种函数类型现在看起来有很大不同，但它们的最终形式是相同的。</p>
<p>&nbsp;&nbsp;&nbsp; TMyClass MyClass1(1,10),MyClass2(2,5); // 产生两个TMyClass对象</p>
<p>&nbsp;&nbsp;&nbsp; Proc.MemberProc = &amp;TMyClass::ThreadProc;&nbsp;&nbsp; // 转换，Proc.ThreadProc就是对应的普通函数指针了</p>
<p>&nbsp;&nbsp;&nbsp; _beginthread(Proc.ThreadProc,4096,&amp;MyClass1);&nbsp;&nbsp; // 开始线程，这里的Proc.ThreadProc实际上是TMyClass::ThreadProc, 它要的this指针是我们给的&amp;MyClass1。<br>&nbsp;&nbsp;&nbsp; _beginthread(Proc.ThreadProc,4096,&amp;MyClass2);<br>&nbsp;&nbsp;&nbsp; system("pause");<br>&nbsp;&nbsp;&nbsp; return 0;<br>}</p>
<p>运行！神奇吧？:-)</p>
<p>其实不止线程回调函数，其实只要是形如Func(void*,...)的回调函数都可以用这种方法直接使用类成员方法。(前提是第一个void*是自定义数据，也就是说它不能有其它功能)。<br><br>转自:http://blog.csdn.net/waiting4you/archive/2007/12/29/2000796.aspx</p>
<img src ="http://www.cppblog.com/justin-shi/aggbug/56813.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/justin-shi/" target="_blank">幽幽</a> 2008-07-22 03:13 <a href="http://www.cppblog.com/justin-shi/archive/2008/07/22/56813.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>滚动控件(ScrollBar)</title><link>http://www.cppblog.com/justin-shi/archive/2008/07/21/56730.html</link><dc:creator>幽幽</dc:creator><author>幽幽</author><pubDate>Mon, 21 Jul 2008 01:57:00 GMT</pubDate><guid>http://www.cppblog.com/justin-shi/archive/2008/07/21/56730.html</guid><wfw:comment>http://www.cppblog.com/justin-shi/comments/56730.html</wfw:comment><comments>http://www.cppblog.com/justin-shi/archive/2008/07/21/56730.html#Feedback</comments><slash:comments>3</slash:comments><wfw:commentRss>http://www.cppblog.com/justin-shi/comments/commentRss/56730.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/justin-shi/services/trackbacks/56730.html</trackback:ping><description><![CDATA[<p align=center><font size=5>滚动控件(ScrollBar)<br><br></font><br>　　滚动条(ScrollBar)主要用来从某一预定义值范围内快速有效地进行选择。滚动条分垂直滚动条和水平滚动条两种。在滚动条内有一个滚动框，用来表示当前的值。用鼠标单击滚动条，可以使滚动框移动一页，鼠标单击滚动条两端的剪头可以使滚动框移动一行，也可以直接拖动滚动框。许多窗口控件如列表框和组合框等都带有滚动条子窗口。Win32的滚动条支持比例滚动框，即用滚动框的大小来反映页相对于整个范围的大小。<br>　　当CreateWindowEx创建滚动条时，其风格常数中带SBS_VERT为水平滚动条，不带SBS_VERT或带SBS_HORZ为垂直滚动条。<br>　　创建控件时应初始化滚动条的各种参数。<br>　　应用程序可以通过调用SendMessage向控件发送如下消息来设定控件各种参数。<br>
<table cellSpacing=1 cellPadding=1 width="97%" align=center bgColor=#ffffff border=0>
    <tbody>
        <tr align=middle bgColor=#cccccc>
            <td>uMsg</td>
            <td>wParam</td>
            <td>lParam</td>
            <td>说明</td>
        </tr>
        <tr bgColor=#cccccc>
            <td width=110 rowSpan=7>SBM_ENABLE_ARROWS</td>
            <td width=110>ESB_DISABLE_BOTH</td>
            <td>0</td>
            <td>禁止双向滚动剪头</td>
        </tr>
        <tr bgColor=#cccccc>
            <td>ESB_DISABLE_DOWN</td>
            <td>0</td>
            <td>禁止向下滚动剪头</td>
        </tr>
        <tr bgColor=#cccccc>
            <td>ESB_DISABLE_LTUP</td>
            <td>0</td>
            <td>禁止向上和向左滚动剪头</td>
        </tr>
        <tr bgColor=#cccccc>
            <td>ESB_DISABLE_LEFT</td>
            <td>0</td>
            <td>禁止向左滚动剪头</td>
        </tr>
        <tr bgColor=#cccccc>
            <td>ESB_DISABLE_RTDN</td>
            <td>0</td>
            <td>禁止向下和向右滚动剪头</td>
        </tr>
        <tr bgColor=#cccccc>
            <td>ESB_DISABLE_UP</td>
            <td>0</td>
            <td>禁止向上滚动剪头</td>
        </tr>
        <tr bgColor=#cccccc>
            <td>ESB_ENABLE_BOTH</td>
            <td>0</td>
            <td>允许双向滚动剪头(撤消各种禁止)</td>
        </tr>
        <tr bgColor=#cccccc>
            <td rowSpan=2>SBM_SETPOS</td>
            <td rowSpan=2>指定位置</td>
            <td>TRUE</td>
            <td>设置滚动框位置，并重绘控件</td>
        </tr>
        <tr bgColor=#cccccc>
            <td>FALSE</td>
            <td>设置滚动框位置，不重绘控件</td>
        </tr>
        <tr bgColor=#cccccc>
            <td>SBM_SETRANGE</td>
            <td>最小值</td>
            <td>最大值</td>
            <td>设置滚动框位置的变化范围</td>
        </tr>
        <tr bgColor=#cccccc>
            <td>SBM_SETRANGEREDRAW</td>
            <td>最小值</td>
            <td>最大值</td>
            <td>设置滚动框位置的变化范围，并重绘控件</td>
        </tr>
        <tr bgColor=#cccccc>
            <td>SBM_SETSCROLLINFO</td>
            <td>TRUE或FALSE</td>
            <td>SCROLLINFO结构指针</td>
            <td>本消息通过一个SCROLLINFO结构来同时指定控件的多种参数，具体指定哪些参数由结构中的fMask成员确定。wParam指定是否重绘控件，详见&#8220;SCROLLINFO结构&#8221;</td>
        </tr>
    </tbody>
</table>
　　当用户在滚动条控件上进行各种操作时，其父窗口将收到WM_HSCROLL或WM_VSCROLL通知消息，同时wParam的低16位带有如下表的消息代码(nScrollCode)，wParam的高16位带滚动框的指定位置(nPos)，该值在消息代码等于SB_THUMBPOSITION或SB_THUMBTRACK时才有效。lParam带控件句柄(hwndScrollBar)。<br>　　应用程序可以根据消息代码做相应的操作，重新设置滚动框位置，控件本身是不会改变滚动框位置的。
<table cellSpacing=1 cellPadding=1 width="97%" align=center bgColor=#ffffff border=0>
    <tbody>
        <tr align=middle bgColor=#cccccc>
            <td>消息代码</td>
            <td width=190>动作</td>
            <td>响应</td>
        </tr>
        <tr bgColor=#cccccc>
            <td>SB_LINEUP<br>SB_LINELEFT</td>
            <td>用户点击了向上(左)剪头</td>
            <td>滚动框位置减一，客户窗口向上(左)滚动一行。<br>注：这两个代码数值相等，因此可以混用，下同。</td>
        </tr>
        <tr bgColor=#cccccc>
            <td>SB_LINEDOWN<br>SB_LINERIGHT</td>
            <td>用户点击了向下(右)剪头</td>
            <td>滚动框位置加一，客户窗口向下(右)滚动一行。</td>
        </tr>
        <tr bgColor=#cccccc>
            <td>SB_PAGEUP<br>SB_PAGELEFT</td>
            <td>用户点击了滚动框以上(左)剪杆</td>
            <td>滚动框位置减去一个大单位，客户窗口向上(左)滚动一页。 </td>
        </tr>
        <tr bgColor=#cccccc>
            <td>SB_PAGEDOWN<br>SB_PAGERIGHT</td>
            <td>用户点击了滚动框以下(右)剪杆</td>
            <td>滚动框位置加上一个大单位，客户窗口向下(右)滚动一页。 </td>
        </tr>
        <tr bgColor=#cccccc>
            <td>SB_THUMBPOSITION</td>
            <td>用户拖动并释放滚动框到指定位置</td>
            <td>设定滚动框到指定位置。客户窗口滚动到指定位置。</td>
        </tr>
        <tr bgColor=#cccccc>
            <td>SB_THUMBTRACK</td>
            <td>用户正在拖动滚动框</td>
            <td>设定滚动框到指定位置。客户窗口滚动到指定位置。如果应用程序需要快速浏览窗口，可以响应本消息重绘窗口，如果不需要快速浏览，可以等待收到SB_THUMBPOSITION消息时重绘窗口。 </td>
        </tr>
        <tr bgColor=#cccccc>
            <td>SB_ENDSCROLL</td>
            <td>用户释放按下剪头或剪杆的鼠标</td>
            <td>无须做任何响应 </td>
        </tr>
    </tbody>
</table>
　　应用程序可以通过调用SendMessage向控件发送如下消息来取得当前控件各种参数。
<table cellSpacing=1 cellPadding=1 width="97%" align=center bgColor=#ffffff border=0>
    <tbody>
        <tr align=middle bgColor=#cccccc>
            <td>uMsg</td>
            <td width=110>wParam</td>
            <td width=110>lParam</td>
            <td>说明</td>
        </tr>
        <tr bgColor=#cccccc>
            <td>SBM_GETPOS</td>
            <td>0</td>
            <td>0</td>
            <td>返回滚动框当前位置。</td>
        </tr>
        <tr bgColor=#cccccc>
            <td>SBM_GETRANGE</td>
            <td>最小值地址指针</td>
            <td>最大值地址指针</td>
            <td>在指定地址中填入32位的滚动框位置的变化范围</td>
        </tr>
        <tr bgColor=#cccccc>
            <td>SBM_GETSCROLLINFO</td>
            <td>0</td>
            <td>SCROLLINFO结构指针</td>
            <td>在一个SCROLLINFO结构中返回控件的多种参数，必须事先设定结构的fMask成员来确定具体要取得哪些参数。详见&#8220;SCROLLINFO结构&#8221;</td>
        </tr>
    </tbody>
</table>
　　当控件需要重画时向每父窗口发送WM_CTLCOLORSCROLLBAR消息,同时在wParam中带控件的设备场景句柄(hDC)，lParam中带控件句柄。如果应用程序响应这个消息并返回一个画刷(brush)句柄，控件将根据这个句柄绘制背景色。<br><br>SCROLLINFO结构：
<table>
    <tbody>
        <tr>
            <td>
            <pre>SCROLLINFO STRUCT
            cbSize        DWORD      ?
            fMask         DWORD      ?
            nMin          DWORD      ?
            nMax          DWORD      ?
            nPage         DWORD      ?
            nPos          DWORD      ?
            nTrackPos     DWORD      ?
            SCROLLINFO ENDS</pre>
            </td>
        </tr>
    </tbody>
</table>
成员说明：<br>　　cbSize: SCROLLINFO结构长度字节数，该值在设置和查询参数时都必须填写。<br>　　fMask: 指定结构中的哪些成员是有效，该值共有如下5种选择，可以选择多种用&#8220;OR&#8221;组合起来，该值在设置和查询参数时都必须填写。<br>　　　　SIF_ALL　　　　　　:整个结构都有效<br>　　　　SIF_DISABLENOSCROLL:该值仅在设定参数时使用，视控件参数设定的需要来对本结构的成员进行取舍。<br>　　　　SIF_PAGE　　　　　 :nPage成员有效<br>　　　　SIF_POS　　　　　　:nPos成员有效<br>　　　　SIF_RANGE　　　　　:nMin和nMax成员有效<br>　　nMin:滚动范围最小值<br>　　nMax:滚动范围最大值<br>　　nPage:页尺寸，用来确定比例滚动框的大小<br>　　nPos:滚动框的位置<br>　　nTrackPos:拖动时滚动框的位置，该参数只能查询，不能设置。<br>
<script src="http://xh.go.nease.net/nnselect.js" type=text/javascript>
</script>
<script language=JavaScript src="http://secure-cn.imrworldwide.com/v51.js" type=text/javascript>
</script>
<noscript></noscript><img height=1 alt="" src="http://secure-cn.imrworldwide.com/cgi-bin/m?rnd=1114584693135&amp;ci=cn-netease&amp;cg=0&amp;sr=1152x864&amp;cd=32&amp;lg=zh-cn&amp;je=y&amp;ck=y&amp;tz=8&amp;ct=lan&amp;hp=n&amp;tl=&amp;si=http%3A//jianzp.go.nease.net/scroll.htm&amp;rp=http%3A//jianzp.go.nease.net/" width=1>&nbsp;</p>
<img src ="http://www.cppblog.com/justin-shi/aggbug/56730.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/justin-shi/" target="_blank">幽幽</a> 2008-07-21 09:57 <a href="http://www.cppblog.com/justin-shi/archive/2008/07/21/56730.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>如何让类的成员函数作为回调函数</title><link>http://www.cppblog.com/justin-shi/archive/2008/07/06/55448.html</link><dc:creator>幽幽</dc:creator><author>幽幽</author><pubDate>Sat, 05 Jul 2008 19:58:00 GMT</pubDate><guid>http://www.cppblog.com/justin-shi/archive/2008/07/06/55448.html</guid><wfw:comment>http://www.cppblog.com/justin-shi/comments/55448.html</wfw:comment><comments>http://www.cppblog.com/justin-shi/archive/2008/07/06/55448.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/justin-shi/comments/commentRss/55448.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/justin-shi/services/trackbacks/55448.html</trackback:ping><description><![CDATA[&nbsp;&nbsp;&nbsp;&nbsp; 摘要: &nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 为什么类(class)的成员函(member function)数不能作为回调函数(callback function)首先来看看回调函数有怎样的特点。windows中，回调函都显式(explicit)使用CALLBACK修饰符(decorator)修饰(decorated)。实际上CALLBACK就是_stdcall参数传...&nbsp;&nbsp;<a href='http://www.cppblog.com/justin-shi/archive/2008/07/06/55448.html'>阅读全文</a><img src ="http://www.cppblog.com/justin-shi/aggbug/55448.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/justin-shi/" target="_blank">幽幽</a> 2008-07-06 03:58 <a href="http://www.cppblog.com/justin-shi/archive/2008/07/06/55448.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于GetDC与GetWindowDC</title><link>http://www.cppblog.com/justin-shi/archive/2008/06/26/54627.html</link><dc:creator>幽幽</dc:creator><author>幽幽</author><pubDate>Thu, 26 Jun 2008 00:27:00 GMT</pubDate><guid>http://www.cppblog.com/justin-shi/archive/2008/06/26/54627.html</guid><wfw:comment>http://www.cppblog.com/justin-shi/comments/54627.html</wfw:comment><comments>http://www.cppblog.com/justin-shi/archive/2008/06/26/54627.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/justin-shi/comments/commentRss/54627.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/justin-shi/services/trackbacks/54627.html</trackback:ping><description><![CDATA[<p><span><font face="Times New Roman" size=2>=============================================================</font></span></p>
<p><font size=2><span><font face="Times New Roman">GetDc</font></span><span>函</span><span>数：</span><span>用于获得</span><span><font face="Times New Roman">hWnd</font></span><span>参数所指定窗口的客户区域的一个设备环境。</span></font></p>
<p><font size=2><span>所获得的设备环境可以是通用、类或者私有类型，具体由指定窗口的类风格决定。对于通用设备环境，</span><span><font face="Times New Roman">GetDc</font></span><span>函数每次获取一个设备环境时都会用默认属性对它进行初始化。该函数获得的类和私有设备环境会与它们最后一次的设置保持一致。当设备环境不再需要时，应该调用</span><span><font face="Times New Roman">ReleaseDC</font></span><span>函数将其释放。</span></font><font size=2><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>GetWindowDC</font></span><span>函数：返回</span><span><font face="Times New Roman">hWnd</font></span><span>参数所指定的窗口的设备环境。</span></font></p>
<p><font size=2><span>获得的设备环境覆盖了整个窗口（包括非客户区），例如标题栏、菜单、滚动条，以及边框。这使得程序能够在非客户区域实现自定义图形，例如自定义标题或者边框。当不再需要该设备环境时，需要调用</span><span><font face="Times New Roman">ReleaseDC</font></span><span>函数释放设备环境。注意，该函数只获得通用设备环境，该设备环境的任何属性改变都不会反映到窗口的私有或者类设备环境中（如果窗口有的话）</span></font><font size=2><span><font face="Times New Roman">&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp;&nbsp;&nbsp;<br>&nbsp;&nbsp; ----------</font></span><span>摘自《</span><span><font face="Times New Roman">Delphi&nbsp;&nbsp;&nbsp; Win32</font></span><span>核心</span><span><font face="Times New Roman">API</font></span><span>参考》</span></font></p>
<p><span><font face="Times New Roman" size=2>=============================================================</font></span></p>
<img src ="http://www.cppblog.com/justin-shi/aggbug/54627.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/justin-shi/" target="_blank">幽幽</a> 2008-06-26 08:27 <a href="http://www.cppblog.com/justin-shi/archive/2008/06/26/54627.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>用IPicture显示图片</title><link>http://www.cppblog.com/justin-shi/archive/2008/06/24/54475.html</link><dc:creator>幽幽</dc:creator><author>幽幽</author><pubDate>Tue, 24 Jun 2008 09:15:00 GMT</pubDate><guid>http://www.cppblog.com/justin-shi/archive/2008/06/24/54475.html</guid><wfw:comment>http://www.cppblog.com/justin-shi/comments/54475.html</wfw:comment><comments>http://www.cppblog.com/justin-shi/archive/2008/06/24/54475.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/justin-shi/comments/commentRss/54475.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/justin-shi/services/trackbacks/54475.html</trackback:ping><description><![CDATA[<span style="COLOR: #0000ff">void</span><span style="COLOR: #000000"> CxxxView::OnDraw(CDC</span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> pDC)<br>{<br>&nbsp;&nbsp;&nbsp; ::CoInitialize(NULL);&nbsp; </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> COM 初始化</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp; HRESULT hr;<br>&nbsp;&nbsp;&nbsp; CFile file;<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; file.Open( </span><span style="COLOR: #800000">"</span><span style="COLOR: #800000">c:\\aa.jpg</span><span style="COLOR: #800000">"</span><span style="COLOR: #000000">, CFile::modeRead </span><span style="COLOR: #000000">|</span><span style="COLOR: #000000"> CFile::shareDenyNone );&nbsp; </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 读入文件内容</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp; DWORD dwSize </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> file.GetLength();<br>&nbsp;&nbsp;&nbsp; HGLOBAL hMem </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> ::GlobalAlloc( GMEM_MOVEABLE, dwSize );<br>&nbsp;&nbsp;&nbsp; LPVOID lpBuf </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> ::GlobalLock( hMem );<br>&nbsp;&nbsp;&nbsp; file.ReadHuge( lpBuf, dwSize );<br>&nbsp;&nbsp;&nbsp; file.Close();<br>&nbsp;&nbsp;&nbsp; ::GlobalUnlock( hMem );<br><br>&nbsp;&nbsp;&nbsp; IStream </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> pStream </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> NULL;<br>&nbsp;&nbsp;&nbsp; IPicture </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> pPicture </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> NULL;<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 由 HGLOBAL 得到 IStream，参数 TRUE 表示释放 IStream 的同时，释放内存</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp; hr </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> ::CreateStreamOnHGlobal( hMem, TRUE, </span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">pStream );<br>&nbsp;&nbsp;&nbsp; ASSERT ( SUCCEEDED(hr) );<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; hr </span><span style="COLOR: #000000">=</span><span style="COLOR: #000000"> ::OleLoadPicture( pStream, dwSize, TRUE, IID_IPicture, ( LPVOID </span><span style="COLOR: #000000">*</span><span style="COLOR: #000000"> )</span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">pPicture );<br>&nbsp;&nbsp;&nbsp; ASSERT(hr</span><span style="COLOR: #000000">==</span><span style="COLOR: #000000">S_OK);<br>&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; </span><span style="COLOR: #0000ff">long</span><span style="COLOR: #000000"> nWidth,nHeight;&nbsp; </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 宽高，MM_HIMETRIC 模式，单位是0.01毫米</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp; pPicture</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">get_Width( </span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">nWidth );&nbsp;&nbsp;&nbsp; </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 宽</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp; pPicture</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">get_Height( </span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">nHeight );&nbsp; </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 高</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; </span><span style="COLOR: #808080">//////</span><span style="COLOR: #008000">//原大显示</span><span style="COLOR: #808080">//////<br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp; CSize sz( nWidth, nHeight );<br>&nbsp;&nbsp;&nbsp; pDC</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">HIMETRICtoDP( </span><span style="COLOR: #000000">&amp;</span><span style="COLOR: #000000">sz );&nbsp; </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 转换 MM_HIMETRIC 模式单位为 MM_TEXT 像素单位</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp; pPicture</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">Render(pDC</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">m_hDC,</span><span style="COLOR: #800080">0</span><span style="COLOR: #000000">,</span><span style="COLOR: #800080">0</span><span style="COLOR: #000000">,sz.cx,sz.cy,<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; </span><span style="COLOR: #800080">0</span><span style="COLOR: #000000">,nHeight,nWidth,</span><span style="COLOR: #000000">-</span><span style="COLOR: #000000">nHeight,NULL);<br>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; </span><span style="COLOR: #808080">//////</span><span style="COLOR: #008000">//按窗口尺寸显示</span><span style="COLOR: #808080">//////</span><span style="COLOR: #008000">//</span><span style="COLOR: #808080"><br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;&nbsp;&nbsp; CRect rect;&nbsp;&nbsp;&nbsp; GetClientRect(&amp;rect);<br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;&nbsp;&nbsp; pPicture-&gt;Render(pDC-&gt;m_hDC,0,0,rect.Width(),rect.Height(),<br></span><span style="COLOR: #008000">//</span><span style="COLOR: #008000">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; 0,nHeight,nWidth,-nHeight,NULL);</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000"><br>&nbsp;&nbsp;&nbsp; </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( pPicture ) pPicture</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">Release();</span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 释放 IPicture 指针</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp; </span><span style="COLOR: #0000ff">if</span><span style="COLOR: #000000"> ( pStream ) pStream</span><span style="COLOR: #000000">-&gt;</span><span style="COLOR: #000000">Release();&nbsp; </span><span style="COLOR: #008000">//</span><span style="COLOR: #008000"> 释放 IStream 指针，同时释放了 hMem</span><span style="COLOR: #008000"><br></span><span style="COLOR: #000000">&nbsp;&nbsp;&nbsp; <br>&nbsp;&nbsp;&nbsp; ::CoUninitialize();<br>}<br></span>
<img src ="http://www.cppblog.com/justin-shi/aggbug/54475.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/justin-shi/" target="_blank">幽幽</a> 2008-06-24 17:15 <a href="http://www.cppblog.com/justin-shi/archive/2008/06/24/54475.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>GetItemPosition和GetItemRect</title><link>http://www.cppblog.com/justin-shi/archive/2008/06/22/54276.html</link><dc:creator>幽幽</dc:creator><author>幽幽</author><pubDate>Sun, 22 Jun 2008 02:13:00 GMT</pubDate><guid>http://www.cppblog.com/justin-shi/archive/2008/06/22/54276.html</guid><wfw:comment>http://www.cppblog.com/justin-shi/comments/54276.html</wfw:comment><comments>http://www.cppblog.com/justin-shi/archive/2008/06/22/54276.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/justin-shi/comments/commentRss/54276.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/justin-shi/services/trackbacks/54276.html</trackback:ping><description><![CDATA[<p>CListCtrl::GetItemPosition </p>
<p>BOOL&nbsp;&nbsp; GetItemPosition(int&nbsp;&nbsp; nItem,LPPOINT&nbsp;&nbsp; lpPoint)&nbsp;&nbsp; const </p>
<p>返回值：如果成功，则返回非零值，否则为0。 </p>
<p>参数：&nbsp;&nbsp; nItem&nbsp;&nbsp; 要获取位置的项的索引值。&nbsp;&nbsp;&nbsp;&nbsp; <br>lpPoint&nbsp;&nbsp; 在视图坐标中接受项左上角位置POINT结构的地址，按视图坐标。&nbsp;&nbsp;&nbsp;&nbsp; </p>
<p>说明：获取列表视图项的位置。 <br>////////////////////////////////////////////////////////////// <br>CListCtrl::GetItemRect </p>
<p>BOOL&nbsp;&nbsp; GetItemRect(int&nbsp;&nbsp; nItem,LPRECT&nbsp;&nbsp; lpRect,UNIT&nbsp;&nbsp; nCode)&nbsp;&nbsp; const </p>
<p>返回值：如果成功，则返回非零值，否则为0。 </p>
<p>参数：&nbsp;&nbsp; nItem&nbsp;&nbsp; 要获取位置的项的索引值。&nbsp;&nbsp;&nbsp;&nbsp; <br>lpRect&nbsp;&nbsp; 接受绑定矩形的RECT结构的地址。&nbsp;&nbsp;&nbsp;&nbsp; <br>nCode&nbsp;&nbsp; 要获取绑定矩形的列表视图项的部分。它可为下列值之一：&nbsp;&nbsp; &#183;&nbsp;&nbsp; LVIR_BOUNDS&nbsp;&nbsp; 返回整个项的绑定矩形，包括图标和标签。&nbsp;&nbsp;&nbsp;&nbsp; <br>&#183;&nbsp;&nbsp; LVIR_ICON&nbsp;&nbsp; 返回图标或小图标的绑定矩形。&nbsp;&nbsp;&nbsp;&nbsp; <br>&#183;&nbsp;&nbsp; LVIR_LABEL&nbsp;&nbsp; 返回项文本的绑定矩形。&nbsp;&nbsp;&nbsp;&nbsp; <br>&nbsp; </p>
<p>说明： <br>在当前视图中获取某项的全部或部分的绑定矩形。 <br></p>
<img src ="http://www.cppblog.com/justin-shi/aggbug/54276.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/justin-shi/" target="_blank">幽幽</a> 2008-06-22 10:13 <a href="http://www.cppblog.com/justin-shi/archive/2008/06/22/54276.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>关于获得MFC窗口其它类指针的方法</title><link>http://www.cppblog.com/justin-shi/archive/2008/06/14/53196.html</link><dc:creator>幽幽</dc:creator><author>幽幽</author><pubDate>Fri, 13 Jun 2008 21:20:00 GMT</pubDate><guid>http://www.cppblog.com/justin-shi/archive/2008/06/14/53196.html</guid><wfw:comment>http://www.cppblog.com/justin-shi/comments/53196.html</wfw:comment><comments>http://www.cppblog.com/justin-shi/archive/2008/06/14/53196.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/justin-shi/comments/commentRss/53196.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/justin-shi/services/trackbacks/53196.html</trackback:ping><description><![CDATA[<p>获得CWinApp:<br>&nbsp;-在CMainFrame,CChildFrame,CDocument,CView中直接调用AfxGetApp()或用theApp<br>&nbsp;-在其它类中只能用AfxGetApp()</p>
<p>获得CMainFrame:<br>&nbsp;-在CMinApp中用AfxGetMainWnd()或者m_pMainWnd<br>&nbsp;-在CChildFrame中可用GetParentFrame()<br>&nbsp;-在其它类中用AfxGetMainWnd()</p>
<p>获得CChildFrame:<br>&nbsp;-在CView中用GetParentFrame()<br>&nbsp;-在CMainFrame中用MDIGetActive()或GetActiveFrame()<br>&nbsp;-在其它类中用AfxGetMainWnd()-&gt;MDIGetActive()或AfxGetMainWnd()-&gt;GetActiveFrame()</p>
<p>获得CDocument:<br>&nbsp;-在CView中用GetDocument()<br>&nbsp;-在CChildFrame中用GetActiveView()-&gt;GetDocument()<br>&nbsp;-在CMainFrame中用<br>&nbsp;&nbsp;-if SDI:GetActiveView()-&gt;GetDocument()<br>&nbsp;&nbsp;-if MDI:MDIGetActive()-&gt;GetActiveView()-&gt;GetDocument()<br>&nbsp;-在其它类中<br>&nbsp;&nbsp;-if SDI:AfxGetMainWnd()-&gt;GetActiveView()-&gt;GetDocument()<br>&nbsp;&nbsp;-if MDI:AfxGetMainWnd()-&gt;MDIGetActive()-&gt;GetActiveView()-&gt;GetDocument()</p>
<p>获得CView:<br>&nbsp;-在CDocument中 POSITION pos = GetFirstViewPosition();GetNextView(pos)<br>&nbsp;-在CChildFrame中 GetActiveView()<br>&nbsp;-在CMainFrame中<br>&nbsp;&nbsp;-if SDI:GetActiveView()<br>&nbsp;&nbsp;-if MDI:MDIGetActive()-&gt;GetActiveView()<br>&nbsp;-在其它类中<br>&nbsp;&nbsp;-if SDI:AfxGetMainWnd()-&gt;GetActiveView()<br>&nbsp;&nbsp;-if MDI:AfxGetMainWnd()-&gt;MDIGetActive()-&gt;GetActiveView()</p>
<p><br>不过要注意在doc中要取得view的指针C*View要注意类C*View声明的问题,<br>因为默认情况下,mfc在*View.h中已经包含了*Doc.h,如果在*Doc.h中包含<br>*View.h,就会引起嵌套包含问题,这样要在*Doc.h中加入 class C*View;<br>而在*Doc.cpp中加入 #include "*View.h"</p>
<p>//////////////////////////////////////////////////////////////////<br>其实完全可以在CYourApp中添加各种视或文档的指针，在那些视或文档初<br>始化的时候将指针传给CYourApp中的对应变量，这样以后不管在哪用上面<br>指针只需(CYourApp*)AfxGetApp()取其属性变量即可，明了而且清楚更是<br>方便我一直专门操作的说：）</p>
<p>//////////////////////////////////////////////////////////////////<br>我先抛块砖，有玉的砸过来！<br>在何时何地，你都可以通过以下方法精确的得到任何一个对象（Application，DocTemplate,Document，View,Frame）<br>1。通过AfxGetApp()得到当前的App对象；<br>2。通过AfxGetMainWnd（）得到主窗口；<br>3。通过CMDIFrameWnd::GetActiveFrame得到当前活动窗口；<br>4。通过GetNextWindow()遍例所有的子窗口；（如果要得到你想要的子窗口，可以通过特定的成员变量来标志）；<br>5。通过CWinApp::GetFirstDocTemplatePostion()以及CWinApp::GetNextDocTemplate()的组合应用来遍历所有的DocTemplate对象，并且用CDocTemplate::GetDocString()来判断当前得到的文档莫板对象是哪个。<br>6。通过CDocTemplate::GetFirstDocPosition()以及CDocTemplate的GetNextDoc（）组合来遍历所有的该模板的文档对象，并用CDocument::GetDocTemplate()来得到文档模板，用CDocment::GetTitle() 或者GetPathName()来判断当前的文档是哪个。<br>7。通过CDocuemt的GetFirstViewPositon()以及GetNextView()来遍历视图对象，一般通过访问View的成员变量来区别各个视图；通过CView::GetDocument()来得到文档对象；<br>8。Frame-&gt;View： 通过GetActiveView方法；<br>9。Frame-&gt;Doc：通过GetActiveDocument();<br>10。View-&gt;Frame：GetParentFrame();<br>11。View-&gt;Doc:GetDocuemt()//前面已经说了。<br>12。Doc-&gt;View:前面说了；<br>13。Doc-&gt;Frame:不知道有没有很直接的方法。<br>MFC应用程序中指针的使用</p>
<p>1) 在View中获得Doc指针<br>2) 在App中获得MainFrame指针<br>3) 在View中获得MainFrame指针<br>4) 获得View（已建立）指针<br>5) 获得当前文档指针<br>6) 获得状态栏与工具栏指针<br>7) 获得状态栏与工具栏变量<br>8) 在Mainframe获得菜单指针<br>9) 在任何类中获得应用程序类<br>10) 从文档类取得视图类的指针(1)<br>11) 在App中获得文档模板指针<br>12) 从文档模板获得文档类指针<br>13) 在文档类中获得文档模板指针<br>14) 从文档类取得视图类的指针(2)<br>15) 从一个视图类取得另一视图类的指针</p>
<p>VC中编程对于刚刚开始学习的同学，最大的障碍和问题就是消息机制和指针获取与<br>操作。其实这些内容基本上是每本VC学习工具书上必讲的内容，而且通过MSDN很多<br>问题都能解决。下面文字主要是个人在编程中指针使用的一些体会，说的不当的地<br>方请指正。一般我们使用的框架是VC提供的Wizard生成的MFC App Wizard(exe)框架，<br>无论是多文档还是单文档，都存在指针获取和操作问题。下面这节内容主要是一般<br>的框架，然后再讲多线程中的指针使用。使用到的类需要包含响应的头文件。首先<br>一般获得本类(视，文档，对话框都支持)实例指针this，用this的目的，主要可以通<br>过类中的函数向其他类或者函数中发指针，以便于在非本类中操作和使用本类中的<br>功能。</p>
<p>&nbsp;1） 在View中获得Doc指针 CYouSDIDoc *pDoc=GetDocument();一个视只能有一个文<br>档。<br>&nbsp;2) 在App中获得MainFrame指针<br>CWinApp 中的 m_pMainWnd变量就是MainFrame的指针<br>也可以： CMainFrame *pMain =(CMainFrame *)AfxGetMainWnd();<br>&nbsp;3) 在View中获得MainFrame指针 CMainFrame *pMain=(CmaimFrame *)AfxGetApp()-&gt;m_pMainWnd;<br>&nbsp;4) 获得View（已建立）指针 CMainFrame *pMain=(CmaimFrame *)AfxGetApp()-&gt;m_pMainWnd;<br>CyouView *pView=(CyouView *)pMain-&gt;GetActiveView();<br>&nbsp;5) 获得当前文档指针 CDocument * pCurrentDoc =(CFrameWnd *)m_pMainWnd-&gt;GetActiveDocument();<br>&nbsp;6) 获得状态栏与工具栏指针 CStatusBar * pStatusBar＝(CStatusBar *)AfxGetMainWnd()-&gt;GetDescendantWindow(AFX_IDW_STATUS_BAR);<br>CToolBar * pToolBar=(CtoolBar *)AfxGetMainWnd()-&gt;GetDescendantWindow(AFX_IDW_TOOLBAR);</p>
<p>&nbsp;7) 如果框架中加入工具栏和状态栏变量还可以这样<br>(CMainFrame *)GetParent()-&gt;m_wndToolBar;<br>(CMainFrame *)GetParent()-&gt;m_wndStatusBar;</p>
<p>&nbsp;8) 在Mainframe获得菜单指针 CMenu *pMenu=m_pMainWnd-&gt;GetMenu();<br>&nbsp;9) 在任何类中获得应用程序类<br>用MFC全局函数AfxGetApp()获得。</p>
<p>&nbsp;10) 从文档类取得视图类的指针<br>我是从<a href="http://download.cqcnc.com/soft/program/article/vc/vc405.html"><u><font color=#0000ff>http://download.cqcnc.com/soft/program/article/vc/vc405.html</font></u></a>学到的，<br>从文档获得视图类指针目的一般为了控制同一文档的多个视图的定位问题，我的体会<br>特别是文字处理CEditView当产生多个视图类时，这个功能是非常需要的。<br>CDocument类提供了两个函数用于视图类的定位：<br>GetFirstViewPosition()和GetNextView()<br>virtual POSITION GetFirstViewPosition() const;<br>virtual CView* GetNextView(POSITION&amp; rPosition) const;</p>
<p>注意：GetNextView()括号中的参数用的是引用方式，因此执行后值可能改变。<br>GetFirstViewPosition()用于返回第一个视图位置（返回的并非视图类指针，而是一<br>个POSITION类型值），GetNextView()有两个功能：返回下一个视图类的指针以及用<br>引用调用的方式来改变传入的POSITION类型参数的值。很明显，在Test程序中，只有<br>一个视图类，因此只需将这两个函数调用一次即可得到CTestView的指针如下（需定<br>义一个POSITION结构变量来辅助操作）：<br>CTestView* pTestView;<br>POSITION pos=GetFirstViewPosition();<br>pTestView=GetNextView(pos);</p>
<p>这样，便可到了CTestView类的指针pTestView.执行完几句后，变量pos=NULL,因为没<br>有下一个视图类，自然也没有下一个视图类的POSITION.但是这几条语句太简单，不<br>具有太强的通用性和安全特征；当象前面说的那样，当要在多个视图为中返回某个指<br>定类的指针时，我们需要遍历所有视图类，直到找到指定类为止。判断一个类指针指<br>向的是否某个类的实例时，可用IsKindOf()成员函数时行检查，如：<br>&nbsp;pView-&gt;IsKindOf(RUNTIME_CLASS(CTestView));<br>即可检查pView所指是否是CTestView类。</p>
<p>有了以上基础，我们已经可以从文档类取得任何类的指针。为了方便，我们将其作<br>为一个文档类的成员函数，它有一个参数，表示要获得哪个类的指针。实现如下：<br>CView* CTestDoc::GetView(CRuntimeClass* pClass)<br>{<br>&nbsp;CView* pView;<br>&nbsp;POSITION pos=GetFirstViewPosition();</p>
<p>&nbsp;while(pos!=NULL){<br>&nbsp;&nbsp;pView=GetNextView(pos);<br>&nbsp;&nbsp;if(!pView-&gt;IsKindOf(pClass))<br>&nbsp;&nbsp;break;<br>&nbsp;}</p>
<p>&nbsp;if(!pView-&gt;IsKindOf(pClass)){<br>&nbsp;&nbsp;AfxMessageBox("Connt Locate the View.\r\n <a href="http://www.vckbase.com/"><u><font color=#0000ff>http://www.VCKBASE.com</font></u></a>");<br>&nbsp;&nbsp;return NULL;<br>&nbsp;}</p>
<p>&nbsp;return pView;<br>}</p>
<p>其中用了两次视图类的成员函数IsKindOf()来判断，是因为退出while循环有三种<br>可能：</p>
<p>1.pos为NULL，即已经不存在下一个视图类供操作；<br>2.pView已符合要求。</p>
<p>1和2同是满足。这是因为GetNextView()的功能是将当前视图指针改变成一个视图<br>的位置同时返回当前视图指针，因此pos是pView的下一个视图类的POSITION,完全<br>有可能既是pos==NULL又是pView符合需要。当所需的视图是最后一个视图是最后一<br>个视图类时就如引。因此需采用两次判断。<br>使用该函数应遵循如下格式（以取得CTestView指针为例）：<br>CTestView* pTestView=(CTestView*)GetView(RUNTIME_CLASS(CTestView));<br>RUNTIME_CLASS是一个宏，可以简单地理解它的作用：将类的名字转化为<br>CRuntimeClass为指针。至于强制类型转换也是为了安全特性考虑的，因为从同一个<br>基类之间的指针类型是互相兼容的。这种强制类型转换也许并不必要，但能避免一<br>些可能出现的麻烦。</p>
<p>3.从一个视图类取得另一视图类的指针综合1和2，很容易得出视图类之间互相获得<br>指针的方法：就是用文档类作中转，先用1的方法得到文档类的指针，再用2的方法，<br>以文档类的视图定位函数取得另一个视图类。同样，可以实现成一个函数：<br>（假设要从CTestAView中取得指向其它视图类的指针）<br>CView* CTestAView::GetView(CRuntimeClass* pClass)<br>{<br>&nbsp;CTestDoc* pDoc=(CTestDoc*)GetDocument();<br>&nbsp;CView* pView;<br>&nbsp;POSITION pos=pDoc-&gt;GetFirstViewPosition();<br>&nbsp;while(pos!=NULL){<br>&nbsp;&nbsp;pView=pDoc-&gt;GetNextView(pos);<br>&nbsp;&nbsp;if(!pView-&gt;IsKindOf(pClass))<br>&nbsp;&nbsp;break;<br>&nbsp;}<br>&nbsp;if(!pView-&gt;IsKindOf(pClass)){<br>&nbsp;&nbsp;AfxMessageBox("Connt Locate the View.");<br>&nbsp;&nbsp;return NULL;<br>&nbsp;}</p>
<p>&nbsp;return pView;<br>}<br>这个函数和2中的GetView()相比，一是多了第一句以取得文档类指针，二是在<br>GetFirstViewPosition()和GetNextView()前加上了文档类指针，以表示它们是文档<br>类成员函数。有了此函数；当要从CTestAView中取得CTestBView的指针时，只需如<br>下：CTestBView* pTestbView=(CTestView*)GetView(RUNTIME_CLASS(CTestBView));<br>11）对于单文档中也可以加入多个文档模板，但是一般的开发就使用MDI方式开发<br>多文档模板，其方法与上述视图的获取方法很接近，这里稍做解释，如果不清楚，<br>请查阅MSDN，（以下四个内容（11、12、13、14）来源：<br><a href="http://sanjianxia.myrice.com/vc/vc45.htm"><u><font color=#0000ff>http://sanjianxia.myrice.com/vc/vc45.htm</font></u></a>）</p>
<p>可以用CWinApp::GetFirstDocTemplatePostion获得应用程序注册的第一个文档模板<br>的位置；利用该值来调用CWinApp::GetNextDocTemplate函数，获得第一个<br>CDocTemplate对象指针。 POSITION GetFirstDocTemplate( ) const;<br>CDocTemplate *GetNextDocTemplate( POSITION &amp; pos ) const;</p>
<p>第二个函数返回由pos 标识的文档模板。POSITION是MFC定义的一个用于迭代或对象<br>指针检索的值。通过这两个函数，应用程序可以遍历整个文档模板列表。如果被检索<br>的文档模板是模板列表中的最后一个，则pos参数被置为NULL。</p>
<p>&nbsp;12）一个文档模板可以有多个文档，每个文档模板都保留并维护了一个所有对应文<br>档的指针列表。<br>用CDocTemplate::GetFirstDocPosition函数获得与文档模板相关的文档集合中第一<br>个文档的位置，并用POSITION值作为CDocTemplate::GetNextDoc的参数来重复遍历与<br>模板相关的文档列表。函数原形为：<br>viaual POSITION GetFirstDocPosition( ) const = 0;<br>visual CDocument *GetNextDoc(POSITION &amp; rPos) const = 0;&nbsp;</p>
<p>如果列表为空，则rPos被置为NULL.</p>
<p>&nbsp;13）在文档中可以调用CDocument::GetDocTemplate获得指向该文档模板的指针。<br>函数原形如下： CDocTemplate * GetDocTemplate ( ) const;<br>如果该文档不属于文档模板管理，则返回值为NULL。</p>
<p>&nbsp;14)一个文档可以有多个视。每一个文档都保留并维护一个所有相关视的列表。<br>CDocument::AddView将一个视连接到文档上，将该视加入到文档相联系的视的列表<br>中，并将视的文档指针指向该文档。当有File/New、File/Open、Windows/New或<br>Window/Split的命令而将一个新创建的视的对象连接到文档上时， MFC会自动调用<br>该函数，框架通过文档/视的结构将文档和视联系起来。当然，程序员也可以根据自<br>己的需要调用该函数。<br>Virtual POSITION GetFirstViewPosition( ) const;<br>Virtual CView * GetNextView( POSITION &amp;rPosition) cosnt;</p>
<p>应用程序可以调用CDocument::GetFirstViewPosition返回与调用文档相联系的视的<br>列表中的第一个视的位置，并调用CDocument::GetNextView返回指定位置的视，并将<br>rPositon的值置为列表中下一个视的POSITION值。如果找到的视为列表中的最后一个<br>视，则将rPosition置为NULL.</p>
<p>&nbsp;15)从一个视图类取得另一视图类的指针<br>这个应用在多视的应用程序中很多见，一般如果自己在主程序或者主框架中做好变<br>量记号，也可以获得，还有比较通用的就是用文档类作中转，以文档类的视图遍历<br>定位，取得另一个视图类。这个功能从本文第10项中可以得到。<br></p>
<img src ="http://www.cppblog.com/justin-shi/aggbug/53196.html" width = "1" height = "1" /><br><br><div align=right><a style="text-decoration:none;" href="http://www.cppblog.com/justin-shi/" target="_blank">幽幽</a> 2008-06-14 05:20 <a href="http://www.cppblog.com/justin-shi/archive/2008/06/14/53196.html#Feedback" target="_blank" style="text-decoration:none;">发表评论</a></div>]]></description></item><item><title>CListCtrl使用详解</title><link>http://www.cppblog.com/justin-shi/archive/2008/06/14/53192.html</link><dc:creator>幽幽</dc:creator><author>幽幽</author><pubDate>Fri, 13 Jun 2008 18:48:00 GMT</pubDate><guid>http://www.cppblog.com/justin-shi/archive/2008/06/14/53192.html</guid><wfw:comment>http://www.cppblog.com/justin-shi/comments/53192.html</wfw:comment><comments>http://www.cppblog.com/justin-shi/archive/2008/06/14/53192.html#Feedback</comments><slash:comments>0</slash:comments><wfw:commentRss>http://www.cppblog.com/justin-shi/comments/commentRss/53192.html</wfw:commentRss><trackback:ping>http://www.cppblog.com/justin-shi/services/trackbacks/53192.html</trackback:ping><description><![CDATA[<table cellSpacing=0 cellPadding=0 width=780 align=center border=0>
    <tbody>
        <tr>
            <td vAlign=top width=600>
            <h3>1。先来介绍REPORT类型的CListCtrl：<br>首先使用下面的语句设置CListCtrl的style：<br>&nbsp;<font color=#0000ff>DWORD SetExtendedStyle( DWORD dwNewStyle );<br></font>其中<br>&nbsp;LVS_EX_CHECKBOXES&nbsp;表示添加CheckBox<br>&nbsp;LVS_EX_FULLROWSELECT&nbsp;表示选择整行<br>&nbsp;LVS_EX_GRIDLINES&nbsp;表示添加表格线</h3>
            <p>如果设置了LVS_EX_CHECKBOXES属性，则可以用<br>&nbsp;<font color=#0000ff>BOOL GetCheck( int nItem ) const;<br></font>来得到某一行是否Checked。</p>
            <p>可以先用下面的语句来删除以前的东西：<br>&nbsp;<font color=#0000ff>for(int k=2;k&gt;=0;k--)&nbsp;//注意要从后往前删，否则出错<br>&nbsp;&nbsp;m_ListCtrl.DeleteColumn(k);<br>&nbsp;m_ListCtrl.DeleteAllItems();</font></p>
            <p>用下面的语句新建列：<br>&nbsp;<font color=#0000ff>m_ListCtrl.InsertColumn(0,_T("文件名"),LVCFMT_IMAGE|LVCFMT_LEFT);<br>&nbsp;m_ListCtrl.InsertColumn(1,_T("仪器类别"));<br>&nbsp;m_ListCtrl.InsertColumn(2,_T("项目类别"));<br></font>&nbsp;<br>其中LVCFMT_IMAGE表示可以在第一列加入图标。如果不要图标可以删去。</p>
            <p>然后设置列宽：<br>&nbsp;<font color=#0000ff>for(j=0;j&lt;3;j++)<br>&nbsp;&nbsp;m_ListCtrl.SetColumnWidth(j ,100);<br></font>&nbsp;<br>以下为列表加入图标，如果不需要图标，可以跳过这一步。注意只在第一次加入，如果多次加入会出错！<br>先在头文件中加入声明：<br>&nbsp;<font color=#0000ff>CImageList m_ImageList;<br></font>这是必要的，如果在cpp的某个函数中加入由于生命期结束，CImageList自动释放，则效果是列表中看不到图标，只看到一个白方块。<br>下面生成CImageList，并将其绑定到CListCtrl中，这是CImageList中还没有图标，只是一个容器：<br>&nbsp;<font color=#0000ff>static int flag=2;<br>&nbsp;if(flag==2){//只调用一次SetImageList，否则出错<br>&nbsp;&nbsp;m_ImageList.Create(128, 128, ILC_COLORDDB|ILC_MASK, 20, 1);&nbsp;<br>&nbsp;&nbsp;m_ListCtrl.SetImageList(&amp;m_ImageList,LVSIL_SMALL);<br>&nbsp;}<br>&nbsp;flag=(flag+1)%2;<br></font>如果CListCtrl已经用过，曾经加过图标进去，这时就要删除上次放进m_ImageList中的Image<br>&nbsp;<font color=#0000ff>for(int kk=0;kk&lt;m_ImageList.GetImageCount();kk++)<br>&nbsp;&nbsp;m_ImageList.Remove(k);<br></font>&nbsp;<br>下面介绍如何向CListCtrl里面加入行，并同时为每一行<strong>动态</strong>加入图标：<br>假设m_listRowCount为要加入的行数。<br>&nbsp;<font color=#0000ff>CBitmap* bitmap;<br>&nbsp;bitmap=new CBitmap[m_list1rowCount];<br>&nbsp;HBITMAP hbitmap;&nbsp;<br>&nbsp;<br>&nbsp;for(int i = 0; i &lt; m_listRowCount; i++)<br>&nbsp;{<br>&nbsp;&nbsp;//为每一行插入相应的缩略图<br>&nbsp;&nbsp;CFile f;<br>&nbsp;&nbsp;CFileException e;&nbsp;&nbsp;<br>&nbsp;&nbsp;if( !f.Open(m_FileName, CFile::modeRead, &amp;e )){&nbsp;//m_FileName为bmp文件名，由你来定<br>&nbsp;&nbsp;&nbsp;hbitmap = (HBITMAP)LoadImage(NULL,path+"blank.bmp",IMAGE_BITMAP,0,0,<br>&nbsp;&nbsp;&nbsp;&nbsp;LR_CREATEDIBSECTION|LR_DEFAULTSIZE|LR_LOADFROMFILE);<br>&nbsp;&nbsp;}else{<br>&nbsp;&nbsp;&nbsp;f.Close();<br>&nbsp;&nbsp;&nbsp;hbitmap = (HBITMAP)LoadImage(NULL,bmpFile,IMAGE_BITMAP,0,0,<br>&nbsp;&nbsp;&nbsp;&nbsp;LR_CREATEDIBSECTION|LR_DEFAULTSIZE|LR_LOADFROMFILE);<br>&nbsp;&nbsp;}<br>&nbsp;&nbsp;bitmap[i].Attach(hbitmap);<br>&nbsp;&nbsp;m_ImageList.Add(&amp;bitmap[i], RGB(0, 128, 128));<br>&nbsp;&nbsp;<br>&nbsp;&nbsp;//插入行<br>&nbsp;&nbsp;m_ListCtrl.InsertItem(i,m_FileName,i);<br>&nbsp;&nbsp;m_ListCtrl.SetItemText(i,1,type);<br>&nbsp;&nbsp;m_ListCtrl.SetItemText(i,2,m_Path);<br>&nbsp;}<br>&nbsp;&nbsp;<br>&nbsp;//记得删除已经没用的临时文件<br>&nbsp;if(m_list1rowCount!=0)<br>&nbsp;&nbsp;delete[] bitmap;</font></p>
            <p>2。如果是ICON类型的CListCtrl，则要做一点点改动：<br>把绑定图标集的代码由<br>&nbsp;<font color=#0000ff>SetImageList(&amp;m_ImageList,LVSIL_SMALL);<br></font>改为<br>&nbsp;<font color=#0000ff>SetImageList(&amp;m_ImageList,LVSIL_NORMAL);</font></p>
            <p>插入行时只用<br>&nbsp;<font color=#0000ff>InsertItem(i,mainSet.m_FileName,i);<br></font>不用<br>&nbsp;<font color=